Optimize pt_chown.
[glibc.git] / hesiod / nss_hesiod / hesiod-grp.c
blob50c53f7893dec30dfb82eaed571037731a7fda6b
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, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
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>
30 #include "nss_hesiod.h"
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>
38 enum nss_status
39 _nss_hesiod_setgrent (int stayopen)
41 return NSS_STATUS_SUCCESS;
44 enum nss_status
45 _nss_hesiod_endgrent (void)
47 return NSS_STATUS_SUCCESS;
50 static enum nss_status
51 lookup (const char *name, const char *type, struct group *grp,
52 char *buffer, size_t buflen, int *errnop)
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 int olderr = errno;
62 context = _nss_hesiod_init ();
63 if (context == NULL)
64 return NSS_STATUS_UNAVAIL;
66 list = hesiod_resolve (context, name, type);
67 if (list == NULL)
69 int err = errno;
70 hesiod_end (context);
71 __set_errno (olderr);
72 return err == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
75 linebuflen = buffer + buflen - data->linebuffer;
76 len = strlen (*list) + 1;
77 if (linebuflen < len)
79 hesiod_free_list (context, list);
80 hesiod_end (context);
81 *errnop = ERANGE;
82 return NSS_STATUS_TRYAGAIN;
85 memcpy (data->linebuffer, *list, len);
86 hesiod_free_list (context, list);
87 hesiod_end (context);
89 parse_res = _nss_files_parse_grent (buffer, grp, data, buflen, errnop);
90 if (parse_res < 1)
92 __set_errno (olderr);
93 return parse_res == -1 ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND;
96 return NSS_STATUS_SUCCESS;
99 enum nss_status
100 _nss_hesiod_getgrnam_r (const char *name, struct group *grp,
101 char *buffer, size_t buflen, int *errnop)
103 return lookup (name, "group", grp, buffer, buflen, errnop);
106 enum nss_status
107 _nss_hesiod_getgrgid_r (gid_t gid, struct group *grp,
108 char *buffer, size_t buflen, int *errnop)
110 char gidstr[21]; /* We will probably never have a gid_t with more
111 than 64 bits. */
113 snprintf (gidstr, sizeof gidstr, "%d", gid);
115 return lookup (gidstr, "gid", grp, buffer, buflen, errnop);
118 static int
119 internal_gid_in_list (const gid_t *list, const gid_t g, long int len)
121 while (len > 0)
123 if (*list == g)
124 return 1;
125 --len;
126 ++list;
128 return 0;
131 static enum nss_status
132 internal_gid_from_group (void *context, const char *groupname, gid_t *group)
134 char **grp_res;
135 enum nss_status status = NSS_STATUS_NOTFOUND;
137 grp_res = hesiod_resolve (context, groupname, "group");
138 if (grp_res != NULL && *grp_res != NULL)
140 char *p = *grp_res;
142 while (*p != '\0' && *p != ':')
143 ++p;
144 while (*p != '\0' && *p == ':')
145 ++p;
146 while (*p != '\0' && *p != ':')
147 ++p;
148 while (*p != '\0' && *p == ':')
149 ++p;
150 if (*p == ':')
152 char *endp;
153 char *q = ++p;
154 long int val;
156 q = p;
157 while (*q != '\0' && *q != ':')
158 ++q;
160 val = strtol (p, &endp, 10);
161 if (sizeof (gid_t) == sizeof (long int) || (gid_t) val == val)
163 *group = val;
164 if (endp == q && endp != p)
165 status = NSS_STATUS_SUCCESS;
168 hesiod_free_list (context, grp_res);
170 return status;
173 enum nss_status
174 _nss_hesiod_initgroups_dyn (const char *user, gid_t group, long int *start,
175 long int *size, gid_t **groupsp, long int limit,
176 int *errnop)
178 enum nss_status status = NSS_STATUS_SUCCESS;
179 char **list = NULL;
180 char *p;
181 void *context;
182 gid_t *groups = *groupsp;
183 int save_errno;
185 context = _nss_hesiod_init ();
186 if (context == NULL)
187 return NSS_STATUS_UNAVAIL;
189 list = hesiod_resolve (context, user, "grplist");
191 if (list == NULL)
193 hesiod_end (context);
194 return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
197 if (!internal_gid_in_list (groups, group, *start))
199 if (__builtin_expect (*start == *size, 0))
201 /* Need a bigger buffer. */
202 gid_t *newgroups;
203 long int newsize;
205 if (limit > 0 && *size == limit)
206 /* We reached the maximum. */
207 goto done;
209 if (limit <= 0)
210 newsize = 2 * *size;
211 else
212 newsize = MIN (limit, 2 * *size);
214 newgroups = realloc (groups, newsize * sizeof (*groups));
215 if (newgroups == NULL)
216 goto done;
217 *groupsp = groups = newgroups;
218 *size = newsize;
221 groups[(*start)++] = group;
224 save_errno = errno;
226 p = *list;
227 while (*p != '\0')
229 char *endp;
230 char *q;
231 long int val;
233 status = NSS_STATUS_NOTFOUND;
235 q = p;
236 while (*q != '\0' && *q != ':' && *q != ',')
237 ++q;
239 if (*q != '\0')
240 *q++ = '\0';
242 __set_errno (0);
243 val = strtol (p, &endp, 10);
244 /* Test whether the number is representable in a variable of
245 type `gid_t'. If not ignore the number. */
246 if ((sizeof (gid_t) == sizeof (long int) || (gid_t) val == val)
247 && errno == 0)
249 if (*endp == '\0' && endp != p)
251 group = val;
252 status = NSS_STATUS_SUCCESS;
254 else
255 status = internal_gid_from_group (context, p, &group);
257 if (status == NSS_STATUS_SUCCESS
258 && !internal_gid_in_list (groups, group, *start))
260 if (__builtin_expect (*start == *size, 0))
262 /* Need a bigger buffer. */
263 gid_t *newgroups;
264 long int newsize;
266 if (limit > 0 && *size == limit)
267 /* We reached the maximum. */
268 goto done;
270 if (limit <= 0)
271 newsize = 2 * *size;
272 else
273 newsize = MIN (limit, 2 * *size);
275 newgroups = realloc (groups, newsize * sizeof (*groups));
276 if (newgroups == NULL)
277 goto done;
278 *groupsp = groups = newgroups;
279 *size = newsize;
282 groups[(*start)++] = group;
286 p = q;
289 __set_errno (save_errno);
291 done:
292 hesiod_free_list (context, list);
293 hesiod_end (context);
295 return NSS_STATUS_SUCCESS;