]>
Commit | Line | Data |
---|---|---|
2b778ceb | 1 | /* Copyright (C) 1997-2021 Free Software Foundation, Inc. |
61eb22d3 UD |
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 | |
41bdb6e2 AJ |
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. | |
61eb22d3 UD |
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 | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
61eb22d3 | 14 | |
41bdb6e2 | 15 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 | 16 | License along with the GNU C Library; if not, see |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
61eb22d3 | 18 | |
bee1e289 | 19 | #include <ctype.h> |
61eb22d3 | 20 | #include <errno.h> |
61eb22d3 | 21 | #include <grp.h> |
bee1e289 | 22 | #include <hesiod.h> |
2f54c82d | 23 | #include <nss.h> |
61eb22d3 UD |
24 | #include <stdio.h> |
25 | #include <stdlib.h> | |
26 | #include <string.h> | |
7603ea28 | 27 | #include <sys/param.h> |
2f54c82d | 28 | |
69787006 FW |
29 | NSS_DECLARE_MODULE_FUNCTIONS (hesiod) |
30 | ||
61eb22d3 UD |
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 | ||
61eb22d3 | 37 | enum nss_status |
51eecc4a | 38 | _nss_hesiod_setgrent (int stayopen) |
61eb22d3 | 39 | { |
2f54c82d | 40 | return NSS_STATUS_SUCCESS; |
61eb22d3 UD |
41 | } |
42 | ||
43 | enum nss_status | |
44 | _nss_hesiod_endgrent (void) | |
45 | { | |
61eb22d3 UD |
46 | return NSS_STATUS_SUCCESS; |
47 | } | |
48 | ||
49 | static enum nss_status | |
50 | lookup (const char *name, const char *type, struct group *grp, | |
d71b808a | 51 | char *buffer, size_t buflen, int *errnop) |
61eb22d3 | 52 | { |
61eb22d3 UD |
53 | struct parser_data *data = (void *) buffer; |
54 | size_t linebuflen; | |
2f54c82d | 55 | void *context; |
61eb22d3 UD |
56 | char **list; |
57 | int parse_res; | |
d71b808a | 58 | size_t len; |
34816665 | 59 | int olderr = errno; |
61eb22d3 | 60 | |
5018f16c | 61 | if (hesiod_init (&context) < 0) |
2f54c82d | 62 | return NSS_STATUS_UNAVAIL; |
61eb22d3 UD |
63 | |
64 | list = hesiod_resolve (context, name, type); | |
65 | if (list == NULL) | |
2f54c82d | 66 | { |
34816665 | 67 | int err = errno; |
2f54c82d | 68 | hesiod_end (context); |
34816665 UD |
69 | __set_errno (olderr); |
70 | return err == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL; | |
2f54c82d | 71 | } |
61eb22d3 UD |
72 | |
73 | linebuflen = buffer + buflen - data->linebuffer; | |
d71b808a UD |
74 | len = strlen (*list) + 1; |
75 | if (linebuflen < len) | |
61eb22d3 UD |
76 | { |
77 | hesiod_free_list (context, list); | |
2f54c82d | 78 | hesiod_end (context); |
d71b808a | 79 | *errnop = ERANGE; |
61eb22d3 UD |
80 | return NSS_STATUS_TRYAGAIN; |
81 | } | |
82 | ||
d71b808a | 83 | memcpy (data->linebuffer, *list, len); |
61eb22d3 | 84 | hesiod_free_list (context, list); |
2f54c82d | 85 | hesiod_end (context); |
61eb22d3 | 86 | |
d71b808a | 87 | parse_res = _nss_files_parse_grent (buffer, grp, data, buflen, errnop); |
61eb22d3 | 88 | if (parse_res < 1) |
34816665 UD |
89 | { |
90 | __set_errno (olderr); | |
91 | return parse_res == -1 ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND; | |
92 | } | |
61eb22d3 UD |
93 | |
94 | return NSS_STATUS_SUCCESS; | |
95 | } | |
96 | ||
97 | enum nss_status | |
98 | _nss_hesiod_getgrnam_r (const char *name, struct group *grp, | |
d71b808a | 99 | char *buffer, size_t buflen, int *errnop) |
61eb22d3 | 100 | { |
2f54c82d | 101 | return lookup (name, "group", grp, buffer, buflen, errnop); |
61eb22d3 UD |
102 | } |
103 | ||
104 | enum nss_status | |
105 | _nss_hesiod_getgrgid_r (gid_t gid, struct group *grp, | |
d71b808a | 106 | char *buffer, size_t buflen, int *errnop) |
61eb22d3 | 107 | { |
61eb22d3 UD |
108 | char gidstr[21]; /* We will probably never have a gid_t with more |
109 | than 64 bits. */ | |
110 | ||
111 | snprintf (gidstr, sizeof gidstr, "%d", gid); | |
112 | ||
2f54c82d | 113 | return lookup (gidstr, "gid", grp, buffer, buflen, errnop); |
61eb22d3 | 114 | } |
bee1e289 UD |
115 | |
116 | static int | |
117 | internal_gid_in_list (const gid_t *list, const gid_t g, long int len) | |
118 | { | |
119 | while (len > 0) | |
120 | { | |
121 | if (*list == g) | |
122 | return 1; | |
123 | --len; | |
124 | ++list; | |
125 | } | |
126 | return 0; | |
127 | } | |
128 | ||
129 | static enum nss_status | |
130 | internal_gid_from_group (void *context, const char *groupname, gid_t *group) | |
131 | { | |
132 | char **grp_res; | |
133 | enum nss_status status = NSS_STATUS_NOTFOUND; | |
134 | ||
135 | grp_res = hesiod_resolve (context, groupname, "group"); | |
136 | if (grp_res != NULL && *grp_res != NULL) | |
137 | { | |
138 | char *p = *grp_res; | |
139 | ||
2eeb9a5d | 140 | /* Skip to third field. */ |
bee1e289 UD |
141 | while (*p != '\0' && *p != ':') |
142 | ++p; | |
2eeb9a5d | 143 | if (*p != '\0') |
bee1e289 UD |
144 | ++p; |
145 | while (*p != '\0' && *p != ':') | |
146 | ++p; | |
2eeb9a5d | 147 | if (*p != '\0') |
bee1e289 UD |
148 | { |
149 | char *endp; | |
150 | char *q = ++p; | |
0a55a284 | 151 | long int val; |
bee1e289 | 152 | |
bee1e289 UD |
153 | while (*q != '\0' && *q != ':') |
154 | ++q; | |
155 | ||
0a55a284 UD |
156 | val = strtol (p, &endp, 10); |
157 | if (sizeof (gid_t) == sizeof (long int) || (gid_t) val == val) | |
158 | { | |
159 | *group = val; | |
160 | if (endp == q && endp != p) | |
161 | status = NSS_STATUS_SUCCESS; | |
162 | } | |
bee1e289 UD |
163 | } |
164 | hesiod_free_list (context, grp_res); | |
165 | } | |
166 | return status; | |
167 | } | |
168 | ||
169 | enum nss_status | |
cf9e9ad9 | 170 | _nss_hesiod_initgroups_dyn (const char *user, gid_t group, long int *start, |
7603ea28 UD |
171 | long int *size, gid_t **groupsp, long int limit, |
172 | int *errnop) | |
bee1e289 UD |
173 | { |
174 | enum nss_status status = NSS_STATUS_SUCCESS; | |
175 | char **list = NULL; | |
176 | char *p; | |
177 | void *context; | |
cf9e9ad9 | 178 | gid_t *groups = *groupsp; |
521a2f65 | 179 | int save_errno; |
bee1e289 | 180 | |
5018f16c | 181 | if (hesiod_init (&context) < 0) |
bee1e289 UD |
182 | return NSS_STATUS_UNAVAIL; |
183 | ||
184 | list = hesiod_resolve (context, user, "grplist"); | |
185 | ||
186 | if (list == NULL) | |
187 | { | |
0a55a284 | 188 | hesiod_end (context); |
bee1e289 UD |
189 | return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL; |
190 | } | |
191 | ||
521a2f65 UD |
192 | save_errno = errno; |
193 | ||
bee1e289 | 194 | p = *list; |
cf9e9ad9 | 195 | while (*p != '\0') |
bee1e289 UD |
196 | { |
197 | char *endp; | |
198 | char *q; | |
0a55a284 | 199 | long int val; |
bee1e289 UD |
200 | |
201 | status = NSS_STATUS_NOTFOUND; | |
202 | ||
203 | q = p; | |
521a2f65 | 204 | while (*q != '\0' && *q != ':' && *q != ',') |
bee1e289 UD |
205 | ++q; |
206 | ||
207 | if (*q != '\0') | |
208 | *q++ = '\0'; | |
209 | ||
521a2f65 | 210 | __set_errno (0); |
0a55a284 | 211 | val = strtol (p, &endp, 10); |
521a2f65 UD |
212 | /* Test whether the number is representable in a variable of |
213 | type `gid_t'. If not ignore the number. */ | |
214 | if ((sizeof (gid_t) == sizeof (long int) || (gid_t) val == val) | |
215 | && errno == 0) | |
0a55a284 UD |
216 | { |
217 | if (*endp == '\0' && endp != p) | |
521a2f65 UD |
218 | { |
219 | group = val; | |
220 | status = NSS_STATUS_SUCCESS; | |
221 | } | |
0a55a284 UD |
222 | else |
223 | status = internal_gid_from_group (context, p, &group); | |
bee1e289 | 224 | |
0a55a284 UD |
225 | if (status == NSS_STATUS_SUCCESS |
226 | && !internal_gid_in_list (groups, group, *start)) | |
cf9e9ad9 | 227 | { |
a1ffb40e | 228 | if (__glibc_unlikely (*start == *size)) |
cf9e9ad9 UD |
229 | { |
230 | /* Need a bigger buffer. */ | |
231 | gid_t *newgroups; | |
7603ea28 UD |
232 | long int newsize; |
233 | ||
234 | if (limit > 0 && *size == limit) | |
235 | /* We reached the maximum. */ | |
236 | goto done; | |
237 | ||
238 | if (limit <= 0) | |
239 | newsize = 2 * *size; | |
240 | else | |
241 | newsize = MIN (limit, 2 * *size); | |
242 | ||
243 | newgroups = realloc (groups, newsize * sizeof (*groups)); | |
cf9e9ad9 UD |
244 | if (newgroups == NULL) |
245 | goto done; | |
246 | *groupsp = groups = newgroups; | |
7603ea28 | 247 | *size = newsize; |
cf9e9ad9 UD |
248 | } |
249 | ||
250 | groups[(*start)++] = group; | |
251 | } | |
0a55a284 | 252 | } |
bee1e289 UD |
253 | |
254 | p = q; | |
255 | } | |
256 | ||
521a2f65 UD |
257 | __set_errno (save_errno); |
258 | ||
cf9e9ad9 | 259 | done: |
bee1e289 | 260 | hesiod_free_list (context, list); |
0a55a284 | 261 | hesiod_end (context); |
bee1e289 UD |
262 | |
263 | return NSS_STATUS_SUCCESS; | |
264 | } |