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