]>
Commit | Line | Data |
---|---|---|
0ecb606c | 1 | /* Copyright (C) 1996-1999,2001-2005,2006 Free Software Foundation, Inc. |
6259ec0d UD |
2 | This file is part of the GNU C Library. |
3 | Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996. | |
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. | |
6259ec0d 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. |
6259ec0d | 14 | |
41bdb6e2 AJ |
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. */ | |
6259ec0d | 19 | |
6259ec0d | 20 | #include <ctype.h> |
1aa43890 | 21 | #include <errno.h> |
3996f34b | 22 | #include <fcntl.h> |
6259ec0d | 23 | #include <netdb.h> |
1aa43890 UD |
24 | #include <nss.h> |
25 | #include <nsswitch.h> | |
6259ec0d | 26 | #include <shadow.h> |
1aa43890 | 27 | #include <stdio_ext.h> |
6259ec0d | 28 | #include <string.h> |
1e2e27fd | 29 | #include <rpc/types.h> |
6259ec0d | 30 | #include <rpcsvc/ypclnt.h> |
1aa43890 | 31 | #include <bits/libc-lock.h> |
26dee9c4 UD |
32 | |
33 | #include "netgroup.h" | |
26dee9c4 | 34 | |
fc9f33e3 | 35 | static service_user *ni; |
1e2e27fd UD |
36 | static enum nss_status (*nss_setspent) (int stayopen); |
37 | static enum nss_status (*nss_getspnam_r) (const char *name, struct spwd * sp, | |
38 | char *buffer, size_t buflen, | |
39 | int *errnop); | |
40 | static enum nss_status (*nss_getspent_r) (struct spwd * sp, char *buffer, | |
41 | size_t buflen, int *errnop); | |
42 | static enum nss_status (*nss_endspent) (void); | |
6259ec0d | 43 | |
7e3be507 UD |
44 | /* Get the declaration of the parser function. */ |
45 | #define ENTNAME spent | |
46 | #define STRUCTURE spwd | |
47 | #define EXTERN_PARSER | |
cc3fa755 | 48 | #include <nss/nss_files/files-parse.c> |
7e3be507 | 49 | |
6259ec0d UD |
50 | /* Structure for remembering -@netgroup and -user members ... */ |
51 | #define BLACKLIST_INITIAL_SIZE 512 | |
52 | #define BLACKLIST_INCREMENT 256 | |
53 | struct blacklist_t | |
1e2e27fd UD |
54 | { |
55 | char *data; | |
56 | int current; | |
57 | int size; | |
58 | }; | |
6259ec0d UD |
59 | |
60 | struct ent_t | |
1e2e27fd | 61 | { |
0ecb606c JJ |
62 | bool netgroup; |
63 | bool files; | |
64 | bool first; | |
65 | enum nss_status setent_status; | |
1e2e27fd UD |
66 | FILE *stream; |
67 | struct blacklist_t blacklist; | |
68 | struct spwd pwd; | |
69 | struct __netgrent netgrdata; | |
70 | }; | |
6259ec0d UD |
71 | typedef struct ent_t ent_t; |
72 | ||
0ecb606c JJ |
73 | static ent_t ext_ent = { false, true, false, NSS_STATUS_SUCCESS, NULL, |
74 | { NULL, 0, 0}, | |
75 | { NULL, NULL, 0, 0, 0, 0, 0, 0, 0}}; | |
6259ec0d UD |
76 | |
77 | /* Protect global state against multiple changers. */ | |
78 | __libc_lock_define_initialized (static, lock) | |
79 | ||
80 | /* Prototypes for local functions. */ | |
81 | static void blacklist_store_name (const char *, ent_t *); | |
82 | static int in_blacklist (const char *, int, ent_t *); | |
2d7da676 | 83 | |
1e2e27fd UD |
84 | /* Initialize the NSS interface/functions. The calling function must |
85 | hold the lock. */ | |
86 | static void | |
87 | init_nss_interface (void) | |
88 | { | |
89 | if (__nss_database_lookup ("shadow_compat", "passwd_compat", | |
90 | "nis", &ni) >= 0) | |
91 | { | |
92 | nss_setspent = __nss_lookup_function (ni, "setspent"); | |
93 | nss_getspnam_r = __nss_lookup_function (ni, "getspnam_r"); | |
94 | nss_getspent_r = __nss_lookup_function (ni, "getspent_r"); | |
95 | nss_endspent = __nss_lookup_function (ni, "endspent"); | |
96 | } | |
97 | } | |
98 | ||
6259ec0d UD |
99 | static void |
100 | give_spwd_free (struct spwd *pwd) | |
101 | { | |
102 | if (pwd->sp_namp != NULL) | |
103 | free (pwd->sp_namp); | |
104 | if (pwd->sp_pwdp != NULL) | |
105 | free (pwd->sp_pwdp); | |
106 | ||
107 | memset (pwd, '\0', sizeof (struct spwd)); | |
b378b9f9 UD |
108 | pwd->sp_warn = -1; |
109 | pwd->sp_inact = -1; | |
110 | pwd->sp_expire = -1; | |
111 | pwd->sp_flag = ~0ul; | |
6259ec0d UD |
112 | } |
113 | ||
114 | static int | |
115 | spwd_need_buflen (struct spwd *pwd) | |
116 | { | |
117 | int len = 0; | |
118 | ||
119 | if (pwd->sp_pwdp != NULL) | |
120 | len += strlen (pwd->sp_pwdp) + 1; | |
121 | ||
122 | return len; | |
123 | } | |
124 | ||
125 | static void | |
126 | copy_spwd_changes (struct spwd *dest, struct spwd *src, | |
127 | char *buffer, size_t buflen) | |
128 | { | |
129 | if (src->sp_pwdp != NULL && strlen (src->sp_pwdp)) | |
130 | { | |
131 | if (buffer == NULL) | |
132 | dest->sp_pwdp = strdup (src->sp_pwdp); | |
133 | else if (dest->sp_pwdp && | |
134 | strlen (dest->sp_pwdp) >= strlen (src->sp_pwdp)) | |
135 | strcpy (dest->sp_pwdp, src->sp_pwdp); | |
136 | else | |
137 | { | |
138 | dest->sp_pwdp = buffer; | |
139 | strcpy (dest->sp_pwdp, src->sp_pwdp); | |
140 | buffer += strlen (dest->sp_pwdp) + 1; | |
141 | buflen = buflen - (strlen (dest->sp_pwdp) + 1); | |
142 | } | |
143 | } | |
144 | if (src->sp_lstchg != 0) | |
145 | dest->sp_lstchg = src->sp_lstchg; | |
146 | if (src->sp_min != 0) | |
147 | dest->sp_min = src->sp_min; | |
148 | if (src->sp_max != 0) | |
149 | dest->sp_max = src->sp_max; | |
b378b9f9 | 150 | if (src->sp_warn != -1) |
6259ec0d | 151 | dest->sp_warn = src->sp_warn; |
b378b9f9 | 152 | if (src->sp_inact != -1) |
6259ec0d | 153 | dest->sp_inact = src->sp_inact; |
b378b9f9 | 154 | if (src->sp_expire != -1) |
6259ec0d | 155 | dest->sp_expire = src->sp_expire; |
b378b9f9 | 156 | if (src->sp_flag != ~0ul) |
6259ec0d UD |
157 | dest->sp_flag = src->sp_flag; |
158 | } | |
159 | ||
160 | static enum nss_status | |
1e2e27fd | 161 | internal_setspent (ent_t *ent, int stayopen) |
6259ec0d UD |
162 | { |
163 | enum nss_status status = NSS_STATUS_SUCCESS; | |
164 | ||
1e2e27fd | 165 | ent->first = ent->netgroup = 0; |
0ecb606c | 166 | ent->files = true; |
6259ec0d | 167 | |
26dee9c4 UD |
168 | /* If something was left over free it. */ |
169 | if (ent->netgroup) | |
170 | __internal_endnetgrent (&ent->netgrdata); | |
c131718c | 171 | |
6259ec0d | 172 | if (ent->blacklist.data != NULL) |
bd355af0 UD |
173 | { |
174 | ent->blacklist.current = 1; | |
175 | ent->blacklist.data[0] = '|'; | |
176 | ent->blacklist.data[1] = '\0'; | |
177 | } | |
178 | else | |
179 | ent->blacklist.current = 0; | |
6259ec0d UD |
180 | |
181 | if (ent->stream == NULL) | |
182 | { | |
1aa43890 | 183 | ent->stream = fopen ("/etc/shadow", "rm"); |
6259ec0d UD |
184 | |
185 | if (ent->stream == NULL) | |
186 | status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; | |
3996f34b UD |
187 | else |
188 | { | |
189 | /* We have to make sure the file is `closed on exec'. */ | |
190 | int result, flags; | |
191 | ||
1aa43890 | 192 | result = flags = fcntl (fileno_unlocked (ent->stream), F_GETFD, 0); |
3996f34b UD |
193 | if (result >= 0) |
194 | { | |
195 | flags |= FD_CLOEXEC; | |
1aa43890 | 196 | result = fcntl (fileno_unlocked (ent->stream), F_SETFD, flags); |
3996f34b UD |
197 | } |
198 | if (result < 0) | |
199 | { | |
200 | /* Something went wrong. Close the stream and return a | |
1e2e27fd | 201 | failure. */ |
3996f34b UD |
202 | fclose (ent->stream); |
203 | ent->stream = NULL; | |
204 | status = NSS_STATUS_UNAVAIL; | |
205 | } | |
1aa43890 UD |
206 | else |
207 | /* We take care of locking ourself. */ | |
208 | __fsetlocking (ent->stream, FSETLOCKING_BYCALLER); | |
3996f34b | 209 | } |
6259ec0d UD |
210 | } |
211 | else | |
212 | rewind (ent->stream); | |
213 | ||
214 | give_spwd_free (&ent->pwd); | |
215 | ||
1e2e27fd | 216 | if (status == NSS_STATUS_SUCCESS && nss_setspent) |
0ecb606c | 217 | ent->setent_status = nss_setspent (stayopen); |
1e2e27fd | 218 | |
6259ec0d UD |
219 | return status; |
220 | } | |
221 | ||
222 | ||
223 | enum nss_status | |
51eecc4a | 224 | _nss_compat_setspent (int stayopen) |
6259ec0d UD |
225 | { |
226 | enum nss_status result; | |
227 | ||
228 | __libc_lock_lock (lock); | |
229 | ||
26dee9c4 | 230 | if (ni == NULL) |
1e2e27fd | 231 | init_nss_interface (); |
c131718c | 232 | |
1e2e27fd | 233 | result = internal_setspent (&ext_ent, stayopen); |
6259ec0d UD |
234 | |
235 | __libc_lock_unlock (lock); | |
236 | ||
237 | return result; | |
238 | } | |
239 | ||
240 | ||
241 | static enum nss_status | |
242 | internal_endspent (ent_t *ent) | |
243 | { | |
1e2e27fd UD |
244 | if (nss_endspent) |
245 | nss_endspent (); | |
246 | ||
6259ec0d UD |
247 | if (ent->stream != NULL) |
248 | { | |
249 | fclose (ent->stream); | |
250 | ent->stream = NULL; | |
251 | } | |
252 | ||
26dee9c4 UD |
253 | if (ent->netgroup) |
254 | __internal_endnetgrent (&ent->netgrdata); | |
255 | ||
0ecb606c JJ |
256 | ent->first = ent->netgroup = false; |
257 | ent->files = true; | |
c131718c | 258 | |
6259ec0d | 259 | if (ent->blacklist.data != NULL) |
bd355af0 UD |
260 | { |
261 | ent->blacklist.current = 1; | |
262 | ent->blacklist.data[0] = '|'; | |
263 | ent->blacklist.data[1] = '\0'; | |
264 | } | |
265 | else | |
266 | ent->blacklist.current = 0; | |
c131718c | 267 | |
6259ec0d UD |
268 | give_spwd_free (&ent->pwd); |
269 | ||
270 | return NSS_STATUS_SUCCESS; | |
271 | } | |
272 | ||
273 | enum nss_status | |
274 | _nss_compat_endspent (void) | |
275 | { | |
276 | enum nss_status result; | |
277 | ||
278 | __libc_lock_lock (lock); | |
279 | ||
280 | result = internal_endspent (&ext_ent); | |
281 | ||
282 | __libc_lock_unlock (lock); | |
283 | ||
284 | return result; | |
285 | } | |
286 | ||
287 | ||
288 | static enum nss_status | |
1e2e27fd UD |
289 | getspent_next_nss_netgr (const char *name, struct spwd *result, ent_t *ent, |
290 | char *group, char *buffer, size_t buflen, | |
291 | int *errnop) | |
6259ec0d | 292 | { |
1e2e27fd | 293 | char *curdomain, *host, *user, *domain, *p2; |
6259ec0d UD |
294 | size_t p2len; |
295 | ||
1e2e27fd UD |
296 | if (!nss_getspnam_r) |
297 | return NSS_STATUS_UNAVAIL; | |
298 | ||
0ecb606c JJ |
299 | /* If the setpwent call failed, say so. */ |
300 | if (ent->setent_status != NSS_STATUS_SUCCESS) | |
301 | return ent->setent_status; | |
302 | ||
1e2e27fd | 303 | if (yp_get_default_domain (&curdomain) != YPERR_SUCCESS) |
6259ec0d | 304 | { |
0ecb606c JJ |
305 | ent->netgroup = false; |
306 | ent->first = false; | |
6259ec0d UD |
307 | give_spwd_free (&ent->pwd); |
308 | return NSS_STATUS_UNAVAIL; | |
309 | } | |
310 | ||
0ecb606c | 311 | if (ent->first == true) |
6259ec0d | 312 | { |
1e2e27fd | 313 | memset (&ent->netgrdata, 0, sizeof (struct __netgrent)); |
26dee9c4 | 314 | __internal_setnetgrent (group, &ent->netgrdata); |
0ecb606c | 315 | ent->first = false; |
6259ec0d UD |
316 | } |
317 | ||
318 | while (1) | |
319 | { | |
60c96635 | 320 | char *saved_cursor; |
1e2e27fd | 321 | enum nss_status status; |
60c96635 UD |
322 | |
323 | saved_cursor = ent->netgrdata.cursor; | |
26dee9c4 | 324 | status = __internal_getnetgrent_r (&host, &user, &domain, |
d71b808a UD |
325 | &ent->netgrdata, buffer, buflen, |
326 | errnop); | |
26dee9c4 | 327 | if (status != 1) |
6259ec0d | 328 | { |
26dee9c4 | 329 | __internal_endnetgrent (&ent->netgrdata); |
0ecb606c | 330 | ent->netgroup = false; |
6259ec0d UD |
331 | give_spwd_free (&ent->pwd); |
332 | return NSS_STATUS_RETURN; | |
333 | } | |
3996f34b | 334 | |
6259ec0d UD |
335 | if (user == NULL || user[0] == '-') |
336 | continue; | |
3996f34b | 337 | |
1e2e27fd | 338 | if (domain != NULL && strcmp (curdomain, domain) != 0) |
6259ec0d UD |
339 | continue; |
340 | ||
cc3fa755 UD |
341 | /* If name != NULL, we are called from getpwnam */ |
342 | if (name != NULL) | |
343 | if (strcmp (user, name) != 0) | |
344 | continue; | |
345 | ||
6259ec0d UD |
346 | p2len = spwd_need_buflen (&ent->pwd); |
347 | if (p2len > buflen) | |
348 | { | |
d71b808a | 349 | *errnop = ERANGE; |
6259ec0d UD |
350 | return NSS_STATUS_TRYAGAIN; |
351 | } | |
352 | p2 = buffer + (buflen - p2len); | |
353 | buflen -= p2len; | |
26dee9c4 | 354 | |
1e2e27fd UD |
355 | if (nss_getspnam_r (user, result, buffer, buflen, errnop) != |
356 | NSS_STATUS_SUCCESS) | |
357 | continue; | |
cc3fa755 | 358 | |
1e2e27fd | 359 | if (!in_blacklist (result->sp_namp, strlen (result->sp_namp), ent)) |
60c96635 | 360 | { |
1e2e27fd UD |
361 | /* Store the User in the blacklist for possible the "+" at the |
362 | end of /etc/passwd */ | |
cc3fa755 UD |
363 | blacklist_store_name (result->sp_namp, ent); |
364 | copy_spwd_changes (result, &ent->pwd, p2, p2len); | |
1e2e27fd | 365 | break; |
60c96635 | 366 | } |
26dee9c4 | 367 | } |
c131718c | 368 | |
26dee9c4 UD |
369 | return NSS_STATUS_SUCCESS; |
370 | } | |
371 | ||
372 | ||
6259ec0d | 373 | static enum nss_status |
1e2e27fd | 374 | getspent_next_nss (struct spwd *result, ent_t *ent, |
d71b808a | 375 | char *buffer, size_t buflen, int *errnop) |
6259ec0d | 376 | { |
1e2e27fd UD |
377 | enum nss_status status; |
378 | char *p2; | |
6259ec0d UD |
379 | size_t p2len; |
380 | ||
1e2e27fd UD |
381 | if (!nss_getspent_r) |
382 | return NSS_STATUS_UNAVAIL; | |
6259ec0d UD |
383 | |
384 | p2len = spwd_need_buflen (&ent->pwd); | |
385 | if (p2len > buflen) | |
386 | { | |
d71b808a | 387 | *errnop = ERANGE; |
6259ec0d UD |
388 | return NSS_STATUS_TRYAGAIN; |
389 | } | |
390 | p2 = buffer + (buflen - p2len); | |
391 | buflen -= p2len; | |
392 | do | |
393 | { | |
1e2e27fd UD |
394 | if ((status = nss_getspent_r (result, buffer, buflen, errnop)) != |
395 | NSS_STATUS_SUCCESS) | |
396 | return status; | |
6259ec0d | 397 | } |
1e2e27fd | 398 | while (in_blacklist (result->sp_namp, strlen (result->sp_namp), ent)); |
6259ec0d UD |
399 | |
400 | copy_spwd_changes (result, &ent->pwd, p2, p2len); | |
401 | ||
26dee9c4 | 402 | return NSS_STATUS_SUCCESS; |
6259ec0d UD |
403 | } |
404 | ||
0ecb606c | 405 | |
26dee9c4 UD |
406 | /* This function handle the +user entrys in /etc/shadow */ |
407 | static enum nss_status | |
1e2e27fd UD |
408 | getspnam_plususer (const char *name, struct spwd *result, ent_t *ent, |
409 | char *buffer, size_t buflen, int *errnop) | |
26dee9c4 | 410 | { |
1e2e27fd UD |
411 | if (!nss_getspnam_r) |
412 | return NSS_STATUS_UNAVAIL; | |
413 | ||
0ecb606c | 414 | struct spwd pwd; |
26dee9c4 | 415 | memset (&pwd, '\0', sizeof (struct spwd)); |
b378b9f9 UD |
416 | pwd.sp_warn = -1; |
417 | pwd.sp_inact = -1; | |
418 | pwd.sp_expire = -1; | |
419 | pwd.sp_flag = ~0ul; | |
c131718c | 420 | |
26dee9c4 | 421 | copy_spwd_changes (&pwd, result, NULL, 0); |
c131718c | 422 | |
0ecb606c | 423 | size_t plen = spwd_need_buflen (&pwd); |
26dee9c4 UD |
424 | if (plen > buflen) |
425 | { | |
d71b808a | 426 | *errnop = ERANGE; |
26dee9c4 UD |
427 | return NSS_STATUS_TRYAGAIN; |
428 | } | |
0ecb606c | 429 | char *p = buffer + (buflen - plen); |
26dee9c4 | 430 | buflen -= plen; |
c131718c | 431 | |
0ecb606c JJ |
432 | enum nss_status status = nss_getspnam_r (name, result, buffer, buflen, |
433 | errnop); | |
434 | if (status != NSS_STATUS_SUCCESS) | |
435 | return status; | |
6591c335 | 436 | |
1e2e27fd UD |
437 | if (in_blacklist (result->sp_namp, strlen (result->sp_namp), ent)) |
438 | return NSS_STATUS_NOTFOUND; | |
c131718c | 439 | |
1e2e27fd UD |
440 | copy_spwd_changes (result, &pwd, p, plen); |
441 | give_spwd_free (&pwd); | |
442 | /* We found the entry. */ | |
c503d3dc | 443 | return NSS_STATUS_SUCCESS; |
26dee9c4 | 444 | } |
6259ec0d | 445 | |
0ecb606c | 446 | |
6259ec0d UD |
447 | static enum nss_status |
448 | getspent_next_file (struct spwd *result, ent_t *ent, | |
d71b808a | 449 | char *buffer, size_t buflen, int *errnop) |
6259ec0d | 450 | { |
7e3be507 | 451 | struct parser_data *data = (void *) buffer; |
6259ec0d UD |
452 | while (1) |
453 | { | |
60c96635 UD |
454 | fpos_t pos; |
455 | int parse_res = 0; | |
c131718c | 456 | char *p; |
6259ec0d UD |
457 | |
458 | do | |
459 | { | |
20f8e666 UD |
460 | /* We need at least 3 characters for one line. */ |
461 | if (__builtin_expect (buflen < 3, 0)) | |
462 | { | |
463 | erange: | |
464 | *errnop = ERANGE; | |
465 | return NSS_STATUS_TRYAGAIN; | |
466 | } | |
467 | ||
60c96635 | 468 | fgetpos (ent->stream, &pos); |
af69217f | 469 | buffer[buflen - 1] = '\xff'; |
1aa43890 UD |
470 | p = fgets_unlocked (buffer, buflen, ent->stream); |
471 | if (p == NULL && feof_unlocked (ent->stream)) | |
34816665 UD |
472 | return NSS_STATUS_NOTFOUND; |
473 | ||
20f8e666 | 474 | if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) |
af69217f | 475 | { |
20f8e666 | 476 | erange_reset: |
af69217f | 477 | fsetpos (ent->stream, &pos); |
20f8e666 | 478 | goto erange; |
af69217f | 479 | } |
6259ec0d UD |
480 | |
481 | /* Skip leading blanks. */ | |
482 | while (isspace (*p)) | |
483 | ++p; | |
484 | } | |
c131718c | 485 | while (*p == '\0' || *p == '#' /* Ignore empty and comment lines. */ |
1e2e27fd UD |
486 | /* Parse the line. If it is invalid, loop to |
487 | get the next line of the file to parse. */ | |
60c96635 | 488 | || !(parse_res = _nss_files_parse_spent (p, result, data, |
d71b808a | 489 | buflen, errnop))); |
6259ec0d | 490 | |
20f8e666 UD |
491 | if (__builtin_expect (parse_res == -1, 0)) |
492 | /* The parser ran out of space. */ | |
493 | goto erange_reset; | |
3996f34b | 494 | |
6259ec0d UD |
495 | if (result->sp_namp[0] != '+' && result->sp_namp[0] != '-') |
496 | /* This is a real entry. */ | |
497 | break; | |
498 | ||
499 | /* -@netgroup */ | |
500 | if (result->sp_namp[0] == '-' && result->sp_namp[1] == '@' | |
501 | && result->sp_namp[2] != '\0') | |
502 | { | |
d71b808a | 503 | /* XXX Do not use fixed length buffers. */ |
1e2e27fd | 504 | char buf2[1024]; |
51eecc4a | 505 | char *user, *host, *domain; |
1e2e27fd | 506 | struct __netgrent netgrdata; |
c131718c | 507 | |
1e2e27fd UD |
508 | bzero (&netgrdata, sizeof (struct __netgrent)); |
509 | __internal_setnetgrent (&result->sp_namp[2], &netgrdata); | |
c131718c | 510 | while (__internal_getnetgrent_r (&host, &user, &domain, |
d71b808a UD |
511 | &netgrdata, buf2, sizeof (buf2), |
512 | errnop)) | |
6259ec0d UD |
513 | { |
514 | if (user != NULL && user[0] != '-') | |
515 | blacklist_store_name (user, ent); | |
516 | } | |
c131718c | 517 | __internal_endnetgrent (&netgrdata); |
6259ec0d UD |
518 | continue; |
519 | } | |
520 | ||
521 | /* +@netgroup */ | |
522 | if (result->sp_namp[0] == '+' && result->sp_namp[1] == '@' | |
523 | && result->sp_namp[2] != '\0') | |
524 | { | |
525 | int status; | |
526 | ||
0ecb606c JJ |
527 | ent->netgroup = true; |
528 | ent->first = true; | |
6259ec0d UD |
529 | copy_spwd_changes (&ent->pwd, result, NULL, 0); |
530 | ||
1e2e27fd UD |
531 | status = getspent_next_nss_netgr (NULL, result, ent, |
532 | &result->sp_namp[2], | |
533 | buffer, buflen, errnop); | |
6259ec0d UD |
534 | if (status == NSS_STATUS_RETURN) |
535 | continue; | |
536 | else | |
537 | return status; | |
538 | } | |
539 | ||
540 | /* -user */ | |
541 | if (result->sp_namp[0] == '-' && result->sp_namp[1] != '\0' | |
542 | && result->sp_namp[1] != '@') | |
543 | { | |
544 | blacklist_store_name (&result->sp_namp[1], ent); | |
545 | continue; | |
546 | } | |
547 | ||
548 | /* +user */ | |
549 | if (result->sp_namp[0] == '+' && result->sp_namp[1] != '\0' | |
550 | && result->sp_namp[1] != '@') | |
551 | { | |
c503d3dc UD |
552 | size_t len = strlen (result->sp_namp); |
553 | char buf[len]; | |
1e2e27fd | 554 | enum nss_status status; |
c131718c | 555 | |
cc3fa755 UD |
556 | /* Store the User in the blacklist for the "+" at the end of |
557 | /etc/passwd */ | |
c503d3dc | 558 | memcpy (buf, &result->sp_namp[1], len); |
1e2e27fd UD |
559 | status = getspnam_plususer (&result->sp_namp[1], result, ent, |
560 | buffer, buflen, errnop); | |
c503d3dc | 561 | blacklist_store_name (buf, ent); |
1e2e27fd UD |
562 | |
563 | if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ | |
564 | break; | |
c503d3dc UD |
565 | /* We couldn't parse the entry */ |
566 | else if (status == NSS_STATUS_RETURN | |
567 | /* entry doesn't exist */ | |
568 | || status == NSS_STATUS_NOTFOUND) | |
1e2e27fd UD |
569 | continue; |
570 | else | |
571 | { | |
572 | if (status == NSS_STATUS_TRYAGAIN) | |
573 | { | |
574 | fsetpos (ent->stream, &pos); | |
575 | *errnop = ERANGE; | |
576 | } | |
577 | return status; | |
578 | } | |
6259ec0d UD |
579 | } |
580 | ||
581 | /* +:... */ | |
582 | if (result->sp_namp[0] == '+' && result->sp_namp[1] == '\0') | |
583 | { | |
0ecb606c JJ |
584 | ent->files = false; |
585 | ent->first = true; | |
6259ec0d UD |
586 | copy_spwd_changes (&ent->pwd, result, NULL, 0); |
587 | ||
1e2e27fd | 588 | return getspent_next_nss (result, ent, buffer, buflen, errnop); |
6259ec0d UD |
589 | } |
590 | } | |
591 | ||
592 | return NSS_STATUS_SUCCESS; | |
593 | } | |
594 | ||
595 | ||
596 | static enum nss_status | |
597 | internal_getspent_r (struct spwd *pw, ent_t *ent, | |
d71b808a | 598 | char *buffer, size_t buflen, int *errnop) |
6259ec0d UD |
599 | { |
600 | if (ent->netgroup) | |
601 | { | |
1e2e27fd | 602 | enum nss_status status; |
6259ec0d UD |
603 | |
604 | /* We are searching members in a netgroup */ | |
605 | /* Since this is not the first call, we don't need the group name */ | |
1e2e27fd UD |
606 | status = getspent_next_nss_netgr (NULL, pw, ent, NULL, buffer, |
607 | buflen, errnop); | |
608 | ||
6259ec0d | 609 | if (status == NSS_STATUS_RETURN) |
d71b808a | 610 | return getspent_next_file (pw, ent, buffer, buflen, errnop); |
6259ec0d UD |
611 | else |
612 | return status; | |
613 | } | |
1e2e27fd UD |
614 | else if (ent->files) |
615 | return getspent_next_file (pw, ent, buffer, buflen, errnop); | |
6259ec0d | 616 | else |
1e2e27fd | 617 | return getspent_next_nss (pw, ent, buffer, buflen, errnop); |
6259ec0d UD |
618 | } |
619 | ||
0ecb606c | 620 | |
6259ec0d | 621 | enum nss_status |
d71b808a UD |
622 | _nss_compat_getspent_r (struct spwd *pwd, char *buffer, size_t buflen, |
623 | int *errnop) | |
6259ec0d | 624 | { |
1e2e27fd | 625 | enum nss_status result = NSS_STATUS_SUCCESS; |
6259ec0d UD |
626 | |
627 | __libc_lock_lock (lock); | |
628 | ||
1e2e27fd | 629 | /* Be prepared that the setpwent function was not called before. */ |
26dee9c4 | 630 | if (ni == NULL) |
1e2e27fd | 631 | init_nss_interface (); |
c131718c | 632 | |
6259ec0d | 633 | if (ext_ent.stream == NULL) |
1e2e27fd | 634 | result = internal_setspent (&ext_ent, 1); |
6259ec0d | 635 | |
1e2e27fd UD |
636 | if (result == NSS_STATUS_SUCCESS) |
637 | result = internal_getspent_r (pwd, &ext_ent, buffer, buflen, errnop); | |
6259ec0d UD |
638 | |
639 | __libc_lock_unlock (lock); | |
640 | ||
1e2e27fd | 641 | return result; |
6259ec0d UD |
642 | } |
643 | ||
0ecb606c | 644 | |
cc3fa755 UD |
645 | /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */ |
646 | static enum nss_status | |
647 | internal_getspnam_r (const char *name, struct spwd *result, ent_t *ent, | |
d71b808a | 648 | char *buffer, size_t buflen, int *errnop) |
cc3fa755 UD |
649 | { |
650 | struct parser_data *data = (void *) buffer; | |
651 | ||
652 | while (1) | |
653 | { | |
654 | fpos_t pos; | |
655 | char *p; | |
656 | int parse_res; | |
657 | ||
658 | do | |
659 | { | |
20f8e666 UD |
660 | /* We need at least 3 characters for one line. */ |
661 | if (__builtin_expect (buflen < 3, 0)) | |
662 | { | |
663 | erange: | |
664 | *errnop = ERANGE; | |
665 | return NSS_STATUS_TRYAGAIN; | |
666 | } | |
667 | ||
cc3fa755 | 668 | fgetpos (ent->stream, &pos); |
af69217f | 669 | buffer[buflen - 1] = '\xff'; |
1aa43890 UD |
670 | p = fgets_unlocked (buffer, buflen, ent->stream); |
671 | if (p == NULL && feof_unlocked (ent->stream)) | |
34816665 UD |
672 | return NSS_STATUS_NOTFOUND; |
673 | ||
af69217f UD |
674 | if (p == NULL || buffer[buflen - 1] != '\xff') |
675 | { | |
20f8e666 | 676 | erange_reset: |
af69217f | 677 | fsetpos (ent->stream, &pos); |
20f8e666 | 678 | goto erange; |
af69217f | 679 | } |
cc3fa755 | 680 | |
c503d3dc UD |
681 | /* Terminate the line for any case. */ |
682 | buffer[buflen - 1] = '\0'; | |
683 | ||
cc3fa755 UD |
684 | /* Skip leading blanks. */ |
685 | while (isspace (*p)) | |
686 | ++p; | |
687 | } | |
1e2e27fd | 688 | while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ |
cc3fa755 | 689 | /* Parse the line. If it is invalid, loop to |
1e2e27fd | 690 | get the next line of the file to parse. */ |
d71b808a UD |
691 | !(parse_res = _nss_files_parse_spent (p, result, data, buflen, |
692 | errnop))); | |
cc3fa755 | 693 | |
20f8e666 UD |
694 | if (__builtin_expect (parse_res == -1, 0)) |
695 | /* The parser ran out of space. */ | |
696 | goto erange_reset; | |
cc3fa755 UD |
697 | |
698 | /* This is a real entry. */ | |
699 | if (result->sp_namp[0] != '+' && result->sp_namp[0] != '-') | |
700 | { | |
701 | if (strcmp (result->sp_namp, name) == 0) | |
702 | return NSS_STATUS_SUCCESS; | |
703 | else | |
704 | continue; | |
705 | } | |
706 | ||
707 | /* -@netgroup */ | |
1e2e27fd UD |
708 | /* If the loaded NSS module does not support this service, add |
709 | all users from a +@netgroup entry to the blacklist, too. */ | |
cc3fa755 UD |
710 | if (result->sp_namp[0] == '-' && result->sp_namp[1] == '@' |
711 | && result->sp_namp[2] != '\0') | |
712 | { | |
c503d3dc UD |
713 | if (innetgr (&result->sp_namp[2], NULL, name, NULL)) |
714 | return NSS_STATUS_NOTFOUND; | |
cc3fa755 UD |
715 | continue; |
716 | } | |
717 | ||
718 | /* +@netgroup */ | |
719 | if (result->sp_namp[0] == '+' && result->sp_namp[1] == '@' | |
720 | && result->sp_namp[2] != '\0') | |
721 | { | |
c503d3dc | 722 | enum nss_status status; |
cc3fa755 | 723 | |
c503d3dc | 724 | if (innetgr (&result->sp_namp[2], NULL, name, NULL)) |
cc3fa755 | 725 | { |
c503d3dc UD |
726 | status = getspnam_plususer (name, result, ent, buffer, |
727 | buflen, errnop); | |
728 | ||
cc3fa755 UD |
729 | if (status == NSS_STATUS_RETURN) |
730 | continue; | |
731 | ||
c503d3dc | 732 | return status; |
1e2e27fd | 733 | } |
cc3fa755 UD |
734 | continue; |
735 | } | |
736 | ||
737 | /* -user */ | |
738 | if (result->sp_namp[0] == '-' && result->sp_namp[1] != '\0' | |
739 | && result->sp_namp[1] != '@') | |
740 | { | |
741 | if (strcmp (&result->sp_namp[1], name) == 0) | |
34816665 | 742 | return NSS_STATUS_NOTFOUND; |
cc3fa755 UD |
743 | else |
744 | continue; | |
745 | } | |
746 | ||
747 | /* +user */ | |
748 | if (result->sp_namp[0] == '+' && result->sp_namp[1] != '\0' | |
749 | && result->sp_namp[1] != '@') | |
750 | { | |
751 | if (strcmp (name, &result->sp_namp[1]) == 0) | |
752 | { | |
753 | enum nss_status status; | |
754 | ||
1e2e27fd UD |
755 | status = getspnam_plususer (name, result, ent, |
756 | buffer, buflen, errnop); | |
757 | ||
cc3fa755 | 758 | if (status == NSS_STATUS_RETURN) |
34816665 UD |
759 | /* We couldn't parse the entry */ |
760 | return NSS_STATUS_NOTFOUND; | |
cc3fa755 UD |
761 | else |
762 | return status; | |
763 | } | |
764 | } | |
765 | ||
766 | /* +:... */ | |
767 | if (result->sp_namp[0] == '+' && result->sp_namp[1] == '\0') | |
768 | { | |
769 | enum nss_status status; | |
770 | ||
1e2e27fd UD |
771 | status = getspnam_plususer (name, result, ent, |
772 | buffer, buflen, errnop); | |
773 | ||
c503d3dc UD |
774 | if (status == NSS_STATUS_SUCCESS) |
775 | /* We found the entry. */ | |
776 | break; | |
777 | else if (status == NSS_STATUS_RETURN) | |
778 | /* We couldn't parse the entry */ | |
779 | return NSS_STATUS_NOTFOUND; | |
cc3fa755 UD |
780 | else |
781 | return status; | |
782 | } | |
783 | } | |
784 | return NSS_STATUS_SUCCESS; | |
785 | } | |
6259ec0d | 786 | |
0ecb606c | 787 | |
6259ec0d UD |
788 | enum nss_status |
789 | _nss_compat_getspnam_r (const char *name, struct spwd *pwd, | |
d71b808a | 790 | char *buffer, size_t buflen, int *errnop) |
6259ec0d | 791 | { |
1e2e27fd | 792 | enum nss_status result; |
0ecb606c JJ |
793 | ent_t ent = { false, true, false, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0}, |
794 | { NULL, NULL, 0, 0, 0, 0, 0, 0, 0}}; | |
6259ec0d UD |
795 | |
796 | if (name[0] == '-' || name[0] == '+') | |
34816665 | 797 | return NSS_STATUS_NOTFOUND; |
6259ec0d | 798 | |
1e2e27fd UD |
799 | __libc_lock_lock (lock); |
800 | ||
26dee9c4 | 801 | if (ni == NULL) |
1e2e27fd UD |
802 | init_nss_interface (); |
803 | ||
804 | __libc_lock_unlock (lock); | |
c131718c | 805 | |
1e2e27fd | 806 | result = internal_setspent (&ent, 0); |
6259ec0d | 807 | |
c503d3dc UD |
808 | if (result == NSS_STATUS_SUCCESS) |
809 | result = internal_getspnam_r (name, pwd, &ent, buffer, buflen, errnop); | |
6259ec0d UD |
810 | |
811 | internal_endspent (&ent); | |
cc3fa755 | 812 | |
1e2e27fd | 813 | return result; |
6259ec0d UD |
814 | } |
815 | ||
0ecb606c | 816 | |
6259ec0d UD |
817 | /* Support routines for remembering -@netgroup and -user entries. |
818 | The names are stored in a single string with `|' as separator. */ | |
819 | static void | |
820 | blacklist_store_name (const char *name, ent_t *ent) | |
821 | { | |
822 | int namelen = strlen (name); | |
823 | char *tmp; | |
824 | ||
825 | /* first call, setup cache */ | |
826 | if (ent->blacklist.size == 0) | |
827 | { | |
828 | ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen); | |
829 | ent->blacklist.data = malloc (ent->blacklist.size); | |
830 | if (ent->blacklist.data == NULL) | |
831 | return; | |
832 | ent->blacklist.data[0] = '|'; | |
833 | ent->blacklist.data[1] = '\0'; | |
834 | ent->blacklist.current = 1; | |
835 | } | |
836 | else | |
837 | { | |
838 | if (in_blacklist (name, namelen, ent)) | |
839 | return; /* no duplicates */ | |
840 | ||
841 | if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size) | |
842 | { | |
843 | ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen); | |
844 | tmp = realloc (ent->blacklist.data, ent->blacklist.size); | |
845 | if (tmp == NULL) | |
846 | { | |
847 | free (ent->blacklist.data); | |
848 | ent->blacklist.size = 0; | |
849 | return; | |
850 | } | |
851 | ent->blacklist.data = tmp; | |
852 | } | |
853 | } | |
854 | ||
855 | tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name); | |
856 | *tmp++ = '|'; | |
857 | *tmp = '\0'; | |
858 | ent->blacklist.current += namelen + 1; | |
859 | ||
860 | return; | |
861 | } | |
862 | ||
0ecb606c | 863 | |
c131718c | 864 | /* Returns TRUE if ent->blacklist contains name, else FALSE. */ |
6259ec0d UD |
865 | static bool_t |
866 | in_blacklist (const char *name, int namelen, ent_t *ent) | |
867 | { | |
868 | char buf[namelen + 3]; | |
c131718c | 869 | char *cp; |
6259ec0d UD |
870 | |
871 | if (ent->blacklist.data == NULL) | |
0ecb606c | 872 | return false; |
6259ec0d | 873 | |
c131718c UD |
874 | buf[0] = '|'; |
875 | cp = stpcpy (&buf[1], name); | |
1e2e27fd | 876 | *cp++ = '|'; |
c131718c | 877 | *cp = '\0'; |
6259ec0d UD |
878 | return strstr (ent->blacklist.data, buf) != NULL; |
879 | } |