]> granicus.if.org Git - linux-pam/blob - modules/pammodutil/modutil_getpwnam.c
Relevant BUGIDs:
[linux-pam] / modules / pammodutil / modutil_getpwnam.c
1 /*
2  * $Id$
3  *
4  * This function provides a thread safer version of getpwnam() for use
5  * with PAM modules that care about this sort of thing.
6  *
7  * XXX - or at least it should provide a thread-safe alternative.
8  */
9
10 #include "pammodutil.h"
11
12 #include <limits.h>
13 #include <pthread.h>
14 #include <pwd.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17
18 static pthread_mutex_t _pammodutil_mutex = PTHREAD_MUTEX_INITIALIZER;
19 static void _pammodutil_lock(void)
20 {
21         pthread_mutex_lock(&_pammodutil_mutex);
22 }
23 static void _pammodutil_unlock(void)
24 {
25         pthread_mutex_unlock(&_pammodutil_mutex);
26 }
27
28 static int intlen(int number)
29
30     int len = 2;
31     while (number != 0) {
32         number /= 10;
33         len++;
34     }
35     return len;
36 }
37
38 struct passwd *_pammodutil_getpwnam(pam_handle_t *pamh, const char *user)
39 {
40 #ifdef HAVE_GETPWNAM_R
41
42     void *buffer=NULL;
43     size_t length = PWD_INITIAL_LENGTH;
44
45     do {
46         int status;
47         void *new_buffer;
48         struct passwd *result = NULL;
49
50         new_buffer = realloc(buffer, sizeof(struct passwd) + length);
51         if (new_buffer == NULL) {
52
53             D(("out of memory"));
54
55             /* no memory for the user - so delete the memory */
56             if (buffer) {
57                 free(buffer);
58             }
59             return NULL;
60         }
61         buffer = new_buffer;
62
63         /* make the re-entrant call to get the pwd structure */
64         status = getpwnam_r(user, buffer,
65                             sizeof(struct passwd) + (char *) buffer,
66                             length, &result);
67         if (!status && (result == buffer)) {
68             char *data_name;
69             const void *ignore;
70             int i;
71
72             data_name = malloc(strlen("_pammodutil_getpwnam") + 1 +
73                                strlen(user) + 1 + intlen(INT_MAX) + 1);
74             if ((pamh != NULL) && (data_name == NULL)) {
75                 D(("was unable to register the data item [%s]",
76                    pam_strerror(pamh, status)));
77                 free(buffer);
78                 return NULL;
79             }
80
81             if (pamh != NULL) {
82                 for (i = 0; i < INT_MAX; i++) {
83                     sprintf(data_name, "_pammodutil_getpwnam_%s_%d", user, i);
84                     _pammodutil_lock();
85                     status = PAM_NO_MODULE_DATA;
86                     if (pam_get_data(pamh, data_name, &ignore) != PAM_SUCCESS) {
87                         status = pam_set_data(pamh, data_name,
88                                               result, _pammodutil_cleanup);
89                     }
90                     _pammodutil_unlock();
91                     if (status == PAM_SUCCESS) {
92                         break;
93                     }
94                 }
95             } else {
96                 status = PAM_SUCCESS;
97             }
98
99             free(data_name);
100
101             if (status == PAM_SUCCESS) {
102                 D(("success"));
103                 return result;
104             }
105
106             D(("was unable to register the data item [%s]",
107                pam_strerror(pamh, status)));
108
109             free(buffer);
110             return NULL;
111
112         }
113         
114         length <<= 1;
115
116     } while (length < PWD_ABSURD_PWD_LENGTH);
117
118     D(("pwd structure took %u bytes or so of memory",
119        length+sizeof(struct passwd)));
120
121     free(buffer);
122     return NULL;
123
124 #else /* ie. ifndef HAVE_GETPWNAM_R */
125
126     /*
127      * Sorry, there does not appear to be a reentrant version of
128      * getpwnam(). So, we use the standard libc function.
129      */
130     
131     return getpwnam(user);
132
133 #endif /* def HAVE_GETPWNAM_R */
134 }