f6c4832cc0cb4c9202e2b97b091d7640d5b389c0
[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         _gbuf = getgrnam (name);
118         if (_gbuf == NULL)
119                 return -1;
120
121         if (copy_group (gbuf, _gbuf) == -1) {
122                 errno = ENOMEM;
123                 return -1;
124         }
125         return 0;
126 }
127
128 gint32
129 Mono_Posix_Syscall_getgrgid (mph_gid_t gid, struct Mono_Posix_Syscall__Group *gbuf)
130 {
131         struct group *_gbuf;
132
133         if (gbuf == NULL) {
134                 errno = EFAULT;
135                 return -1;
136         }
137
138         _gbuf = getgrgid (gid);
139         if (_gbuf == NULL)
140                 return -1;
141
142         if (copy_group (gbuf, _gbuf) == -1) {
143                 errno = ENOMEM;
144                 return -1;
145         }
146         return 0;
147 }
148
149 #ifdef HAVE_GETGRNAM_R
150 gint32
151 Mono_Posix_Syscall_getgrnam_r (const char *name, 
152         struct Mono_Posix_Syscall__Group *gbuf,
153         struct group **gbufp)
154 {
155         char *buf, *buf2;
156         size_t buflen;
157         int r;
158         struct group _grbuf;
159
160         if (gbuf == NULL) {
161                 errno = EFAULT;
162                 return -1;
163         }
164
165         buf = buf2 = NULL;
166         buflen = 2;
167
168         do {
169                 buf2 = realloc (buf, buflen *= 2);
170                 if (buf2 == NULL) {
171                         free (buf);
172                         errno = ENOMEM;
173                         return -1;
174                 }
175                 buf = buf2;
176         } while ((r = getgrnam_r (name, &_grbuf, buf, buflen, gbufp)) && 
177                         recheck_range (r));
178
179         if (r == 0 && copy_group (gbuf, &_grbuf) == -1)
180                 r = errno = ENOMEM;
181         free (buf);
182
183         return r;
184 }
185 #endif /* ndef HAVE_GETGRNAM_R */
186
187 #ifdef HAVE_GETGRGID_R
188 gint32
189 Mono_Posix_Syscall_getgrgid_r (mph_gid_t gid,
190         struct Mono_Posix_Syscall__Group *gbuf,
191         struct group **gbufp)
192 {
193         char *buf, *buf2;
194         size_t buflen;
195         int r;
196         struct group _grbuf;
197
198         if (gbuf == NULL) {
199                 errno = EFAULT;
200                 return -1;
201         }
202
203         buf = buf2 = NULL;
204         buflen = 2;
205
206         do {
207                 buf2 = realloc (buf, buflen *= 2);
208                 if (buf2 == NULL) {
209                         free (buf);
210                         errno = ENOMEM;
211                         return -1;
212                 }
213                 buf = buf2;
214         } while ((r = getgrgid_r (gid, &_grbuf, buf, buflen, gbufp)) && 
215                         recheck_range (r));
216
217         if (r == 0 && copy_group (gbuf, &_grbuf) == -1)
218                 r = errno = ENOMEM;
219         free (buf);
220
221         return r;
222 }
223 #endif /* ndef HAVE_GETGRGID_R */
224
225 gint32
226 Mono_Posix_Syscall_getgrent (struct Mono_Posix_Syscall__Group *grbuf)
227 {
228         struct group *gr;
229
230         if (grbuf == NULL) {
231                 errno = EFAULT;
232                 return -1;
233         }
234
235         gr = getgrent ();
236         if (gr == NULL)
237                 return -1;
238
239         if (copy_group (grbuf, gr) == -1) {
240                 errno = ENOMEM;
241                 return -1;
242         }
243         return 0;
244 }
245
246 #ifdef HAVE_FGETGRENT
247 gint32
248 Mono_Posix_Syscall_fgetgrent (FILE *stream, struct Mono_Posix_Syscall__Group *grbuf)
249 {
250         struct group *gr;
251
252         if (grbuf == NULL) {
253                 errno = EFAULT;
254                 return -1;
255         }
256
257         gr = fgetgrent (stream);
258         if (gr == NULL)
259                 return -1;
260
261         if (copy_group (grbuf, gr) == -1) {
262                 errno = ENOMEM;
263                 return -1;
264         }
265         return 0;
266 }
267 #endif /* ndef HAVE_FGETGRENT */
268
269 gint32
270 Mono_Posix_Syscall_setgroups (mph_size_t size, mph_gid_t *list)
271 {
272         mph_return_if_size_t_overflow (size);
273         return setgroups ((size_t) size, list);
274 }
275
276 G_END_DECLS
277
278 /*
279  * vim: noexpandtab
280  */