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