* Makefile: Don't build make-map.exe.
[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 gint32
230 Mono_Posix_Syscall_getgrent (struct Mono_Posix_Syscall__Group *grbuf)
231 {
232         struct group *gr;
233
234         if (grbuf == NULL) {
235                 errno = EFAULT;
236                 return -1;
237         }
238
239         errno = 0;
240         gr = getgrent ();
241         if (gr == NULL)
242                 return -1;
243
244         if (copy_group (grbuf, gr) == -1) {
245                 errno = ENOMEM;
246                 return -1;
247         }
248         return 0;
249 }
250
251 #ifdef HAVE_FGETGRENT
252 gint32
253 Mono_Posix_Syscall_fgetgrent (void *stream, struct Mono_Posix_Syscall__Group *grbuf)
254 {
255         struct group *gr;
256
257         if (grbuf == NULL) {
258                 errno = EFAULT;
259                 return -1;
260         }
261
262         errno = 0;
263         gr = fgetgrent ((FILE*) stream);
264         if (gr == NULL)
265                 return -1;
266
267         if (copy_group (grbuf, gr) == -1) {
268                 errno = ENOMEM;
269                 return -1;
270         }
271         return 0;
272 }
273 #endif /* ndef HAVE_FGETGRENT */
274
275 gint32
276 Mono_Posix_Syscall_setgroups (mph_size_t size, mph_gid_t *list)
277 {
278         mph_return_if_size_t_overflow (size);
279         return setgroups ((size_t) size, list);
280 }
281
282 int
283 Mono_Posix_Syscall_setgrent (void)
284 {
285         errno = 0;
286         setgrent ();
287         return errno == 0 ? 0 : -1;
288 }
289
290 int
291 Mono_Posix_Syscall_endgrent (void)
292 {
293         errno = 0;
294         endgrent();
295         return errno == 0 ? 0 : -1;
296 }
297
298
299 G_END_DECLS
300
301 /*
302  * vim: noexpandtab
303  */