]> granicus.if.org Git - linux-pam/blob - modules/pammodutil/modutil_getpwuid.c
Relevant BUGIDs:
[linux-pam] / modules / pammodutil / modutil_getpwuid.c
1 /*
2  * $Id$
3  *
4  * This function provides a thread safer version of getpwuid() 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 static int longlen(long number)
39
40     int len = 2;
41     while (number != 0) {
42         number /= 10;
43         len++;
44     }
45     return len;
46 }
47
48 struct passwd *_pammodutil_getpwuid(pam_handle_t *pamh, uid_t uid)
49 {
50 #ifdef HAVE_GETPWUID_R
51
52     void *buffer=NULL;
53     size_t length = PWD_INITIAL_LENGTH;
54
55     do {
56         int status;
57         void *new_buffer;
58         struct passwd *result = NULL;
59
60         new_buffer = realloc(buffer, sizeof(struct passwd) + length);
61         if (new_buffer == NULL) {
62
63             D(("out of memory"));
64
65             /* no memory for the user - so delete the memory */
66             if (buffer) {
67                 free(buffer);
68             }
69             return NULL;
70         }
71         buffer = new_buffer;
72
73         /* make the re-entrant call to get the pwd structure */
74         status = getpwuid_r(uid, buffer,
75                             sizeof(struct passwd) + (char *) buffer,
76                             length, &result);
77         if (!status && (result == buffer)) {
78             char *data_name;
79             const void *ignore;
80             int i;
81
82             data_name = malloc(strlen("_pammodutil_getpwuid") + 1 +
83                                longlen((long) uid) + 1 + intlen(INT_MAX) + 1);
84             if ((pamh != NULL) && (data_name == NULL)) {
85                 D(("was unable to register the data item [%s]",
86                    pam_strerror(pamh, status)));
87                 free(buffer);
88                 return NULL;
89             }
90
91             if (pamh != NULL) {
92                 for (i = 0; i < INT_MAX; i++) {
93                     sprintf(data_name, "_pammodutil_getpwuid_%ld_%d",
94                             (long) uid, i);
95                     _pammodutil_lock();
96                     status = PAM_NO_MODULE_DATA;
97                     if (pam_get_data(pamh, data_name, &ignore) != PAM_SUCCESS) {
98                         status = pam_set_data(pamh, data_name,
99                                               result, _pammodutil_cleanup);
100                     }
101                     _pammodutil_unlock();
102                     if (status == PAM_SUCCESS) {
103                         break;
104                     }
105                 }
106             } else {
107                 status = PAM_SUCCESS;
108             }
109
110             free(data_name);
111
112             if (status == PAM_SUCCESS) {
113                 D(("success"));
114                 return result;
115             }
116
117             D(("was unable to register the data item [%s]",
118                pam_strerror(pamh, status)));
119
120             free(buffer);
121             return NULL;
122
123         }
124         
125         length <<= 1;
126
127     } while (length < PWD_ABSURD_PWD_LENGTH);
128
129     D(("pwd structure took %u bytes or so of memory",
130        length+sizeof(struct passwd)));
131
132     free(buffer);
133     return NULL;
134
135 #else /* ie. ifndef HAVE_GETPWUID_R */
136
137     /*
138      * Sorry, there does not appear to be a reentrant version of
139      * getpwuid(). So, we use the standard libc function.
140      */
141     
142     return getpwuid(uid);
143
144 #endif /* def HAVE_GETPWUID_R */
145 }