]> git.ipfire.org Git - thirdparty/glibc.git/blob - hesiod/nss_hesiod/hesiod-grp.c
fdaf1f26f7711b23ae333a3994e6935e70bfcc13
[thirdparty/glibc.git] / hesiod / nss_hesiod / hesiod-grp.c
1 /* Copyright (C) 1997, 1999, 2000 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
19
20 #include <ctype.h>
21 #include <errno.h>
22 #include <grp.h>
23 #include <hesiod.h>
24 #include <nss.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/param.h>
29
30 #include "nss_hesiod.h"
31
32 /* Get the declaration of the parser function. */
33 #define ENTNAME grent
34 #define STRUCTURE group
35 #define EXTERN_PARSER
36 #include <nss/nss_files/files-parse.c>
37
38 enum nss_status
39 _nss_hesiod_setgrent (int stayopen)
40 {
41 return NSS_STATUS_SUCCESS;
42 }
43
44 enum nss_status
45 _nss_hesiod_endgrent (void)
46 {
47 return NSS_STATUS_SUCCESS;
48 }
49
50 static enum nss_status
51 lookup (const char *name, const char *type, struct group *grp,
52 char *buffer, size_t buflen, int *errnop)
53 {
54 struct parser_data *data = (void *) buffer;
55 size_t linebuflen;
56 void *context;
57 char **list;
58 int parse_res;
59 size_t len;
60
61 context = _nss_hesiod_init ();
62 if (context == NULL)
63 return NSS_STATUS_UNAVAIL;
64
65 list = hesiod_resolve (context, name, type);
66 if (list == NULL)
67 {
68 hesiod_end (context);
69 return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
70 }
71
72 linebuflen = buffer + buflen - data->linebuffer;
73 len = strlen (*list) + 1;
74 if (linebuflen < len)
75 {
76 hesiod_free_list (context, list);
77 hesiod_end (context);
78 *errnop = ERANGE;
79 return NSS_STATUS_TRYAGAIN;
80 }
81
82 memcpy (data->linebuffer, *list, len);
83 hesiod_free_list (context, list);
84 hesiod_end (context);
85
86 parse_res = _nss_files_parse_grent (buffer, grp, data, buflen, errnop);
87 if (parse_res < 1)
88 return parse_res == -1 ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND;
89
90 return NSS_STATUS_SUCCESS;
91 }
92
93 enum nss_status
94 _nss_hesiod_getgrnam_r (const char *name, struct group *grp,
95 char *buffer, size_t buflen, int *errnop)
96 {
97 return lookup (name, "group", grp, buffer, buflen, errnop);
98 }
99
100 enum nss_status
101 _nss_hesiod_getgrgid_r (gid_t gid, struct group *grp,
102 char *buffer, size_t buflen, int *errnop)
103 {
104 char gidstr[21]; /* We will probably never have a gid_t with more
105 than 64 bits. */
106
107 snprintf (gidstr, sizeof gidstr, "%d", gid);
108
109 return lookup (gidstr, "gid", grp, buffer, buflen, errnop);
110 }
111
112 static int
113 internal_gid_in_list (const gid_t *list, const gid_t g, long int len)
114 {
115 while (len > 0)
116 {
117 if (*list == g)
118 return 1;
119 --len;
120 ++list;
121 }
122 return 0;
123 }
124
125 static enum nss_status
126 internal_gid_from_group (void *context, const char *groupname, gid_t *group)
127 {
128 char **grp_res;
129 enum nss_status status = NSS_STATUS_NOTFOUND;
130
131 grp_res = hesiod_resolve (context, groupname, "group");
132 if (grp_res != NULL && *grp_res != NULL)
133 {
134 char *p = *grp_res;
135
136 while (*p != '\0' && *p != ':')
137 ++p;
138 while (*p != '\0' && *p == ':')
139 ++p;
140 while (*p != '\0' && *p != ':')
141 ++p;
142 while (*p != '\0' && *p == ':')
143 ++p;
144 if (*p == ':')
145 {
146 char *endp;
147 char *q = ++p;
148 long int val;
149
150 q = p;
151 while (*q != '\0' && *q != ':')
152 ++q;
153
154 val = strtol (p, &endp, 10);
155 if (sizeof (gid_t) == sizeof (long int) || (gid_t) val == val)
156 {
157 *group = val;
158 if (endp == q && endp != p)
159 status = NSS_STATUS_SUCCESS;
160 }
161 }
162 hesiod_free_list (context, grp_res);
163 }
164 return status;
165 }
166
167 enum nss_status
168 _nss_hesiod_initgroups_dyn (const char *user, gid_t group, long int *start,
169 long int *size, gid_t **groupsp, long int limit,
170 int *errnop)
171 {
172 enum nss_status status = NSS_STATUS_SUCCESS;
173 char **list = NULL;
174 char *p;
175 void *context;
176 gid_t *groups = *groupsp;
177 int save_errno;
178
179 context = _nss_hesiod_init ();
180 if (context == NULL)
181 return NSS_STATUS_UNAVAIL;
182
183 list = hesiod_resolve (context, user, "grplist");
184
185 if (list == NULL)
186 {
187 hesiod_end (context);
188 return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
189 }
190
191 if (!internal_gid_in_list (groups, group, *start))
192 {
193 if (__builtin_expect (*start == *size, 0))
194 {
195 /* Need a bigger buffer. */
196 gid_t *newgroups;
197 long int newsize;
198
199 if (limit > 0 && *size == limit)
200 /* We reached the maximum. */
201 goto done;
202
203 if (limit <= 0)
204 newsize = 2 * *size;
205 else
206 newsize = MIN (limit, 2 * *size);
207
208 newgroups = realloc (groups, newsize * sizeof (*groups));
209 if (newgroups == NULL)
210 goto done;
211 *groupsp = groups = newgroups;
212 *size = newsize;
213 }
214
215 groups[(*start)++] = group;
216 }
217
218 save_errno = errno;
219
220 p = *list;
221 while (*p != '\0')
222 {
223 char *endp;
224 char *q;
225 long int val;
226
227 status = NSS_STATUS_NOTFOUND;
228
229 q = p;
230 while (*q != '\0' && *q != ':' && *q != ',')
231 ++q;
232
233 if (*q != '\0')
234 *q++ = '\0';
235
236 __set_errno (0);
237 val = strtol (p, &endp, 10);
238 /* Test whether the number is representable in a variable of
239 type `gid_t'. If not ignore the number. */
240 if ((sizeof (gid_t) == sizeof (long int) || (gid_t) val == val)
241 && errno == 0)
242 {
243 if (*endp == '\0' && endp != p)
244 {
245 group = val;
246 status = NSS_STATUS_SUCCESS;
247 }
248 else
249 status = internal_gid_from_group (context, p, &group);
250
251 if (status == NSS_STATUS_SUCCESS
252 && !internal_gid_in_list (groups, group, *start))
253 {
254 if (__builtin_expect (*start == *size, 0))
255 {
256 /* Need a bigger buffer. */
257 gid_t *newgroups;
258 long int newsize;
259
260 if (limit > 0 && *size == limit)
261 /* We reached the maximum. */
262 goto done;
263
264 if (limit <= 0)
265 newsize = 2 * *size;
266 else
267 newsize = MIN (limit, 2 * *size);
268
269 newgroups = realloc (groups, newsize * sizeof (*groups));
270 if (newgroups == NULL)
271 goto done;
272 *groupsp = groups = newgroups;
273 *size = newsize;
274 }
275
276 groups[(*start)++] = group;
277 }
278 }
279
280 p = q;
281 }
282
283 __set_errno (save_errno);
284
285 done:
286 hesiod_free_list (context, list);
287 hesiod_end (context);
288
289 return NSS_STATUS_SUCCESS;
290 }