2005-02-07 Ben Maurer <bmaurer@ximian.com>
[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 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         struct group **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, gbufp)) && 
180                         recheck_range (r));
181
182         if (r == 0 && copy_group (gbuf, &_grbuf) == -1)
183                 r = errno = ENOMEM;
184         free (buf);
185
186         return r;
187 }
188 #endif /* ndef HAVE_GETGRNAM_R */
189
190 #ifdef HAVE_GETGRGID_R
191 gint32
192 Mono_Posix_Syscall_getgrgid_r (mph_gid_t gid,
193         struct Mono_Posix_Syscall__Group *gbuf,
194         struct group **gbufp)
195 {
196         char *buf, *buf2;
197         size_t buflen;
198         int r;
199         struct group _grbuf;
200
201         if (gbuf == NULL) {
202                 errno = EFAULT;
203                 return -1;
204         }
205
206         buf = buf2 = NULL;
207         buflen = 2;
208
209         do {
210                 buf2 = realloc (buf, buflen *= 2);
211                 if (buf2 == NULL) {
212                         free (buf);
213                         errno = ENOMEM;
214                         return -1;
215                 }
216                 buf = buf2;
217                 errno = 0;
218         } while ((r = getgrgid_r (gid, &_grbuf, buf, buflen, gbufp)) && 
219                         recheck_range (r));
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 (FILE *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 (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 G_END_DECLS
283
284 /*
285  * vim: noexpandtab
286  */