1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20: #include <ctype.h>
21: #include <dlfcn.h>
22: #include <errno.h>
23: #include <netdb.h>
24: #include <bits/libc-lock.h>
25: #include <search.h>
26: #include <stdio.h>
27: #include <stdio_ext.h>
28: #include <stdlib.h>
29: #include <string.h>
30:
31: #include <aliases.h>
32: #include <grp.h>
33: #include <netinet/ether.h>
34: #include <pwd.h>
35: #include <shadow.h>
36:
37: #if !defined DO_STATIC_NSS || defined SHARED
38: # include <gnu/lib-names.h>
39: #endif
40:
41: #include "nsswitch.h"
42: #include "../nscd/nscd_proto.h"
43:
44:
45: static name_database *nss_parse_file (const char *fname) internal_function;
46: static name_database_entry *nss_getline (char *line) internal_function;
47: static service_user *nss_parse_service_list (const char *line)
48: internal_function;
49: static service_library *nss_new_service (name_database *database,
50: const char *name) internal_function;
51:
52:
53:
54: #define DEFINE_DATABASE(name) \
55: extern service_user *__nss_##name##_database attribute_hidden; \
56: weak_extern (__nss_##name##_database)
57: #include "databases.def"
58: #undef DEFINE_DATABASE
59:
60:
61: static const struct
62: {
63: const char name[10];
64: service_user **dbp;
65: } databases[] =
66: {
67: #define DEFINE_DATABASE(name) \
68: { #name, &__nss_##name##_database },
69: #include "databases.def"
70: #undef DEFINE_DATABASE
71: };
72: #define ndatabases (sizeof (databases) / sizeof (databases[0]))
73:
74:
75: __libc_lock_define_initialized (static, lock)
76:
77: #if !defined DO_STATIC_NSS || defined SHARED
78:
79: static const char *const __nss_shlib_revision = LIBNSS_FILES_SO + 15;
80: #endif
81:
82:
83: static name_database *service_table;
84:
85:
86:
87:
88: int
89: __nss_database_lookup (const char *database, const char *alternate_name,
90: const char *defconfig, service_user **ni)
91: {
92:
93: __libc_lock_lock (lock);
94:
95:
96:
97: if (*ni != NULL)
98: {
99: __libc_lock_unlock (lock);
100: return 0;
101: }
102:
103:
104: if (service_table == NULL)
105:
106: service_table = nss_parse_file (_PATH_NSSWITCH_CONF);
107:
108:
109: if (service_table != NULL)
110: {
111:
112: name_database_entry *entry;
113:
114:
115:
116: for (entry = service_table->entry; entry != NULL; entry = entry->next)
117: if (strcmp (database, entry->name) == 0)
118: *ni = entry->service;
119:
120: if (*ni == NULL && alternate_name != NULL)
121:
122:
123: for (entry = service_table->entry; entry != NULL; entry = entry->next)
124: if (strcmp (alternate_name, entry->name) == 0)
125: *ni = entry->service;
126: }
127:
128:
129:
130:
131:
132:
133: if (*ni == NULL)
134: *ni = nss_parse_service_list (defconfig
135: ?: "nis [NOTFOUND=return] files");
136:
137: __libc_lock_unlock (lock);
138:
139: return 0;
140: }
141: libc_hidden_def (__nss_database_lookup)
142:
143:
144:
145:
146:
147: int
148: __nss_lookup (service_user **ni, const char *fct_name, void **fctp)
149: {
150: *fctp = __nss_lookup_function (*ni, fct_name);
151:
152: while (*fctp == NULL
153: && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE
154: && (*ni)->next != NULL)
155: {
156: *ni = (*ni)->next;
157:
158: *fctp = __nss_lookup_function (*ni, fct_name);
159: }
160:
161: return *fctp != NULL ? 0 : (*ni)->next == NULL ? 1 : -1;
162: }
163:
164:
165:
166:
167:
168: int
169: __nss_next (service_user **ni, const char *fct_name, void **fctp, int status,
170: int all_values)
171: {
172: if (all_values)
173: {
174: if (nss_next_action (*ni, NSS_STATUS_TRYAGAIN) == NSS_ACTION_RETURN
175: && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_RETURN
176: && nss_next_action (*ni, NSS_STATUS_NOTFOUND) == NSS_ACTION_RETURN
177: && nss_next_action (*ni, NSS_STATUS_SUCCESS) == NSS_ACTION_RETURN)
178: return 1;
179: }
180: else
181: {
182:
183: if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN)
184: __libc_fatal ("illegal status in __nss_next");
185:
186: if (nss_next_action (*ni, status) == NSS_ACTION_RETURN)
187: return 1;
188: }
189:
190: if ((*ni)->next == NULL)
191: return -1;
192:
193: do
194: {
195: *ni = (*ni)->next;
196:
197: *fctp = __nss_lookup_function (*ni, fct_name);
198: }
199: while (*fctp == NULL
200: && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE
201: && (*ni)->next != NULL);
202:
203: return *fctp != NULL ? 0 : -1;
204: }
205: libc_hidden_def (__nss_next)
206:
207:
208: int
209: __nss_configure_lookup (const char *dbname, const char *service_line)
210: {
211: service_user *new_db;
212: size_t cnt;
213:
214: for (cnt = 0; cnt < ndatabases; ++cnt)
215: {
216: int cmp = strcmp (dbname, databases[cnt].name);
217: if (cmp == 0)
218: break;
219: if (cmp < 0)
220: {
221: __set_errno (EINVAL);
222: return -1;
223: }
224: }
225:
226: if (cnt == ndatabases)
227: {
228: __set_errno (EINVAL);
229: return -1;
230: }
231:
232:
233: if (databases[cnt].dbp == NULL)
234:
235: return 0;
236:
237:
238: new_db = nss_parse_service_list (service_line);
239: if (new_db == NULL)
240: {
241:
242: __set_errno (EINVAL);
243: return -1;
244: }
245:
246:
247: __libc_lock_lock (lock);
248:
249:
250: *databases[cnt].dbp = new_db;
251:
252: __libc_lock_unlock (lock);
253:
254: return 0;
255: }
256:
257:
258:
259: static int
260: known_compare (const void *p1, const void *p2)
261: {
262: return p1 == p2 ? 0 : strcmp (*(const char *const *) p1,
263: *(const char *const *) p2);
264: }
265:
266:
267: void *
268: __nss_lookup_function (service_user *ni, const char *fct_name)
269: {
270: void **found, *result;
271:
272:
273: __libc_lock_lock (lock);
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284: found = __tsearch (&fct_name, &ni->known, &known_compare);
285: if (*found != &fct_name)
286:
287: result = ((known_function *) *found)->fct_ptr;
288: else
289: {
290:
291:
292:
293:
294:
295: known_function *known = malloc (sizeof *known);
296: if (! known)
297: {
298: remove_from_tree:
299:
300:
301: __tdelete (&fct_name, &ni->known, &known_compare);
302: result = NULL;
303: }
304: else
305: {
306:
307: *found = known;
308: known->fct_name = fct_name;
309:
310: if (ni->library == NULL)
311: {
312:
313:
314:
315:
316:
317: static name_database default_table;
318: ni->library = nss_new_service (service_table ?: &default_table,
319: ni->name);
320: if (ni->library == NULL)
321: {
322:
323: free (known);
324: goto remove_from_tree;
325: }
326: }
327:
328: #if !defined DO_STATIC_NSS || defined SHARED
329: if (ni->library->lib_handle == NULL)
330: {
331:
332: size_t shlen = (7 + strlen (ni->library->name) + 3
333: + strlen (__nss_shlib_revision) + 1);
334: int saved_errno = errno;
335: char shlib_name[shlen];
336:
337:
338: __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name,
339: "libnss_"),
340: ni->library->name),
341: ".so"),
342: __nss_shlib_revision);
343:
344: ni->library->lib_handle = __libc_dlopen (shlib_name);
345: if (ni->library->lib_handle == NULL)
346: {
347:
348: ni->library->lib_handle = (void *) -1l;
349: __set_errno (saved_errno);
350: }
351: }
352:
353: if (ni->library->lib_handle == (void *) -1l)
354:
355: result = NULL;
356: else
357: {
358:
359: size_t namlen = (5 + strlen (ni->library->name) + 1
360: + strlen (fct_name) + 1);
361: char name[namlen];
362:
363:
364: __stpcpy (__stpcpy (__stpcpy (__stpcpy (name, "_nss_"),
365: ni->library->name),
366: "_"),
367: fct_name);
368:
369:
370: result = __libc_dlsym (ni->library->lib_handle, name);
371: }
372: #else
373:
374: {
375: # define DEFINE_ENT(h,nm) \
376: { #h"_get"#nm"ent_r", _nss_##h##_get##nm##ent_r }, \
377: { #h"_end"#nm"ent", _nss_##h##_end##nm##ent }, \
378: { #h"_set"#nm"ent", _nss_##h##_set##nm##ent },
379: # define DEFINE_GET(h,nm) \
380: { #h"_get"#nm"_r", _nss_##h##_get##nm##_r },
381: # define DEFINE_GETBY(h,nm,ky) \
382: { #h"_get"#nm"by"#ky"_r", _nss_##h##_get##nm##by##ky##_r },
383: static struct fct_tbl { const char *fname; void *fp; } *tp, tbl[] =
384: {
385: # include "function.def"
386: { NULL, NULL }
387: };
388: size_t namlen = (5 + strlen (ni->library->name) + 1
389: + strlen (fct_name) + 1);
390: char name[namlen];
391:
392:
393: __stpcpy (__stpcpy (__stpcpy (name, ni->library->name),
394: "_"),
395: fct_name);
396:
397: result = NULL;
398: for (tp = &tbl[0]; tp->fname; tp++)
399: if (strcmp (tp->fname, name) == 0)
400: {
401: result = tp->fp;
402: break;
403: }
404: }
405: #endif
406:
407:
408:
409: known->fct_ptr = result;
410: }
411: }
412:
413:
414: __libc_lock_unlock (lock);
415:
416: return result;
417: }
418: libc_hidden_def (__nss_lookup_function)
419:
420:
421: static name_database *
422: internal_function
423: nss_parse_file (const char *fname)
424: {
425: FILE *fp;
426: name_database *result;
427: name_database_entry *last;
428: char *line;
429: size_t len;
430:
431:
432: fp = fopen (fname, "rc");
433: if (fp == NULL)
434: return NULL;
435:
436:
437: __fsetlocking (fp, FSETLOCKING_BYCALLER);
438:
439: result = (name_database *) malloc (sizeof (name_database));
440: if (result == NULL)
441: return NULL;
442:
443: result->entry = NULL;
444: result->library = NULL;
445: last = NULL;
446: line = NULL;
447: len = 0;
448: do
449: {
450: name_database_entry *this;
451: ssize_t n;
452:
453: n = __getline (&line, &len, fp);
454: if (n < 0)
455: break;
456: if (line[n - 1] == '\n')
457: line[n - 1] = '\0';
458:
459:
460:
461:
462: *__strchrnul (line, '#') = '\0';
463:
464:
465: if (line[0] == '\0')
466: continue;
467:
468:
469: this = nss_getline (line);
470: if (this != NULL)
471: {
472: if (last != NULL)
473: last->next = this;
474: else
475: result->entry = this;
476:
477: last = this;
478: }
479: }
480: while (!feof_unlocked (fp));
481:
482:
483: free (line);
484:
485: fclose (fp);
486:
487: return result;
488: }
489:
490:
491:
492:
493:
494: static service_user *
495: internal_function
496: nss_parse_service_list (const char *line)
497: {
498: service_user *result = NULL, **nextp = &result;
499:
500: while (1)
501: {
502: service_user *new_service;
503: const char *name;
504:
505: while (isspace (line[0]))
506: ++line;
507: if (line[0] == '\0')
508:
509: return result;
510:
511:
512: name = line;
513: while (line[0] != '\0' && !isspace (line[0]) && line[0] != '[')
514: ++line;
515: if (name == line)
516: return result;
517:
518:
519: new_service = (service_user *) malloc (sizeof (service_user)
520: + (line - name + 1));
521: if (new_service == NULL)
522: return result;
523:
524: *((char *) __mempcpy (new_service->name, name, line - name)) = '\0';
525:
526:
527: new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE;
528: new_service->actions[2 + NSS_STATUS_UNAVAIL] = NSS_ACTION_CONTINUE;
529: new_service->actions[2 + NSS_STATUS_NOTFOUND] = NSS_ACTION_CONTINUE;
530: new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN;
531: new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN;
532: new_service->library = NULL;
533: new_service->known = NULL;
534: new_service->next = NULL;
535:
536: while (isspace (line[0]))
537: ++line;
538:
539: if (line[0] == '[')
540: {
541:
542: do
543: ++line;
544: while (line[0] != '\0' && isspace (line[0]));
545:
546: do
547: {
548: int not;
549: enum nss_status status;
550: lookup_actions action;
551:
552:
553: not = line[0] == '!';
554: if (not)
555: ++line;
556:
557:
558: name = line;
559: while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
560: && line[0] != ']')
561: ++line;
562:
563:
564: if (line - name == 7)
565: {
566: if (__strncasecmp (name, "SUCCESS", 7) == 0)
567: status = NSS_STATUS_SUCCESS;
568: else if (__strncasecmp (name, "UNAVAIL", 7) == 0)
569: status = NSS_STATUS_UNAVAIL;
570: else
571: return result;
572: }
573: else if (line - name == 8)
574: {
575: if (__strncasecmp (name, "NOTFOUND", 8) == 0)
576: status = NSS_STATUS_NOTFOUND;
577: else if (__strncasecmp (name, "TRYAGAIN", 8) == 0)
578: status = NSS_STATUS_TRYAGAIN;
579: else
580: return result;
581: }
582: else
583: return result;
584:
585: while (isspace (line[0]))
586: ++line;
587: if (line[0] !=