]> git.ipfire.org Git - thirdparty/glibc.git/blob - hesiod/nss_hesiod/hesiod-grp.c
Use glibc_likely instead __builtin_expect.
[thirdparty/glibc.git] / hesiod / nss_hesiod / hesiod-grp.c
1 /* Copyright (C) 1997-2014 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, see
17 <http://www.gnu.org/licenses/>. */
18
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>
28
29 #include "nss_hesiod.h"
30
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>
36
37 enum nss_status
38 _nss_hesiod_setgrent (int stayopen)
39 {
40 return NSS_STATUS_SUCCESS;
41 }
42
43 enum nss_status
44 _nss_hesiod_endgrent (void)
45 {
46 return NSS_STATUS_SUCCESS;
47 }
48
49 static enum nss_status
50 lookup (const char *name, const char *type, struct group *grp,
51 char *buffer, size_t buflen, int *errnop)
52 {
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;
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 int err = errno;
69 hesiod_end (context);
70 __set_errno (olderr);
71 return err == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
72 }
73
74 linebuflen = buffer + buflen - data->linebuffer;
75 len = strlen (*list) + 1;
76 if (linebuflen < len)
77 {
78 hesiod_free_list (context, list);
79 hesiod_end (context);
80 *errnop = ERANGE;
81 return NSS_STATUS_TRYAGAIN;
82 }
83
84 memcpy (data->linebuffer, *list, len);
85 hesiod_free_list (context, list);
86 hesiod_end (context);
87
88 parse_res = _nss_files_parse_grent (buffer, grp, data, buflen, errnop);
89 if (parse_res < 1)
90 {
91 __set_errno (olderr);
92 return parse_res == -1 ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND;
93 }
94
95 return NSS_STATUS_SUCCESS;
96 }
97
98 enum nss_status
99 _nss_hesiod_getgrnam_r (const char *name, struct group *grp,
100 char *buffer, size_t buflen, int *errnop)
101 {
102 return lookup (name, "group", grp, buffer, buflen, errnop);
103 }
104
105 enum nss_status
106 _nss_hesiod_getgrgid_r (gid_t gid, struct group *grp,
107 char *buffer, size_t buflen, int *errnop)
108 {
109 char gidstr[21]; /* We will probably never have a gid_t with more
110 than 64 bits. */
111
112 snprintf (gidstr, sizeof gidstr, "%d", gid);
113
114 return lookup (gidstr, "gid", grp, buffer, buflen, errnop);
115 }
116
117 static int
118 internal_gid_in_list (const gid_t *list, const gid_t g, long int len)
119 {
120 while (len > 0)
121 {
122 if (*list == g)
123 return 1;
124 --len;
125 ++list;
126 }
127 return 0;
128 }
129
130 static enum nss_status
131 internal_gid_from_group (void *context, const char *groupname, gid_t *group)
132 {
133 char **grp_res;
134 enum nss_status status = NSS_STATUS_NOTFOUND;
135
136 grp_res = hesiod_resolve (context, groupname, "group");
137 if (grp_res != NULL && *grp_res != NULL)
138 {
139 char *p = *grp_res;
140
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')
149 {
150 char *endp;
151 char *q = ++p;
152 long int val;
153
154 while (*q != '\0' && *q != ':')
155 ++q;
156
157 val = strtol (p, &endp, 10);
158 if (sizeof (gid_t) == sizeof (long int) || (gid_t) val == val)
159 {
160 *group = val;
161 if (endp == q && endp != p)
162 status = NSS_STATUS_SUCCESS;
163 }
164 }
165 hesiod_free_list (context, grp_res);
166 }
167 return status;
168 }
169
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)
174 {
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;
181
182 context = _nss_hesiod_init ();
183 if (context == NULL)
184 return NSS_STATUS_UNAVAIL;
185
186 list = hesiod_resolve (context, user, "grplist");
187
188 if (list == NULL)
189 {
190 hesiod_end (context);
191 return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
192 }
193
194 save_errno = errno;
195
196 p = *list;
197 while (*p != '\0')
198 {
199 char *endp;
200 char *q;
201 long int val;
202
203 status = NSS_STATUS_NOTFOUND;
204
205 q = p;
206 while (*q != '\0' && *q != ':' && *q != ',')
207 ++q;
208
209 if (*q != '\0')
210 *q++ = '\0';
211
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)
218 {
219 if (*endp == '\0' && endp != p)
220 {
221 group = val;
222 status = NSS_STATUS_SUCCESS;
223 }
224 else
225 status = internal_gid_from_group (context, p, &group);
226
227 if (status == NSS_STATUS_SUCCESS
228 && !internal_gid_in_list (groups, group, *start))
229 {
230 if (__glibc_unlikely (*start == *size))
231 {
232 /* Need a bigger buffer. */
233 gid_t *newgroups;
234 long int newsize;
235
236 if (limit > 0 && *size == limit)
237 /* We reached the maximum. */
238 goto done;
239
240 if (limit <= 0)
241 newsize = 2 * *size;
242 else
243 newsize = MIN (limit, 2 * *size);
244
245 newgroups = realloc (groups, newsize * sizeof (*groups));
246 if (newgroups == NULL)
247 goto done;
248 *groupsp = groups = newgroups;
249 *size = newsize;
250 }
251
252 groups[(*start)++] = group;
253 }
254 }
255
256 p = q;
257 }
258
259 __set_errno (save_errno);
260
261 done:
262 hesiod_free_list (context, list);
263 hesiod_end (context);
264
265 return NSS_STATUS_SUCCESS;
266 }