Mac OS X and BSD portability fixes. MonoPosixHelper should now cleanly
[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 gint32
141 Mono_Posix_Syscall_getpwnam_r (const char *name, 
142         struct Mono_Posix_Syscall__Passwd *pwbuf,
143         struct passwd **pwbufp)
144 {
145         char *buf, *buf2;
146         size_t buflen;
147         int r;
148         struct passwd _pwbuf;
149
150         if (pwbuf == NULL) {
151                 errno = EFAULT;
152                 return -1;
153         }
154
155         buf = buf2 = NULL;
156         buflen = 2;
157
158         do {
159                 buf2 = realloc (buf, buflen *= 2);
160                 if (buf2 == NULL) {
161                         free (buf);
162                         errno = ENOMEM;
163                         return -1;
164                 }
165                 buf = buf2;
166         } while ((r = getpwnam_r (name, &_pwbuf, buf, buflen, pwbufp)) && r == ERANGE);
167
168         if (r == 0 && copy_passwd (pwbuf, &_pwbuf) == -1)
169                 r = errno = ENOMEM;
170         free (buf);
171
172         return r;
173 }
174
175 gint32
176 Mono_Posix_Syscall_getpwuid_r (mph_uid_t uid,
177         struct Mono_Posix_Syscall__Passwd *pwbuf,
178         struct passwd **pwbufp)
179 {
180         char *buf, *buf2;
181         size_t buflen;
182         int r;
183         struct passwd _pwbuf;
184
185         if (pwbuf == NULL) {
186                 errno = EFAULT;
187                 return -1;
188         }
189
190         buf = buf2 = NULL;
191         buflen = 2;
192
193         do {
194                 buf2 = realloc (buf, buflen *= 2);
195                 if (buf2 == NULL) {
196                         free (buf);
197                         errno = ENOMEM;
198                         return -1;
199                 }
200                 buf = buf2;
201         } while ((r = getpwuid_r (uid, &_pwbuf, buf, buflen, pwbufp)) && r == ERANGE);
202
203         if (r == 0 && copy_passwd (pwbuf, &_pwbuf) == -1)
204                 r = errno = ENOMEM;
205         free (buf);
206
207         return r;
208 }
209
210 gint32
211 Mono_Posix_Syscall_getpwent (struct Mono_Posix_Syscall__Passwd *pwbuf)
212 {
213         struct passwd *pw;
214
215         if (pwbuf == NULL) {
216                 errno = EFAULT;
217                 return -1;
218         }
219
220         pw = getpwent ();
221         if (pw == NULL)
222                 return -1;
223
224         if (copy_passwd (pwbuf, pw) == -1) {
225                 errno = ENOMEM;
226                 return -1;
227         }
228         return 0;
229 }
230
231 #ifdef HAVE_FGETPWENT
232 gint32
233 Mono_Posix_Syscall_fgetpwent (FILE *stream, struct Mono_Posix_Syscall__Passwd *pwbuf)
234 {
235         struct passwd *pw;
236
237         if (pwbuf == NULL) {
238                 errno = EFAULT;
239                 return -1;
240         }
241
242         pw = fgetpwent (stream);
243         if (pw == NULL)
244                 return -1;
245
246         if (copy_passwd (pwbuf, pw) == -1) {
247                 errno = ENOMEM;
248                 return -1;
249         }
250         return 0;
251 }
252 #endif /* ndef FGETPWENT */
253
254 G_END_DECLS
255
256 /*
257  * vim: noexpandtab
258  */