1 /* 2 * Interface for fake PAM library, used for testing. 3 * 4 * This contains the basic public interfaces for the fake PAM library, used 5 * for testing, and some general utility functions. 6 * 7 * The canonical version of this file is maintained in the rra-c-util package, 8 * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>. 9 * 10 * Written by Russ Allbery <eagle@eyrie.org> 11 * Copyright 2010-2011, 2014 12 * The Board of Trustees of the Leland Stanford Junior University 13 * 14 * Permission is hereby granted, free of charge, to any person obtaining a 15 * copy of this software and associated documentation files (the "Software"), 16 * to deal in the Software without restriction, including without limitation 17 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 18 * and/or sell copies of the Software, and to permit persons to whom the 19 * Software is furnished to do so, subject to the following conditions: 20 * 21 * The above copyright notice and this permission notice shall be included in 22 * all copies or substantial portions of the Software. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 27 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 30 * DEALINGS IN THE SOFTWARE. 31 * 32 * SPDX-License-Identifier: MIT 33 */ 34 35 #include <config.h> 36 #include <portable/pam.h> 37 #include <portable/system.h> 38 39 #include <errno.h> 40 #include <pwd.h> 41 42 #include <tests/fakepam/pam.h> 43 44 /* Stores the static struct passwd returned by getpwnam if the name matches. */ 45 static struct passwd *pwd_info = NULL; 46 47 /* Used for unused parameters to silence gcc warnings. */ 48 #define UNUSED __attribute__((__unused__)) 49 50 51 /* 52 * Initializes the pam_handle_t data structure. This function is only called 53 * from test programs, not from any of the module code. We can put anything 54 * we want in this structure, since it's opaque to the regular code. 55 */ 56 int 57 pam_start(const char *service_name, const char *user, 58 const struct pam_conv *pam_conversation, pam_handle_t **pamh) 59 { 60 struct pam_handle *handle; 61 62 handle = calloc(1, sizeof(struct pam_handle)); 63 if (handle == NULL) 64 return PAM_BUF_ERR; 65 handle->service = service_name; 66 handle->user = user; 67 handle->conversation = pam_conversation; 68 *pamh = handle; 69 return PAM_SUCCESS; 70 } 71 72 73 /* 74 * Free the pam_handle_t data structure and related resources. This is 75 * important to test the data cleanups. Freeing the memory is not strictly 76 * required since it's only used for testing, but it helps keep our memory 77 * usage clean so that we can run the test suite under valgrind. 78 */ 79 int 80 pam_end(pam_handle_t *pamh, int status) 81 { 82 struct fakepam_data *item, *next; 83 size_t i; 84 85 if (pamh->environ != NULL) { 86 for (i = 0; pamh->environ[i] != NULL; i++) 87 free(pamh->environ[i]); 88 free(pamh->environ); 89 } 90 free(pamh->authtok); 91 free(pamh->oldauthtok); 92 free(pamh->rhost); 93 free(pamh->ruser); 94 free(pamh->tty); 95 for (item = pamh->data; item != NULL;) { 96 if (item->cleanup != NULL) 97 item->cleanup(pamh, item->data, status); 98 free(item->name); 99 next = item->next; 100 free(item); 101 item = next; 102 } 103 free(pamh); 104 return PAM_SUCCESS; 105 } 106 107 108 /* 109 * Interface specific to this fake PAM library to set the struct passwd that's 110 * returned by getpwnam queries if the name matches. 111 */ 112 void 113 pam_set_pwd(struct passwd *pwd) 114 { 115 pwd_info = pwd; 116 } 117 118 119 /* 120 * For testing purposes, we want to be able to intercept getpwnam. This is 121 * fairly easy on platforms that have pam_modutil_getpwnam, since then our 122 * code will always call that function and we can provide an implementation 123 * that does whatever we want. For platforms that don't have that function, 124 * we'll try to intercept the C library getpwnam function. 125 * 126 * We store only one struct passwd data structure statically. If the user 127 * we're looking up matches that, we return it; otherwise, we return NULL. 128 */ 129 #ifdef HAVE_PAM_MODUTIL_GETPWNAM 130 struct passwd * 131 pam_modutil_getpwnam(pam_handle_t *pamh UNUSED, const char *name) 132 { 133 if (pwd_info != NULL && strcmp(pwd_info->pw_name, name) == 0) 134 return pwd_info; 135 else { 136 errno = 0; 137 return NULL; 138 } 139 } 140 #else 141 struct passwd * 142 getpwnam(const char *name) 143 { 144 if (pwd_info != NULL && strcmp(pwd_info->pw_name, name) == 0) 145 return pwd_info; 146 else { 147 errno = 0; 148 return NULL; 149 } 150 } 151 #endif 152