Update copyright dates with scripts/update-copyrights.
[glibc.git] / hesiod / nss_hesiod / hesiod-grp.c
blob0909a853a37ad5ddd2d09040f9467b54dad96ae4
1 /* Copyright (C) 1997-2015 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 save_errno = errno;
196 p = *list;
197 while (*p != '\0')
199 char *endp;
200 char *q;
201 long int val;
203 status = NSS_STATUS_NOTFOUND;
205 q = p;
206 while (*q != '\0' && *q != ':' && *q != ',')
207 ++q;
209 if (*q != '\0')
210 *q++ = '\0';
212 __set_errno (0);
213 val = strtol (p, &endp, 10);
214 /* Test whether the number is representable in a variable of
215 type `gid_t'. If not ignore the number. */
216 if ((sizeof (gid_t) == sizeof (long int) || (gid_t) val == val)
217 && errno == 0)
219 if (*endp == '\0' && endp != p)
221 group = val;
222 status = NSS_STATUS_SUCCESS;
224 else
225 status = internal_gid_from_group (context, p, &group);
227 if (status == NSS_STATUS_SUCCESS
228 && !internal_gid_in_list (groups, group, *start))
230 if (__glibc_unlikely (*start == *size))
232 /* Need a bigger buffer. */
233 gid_t *newgroups;
234 long int newsize;
236 if (limit > 0 && *size == limit)
237 /* We reached the maximum. */
238 goto done;
240 if (limit <= 0)
241 newsize = 2 * *size;
242 else
243 newsize = MIN (limit, 2 * *size);
245 newgroups = realloc (groups, newsize * sizeof (*groups));
246 if (newgroups == NULL)
247 goto done;
248 *groupsp = groups = newgroups;
249 *size = newsize;
252 groups[(*start)++] = group;
256 p = q;
259 __set_errno (save_errno);
261 done:
262 hesiod_free_list (context, list);
263 hesiod_end (context);
265 return NSS_STATUS_SUCCESS;