[xbuild] Fix bug #674630.
[mono.git] / support / grp.c
1 /*
2  * <grp.h> wrapper functions.
3  *
4  * Authors:
5  *   Jonathan Pryor (jonpryor@vt.edu)
6  *
7  * Copyright (C) 2004-2005 Jonathan Pryor
8  */
9
10 #include <sys/types.h>
11 #include <sys/param.h>
12 #include <grp.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <errno.h>
16 #include <string.h>
17 #include <unistd.h>     /* for setgroups on Mac OS X */
18
19 #include "map.h"
20 #include "mph.h"
21
22 G_BEGIN_DECLS
23
24 static void
25 count_members (char **gr_mem, int *count, size_t *mem)
26 {
27         char *cur;
28         *count = 0;
29
30         // ensure that later (*mem)+1 doesn't result in integer overflow
31         if (*mem > INT_MAX - 1)
32                 return;
33
34         for (cur = *gr_mem; cur != NULL; cur = *++gr_mem) {
35                 size_t len;
36                 len = strlen (cur);
37
38                 if (!(len < INT_MAX - ((*mem) + 1)))
39                         break;
40
41                 ++(*count);
42                 *mem += (len + 1);
43         }
44 }
45
46 static int
47 copy_group (struct Mono_Posix_Syscall__Group *to, struct group *from)
48 {
49         size_t nlen, plen, buflen;
50         int i, count;
51         char *cur, **to_mem;
52
53         to->gr_gid    = from->gr_gid;
54
55         to->gr_name   = NULL;
56         to->gr_passwd = NULL;
57         to->gr_mem    = NULL;
58         to->_gr_buf_  = NULL;
59
60         nlen = strlen (from->gr_name);
61         plen = strlen (from->gr_passwd);
62
63         buflen = 2;
64
65         if (!(nlen < INT_MAX - buflen))
66                 return -1;
67         buflen += nlen;
68
69         if (!(plen < INT_MAX - buflen))
70                 return -1;
71         buflen += plen;
72
73         count = 0;
74         count_members (from->gr_mem, &count, &buflen);
75
76         to->_gr_nmem_ = count;
77         cur = to->_gr_buf_ = (char*) malloc (buflen);
78         to_mem = to->gr_mem = malloc (sizeof(char*)*(count+1));
79         if (to->_gr_buf_ == NULL || to->gr_mem == NULL) {
80                 free (to->_gr_buf_);
81                 free (to->gr_mem);
82                 return -1;
83         }
84
85         to->gr_name = strcpy (cur, from->gr_name);
86         cur += (nlen + 1);
87         to->gr_passwd = strcpy (cur, from->gr_passwd);
88         cur += (plen + 1);
89
90         for (i = 0; i != count; ++i) {
91                 to_mem [i] = strcpy (cur, from->gr_mem[i]);
92                 cur += (strlen (from->gr_mem[i])+1);
93         }
94         to_mem [i] = NULL;
95
96         return 0;
97 }
98
99 gint32
100 Mono_Posix_Syscall_getgrnam (const char *name, struct Mono_Posix_Syscall__Group *gbuf)
101 {
102         struct group *_gbuf;
103
104         if (gbuf == NULL) {
105                 errno = EFAULT;
106                 return -1;
107         }
108
109         errno = 0;
110         _gbuf = getgrnam (name);
111         if (_gbuf == NULL)
112                 return -1;
113
114         if (copy_group (gbuf, _gbuf) == -1) {
115                 errno = ENOMEM;
116                 return -1;
117         }
118         return 0;
119 }
120
121 gint32
122 Mono_Posix_Syscall_getgrgid (mph_gid_t gid, struct Mono_Posix_Syscall__Group *gbuf)
123 {
124         struct group *_gbuf;
125
126         if (gbuf == NULL) {
127                 errno = EFAULT;
128                 return -1;
129         }
130
131         errno = 0;
132         _gbuf = getgrgid (gid);
133         if (_gbuf == NULL)
134                 return -1;
135
136         if (copy_group (gbuf, _gbuf) == -1) {
137                 errno = ENOMEM;
138                 return -1;
139         }
140         return 0;
141 }
142
143 #ifdef HAVE_GETGRNAM_R
144 gint32
145 Mono_Posix_Syscall_getgrnam_r (const char *name, 
146         struct Mono_Posix_Syscall__Group *gbuf,
147         void **gbufp)
148 {
149         char *buf, *buf2;
150         size_t buflen;
151         int r;
152         struct group _grbuf;
153
154         if (gbuf == NULL) {
155                 errno = EFAULT;
156                 return -1;
157         }
158
159         buf = buf2 = NULL;
160         buflen = 2;
161
162         do {
163                 buf2 = realloc (buf, buflen *= 2);
164                 if (buf2 == NULL) {
165                         free (buf);
166                         errno = ENOMEM;
167                         return -1;
168                 }
169                 buf = buf2;
170                 errno = 0;
171         } while ((r = getgrnam_r (name, &_grbuf, buf, buflen, (struct group**) gbufp)) && 
172                         recheck_range (r));
173
174         /* On Solaris, this function returns 0 even if the entry was not found */
175         if (r == 0 && !(*gbufp))
176                 r = errno = ENOENT;
177
178         if (r == 0 && copy_group (gbuf, &_grbuf) == -1)
179                 r = errno = ENOMEM;
180         free (buf);
181
182         return r;
183 }
184 #endif /* ndef HAVE_GETGRNAM_R */
185
186 #ifdef HAVE_GETGRGID_R
187 gint32
188 Mono_Posix_Syscall_getgrgid_r (mph_gid_t gid,
189         struct Mono_Posix_Syscall__Group *gbuf,
190         void **gbufp)
191 {
192         char *buf, *buf2;
193         size_t buflen;
194         int r;
195         struct group _grbuf;
196
197         if (gbuf == NULL) {
198                 errno = EFAULT;
199                 return -1;
200         }
201
202         buf = buf2 = NULL;
203         buflen = 2;
204
205         do {
206                 buf2 = realloc (buf, buflen *= 2);
207                 if (buf2 == NULL) {
208                         free (buf);
209                         errno = ENOMEM;
210                         return -1;
211                 }
212                 buf = buf2;
213                 errno = 0;
214         } while ((r = getgrgid_r (gid, &_grbuf, buf, buflen, (struct group**) gbufp)) && 
215                         recheck_range (r));
216
217         /* On Solaris, this function returns 0 even if the entry was not found */
218         if (r == 0 && !(*gbufp))
219                 r = errno = ENOENT;
220
221         if (r == 0 && copy_group (gbuf, &_grbuf) == -1)
222                 r = errno = ENOMEM;
223         free (buf);
224
225         return r;
226 }
227 #endif /* ndef HAVE_GETGRGID_R */
228
229 #if HAVE_GETGRENT
230 gint32
231 Mono_Posix_Syscall_getgrent (struct Mono_Posix_Syscall__Group *grbuf)
232 {
233         struct group *gr;
234
235         if (grbuf == NULL) {
236                 errno = EFAULT;
237                 return -1;
238         }
239
240         errno = 0;
241         gr = getgrent ();
242         if (gr == NULL)
243                 return -1;
244
245         if (copy_group (grbuf, gr) == -1) {
246                 errno = ENOMEM;
247                 return -1;
248         }
249         return 0;
250 }
251 #endif  /* def HAVE_GETGRENT */
252
253 #ifdef HAVE_FGETGRENT
254 gint32
255 Mono_Posix_Syscall_fgetgrent (void *stream, struct Mono_Posix_Syscall__Group *grbuf)
256 {
257         struct group *gr;
258
259         if (grbuf == NULL) {
260                 errno = EFAULT;
261                 return -1;
262         }
263
264         errno = 0;
265         gr = fgetgrent ((FILE*) stream);
266         if (gr == NULL)
267                 return -1;
268
269         if (copy_group (grbuf, gr) == -1) {
270                 errno = ENOMEM;
271                 return -1;
272         }
273         return 0;
274 }
275 #endif /* ndef HAVE_FGETGRENT */
276
277 #if HAVE_SETGROUPS
278 gint32
279 Mono_Posix_Syscall_setgroups (mph_size_t size, mph_gid_t *list)
280 {
281         mph_return_if_size_t_overflow (size);
282         return setgroups ((size_t) size, list);
283 }
284 #endif  /* def HAVE_SETGROUPS */
285
286 #if HAVE_SETGRENT
287 int
288 Mono_Posix_Syscall_setgrent (void)
289 {
290         errno = 0;
291         do {
292                 setgrent ();
293         } while (errno == EINTR);
294         mph_return_if_val_in_list5(errno, EIO, EMFILE, ENFILE, ENOMEM, ERANGE);
295         return 0;
296 }
297 #endif  /* def HAVE_SETGRENT */
298
299 #if HAVE_ENDGRENT
300 int
301 Mono_Posix_Syscall_endgrent (void)
302 {
303         endgrent();
304         return 0;
305 }
306 #endif  /* def HAVE_ENDGRENT */
307
308
309 G_END_DECLS
310
311 /*
312  * vim: noexpandtab
313  */