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
pam_start(const char * service_name,const char * user,const struct pam_conv * pam_conversation,pam_handle_t ** pamh)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
pam_end(pam_handle_t * pamh,int status)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
pam_set_pwd(struct passwd * pwd)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 *
pam_modutil_getpwnam(pam_handle_t * pamh UNUSED,const char * name)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 *
getpwnam(const char * name)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