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