Replace FSF snail mail address with URLs.
[glibc.git] / hesiod / nss_hesiod / hesiod-grp.c
blob5c14554ce9fd647e30381c70336be95b8a975f00
1 /* Copyright (C) 1997, 1999, 2000, 2002 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
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.
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.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
19 #include <ctype.h>
20 #include <errno.h>
21 #include <grp.h>
22 #include <hesiod.h>
23 #include <nss.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/param.h>
29 #include "nss_hesiod.h"
31 /* Get the declaration of the parser function. */
32 #define ENTNAME grent
33 #define STRUCTURE group
34 #define EXTERN_PARSER
35 #include <nss/nss_files/files-parse.c>
37 enum nss_status
38 _nss_hesiod_setgrent (int stayopen)
40 return NSS_STATUS_SUCCESS;
43 enum nss_status
44 _nss_hesiod_endgrent (void)
46 return NSS_STATUS_SUCCESS;
49 static enum nss_status
50 lookup (const char *name, const char *type, struct group *grp,
51 char *buffer, size_t buflen, int *errnop)
53 struct parser_data *data = (void *) buffer;
54 size_t linebuflen;
55 void *context;
56 char **list;
57 int parse_res;
58 size_t len;
59 int olderr = errno;
61 context = _nss_hesiod_init ();
62 if (context == NULL)
63 return NSS_STATUS_UNAVAIL;
65 list = hesiod_resolve (context, name, type);
66 if (list == NULL)
68 int err = errno;
69 hesiod_end (context);
70 __set_errno (olderr);
71 return err == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
74 linebuflen = buffer + buflen - data->linebuffer;
75 len = strlen (*list) + 1;
76 if (linebuflen < len)
78 hesiod_free_list (context, list);
79 hesiod_end (context);
80 *errnop = ERANGE;
81 return NSS_STATUS_TRYAGAIN;
84 memcpy (data->linebuffer, *list, len);
85 hesiod_free_list (context, list);
86 hesiod_end (context);
88 parse_res = _nss_files_parse_grent (buffer, grp, data, buflen, errnop);
89 if (parse_res < 1)
91 __set_errno (olderr);
92 return parse_res == -1 ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND;
95 return NSS_STATUS_SUCCESS;
98 enum nss_status
99 _nss_hesiod_getgrnam_r (const char *name, struct group *grp,
100 char *buffer, size_t buflen, int *errnop)
102 return lookup (name, "group", grp, buffer, buflen, errnop);
105 enum nss_status
106 _nss_hesiod_getgrgid_r (gid_t gid, struct group *grp,
107 char *buffer, size_t buflen, int *errnop)
109 char gidstr[21]; /* We will probably never have a gid_t with more
110 than 64 bits. */
112 snprintf (gidstr, sizeof gidstr, "%d", gid);
114 return lookup (gidstr, "gid", grp, buffer, buflen, errnop);
117 static int
118 internal_gid_in_list (const gid_t *list, const gid_t g, long int len)
120 while (len > 0)
122 if (*list == g)
123 return 1;
124 --len;
125 ++list;
127 return 0;
130 static enum nss_status
131 internal_gid_from_group (void *context, const char *groupname, gid_t *group)
133 char **grp_res;
134 enum nss_status status = NSS_STATUS_NOTFOUND;
136 grp_res = hesiod_resolve (context, groupname, "group");
137 if (grp_res != NULL && *grp_res != NULL)
139 char *p = *grp_res;
141 /* Skip to third field. */
142 while (*p != '\0' && *p != ':')
143 ++p;
144 if (*p != '\0')
145 ++p;
146 while (*p != '\0' && *p != ':')
147 ++p;
148 if (*p != '\0')
150 char *endp;
151 char *q = ++p;
152 long int val;
154 while (*q != '\0' && *q != ':')
155 ++q;
157 val = strtol (p, &endp, 10);
158 if (sizeof (gid_t) == sizeof (long int) || (gid_t) val == val)
160 *group = val;
161 if (endp == q && endp != p)
162 status = NSS_STATUS_SUCCESS;
165 hesiod_free_list (context, grp_res);
167 return status;
170 enum nss_status
171 _nss_hesiod_initgroups_dyn (const char *user, gid_t group, long int *start,
172 long int *size, gid_t **groupsp, long int limit,
173 int *errnop)
175 enum nss_status status = NSS_STATUS_SUCCESS;
176 char **list = NULL;
177 char *p;
178 void *context;
179 gid_t *groups = *groupsp;
180 int save_errno;
182 context = _nss_hesiod_init ();
183 if (context == NULL)
184 return NSS_STATUS_UNAVAIL;
186 list = hesiod_resolve (context, user, "grplist");
188 if (list == NULL)
190 hesiod_end (context);
191 return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
194 if (!internal_gid_in_list (groups, group, *start))
196 if (__builtin_expect (*start == *size, 0))
198 /* Need a bigger buffer. */
199 gid_t *newgroups;
200 long int newsize;
202 if (limit > 0 && *size == limit)
203 /* We reached the maximum. */
204 goto done;
206 if (limit <= 0)
207 newsize = 2 * *size;
208 else
209 newsize = MIN (limit, 2 * *size);
211 newgroups = realloc (groups, newsize * sizeof (*groups));
212 if (newgroups == NULL)
213 goto done;
214 *groupsp = groups = newgroups;
215 *size = newsize;
218 groups[(*start)++] = group;
221 save_errno = errno;
223 p = *list;
224 while (*p != '\0')
226 char *endp;
227 char *q;
228 long int val;
230 status = NSS_STATUS_NOTFOUND;
232 q = p;
233 while (*q != '\0' && *q != ':' && *q != ',')
234 ++q;
236 if (*q != '\0')
237 *q++ = '\0';
239 __set_errno (0);
240 val = strtol (p, &endp, 10);
241 /* Test whether the number is representable in a variable of
242 type `gid_t'. If not ignore the number. */
243 if ((sizeof (gid_t) == sizeof (long int) || (gid_t) val == val)
244 && errno == 0)
246 if (*endp == '\0' && endp != p)
248 group = val;
249 status = NSS_STATUS_SUCCESS;
251 else
252 status = internal_gid_from_group (context, p, &group);
254 if (status == NSS_STATUS_SUCCESS
255 && !internal_gid_in_list (groups, group, *start))
257 if (__builtin_expect (*start == *size, 0))
259 /* Need a bigger buffer. */
260 gid_t *newgroups;
261 long int newsize;
263 if (limit > 0 && *size == limit)
264 /* We reached the maximum. */
265 goto done;
267 if (limit <= 0)
268 newsize = 2 * *size;
269 else
270 newsize = MIN (limit, 2 * *size);
272 newgroups = realloc (groups, newsize * sizeof (*groups));
273 if (newgroups == NULL)
274 goto done;
275 *groupsp = groups = newgroups;
276 *size = newsize;
279 groups[(*start)++] = group;
283 p = q;
286 __set_errno (save_errno);
288 done:
289 hesiod_free_list (context, list);
290 hesiod_end (context);
292 return NSS_STATUS_SUCCESS;