1 PAM Testing Framework
2
3Overview
4
5 The files in this directory provide a shim PAM library that's used for
6 testing and a test framework used to exercise a PAM module.
7
8 This library and its include files define the minimum amount
9 of the PAM module interface so that PAM modules can be tested without
10 such problems as needing configuration files in /etc/pam.d or needing
11 changes to the system configuration to run a testing PAM module
12 instead of the normal system PAM modules.
13
14 The goal of this library is that all PAM code should be able to be
15 left unchanged and the code just linked with the fakepam library
16 rather than the regular PAM library. The testing code can then call
17 pam_start and pam_end as defined in the fakepam/pam.h header file and
18 inspect internal PAM state as needed.
19
20 The library also provides an interface to exercise a PAM module via an
21 interaction script, so that as much of the testing process as possible
22 is moved into simple text files instead of C code. That test script
23 format supports specifying the PAM configuration, the PAM interfaces
24 to run, the expected prompts and replies, and the expected log
25 messages. That interface is defined in fakepam/script.h.
26
27Fake PAM Library
28
29 Unfortunately, the standard PAM library for most operating systems
30 does not provide a reasonable testing framework. The primary problem
31 is configuration: the PAM library usually hard-codes a configuration
32 location such as /etc/pam.conf or /etc/pam.d/<application>. But there
33 are other problems as well, such as capturing logging rather than
34 having it go to syslog and inspecting PAM internal state to make sure
35 that it's updated properly by the module.
36
37 This library implements some of the same API as the system PAM library
38 and uses the system PAM library headers, but the underlying
39 implementation does not call the system PAM library or dynamically
40 load modules. Instead, it's meant to be linked into a single
41 executable along with the implementation of a PAM module. It does not
42 provide most of the application-level PAM interfaces (so one cannot
43 link a PAM-using application against it), just the interfaces called
44 by a module. The caller of the library can then call the module API
45 (such as pam_sm_authenticate) directly.
46
47 All of the internal state maintained by the PAM library is made
48 available to the test program linked with this library. See
49 fakepam/pam.h for the data structures. This allows verification that
50 the PAM module is setting the internal PAM state properly.
51
52 User Handling
53
54 In order to write good test suites, one often has to be able to
55 authenticate as a variety of users, but PAM modules may expect the
56 authenticating user to exist on the system. The fakepam library
57 provides a pam_modutil_getpwnam (if available) or a getpwnam
58 implementation that returns information for a single user (and user
59 unknown for everyone else). To set the information for the one valid
60 user, call the pam_set_pwd function and provide a struct passwd that
61 will be returned by pam_modutil_getpwnam.
62
63 The fakepam library also provides a replacement krb5_kuserok function
64 for testing PAM modules that use Kerberos. This source file should
65 only be included in packages that are building with Kerberos. It
66 implements the same functionality as the default krb5_kuserok
67 function, but looks for .k5login in the home directory configured by
68 the test framework instead of using getpwnam.
69
70 Only those two functions are intercepted, so if the module looks up
71 users in other ways, it may still bypass the fakepam library and look
72 at system users.
73
74 Output Handling
75
76 The fakepam library intercepts the PAM functions that would normally
77 log to syslog and instead accumulates the output in a static string
78 variable. To retrieve the logging output so far, call pam_output,
79 which returns a struct of all the output strings up to that point and
80 resets the accumulated output.
81
82Scripted PAM Testing
83
84 Also provided as part of the fakepam library is a test framework for
85 testing PAM modules. This test framework allows most of the testing
86 process to be encapsulated in a text configuration file per test,
87 rather than in a tedious set of checks and calls written in C.
88
89 Test API
90
91 The basic test API is to call either run_script (to run a single test
92 script) or run_script_dir (to run all scripts in a particular
93 directory). Both take a configuration struct that controls how the
94 PAM library is set up and called.
95
96 That configuration struct takes the following elements:
97
98 user
99 The user as which to authenticate, passed into pam_start and also
100 substituted for the %u escape. This should match the user whose
101 home directory information is configured using pam_set_pwd if that
102 function is in use.
103
104 password
105 Only used for the %p escape. This is not used to set the
106 authentication token in the PAM library (see authtok below).
107
108 newpass
109 Only used for the %n escape.
110
111 extra
112 An array of up to 10 additional strings used by the %0 through %9
113 escapes when parsing the configuration file, as discussed below.
114
115 authtok
116 Sets the default value of the PAM_AUTHTOK data item. This will be
117 set immediately after initializing the PAM library and before
118 calling any PAM module functions.
119
120 authtok
121 Like authtok, but for the PAM_OLDAUTHTOK data item.
122
123 callback
124 This, and the associated data element, specifies a callback that's
125 called at the end of processing of the script before calling
126 pam_end. This can be used to inspect and verify the internal
127 state of PAM. The data element is an opaque pointer passed into
128 the callback.
129
130 Test Script Basic Format
131
132 Test scripts are composed of one or more sections. Each section
133 begins with:
134
135 [<section>]
136
137 starting in column 1, where <section> is the name of the section. The
138 valid section types and the format of their contents are described
139 below.
140
141 Blank lines and lines starting with # are ignored.
142
143 Several strings undergo %-escape expansion as mentioned below. For
144 any such string, the following escapes are supported:
145
146 %i Current UID (not the UID of the target user)
147 %n New password
148 %p Password
149 %u Username
150 %0 extra[0]
151 ...
152 %9 extra[9]
153
154 All of these are set in the script_config struct.
155
156 Regular expression matching is supported for output lines and for
157 prompts. To mark an expected prompt or output line as a regular
158 expression, it must begin and end with a slash (/). Slashes inside
159 the regular expression do not need to be escaped. If regular
160 expression support is not available in the C library, those matching
161 tests will be skipped.
162
163 The [options] Section
164
165 The [options] section contains the PAM configuration that will be
166 passed to the module. These are the options that are normally listed
167 in the PAM configuration file after the name of the module. The
168 syntax of this section is one or more lines of the form:
169
170 <group> = <options>
171
172 where <group> is one of "account", "auth", "password", or "session".
173 The options are space-delimited and may be either option names or
174 option=value pairs.
175
176 The [run] Section
177
178 The [run] section specifies what PAM interfaces to call. It consists
179 of one or more lines in the format:
180
181 <call> = <status>
182
183 where <call> is the PAM call to make and <status> is the status code
184 that it should return. <call> is one of the PAM module interface
185 functions without the leading "pam_sm_", so one of "acct_mgmt",
186 "authenticate", "setcred", "chauthtok", "open_session", or
187 "close_session". The return status is one of the PAM constants
188 defined for return status, such as PAM_IGNORE or PAM_SUCCESS. The
189 test framework will ensure that the PAM call returns the appropriate
190 status.
191
192 The <call> may be optionally followed by an open parentheses and then
193 a list of flags separated by |, or syntactically:
194
195 <call>(<flag>|<flag>|...) = <status>
196
197 In this form, rather than passing a flags value of 0 to the PAM call,
198 the test framework will pass the combination of the provided flags.
199 The flags are PAM constants without the leading PAM_, so (for example)
200 DELETE_CRED, ESTABLISH_CRED, REFRESH_CRED, or REINITIALIZE_CRED for
201 the "setcred" call.
202
203 As a special case, <call> may be "end" to specify flags to pass to the
204 pam_end call (such as PAM_DATA_SILENT).
205
206 The [end] Section
207
208 The [end] section defines how to call pam_end. It currently takes
209 only one setting, flags, the syntax of which is:
210
211 flags = <flag>|<flag>
212
213 This allows PAM_DATA_SILENT or other flags to be passed to pam_end
214 when running the test script.
215
216 The [output] Section
217
218 The [output] section defines the logging output expected from the
219 module. It consists of zero or more lines in the format:
220
221 <priority> <output>
222 <priority> /<regex>/
223
224 where <priority> is a syslog priority and <output> is the remaining
225 output or a regular expression to match against the output. Valid
226 values for <priority> are DEBUG, INFO, NOTICE, ERR, and CRIT.
227 <output> and <regex> may contain spaces and undergoes %-escape
228 expansion.
229
230 The replacement values are taken from the script_config struct passed
231 as a parameter to run_script or run_script_dir.
232
233 If the [output] section is missing entirely, the test framework will
234 expect there to be no logging output from the PAM module.
235
236 This defines the logging output, not the prompts returned through the
237 conversation function. For that, see the next section.
238
239 The [prompts] Section
240
241 The [prompts] section defines the prompts that the PAM module is
242 expected to send via the conversation function, and the responses that
243 the test harness will send back (if any). This consists of zero or
244 more lines in one of the following formats:
245
246 <type> = <prompt>
247 <type> = /<prompt>/
248 <type> = <prompt>|<response>
249 <type> = /<prompt>/|<response>
250
251 The <type> is the style of prompt, chosen from "echo_off", "echo_on",
252 "error_msg", and "info". The <prompt> is the actual prompt sent and
253 undergoes %-escape expansion. It may be enclosed in slashes (/) to
254 indicate that it's a regular expression instead of literal text. The
255 <response> if present (and its presence is signaled by the |
256 character) contains the response sent back by the test framework and
257 also undergoes %-escape expansion. The response starts with the final
258 | character on the line, so <prompt> regular expressions may freely
259 use | inside the regular expression.
260
261 If the [prompts] section is present and empty, the test harness will
262 check that the PAM module does not send any prompts. If the [prompts]
263 section is absent entirely, the conversation function passed to the
264 PAM module will be NULL.
265
266License
267
268 This file is part of the documentation of rra-c-util, which can be
269 found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
270
271 Copyright 2011-2012, 2020-2021 Russ Allbery <eagle@eyrie.org>
272
273 Copying and distribution of this file, with or without modification,
274 are permitted in any medium without royalty provided the copyright
275 notice and this notice are preserved. This file is offered as-is,
276 without any warranty.
277