More Mac OS X portability fixes. On Linux, getgrnam_r & co. return the error
[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)) && 
167                         recheck_range (r));
168
169         if (r == 0 && copy_passwd (pwbuf, &_pwbuf) == -1)
170                 r = errno = ENOMEM;
171         free (buf);
172
173         return r;
174 }
175
176 gint32
177 Mono_Posix_Syscall_getpwuid_r (mph_uid_t uid,
178         struct Mono_Posix_Syscall__Passwd *pwbuf,
179         struct passwd **pwbufp)
180 {
181         char *buf, *buf2;
182         size_t buflen;
183         int r;
184         struct passwd _pwbuf;
185
186         if (pwbuf == NULL) {
187                 errno = EFAULT;
188                 return -1;
189         }
190
191         buf = buf2 = NULL;
192         buflen = 2;
193
194         do {
195                 buf2 = realloc (buf, buflen *= 2);
196                 if (buf2 == NULL) {
197                         free (buf);
198                         errno = ENOMEM;
199                         return -1;
200                 }
201                 buf = buf2;
202         } while ((r = getpwuid_r (uid, &_pwbuf, buf, buflen, pwbufp)) && 
203                         recheck_range (r));
204
205         if (r == 0 && copy_passwd (pwbuf, &_pwbuf) == -1)
206                 r = errno = ENOMEM;
207         free (buf);
208
209         return r;
210 }
211
212 gint32
213 Mono_Posix_Syscall_getpwent (struct Mono_Posix_Syscall__Passwd *pwbuf)
214 {
215         struct passwd *pw;
216
217         if (pwbuf == NULL) {
218                 errno = EFAULT;
219                 return -1;
220         }
221
222         pw = getpwent ();
223         if (pw == NULL)
224                 return -1;
225
226         if (copy_passwd (pwbuf, pw) == -1) {
227                 errno = ENOMEM;
228                 return -1;
229         }
230         return 0;
231 }
232
233 #ifdef HAVE_FGETPWENT
234 gint32
235 Mono_Posix_Syscall_fgetpwent (FILE *stream, struct Mono_Posix_Syscall__Passwd *pwbuf)
236 {
237         struct passwd *pw;
238
239         if (pwbuf == NULL) {
240                 errno = EFAULT;
241                 return -1;
242         }
243
244         pw = fgetpwent (stream);
245         if (pw == NULL)
246                 return -1;
247
248         if (copy_passwd (pwbuf, pw) == -1) {
249                 errno = ENOMEM;
250                 return -1;
251         }
252         return 0;
253 }
254 #endif /* ndef FGETPWENT */
255
256 G_END_DECLS
257
258 /*
259  * vim: noexpandtab
260  */