]>
Commit | Line | Data |
---|---|---|
5615eaf2 RM |
1 | /* Copyright (C) 1996-1999,2001-2006,2007,2011 |
2 | Free Software Foundation, Inc. | |
6259ec0d UD |
3 | This file is part of the GNU C Library. |
4 | Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996. | |
5 | ||
6 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
7 | modify it under the terms of the GNU Lesser General Public |
8 | License as published by the Free Software Foundation; either | |
9 | version 2.1 of the License, or (at your option) any later version. | |
6259ec0d UD |
10 | |
11 | The GNU C Library is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 14 | Lesser General Public License for more details. |
6259ec0d | 15 | |
41bdb6e2 AJ |
16 | You should have received a copy of the GNU Lesser General Public |
17 | License along with the GNU C Library; if not, write to the Free | |
18 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
19 | 02111-1307 USA. */ | |
6259ec0d | 20 | |
6259ec0d | 21 | #include <ctype.h> |
b4431a72 | 22 | #include <errno.h> |
3996f34b | 23 | #include <fcntl.h> |
6259ec0d | 24 | #include <netdb.h> |
b4431a72 UD |
25 | #include <nss.h> |
26 | #include <nsswitch.h> | |
27 | #include <pwd.h> | |
28 | #include <stdio_ext.h> | |
6259ec0d | 29 | #include <string.h> |
1e2e27fd | 30 | #include <rpc/types.h> |
6259ec0d | 31 | #include <rpcsvc/ypclnt.h> |
1e2e27fd | 32 | #include <bits/libc-lock.h> |
cc783763 | 33 | #include <kernel-features.h> |
6259ec0d UD |
34 | |
35 | #include "netgroup.h" | |
26dee9c4 | 36 | |
fc9f33e3 | 37 | static service_user *ni; |
1e2e27fd UD |
38 | static enum nss_status (*nss_setpwent) (int stayopen); |
39 | static enum nss_status (*nss_getpwnam_r) (const char *name, | |
40 | struct passwd * pwd, char *buffer, | |
41 | size_t buflen, int *errnop); | |
42 | static enum nss_status (*nss_getpwuid_r) (uid_t uid, struct passwd * pwd, | |
43 | char *buffer, size_t buflen, | |
44 | int *errnop); | |
45 | static enum nss_status (*nss_getpwent_r) (struct passwd * pwd, char *buffer, | |
46 | size_t buflen, int *errnop); | |
47 | static enum nss_status (*nss_endpwent) (void); | |
6259ec0d | 48 | |
7e3be507 UD |
49 | /* Get the declaration of the parser function. */ |
50 | #define ENTNAME pwent | |
51 | #define STRUCTURE passwd | |
52 | #define EXTERN_PARSER | |
cc3fa755 | 53 | #include <nss/nss_files/files-parse.c> |
7e3be507 | 54 | |
6259ec0d UD |
55 | /* Structure for remembering -@netgroup and -user members ... */ |
56 | #define BLACKLIST_INITIAL_SIZE 512 | |
57 | #define BLACKLIST_INCREMENT 256 | |
58 | struct blacklist_t | |
1e2e27fd UD |
59 | { |
60 | char *data; | |
61 | int current; | |
62 | int size; | |
63 | }; | |
6259ec0d UD |
64 | |
65 | struct ent_t | |
1e2e27fd | 66 | { |
cb62745a UD |
67 | bool netgroup; |
68 | bool first; | |
69 | bool files; | |
70 | enum nss_status setent_status; | |
1e2e27fd UD |
71 | FILE *stream; |
72 | struct blacklist_t blacklist; | |
73 | struct passwd pwd; | |
74 | struct __netgrent netgrdata; | |
75 | }; | |
6259ec0d UD |
76 | typedef struct ent_t ent_t; |
77 | ||
cb62745a UD |
78 | static ent_t ext_ent = { false, false, true, NSS_STATUS_SUCCESS, NULL, |
79 | { NULL, 0, 0 }, | |
80 | { NULL, NULL, 0, 0, NULL, NULL, NULL }}; | |
6259ec0d UD |
81 | |
82 | /* Protect global state against multiple changers. */ | |
83 | __libc_lock_define_initialized (static, lock) | |
84 | ||
cc783763 UD |
85 | /* Positive if O_CLOEXEC is supported, negative if it is not supported, |
86 | zero if it is still undecided. This variable is shared with the | |
87 | other compat functions. */ | |
88 | #ifdef __ASSUME_O_CLOEXEC | |
89 | # define __compat_have_cloexec 1 | |
90 | #else | |
91 | # ifdef O_CLOEXEC | |
92 | extern int __compat_have_cloexec; | |
93 | # else | |
94 | # define __compat_have_cloexec -1 | |
95 | # endif | |
96 | #endif | |
97 | ||
6259ec0d UD |
98 | /* Prototypes for local functions. */ |
99 | static void blacklist_store_name (const char *, ent_t *); | |
100 | static int in_blacklist (const char *, int, ent_t *); | |
2d7da676 | 101 | |
1e2e27fd UD |
102 | /* Initialize the NSS interface/functions. The calling function must |
103 | hold the lock. */ | |
104 | static void | |
105 | init_nss_interface (void) | |
106 | { | |
107 | if (__nss_database_lookup ("passwd_compat", NULL, "nis", &ni) >= 0) | |
108 | { | |
109 | nss_setpwent = __nss_lookup_function (ni, "setpwent"); | |
110 | nss_getpwnam_r = __nss_lookup_function (ni, "getpwnam_r"); | |
111 | nss_getpwuid_r = __nss_lookup_function (ni, "getpwuid_r"); | |
112 | nss_getpwent_r = __nss_lookup_function (ni, "getpwent_r"); | |
113 | nss_endpwent = __nss_lookup_function (ni, "endpwent"); | |
114 | } | |
115 | } | |
116 | ||
6259ec0d UD |
117 | static void |
118 | give_pwd_free (struct passwd *pwd) | |
119 | { | |
72e6cdfa UD |
120 | free (pwd->pw_name); |
121 | free (pwd->pw_passwd); | |
122 | free (pwd->pw_gecos); | |
123 | free (pwd->pw_dir); | |
124 | free (pwd->pw_shell); | |
6259ec0d UD |
125 | |
126 | memset (pwd, '\0', sizeof (struct passwd)); | |
127 | } | |
128 | ||
129 | static size_t | |
130 | pwd_need_buflen (struct passwd *pwd) | |
131 | { | |
132 | size_t len = 0; | |
133 | ||
134 | if (pwd->pw_passwd != NULL) | |
135 | len += strlen (pwd->pw_passwd) + 1; | |
136 | ||
137 | if (pwd->pw_gecos != NULL) | |
138 | len += strlen (pwd->pw_gecos) + 1; | |
139 | ||
140 | if (pwd->pw_dir != NULL) | |
141 | len += strlen (pwd->pw_dir) + 1; | |
142 | ||
143 | if (pwd->pw_shell != NULL) | |
144 | len += strlen (pwd->pw_shell) + 1; | |
145 | ||
146 | return len; | |
147 | } | |
148 | ||
149 | static void | |
150 | copy_pwd_changes (struct passwd *dest, struct passwd *src, | |
151 | char *buffer, size_t buflen) | |
152 | { | |
153 | if (src->pw_passwd != NULL && strlen (src->pw_passwd)) | |
154 | { | |
155 | if (buffer == NULL) | |
156 | dest->pw_passwd = strdup (src->pw_passwd); | |
157 | else if (dest->pw_passwd && | |
158 | strlen (dest->pw_passwd) >= strlen (src->pw_passwd)) | |
159 | strcpy (dest->pw_passwd, src->pw_passwd); | |
160 | else | |
161 | { | |
162 | dest->pw_passwd = buffer; | |
163 | strcpy (dest->pw_passwd, src->pw_passwd); | |
164 | buffer += strlen (dest->pw_passwd) + 1; | |
165 | buflen = buflen - (strlen (dest->pw_passwd) + 1); | |
166 | } | |
167 | } | |
168 | ||
169 | if (src->pw_gecos != NULL && strlen (src->pw_gecos)) | |
170 | { | |
171 | if (buffer == NULL) | |
172 | dest->pw_gecos = strdup (src->pw_gecos); | |
173 | else if (dest->pw_gecos && | |
174 | strlen (dest->pw_gecos) >= strlen (src->pw_gecos)) | |
175 | strcpy (dest->pw_gecos, src->pw_gecos); | |
176 | else | |
177 | { | |
178 | dest->pw_gecos = buffer; | |
179 | strcpy (dest->pw_gecos, src->pw_gecos); | |
180 | buffer += strlen (dest->pw_gecos) + 1; | |
181 | buflen = buflen - (strlen (dest->pw_gecos) + 1); | |
182 | } | |
183 | } | |
184 | if (src->pw_dir != NULL && strlen (src->pw_dir)) | |
185 | { | |
186 | if (buffer == NULL) | |
187 | dest->pw_dir = strdup (src->pw_dir); | |
1e2e27fd | 188 | else if (dest->pw_dir && strlen (dest->pw_dir) >= strlen (src->pw_dir)) |
6259ec0d UD |
189 | strcpy (dest->pw_dir, src->pw_dir); |
190 | else | |
191 | { | |
192 | dest->pw_dir = buffer; | |
193 | strcpy (dest->pw_dir, src->pw_dir); | |
194 | buffer += strlen (dest->pw_dir) + 1; | |
195 | buflen = buflen - (strlen (dest->pw_dir) + 1); | |
196 | } | |
197 | } | |
198 | ||
199 | if (src->pw_shell != NULL && strlen (src->pw_shell)) | |
200 | { | |
201 | if (buffer == NULL) | |
202 | dest->pw_shell = strdup (src->pw_shell); | |
203 | else if (dest->pw_shell && | |
204 | strlen (dest->pw_shell) >= strlen (src->pw_shell)) | |
205 | strcpy (dest->pw_shell, src->pw_shell); | |
206 | else | |
207 | { | |
208 | dest->pw_shell = buffer; | |
209 | strcpy (dest->pw_shell, src->pw_shell); | |
210 | buffer += strlen (dest->pw_shell) + 1; | |
211 | buflen = buflen - (strlen (dest->pw_shell) + 1); | |
212 | } | |
213 | } | |
214 | } | |
215 | ||
7ef90c15 | 216 | static enum nss_status |
cb62745a | 217 | internal_setpwent (ent_t *ent, int stayopen, int needent) |
6259ec0d UD |
218 | { |
219 | enum nss_status status = NSS_STATUS_SUCCESS; | |
220 | ||
cb62745a UD |
221 | ent->first = ent->netgroup = false; |
222 | ent->files = true; | |
223 | ent->setent_status = NSS_STATUS_SUCCESS; | |
6259ec0d UD |
224 | |
225 | /* If something was left over free it. */ | |
226 | if (ent->netgroup) | |
227 | __internal_endnetgrent (&ent->netgrdata); | |
228 | ||
6259ec0d | 229 | if (ent->blacklist.data != NULL) |
bd355af0 UD |
230 | { |
231 | ent->blacklist.current = 1; | |
232 | ent->blacklist.data[0] = '|'; | |
233 | ent->blacklist.data[1] = '\0'; | |
234 | } | |
235 | else | |
236 | ent->blacklist.current = 0; | |
6259ec0d UD |
237 | |
238 | if (ent->stream == NULL) | |
239 | { | |
cc783763 | 240 | ent->stream = fopen ("/etc/passwd", "rme"); |
6259ec0d UD |
241 | |
242 | if (ent->stream == NULL) | |
243 | status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; | |
3996f34b UD |
244 | else |
245 | { | |
246 | /* We have to make sure the file is `closed on exec'. */ | |
cc783763 | 247 | int result = 0; |
3996f34b | 248 | |
cc783763 | 249 | if (__compat_have_cloexec <= 0) |
3996f34b | 250 | { |
cc783763 UD |
251 | int flags; |
252 | result = flags = fcntl (fileno_unlocked (ent->stream), F_GETFD, | |
253 | 0); | |
254 | if (result >= 0) | |
255 | { | |
256 | #if defined O_CLOEXEC && !defined __ASSUME_O_CLOEXEC | |
257 | if (__compat_have_cloexec == 0) | |
258 | __compat_have_cloexec = (flags & FD_CLOEXEC) ? 1 : -1; | |
259 | ||
260 | if (__compat_have_cloexec < 0) | |
261 | #endif | |
262 | { | |
263 | flags |= FD_CLOEXEC; | |
264 | result = fcntl (fileno_unlocked (ent->stream), F_SETFD, | |
265 | flags); | |
266 | } | |
267 | } | |
3996f34b | 268 | } |
cc783763 | 269 | |
3996f34b UD |
270 | if (result < 0) |
271 | { | |
272 | /* Something went wrong. Close the stream and return a | |
1e2e27fd | 273 | failure. */ |
3996f34b UD |
274 | fclose (ent->stream); |
275 | ent->stream = NULL; | |
276 | status = NSS_STATUS_UNAVAIL; | |
277 | } | |
1aa43890 UD |
278 | else |
279 | /* We take care of locking ourself. */ | |
280 | __fsetlocking (ent->stream, FSETLOCKING_BYCALLER); | |
3996f34b | 281 | } |
6259ec0d UD |
282 | } |
283 | else | |
284 | rewind (ent->stream); | |
285 | ||
286 | give_pwd_free (&ent->pwd); | |
287 | ||
cb62745a UD |
288 | if (needent && status == NSS_STATUS_SUCCESS && nss_setpwent) |
289 | ent->setent_status = nss_setpwent (stayopen); | |
1e2e27fd | 290 | |
6259ec0d UD |
291 | return status; |
292 | } | |
293 | ||
294 | ||
295 | enum nss_status | |
51eecc4a | 296 | _nss_compat_setpwent (int stayopen) |
6259ec0d UD |
297 | { |
298 | enum nss_status result; | |
299 | ||
300 | __libc_lock_lock (lock); | |
301 | ||
26dee9c4 | 302 | if (ni == NULL) |
1e2e27fd | 303 | init_nss_interface (); |
26dee9c4 | 304 | |
cb62745a | 305 | result = internal_setpwent (&ext_ent, stayopen, 1); |
6259ec0d UD |
306 | |
307 | __libc_lock_unlock (lock); | |
308 | ||
309 | return result; | |
310 | } | |
311 | ||
312 | ||
313 | static enum nss_status | |
314 | internal_endpwent (ent_t *ent) | |
315 | { | |
1e2e27fd UD |
316 | if (nss_endpwent) |
317 | nss_endpwent (); | |
318 | ||
6259ec0d UD |
319 | if (ent->stream != NULL) |
320 | { | |
321 | fclose (ent->stream); | |
322 | ent->stream = NULL; | |
323 | } | |
324 | ||
60c96635 UD |
325 | if (ent->netgroup) |
326 | __internal_endnetgrent (&ent->netgrdata); | |
3996f34b | 327 | |
cb62745a | 328 | ent->first = ent->netgroup = false; |
26dee9c4 | 329 | |
6259ec0d | 330 | if (ent->blacklist.data != NULL) |
bd355af0 UD |
331 | { |
332 | ent->blacklist.current = 1; | |
333 | ent->blacklist.data[0] = '|'; | |
1e2e27fd | 334 | ent->blacklist.data[1] = '\0'; |
bd355af0 UD |
335 | } |
336 | else | |
337 | ent->blacklist.current = 0; | |
6259ec0d UD |
338 | |
339 | give_pwd_free (&ent->pwd); | |
340 | ||
341 | return NSS_STATUS_SUCCESS; | |
342 | } | |
343 | ||
344 | enum nss_status | |
345 | _nss_compat_endpwent (void) | |
346 | { | |
347 | enum nss_status result; | |
348 | ||
349 | __libc_lock_lock (lock); | |
350 | ||
6259ec0d UD |
351 | result = internal_endpwent (&ext_ent); |
352 | ||
353 | __libc_lock_unlock (lock); | |
354 | ||
355 | return result; | |
356 | } | |
357 | ||
1e2e27fd | 358 | |
6259ec0d | 359 | static enum nss_status |
1e2e27fd UD |
360 | getpwent_next_nss_netgr (const char *name, struct passwd *result, ent_t *ent, |
361 | char *group, char *buffer, size_t buflen, | |
362 | int *errnop) | |
6259ec0d | 363 | { |
6d4d8e8e | 364 | char *curdomain = NULL, *host, *user, *domain, *p2; |
1e2e27fd | 365 | int status; |
f8b87ef0 | 366 | size_t p2len; |
c131718c | 367 | |
1e2e27fd UD |
368 | /* Leave function if NSS module does not support getpwnam_r, |
369 | we need this function here. */ | |
370 | if (!nss_getpwnam_r) | |
371 | return NSS_STATUS_UNAVAIL; | |
372 | ||
6d4d8e8e | 373 | if (ent->first) |
6259ec0d | 374 | { |
63551311 | 375 | memset (&ent->netgrdata, 0, sizeof (struct __netgrent)); |
6259ec0d | 376 | __internal_setnetgrent (group, &ent->netgrdata); |
cb62745a | 377 | ent->first = false; |
6259ec0d UD |
378 | } |
379 | ||
380 | while (1) | |
381 | { | |
7e3be507 | 382 | status = __internal_getnetgrent_r (&host, &user, &domain, |
d71b808a UD |
383 | &ent->netgrdata, buffer, buflen, |
384 | errnop); | |
6259ec0d UD |
385 | if (status != 1) |
386 | { | |
387 | __internal_endnetgrent (&ent->netgrdata); | |
388 | ent->netgroup = 0; | |
389 | give_pwd_free (&ent->pwd); | |
390 | return NSS_STATUS_RETURN; | |
391 | } | |
392 | ||
393 | if (user == NULL || user[0] == '-') | |
394 | continue; | |
395 | ||
6d4d8e8e AS |
396 | if (domain != NULL) |
397 | { | |
398 | if (curdomain == NULL | |
399 | && yp_get_default_domain (&curdomain) != YPERR_SUCCESS) | |
400 | { | |
401 | __internal_endnetgrent (&ent->netgrdata); | |
402 | ent->netgroup = false; | |
403 | give_pwd_free (&ent->pwd); | |
404 | return NSS_STATUS_UNAVAIL; | |
405 | } | |
406 | if (strcmp (curdomain, domain) != 0) | |
407 | continue; | |
408 | } | |
6259ec0d | 409 | |
6591c335 | 410 | /* If name != NULL, we are called from getpwnam. */ |
cc3fa755 UD |
411 | if (name != NULL) |
412 | if (strcmp (user, name) != 0) | |
413 | continue; | |
414 | ||
6259ec0d UD |
415 | p2len = pwd_need_buflen (&ent->pwd); |
416 | if (p2len > buflen) | |
417 | { | |
d71b808a | 418 | *errnop = ERANGE; |
6259ec0d UD |
419 | return NSS_STATUS_TRYAGAIN; |
420 | } | |
421 | p2 = buffer + (buflen - p2len); | |
422 | buflen -= p2len; | |
6591c335 | 423 | |
1e2e27fd UD |
424 | if (nss_getpwnam_r (user, result, buffer, buflen, errnop) != |
425 | NSS_STATUS_SUCCESS) | |
26dee9c4 | 426 | continue; |
3996f34b | 427 | |
1e2e27fd | 428 | if (!in_blacklist (result->pw_name, strlen (result->pw_name), ent)) |
26dee9c4 | 429 | { |
1e2e27fd UD |
430 | /* Store the User in the blacklist for possible the "+" at the |
431 | end of /etc/passwd */ | |
cc3fa755 | 432 | blacklist_store_name (result->pw_name, ent); |
26dee9c4 UD |
433 | copy_pwd_changes (result, &ent->pwd, p2, p2len); |
434 | break; | |
435 | } | |
436 | } | |
437 | ||
438 | return NSS_STATUS_SUCCESS; | |
439 | } | |
440 | ||
1e2e27fd | 441 | /* get the next user from NSS (+ entry) */ |
26dee9c4 | 442 | static enum nss_status |
1e2e27fd | 443 | getpwent_next_nss (struct passwd *result, ent_t *ent, char *buffer, |
d71b808a | 444 | size_t buflen, int *errnop) |
6259ec0d | 445 | { |
1e2e27fd UD |
446 | enum nss_status status; |
447 | char *p2; | |
f8b87ef0 | 448 | size_t p2len; |
6259ec0d | 449 | |
1e2e27fd UD |
450 | /* Return if NSS module does not support getpwent_r. */ |
451 | if (!nss_getpwent_r) | |
452 | return NSS_STATUS_UNAVAIL; | |
6259ec0d | 453 | |
cb62745a UD |
454 | /* If the setpwent call failed, say so. */ |
455 | if (ent->setent_status != NSS_STATUS_SUCCESS) | |
456 | return ent->setent_status; | |
457 | ||
6259ec0d UD |
458 | p2len = pwd_need_buflen (&ent->pwd); |
459 | if (p2len > buflen) | |
460 | { | |
d71b808a | 461 | *errnop = ERANGE; |
6259ec0d UD |
462 | return NSS_STATUS_TRYAGAIN; |
463 | } | |
464 | p2 = buffer + (buflen - p2len); | |
465 | buflen -= p2len; | |
3996f34b | 466 | |
1e2e27fd | 467 | if (ent->first) |
cb62745a | 468 | ent->first = false; |
3996f34b | 469 | |
1e2e27fd UD |
470 | do |
471 | { | |
472 | if ((status = nss_getpwent_r (result, buffer, buflen, errnop)) != | |
473 | NSS_STATUS_SUCCESS) | |
474 | return status; | |
6259ec0d | 475 | } |
1e2e27fd | 476 | while (in_blacklist (result->pw_name, strlen (result->pw_name), ent)); |
6259ec0d UD |
477 | |
478 | copy_pwd_changes (result, &ent->pwd, p2, p2len); | |
479 | ||
26dee9c4 | 480 | return NSS_STATUS_SUCCESS; |
6259ec0d UD |
481 | } |
482 | ||
26dee9c4 UD |
483 | /* This function handle the +user entrys in /etc/passwd */ |
484 | static enum nss_status | |
04c216a8 UD |
485 | getpwnam_plususer (const char *name, struct passwd *result, ent_t *ent, |
486 | char *buffer, size_t buflen, int *errnop) | |
26dee9c4 | 487 | { |
1e2e27fd UD |
488 | if (!nss_getpwnam_r) |
489 | return NSS_STATUS_UNAVAIL; | |
490 | ||
016c70ea | 491 | struct passwd pwd; |
26dee9c4 | 492 | memset (&pwd, '\0', sizeof (struct passwd)); |
c131718c | 493 | |
26dee9c4 | 494 | copy_pwd_changes (&pwd, result, NULL, 0); |
c131718c | 495 | |
016c70ea | 496 | size_t plen = pwd_need_buflen (&pwd); |
26dee9c4 UD |
497 | if (plen > buflen) |
498 | { | |
d71b808a | 499 | *errnop = ERANGE; |
26dee9c4 UD |
500 | return NSS_STATUS_TRYAGAIN; |
501 | } | |
016c70ea | 502 | char *p = buffer + (buflen - plen); |
26dee9c4 | 503 | buflen -= plen; |
c131718c | 504 | |
016c70ea UD |
505 | enum nss_status status = nss_getpwnam_r (name, result, buffer, buflen, |
506 | errnop); | |
507 | if (status != NSS_STATUS_SUCCESS) | |
508 | return status; | |
04c216a8 | 509 | |
1e2e27fd UD |
510 | if (in_blacklist (result->pw_name, strlen (result->pw_name), ent)) |
511 | return NSS_STATUS_NOTFOUND; | |
c131718c | 512 | |
1e2e27fd UD |
513 | copy_pwd_changes (result, &pwd, p, plen); |
514 | give_pwd_free (&pwd); | |
515 | /* We found the entry. */ | |
516 | return NSS_STATUS_SUCCESS; | |
26dee9c4 | 517 | } |
6259ec0d UD |
518 | |
519 | static enum nss_status | |
520 | getpwent_next_file (struct passwd *result, ent_t *ent, | |
d71b808a | 521 | char *buffer, size_t buflen, int *errnop) |
6259ec0d | 522 | { |
7e3be507 | 523 | struct parser_data *data = (void *) buffer; |
6259ec0d UD |
524 | while (1) |
525 | { | |
60c96635 | 526 | fpos_t pos; |
26dee9c4 | 527 | char *p; |
60c96635 | 528 | int parse_res; |
6259ec0d UD |
529 | |
530 | do | |
531 | { | |
20f8e666 UD |
532 | /* We need at least 3 characters for one line. */ |
533 | if (__builtin_expect (buflen < 3, 0)) | |
534 | { | |
535 | erange: | |
536 | *errnop = ERANGE; | |
537 | return NSS_STATUS_TRYAGAIN; | |
538 | } | |
539 | ||
60c96635 | 540 | fgetpos (ent->stream, &pos); |
af69217f | 541 | buffer[buflen - 1] = '\xff'; |
1aa43890 UD |
542 | p = fgets_unlocked (buffer, buflen, ent->stream); |
543 | if (p == NULL && feof_unlocked (ent->stream)) | |
34816665 UD |
544 | return NSS_STATUS_NOTFOUND; |
545 | ||
20f8e666 | 546 | if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) |
d71b808a | 547 | { |
20f8e666 | 548 | erange_reset: |
af69217f | 549 | fsetpos (ent->stream, &pos); |
20f8e666 | 550 | goto erange; |
d71b808a | 551 | } |
6259ec0d UD |
552 | |
553 | /* Terminate the line for any case. */ | |
554 | buffer[buflen - 1] = '\0'; | |
555 | ||
556 | /* Skip leading blanks. */ | |
557 | while (isspace (*p)) | |
558 | ++p; | |
559 | } | |
1e2e27fd UD |
560 | while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ |
561 | /* Parse the line. If it is invalid, loop to | |
562 | get the next line of the file to parse. */ | |
d71b808a UD |
563 | !(parse_res = _nss_files_parse_pwent (p, result, data, buflen, |
564 | errnop))); | |
60c96635 | 565 | |
20f8e666 UD |
566 | if (__builtin_expect (parse_res == -1, 0)) |
567 | /* The parser ran out of space. */ | |
568 | goto erange_reset; | |
6259ec0d UD |
569 | |
570 | if (result->pw_name[0] != '+' && result->pw_name[0] != '-') | |
571 | /* This is a real entry. */ | |
572 | break; | |
573 | ||
574 | /* -@netgroup */ | |
575 | if (result->pw_name[0] == '-' && result->pw_name[1] == '@' | |
576 | && result->pw_name[2] != '\0') | |
577 | { | |
d71b808a | 578 | /* XXX Do not use fixed length buffer. */ |
c131718c | 579 | char buf2[1024]; |
6259ec0d | 580 | char *user, *host, *domain; |
c131718c | 581 | struct __netgrent netgrdata; |
6259ec0d | 582 | |
c131718c UD |
583 | bzero (&netgrdata, sizeof (struct __netgrent)); |
584 | __internal_setnetgrent (&result->pw_name[2], &netgrdata); | |
d71b808a UD |
585 | while (__internal_getnetgrent_r (&host, &user, &domain, &netgrdata, |
586 | buf2, sizeof (buf2), errnop)) | |
6259ec0d UD |
587 | { |
588 | if (user != NULL && user[0] != '-') | |
589 | blacklist_store_name (user, ent); | |
590 | } | |
c131718c | 591 | __internal_endnetgrent (&netgrdata); |
6259ec0d UD |
592 | continue; |
593 | } | |
594 | ||
595 | /* +@netgroup */ | |
596 | if (result->pw_name[0] == '+' && result->pw_name[1] == '@' | |
597 | && result->pw_name[2] != '\0') | |
598 | { | |
04c216a8 | 599 | enum nss_status status; |
6259ec0d | 600 | |
cb62745a UD |
601 | ent->netgroup = true; |
602 | ent->first = true; | |
6259ec0d UD |
603 | copy_pwd_changes (&ent->pwd, result, NULL, 0); |
604 | ||
1e2e27fd UD |
605 | status = getpwent_next_nss_netgr (NULL, result, ent, |
606 | &result->pw_name[2], | |
607 | buffer, buflen, errnop); | |
6259ec0d UD |
608 | if (status == NSS_STATUS_RETURN) |
609 | continue; | |
610 | else | |
34816665 | 611 | return status; |
6259ec0d UD |
612 | } |
613 | ||
614 | /* -user */ | |
615 | if (result->pw_name[0] == '-' && result->pw_name[1] != '\0' | |
616 | && result->pw_name[1] != '@') | |
617 | { | |
618 | blacklist_store_name (&result->pw_name[1], ent); | |
619 | continue; | |
620 | } | |
621 | ||
622 | /* +user */ | |
623 | if (result->pw_name[0] == '+' && result->pw_name[1] != '\0' | |
624 | && result->pw_name[1] != '@') | |
625 | { | |
bbca27a4 UD |
626 | size_t len = strlen (result->pw_name); |
627 | char buf[len]; | |
26dee9c4 | 628 | enum nss_status status; |
c131718c | 629 | |
cc3fa755 UD |
630 | /* Store the User in the blacklist for the "+" at the end of |
631 | /etc/passwd */ | |
bbca27a4 | 632 | memcpy (buf, &result->pw_name[1], len); |
04c216a8 UD |
633 | status = getpwnam_plususer (&result->pw_name[1], result, ent, |
634 | buffer, buflen, errnop); | |
635 | blacklist_store_name (buf, ent); | |
636 | ||
1e2e27fd | 637 | if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ |
26dee9c4 | 638 | break; |
1e2e27fd UD |
639 | else if (status == NSS_STATUS_RETURN /* We couldn't parse the entry */ |
640 | || status == NSS_STATUS_NOTFOUND) /* entry doesn't exist */ | |
641 | continue; | |
6259ec0d | 642 | else |
1e2e27fd UD |
643 | { |
644 | if (status == NSS_STATUS_TRYAGAIN) | |
645 | { | |
646 | /* The parser ran out of space */ | |
647 | fsetpos (ent->stream, &pos); | |
648 | *errnop = ERANGE; | |
649 | } | |
650 | return status; | |
651 | } | |
6259ec0d UD |
652 | } |
653 | ||
654 | /* +:... */ | |
655 | if (result->pw_name[0] == '+' && result->pw_name[1] == '\0') | |
656 | { | |
cb62745a UD |
657 | ent->files = false; |
658 | ent->first = true; | |
6259ec0d UD |
659 | copy_pwd_changes (&ent->pwd, result, NULL, 0); |
660 | ||
1e2e27fd | 661 | return getpwent_next_nss (result, ent, buffer, buflen, errnop); |
6259ec0d UD |
662 | } |
663 | } | |
664 | ||
665 | return NSS_STATUS_SUCCESS; | |
666 | } | |
667 | ||
668 | ||
669 | static enum nss_status | |
670 | internal_getpwent_r (struct passwd *pw, ent_t *ent, char *buffer, | |
d71b808a | 671 | size_t buflen, int *errnop) |
6259ec0d UD |
672 | { |
673 | if (ent->netgroup) | |
674 | { | |
04c216a8 | 675 | enum nss_status status; |
6259ec0d UD |
676 | |
677 | /* We are searching members in a netgroup */ | |
678 | /* Since this is not the first call, we don't need the group name */ | |
1e2e27fd UD |
679 | status = getpwent_next_nss_netgr (NULL, pw, ent, NULL, buffer, buflen, |
680 | errnop); | |
6259ec0d | 681 | if (status == NSS_STATUS_RETURN) |
d71b808a | 682 | return getpwent_next_file (pw, ent, buffer, buflen, errnop); |
6259ec0d UD |
683 | else |
684 | return status; | |
685 | } | |
1e2e27fd UD |
686 | else if (ent->files) |
687 | return getpwent_next_file (pw, ent, buffer, buflen, errnop); | |
6259ec0d | 688 | else |
1e2e27fd UD |
689 | return getpwent_next_nss (pw, ent, buffer, buflen, errnop); |
690 | ||
6259ec0d UD |
691 | } |
692 | ||
693 | enum nss_status | |
d71b808a UD |
694 | _nss_compat_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen, |
695 | int *errnop) | |
6259ec0d | 696 | { |
1e2e27fd | 697 | enum nss_status result = NSS_STATUS_SUCCESS; |
6259ec0d UD |
698 | |
699 | __libc_lock_lock (lock); | |
700 | ||
1e2e27fd | 701 | /* Be prepared that the setpwent function was not called before. */ |
26dee9c4 | 702 | if (ni == NULL) |
1e2e27fd | 703 | init_nss_interface (); |
26dee9c4 | 704 | |
6259ec0d | 705 | if (ext_ent.stream == NULL) |
cb62745a | 706 | result = internal_setpwent (&ext_ent, 1, 1); |
6259ec0d | 707 | |
1e2e27fd UD |
708 | if (result == NSS_STATUS_SUCCESS) |
709 | result = internal_getpwent_r (pwd, &ext_ent, buffer, buflen, errnop); | |
6259ec0d UD |
710 | |
711 | __libc_lock_unlock (lock); | |
712 | ||
1e2e27fd | 713 | return result; |
6259ec0d UD |
714 | } |
715 | ||
cc3fa755 UD |
716 | /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */ |
717 | static enum nss_status | |
718 | internal_getpwnam_r (const char *name, struct passwd *result, ent_t *ent, | |
d71b808a | 719 | char *buffer, size_t buflen, int *errnop) |
cc3fa755 UD |
720 | { |
721 | struct parser_data *data = (void *) buffer; | |
722 | ||
723 | while (1) | |
724 | { | |
725 | fpos_t pos; | |
726 | char *p; | |
727 | int parse_res; | |
728 | ||
729 | do | |
730 | { | |
20f8e666 UD |
731 | /* We need at least 3 characters for one line. */ |
732 | if (__builtin_expect (buflen < 3, 0)) | |
733 | { | |
734 | erange: | |
735 | *errnop = ERANGE; | |
736 | return NSS_STATUS_TRYAGAIN; | |
737 | } | |
738 | ||
cc3fa755 | 739 | fgetpos (ent->stream, &pos); |
af69217f | 740 | buffer[buflen - 1] = '\xff'; |
1aa43890 UD |
741 | p = fgets_unlocked (buffer, buflen, ent->stream); |
742 | if (p == NULL && feof_unlocked (ent->stream)) | |
0c6cee5d | 743 | { |
0c6cee5d UD |
744 | return NSS_STATUS_NOTFOUND; |
745 | } | |
20f8e666 | 746 | if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) |
cc3fa755 | 747 | { |
20f8e666 | 748 | erange_reset: |
af69217f | 749 | fsetpos (ent->stream, &pos); |
20f8e666 | 750 | goto erange; |
cc3fa755 UD |
751 | } |
752 | ||
753 | /* Terminate the line for any case. */ | |
754 | buffer[buflen - 1] = '\0'; | |
755 | ||
756 | /* Skip leading blanks. */ | |
757 | while (isspace (*p)) | |
758 | ++p; | |
759 | } | |
1e2e27fd | 760 | while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ |
cc3fa755 | 761 | /* Parse the line. If it is invalid, loop to |
1e2e27fd | 762 | get the next line of the file to parse. */ |
d71b808a UD |
763 | !(parse_res = _nss_files_parse_pwent (p, result, data, buflen, |
764 | errnop))); | |
cc3fa755 | 765 | |
20f8e666 UD |
766 | if (__builtin_expect (parse_res == -1, 0)) |
767 | /* The parser ran out of space. */ | |
768 | goto erange_reset; | |
cc3fa755 UD |
769 | |
770 | /* This is a real entry. */ | |
771 | if (result->pw_name[0] != '+' && result->pw_name[0] != '-') | |
772 | { | |
773 | if (strcmp (result->pw_name, name) == 0) | |
774 | return NSS_STATUS_SUCCESS; | |
775 | else | |
776 | continue; | |
777 | } | |
778 | ||
779 | /* -@netgroup */ | |
780 | if (result->pw_name[0] == '-' && result->pw_name[1] == '@' | |
781 | && result->pw_name[2] != '\0') | |
782 | { | |
04c216a8 UD |
783 | if (innetgr (&result->pw_name[2], NULL, name, NULL)) |
784 | return NSS_STATUS_NOTFOUND; | |
cc3fa755 UD |
785 | continue; |
786 | } | |
787 | ||
788 | /* +@netgroup */ | |
789 | if (result->pw_name[0] == '+' && result->pw_name[1] == '@' | |
790 | && result->pw_name[2] != '\0') | |
791 | { | |
04c216a8 | 792 | enum nss_status status; |
cc3fa755 | 793 | |
04c216a8 | 794 | if (innetgr (&result->pw_name[2], NULL, name, NULL)) |
cc3fa755 | 795 | { |
04c216a8 UD |
796 | status = getpwnam_plususer (name, result, ent, buffer, |
797 | buflen, errnop); | |
cc3fa755 | 798 | |
1e2e27fd UD |
799 | if (status == NSS_STATUS_RETURN) |
800 | continue; | |
04c216a8 UD |
801 | |
802 | return status; | |
803 | } | |
cc3fa755 UD |
804 | continue; |
805 | } | |
806 | ||
807 | /* -user */ | |
808 | if (result->pw_name[0] == '-' && result->pw_name[1] != '\0' | |
809 | && result->pw_name[1] != '@') | |
810 | { | |
811 | if (strcmp (&result->pw_name[1], name) == 0) | |
34816665 | 812 | return NSS_STATUS_NOTFOUND; |
cc3fa755 UD |
813 | else |
814 | continue; | |
815 | } | |
816 | ||
817 | /* +user */ | |
818 | if (result->pw_name[0] == '+' && result->pw_name[1] != '\0' | |
819 | && result->pw_name[1] != '@') | |
820 | { | |
821 | if (strcmp (name, &result->pw_name[1]) == 0) | |
822 | { | |
823 | enum nss_status status; | |
824 | ||
04c216a8 | 825 | status = getpwnam_plususer (name, result, ent, buffer, buflen, |
d71b808a | 826 | errnop); |
cc3fa755 UD |
827 | if (status == NSS_STATUS_RETURN) |
828 | /* We couldn't parse the entry */ | |
829 | return NSS_STATUS_NOTFOUND; | |
830 | else | |
831 | return status; | |
832 | } | |
833 | } | |
834 | ||
835 | /* +:... */ | |
836 | if (result->pw_name[0] == '+' && result->pw_name[1] == '\0') | |
837 | { | |
838 | enum nss_status status; | |
839 | ||
04c216a8 UD |
840 | status = getpwnam_plususer (name, result, ent, |
841 | buffer, buflen, errnop); | |
1e2e27fd | 842 | if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ |
cc3fa755 | 843 | break; |
1e2e27fd UD |
844 | else if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ |
845 | return NSS_STATUS_NOTFOUND; | |
cc3fa755 | 846 | else |
1e2e27fd | 847 | return status; |
cc3fa755 UD |
848 | } |
849 | } | |
850 | return NSS_STATUS_SUCCESS; | |
851 | } | |
6259ec0d UD |
852 | |
853 | enum nss_status | |
854 | _nss_compat_getpwnam_r (const char *name, struct passwd *pwd, | |
d71b808a | 855 | char *buffer, size_t buflen, int *errnop) |
6259ec0d | 856 | { |
1e2e27fd | 857 | enum nss_status result; |
cb62745a UD |
858 | ent_t ent = { false, false, true, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }, |
859 | { NULL, NULL, 0, 0, NULL, NULL, NULL }}; | |
6259ec0d UD |
860 | |
861 | if (name[0] == '-' || name[0] == '+') | |
34816665 | 862 | return NSS_STATUS_NOTFOUND; |
6259ec0d | 863 | |
26dee9c4 UD |
864 | __libc_lock_lock (lock); |
865 | ||
866 | if (ni == NULL) | |
1e2e27fd | 867 | init_nss_interface (); |
c131718c | 868 | |
26dee9c4 | 869 | __libc_lock_unlock (lock); |
6259ec0d | 870 | |
cb62745a | 871 | result = internal_setpwent (&ent, 0, 0); |
6259ec0d | 872 | |
1e2e27fd UD |
873 | if (result == NSS_STATUS_SUCCESS) |
874 | result = internal_getpwnam_r (name, pwd, &ent, buffer, buflen, errnop); | |
6259ec0d UD |
875 | |
876 | internal_endpwent (&ent); | |
cc3fa755 | 877 | |
1e2e27fd | 878 | return result; |
6259ec0d UD |
879 | } |
880 | ||
cc3fa755 UD |
881 | /* This function handle the + entry in /etc/passwd for getpwuid */ |
882 | static enum nss_status | |
883 | getpwuid_plususer (uid_t uid, struct passwd *result, char *buffer, | |
1e2e27fd | 884 | size_t buflen, int *errnop) |
cc3fa755 | 885 | { |
cc3fa755 | 886 | struct passwd pwd; |
cc3fa755 UD |
887 | char *p; |
888 | size_t plen; | |
889 | ||
1e2e27fd UD |
890 | if (!nss_getpwuid_r) |
891 | return NSS_STATUS_UNAVAIL; | |
892 | ||
cc3fa755 UD |
893 | memset (&pwd, '\0', sizeof (struct passwd)); |
894 | ||
895 | copy_pwd_changes (&pwd, result, NULL, 0); | |
896 | ||
897 | plen = pwd_need_buflen (&pwd); | |
898 | if (plen > buflen) | |
899 | { | |
d71b808a | 900 | *errnop = ERANGE; |
cc3fa755 UD |
901 | return NSS_STATUS_TRYAGAIN; |
902 | } | |
903 | p = buffer + (buflen - plen); | |
904 | buflen -= plen; | |
905 | ||
1e2e27fd UD |
906 | if (nss_getpwuid_r (uid, result, buffer, buflen, errnop) == |
907 | NSS_STATUS_SUCCESS) | |
cc3fa755 UD |
908 | { |
909 | copy_pwd_changes (result, &pwd, p, plen); | |
910 | give_pwd_free (&pwd); | |
911 | /* We found the entry. */ | |
912 | return NSS_STATUS_SUCCESS; | |
913 | } | |
914 | else | |
915 | { | |
916 | /* Give buffer the old len back */ | |
917 | buflen += plen; | |
918 | give_pwd_free (&pwd); | |
919 | } | |
920 | return NSS_STATUS_RETURN; | |
921 | } | |
922 | ||
1e2e27fd | 923 | /* Searches in /etc/passwd and the NSS subsystem for a special user id */ |
cc3fa755 UD |
924 | static enum nss_status |
925 | internal_getpwuid_r (uid_t uid, struct passwd *result, ent_t *ent, | |
1e2e27fd | 926 | char *buffer, size_t buflen, int *errnop) |
cc3fa755 UD |
927 | { |
928 | struct parser_data *data = (void *) buffer; | |
929 | ||
930 | while (1) | |
931 | { | |
932 | fpos_t pos; | |
933 | char *p; | |
934 | int parse_res; | |
935 | ||
936 | do | |
1e2e27fd | 937 | { |
20f8e666 UD |
938 | /* We need at least 3 characters for one line. */ |
939 | if (__builtin_expect (buflen < 3, 0)) | |
940 | { | |
941 | erange: | |
942 | *errnop = ERANGE; | |
943 | return NSS_STATUS_TRYAGAIN; | |
944 | } | |
945 | ||
1e2e27fd UD |
946 | fgetpos (ent->stream, &pos); |
947 | buffer[buflen - 1] = '\xff'; | |
1aa43890 UD |
948 | p = fgets_unlocked (buffer, buflen, ent->stream); |
949 | if (p == NULL && feof_unlocked (ent->stream)) | |
34816665 UD |
950 | return NSS_STATUS_NOTFOUND; |
951 | ||
20f8e666 | 952 | if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) |
1e2e27fd | 953 | { |
20f8e666 | 954 | erange_reset: |
1e2e27fd | 955 | fsetpos (ent->stream, &pos); |
20f8e666 | 956 | goto erange; |
1e2e27fd UD |
957 | } |
958 | ||
959 | /* Terminate the line for any case. */ | |
960 | buffer[buflen - 1] = '\0'; | |
961 | ||
962 | /* Skip leading blanks. */ | |
963 | while (isspace (*p)) | |
964 | ++p; | |
965 | } | |
966 | while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ | |
967 | /* Parse the line. If it is invalid, loop to | |
968 | get the next line of the file to parse. */ | |
969 | !(parse_res = _nss_files_parse_pwent (p, result, data, buflen, | |
970 | errnop))); | |
cc3fa755 | 971 | |
20f8e666 UD |
972 | if (__builtin_expect (parse_res == -1, 0)) |
973 | /* The parser ran out of space. */ | |
974 | goto erange_reset; | |
cc3fa755 UD |
975 | |
976 | /* This is a real entry. */ | |
977 | if (result->pw_name[0] != '+' && result->pw_name[0] != '-') | |
1e2e27fd UD |
978 | { |
979 | if (result->pw_uid == uid) | |
980 | return NSS_STATUS_SUCCESS; | |
981 | else | |
982 | continue; | |
983 | } | |
cc3fa755 UD |
984 | |
985 | /* -@netgroup */ | |
986 | if (result->pw_name[0] == '-' && result->pw_name[1] == '@' | |
1e2e27fd UD |
987 | && result->pw_name[2] != '\0') |
988 | { | |
bbca27a4 UD |
989 | /* -1, because we remove first two character of pw_name. */ |
990 | size_t len = strlen (result->pw_name) - 1; | |
991 | char buf[len]; | |
04c216a8 | 992 | enum nss_status status; |
cc3fa755 | 993 | |
bbca27a4 | 994 | memcpy (buf, &result->pw_name[2], len); |
04c216a8 UD |
995 | |
996 | status = getpwuid_plususer (uid, result, buffer, buflen, errnop); | |
997 | if (status == NSS_STATUS_SUCCESS && | |
998 | innetgr (buf, NULL, result->pw_name, NULL)) | |
34816665 UD |
999 | return NSS_STATUS_NOTFOUND; |
1000 | ||
1e2e27fd UD |
1001 | continue; |
1002 | } | |
cc3fa755 UD |
1003 | |
1004 | /* +@netgroup */ | |
1005 | if (result->pw_name[0] == '+' && result->pw_name[1] == '@' | |
1e2e27fd UD |
1006 | && result->pw_name[2] != '\0') |
1007 | { | |
bbca27a4 UD |
1008 | /* -1, because we remove first two characters of pw_name. */ |
1009 | size_t len = strlen (result->pw_name) - 1; | |
1010 | char buf[len]; | |
04c216a8 | 1011 | enum nss_status status; |
cc3fa755 | 1012 | |
bbca27a4 | 1013 | memcpy (buf, &result->pw_name[2], len); |
cc3fa755 | 1014 | |
04c216a8 UD |
1015 | status = getpwuid_plususer (uid, result, buffer, buflen, errnop); |
1016 | ||
1017 | if (status == NSS_STATUS_RETURN) | |
1018 | continue; | |
cc3fa755 | 1019 | |
04c216a8 UD |
1020 | if (status == NSS_STATUS_SUCCESS) |
1021 | { | |
1022 | if (innetgr (buf, NULL, result->pw_name, NULL)) | |
cc3fa755 | 1023 | return NSS_STATUS_SUCCESS; |
04c216a8 | 1024 | } |
1e2e27fd UD |
1025 | else if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ |
1026 | return NSS_STATUS_NOTFOUND; | |
04c216a8 | 1027 | else |
1e2e27fd | 1028 | return status; |
04c216a8 | 1029 | |
1e2e27fd | 1030 | continue; |
cc3fa755 UD |
1031 | } |
1032 | ||
1033 | /* -user */ | |
1034 | if (result->pw_name[0] == '-' && result->pw_name[1] != '\0' | |
1e2e27fd UD |
1035 | && result->pw_name[1] != '@') |
1036 | { | |
bbca27a4 UD |
1037 | size_t len = strlen (result->pw_name); |
1038 | char buf[len]; | |
04c216a8 UD |
1039 | enum nss_status status; |
1040 | ||
bbca27a4 | 1041 | memcpy (buf, &result->pw_name[1], len); |
04c216a8 UD |
1042 | |
1043 | status = getpwuid_plususer (uid, result, buffer, buflen, errnop); | |
1044 | if (status == NSS_STATUS_SUCCESS && | |
1045 | innetgr (buf, NULL, result->pw_name, NULL)) | |
34816665 | 1046 | return NSS_STATUS_NOTFOUND; |
1e2e27fd UD |
1047 | continue; |
1048 | } | |
cc3fa755 UD |
1049 | |
1050 | /* +user */ | |
1051 | if (result->pw_name[0] == '+' && result->pw_name[1] != '\0' | |
1e2e27fd UD |
1052 | && result->pw_name[1] != '@') |
1053 | { | |
bbca27a4 UD |
1054 | size_t len = strlen (result->pw_name); |
1055 | char buf[len]; | |
cc3fa755 UD |
1056 | enum nss_status status; |
1057 | ||
bbca27a4 | 1058 | memcpy (buf, &result->pw_name[1], len); |
04c216a8 UD |
1059 | |
1060 | status = getpwuid_plususer (uid, result, buffer, buflen, errnop); | |
1061 | ||
1062 | if (status == NSS_STATUS_RETURN) | |
cc3fa755 | 1063 | continue; |
04c216a8 UD |
1064 | |
1065 | if (status == NSS_STATUS_SUCCESS) | |
1066 | { | |
1067 | if (strcmp (buf, result->pw_name) == 0) | |
1068 | return NSS_STATUS_SUCCESS; | |
1069 | } | |
1e2e27fd UD |
1070 | else if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ |
1071 | return NSS_STATUS_NOTFOUND; | |
04c216a8 | 1072 | else |
1e2e27fd | 1073 | return status; |
04c216a8 | 1074 | |
1e2e27fd UD |
1075 | continue; |
1076 | } | |
cc3fa755 UD |
1077 | |
1078 | /* +:... */ | |
1079 | if (result->pw_name[0] == '+' && result->pw_name[1] == '\0') | |
1e2e27fd UD |
1080 | { |
1081 | enum nss_status status; | |
1082 | ||
1083 | status = getpwuid_plususer (uid, result, buffer, buflen, errnop); | |
1084 | if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ | |
1085 | break; | |
1086 | else if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ | |
1087 | return NSS_STATUS_NOTFOUND; | |
1088 | else | |
1089 | return status; | |
1090 | } | |
cc3fa755 UD |
1091 | } |
1092 | return NSS_STATUS_SUCCESS; | |
1093 | } | |
6259ec0d UD |
1094 | |
1095 | enum nss_status | |
1096 | _nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd, | |
1e2e27fd | 1097 | char *buffer, size_t buflen, int *errnop) |
6259ec0d | 1098 | { |
1e2e27fd | 1099 | enum nss_status result; |
cb62745a UD |
1100 | ent_t ent = { false, false, true, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }, |
1101 | { NULL, NULL, 0, 0, NULL, NULL, NULL }}; | |
c131718c | 1102 | |
26dee9c4 | 1103 | __libc_lock_lock (lock); |
c131718c | 1104 | |
26dee9c4 | 1105 | if (ni == NULL) |
1e2e27fd | 1106 | init_nss_interface (); |
c131718c | 1107 | |
26dee9c4 | 1108 | __libc_lock_unlock (lock); |
c131718c | 1109 | |
cb62745a | 1110 | result = internal_setpwent (&ent, 0, 0); |
6259ec0d | 1111 | |
1e2e27fd UD |
1112 | if (result == NSS_STATUS_SUCCESS) |
1113 | result = internal_getpwuid_r (uid, pwd, &ent, buffer, buflen, errnop); | |
6259ec0d UD |
1114 | |
1115 | internal_endpwent (&ent); | |
cc3fa755 | 1116 | |
1e2e27fd | 1117 | return result; |
6259ec0d UD |
1118 | } |
1119 | ||
1120 | ||
1121 | /* Support routines for remembering -@netgroup and -user entries. | |
1122 | The names are stored in a single string with `|' as separator. */ | |
1123 | static void | |
1124 | blacklist_store_name (const char *name, ent_t *ent) | |
1125 | { | |
1126 | int namelen = strlen (name); | |
1127 | char *tmp; | |
1128 | ||
1129 | /* first call, setup cache */ | |
1130 | if (ent->blacklist.size == 0) | |
1131 | { | |
1132 | ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen); | |
1133 | ent->blacklist.data = malloc (ent->blacklist.size); | |
1134 | if (ent->blacklist.data == NULL) | |
1135 | return; | |
1136 | ent->blacklist.data[0] = '|'; | |
1137 | ent->blacklist.data[1] = '\0'; | |
1138 | ent->blacklist.current = 1; | |
1139 | } | |
1140 | else | |
1141 | { | |
1142 | if (in_blacklist (name, namelen, ent)) | |
1143 | return; /* no duplicates */ | |
1144 | ||
1145 | if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size) | |
1146 | { | |
1147 | ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen); | |
1148 | tmp = realloc (ent->blacklist.data, ent->blacklist.size); | |
1149 | if (tmp == NULL) | |
1150 | { | |
1151 | free (ent->blacklist.data); | |
1152 | ent->blacklist.size = 0; | |
1153 | return; | |
1154 | } | |
1155 | ent->blacklist.data = tmp; | |
1156 | } | |
1157 | } | |
1158 | ||
1159 | tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name); | |
1160 | *tmp++ = '|'; | |
1161 | *tmp = '\0'; | |
1162 | ent->blacklist.current += namelen + 1; | |
1163 | ||
1164 | return; | |
1165 | } | |
1166 | ||
cb62745a | 1167 | /* Returns TRUE if ent->blacklist contains name, else FALSE. */ |
6259ec0d UD |
1168 | static bool_t |
1169 | in_blacklist (const char *name, int namelen, ent_t *ent) | |
1170 | { | |
1171 | char buf[namelen + 3]; | |
c131718c | 1172 | char *cp; |
6259ec0d UD |
1173 | |
1174 | if (ent->blacklist.data == NULL) | |
1175 | return FALSE; | |
1176 | ||
c131718c UD |
1177 | buf[0] = '|'; |
1178 | cp = stpcpy (&buf[1], name); | |
1e2e27fd | 1179 | *cp++ = '|'; |
c131718c | 1180 | *cp = '\0'; |
6259ec0d UD |
1181 | return strstr (ent->blacklist.data, buf) != NULL; |
1182 | } |