* configure.in: Add new function/header/type checks for use by
[mono.git] / support / pwd.c
1 /*
2  * <pwd.h> wrapper functions.
3  *
4  * Authors:
5  *   Jonathan Pryor (jonpryor@vt.edu)
6  *
7  * Copyright (C) 2004 Jonathan Pryor
8  */
9
10 #include <pwd.h>
11 #include <errno.h>
12 #include <string.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15
16 #include "mph.h"
17
18 G_BEGIN_DECLS
19
20 struct Mono_Posix_Syscall__Passwd {
21         /* string */ char      *pw_name;
22         /* string */ char      *pw_passwd;
23         /* uid_t  */ mph_uid_t  pw_uid;
24         /* gid_t  */ mph_gid_t  pw_gid;
25         /* string */ char      *pw_gecos;
26         /* string */ char      *pw_dir;
27         /* string */ char      *pw_shell;
28         /* string */ char      *_pw_buf_;
29 };
30
31 /*
32  * Copy the native `passwd' structure to it's managed representation.
33  *
34  * To minimize separate mallocs, all the strings are allocated within the same
35  * memory block (stored in _pw_buf_).
36  */
37 static int
38 copy_passwd (struct Mono_Posix_Syscall__Passwd *to, struct passwd *from)
39 {
40         enum {PW_NAME = 0, PW_PASSWD, PW_GECOS, PW_DIR, PW_SHELL, PW_LAST};
41         size_t buflen, len[PW_LAST];
42         /* bool */ unsigned char copy[PW_LAST] = {0};
43         const char *source[PW_LAST];
44         char **dest[PW_LAST];
45         int i;
46         char *cur;
47
48         to->pw_uid    = from->pw_uid;
49         to->pw_gid    = from->pw_gid;
50
51         to->pw_name   = NULL;
52         to->pw_passwd = NULL;
53         to->pw_gecos  = NULL;
54         to->pw_dir    = NULL;
55         to->pw_shell  = NULL;
56         to->_pw_buf_  = NULL;
57
58         source[PW_NAME]   = from->pw_name;
59         source[PW_PASSWD] = from->pw_passwd;
60         source[PW_GECOS]  = from->pw_gecos;
61         source[PW_DIR]    = from->pw_dir;
62         source[PW_SHELL]  = from->pw_shell;
63
64         dest[PW_NAME]   = &to->pw_name;
65         dest[PW_PASSWD] = &to->pw_passwd;
66         dest[PW_GECOS]  = &to->pw_gecos;
67         dest[PW_DIR]    = &to->pw_dir;
68         dest[PW_SHELL]  = &to->pw_shell;
69
70         buflen = PW_LAST;
71
72         /* over-rigorous checking for integer overflow */
73         for (i = 0; i != PW_LAST; ++i) {
74                 len[i] = strlen (source[i]);
75                 if (len[i] < INT_MAX - buflen) {
76                         buflen += len[i];
77                         copy[i] = 1;
78                 }
79         }
80
81         cur = to->_pw_buf_ = (char*) malloc (buflen);
82         if (cur == NULL) {
83                 return -1;
84         }
85
86         for (i = 0; i != PW_LAST; ++i) {
87                 if (copy[i]) {
88                         *dest[i] = strcpy (cur, source[i]);
89                         cur += (len[i] + 1);
90                 }
91         }
92
93         return 0;
94 }
95
96 gint32
97 Mono_Posix_Syscall_getpwnam (const char *name, struct Mono_Posix_Syscall__Passwd *pwbuf)
98 {
99         struct passwd *pw;
100
101         if (pwbuf == NULL) {
102                 errno = EFAULT;
103                 return -1;
104         }
105
106         pw = getpwnam (name);
107         if (pw == NULL)
108                 return -1;
109
110         if (copy_passwd (pwbuf, pw) == -1) {
111                 errno = ENOMEM;
112                 return -1;
113         }
114         return 0;
115 }
116
117 gint32
118 Mono_Posix_Syscall_getpwuid (mph_uid_t uid, struct Mono_Posix_Syscall__Passwd *pwbuf)
119 {
120         struct passwd *pw;
121
122         if (pwbuf == NULL) {
123                 errno = EFAULT;
124                 return -1;
125         }
126
127         errno = 0;
128         pw = getpwuid (uid);
129         if (pw == NULL) {
130                 return -1;
131         }
132
133         if (copy_passwd (pwbuf, pw) == -1) {
134                 errno = ENOMEM;
135                 return -1;
136         }
137         return 0;
138 }
139
140 #ifdef HAVE_GETPWNAM_R
141 gint32
142 Mono_Posix_Syscall_getpwnam_r (const char *name, 
143         struct Mono_Posix_Syscall__Passwd *pwbuf,
144         struct passwd **pwbufp)
145 {
146         char *buf, *buf2;
147         size_t buflen;
148         int r;
149         struct passwd _pwbuf;
150
151         if (pwbuf == NULL) {
152                 errno = EFAULT;
153                 return -1;
154         }
155
156         buf = buf2 = NULL;
157         buflen = 2;
158
159         do {
160                 buf2 = realloc (buf, buflen *= 2);
161                 if (buf2 == NULL) {
162                         free (buf);
163                         errno = ENOMEM;
164                         return -1;
165                 }
166                 buf = buf2;
167         } while ((r = getpwnam_r (name, &_pwbuf, buf, buflen, pwbufp)) && 
168                         recheck_range (r));
169
170         if (r == 0 && copy_passwd (pwbuf, &_pwbuf) == -1)
171                 r = errno = ENOMEM;
172         free (buf);
173
174         return r;
175 }
176 #endif /* ndef HAVE_GETPWNAM_R */
177
178 #ifdef HAVE_GETPWUID_R
179 gint32
180 Mono_Posix_Syscall_getpwuid_r (mph_uid_t uid,
181         struct Mono_Posix_Syscall__Passwd *pwbuf,
182         struct passwd **pwbufp)
183 {
184         char *buf, *buf2;
185         size_t buflen;
186         int r;
187         struct passwd _pwbuf;
188
189         if (pwbuf == NULL) {
190                 errno = EFAULT;
191                 return -1;
192         }
193
194         buf = buf2 = NULL;
195         buflen = 2;
196
197         do {
198                 buf2 = realloc (buf, buflen *= 2);
199                 if (buf2 == NULL) {
200                         free (buf);
201                         errno = ENOMEM;
202                         return -1;
203                 }
204                 buf = buf2;
205         } while ((r = getpwuid_r (uid, &_pwbuf, buf, buflen, pwbufp)) && 
206                         recheck_range (r));
207
208         if (r == 0 && copy_passwd (pwbuf, &_pwbuf) == -1)
209                 r = errno = ENOMEM;
210         free (buf);
211
212         return r;
213 }
214 #endif /* ndef HAVE_GETPWUID_R */
215
216 gint32
217 Mono_Posix_Syscall_getpwent (struct Mono_Posix_Syscall__Passwd *pwbuf)
218 {
219         struct passwd *pw;
220
221         if (pwbuf == NULL) {
222                 errno = EFAULT;
223                 return -1;
224         }
225
226         pw = getpwent ();
227         if (pw == NULL)
228                 return -1;
229
230         if (copy_passwd (pwbuf, pw) == -1) {
231                 errno = ENOMEM;
232                 return -1;
233         }
234         return 0;
235 }
236
237 #ifdef HAVE_FGETPWENT
238 gint32
239 Mono_Posix_Syscall_fgetpwent (FILE *stream, struct Mono_Posix_Syscall__Passwd *pwbuf)
240 {
241         struct passwd *pw;
242
243         if (pwbuf == NULL) {
244                 errno = EFAULT;
245                 return -1;
246         }
247
248         pw = fgetpwent (stream);
249         if (pw == NULL)
250                 return -1;
251
252         if (copy_passwd (pwbuf, pw) == -1) {
253                 errno = ENOMEM;
254                 return -1;
255         }
256         return 0;
257 }
258 #endif /* ndef HAVE_FGETPWENT */
259
260 G_END_DECLS
261
262 /*
263  * vim: noexpandtab
264  */