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