1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21: #include <argp.h>
22: #include <assert.h>
23: #include <dirent.h>
24: #include <errno.h>
25: #include <error.h>
26: #include <fcntl.h>
27: #include <libintl.h>
28: #include <locale.h>
29: #include <paths.h>
30: #include <pthread.h>
31: #include <signal.h>
32: #include <stdbool.h>
33: #include <stdio.h>
34: #include <stdlib.h>
35: #include <string.h>
36: #include <syslog.h>
37: #include <unistd.h>
38: #include <sys/mman.h>
39: #include <sys/socket.h>
40: #include <sys/stat.h>
41: #include <sys/uio.h>
42: #include <sys/un.h>
43:
44: #include "dbg_log.h"
45: #include "nscd.h"
46: #include "selinux.h"
47: #include "../nss/nsswitch.h"
48: #include <device-nrs.h>
49:
50:
51: #include <version.h>
52:
53: #define PACKAGE _libc_intl_domainname
54:
55:
56:
57:
58:
59:
60: typedef struct
61: {
62: int num_active;
63: pthread_cond_t thread_exit_cv;
64: pthread_mutex_t mutex;
65: } thread_info_t;
66:
67: thread_info_t thread_info;
68:
69: int do_shutdown;
70: int disabled_passwd;
71: int disabled_group;
72: int go_background = 1;
73:
74: static const char *conffile = _PATH_NSCDCONF;
75:
76: time_t start_time;
77:
78: uintptr_t pagesize_m1;
79:
80: int paranoia;
81: time_t restart_time;
82: time_t restart_interval = RESTART_INTERVAL;
83: const char *oldcwd;
84: uid_t old_uid;
85: gid_t old_gid;
86:
87: static int check_pid (const char *file);
88: static int write_pid (const char *file);
89:
90:
91: static void print_version (FILE *stream, struct argp_state *state);
92: void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
93:
94:
95: static const struct argp_option options[] =
96: {
97: { "config-file", 'f', N_("NAME"), 0,
98: N_("Read configuration data from NAME") },
99: { "debug", 'd', NULL, 0,
100: N_("Do not fork and display messages on the current tty") },
101: { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
102: { "shutdown", 'K', NULL, 0, N_("Shut the server down") },
103: { "statistic", 'g', NULL, 0, N_("Print current configuration statistic") },
104: { "invalidate", 'i', N_("TABLE"), 0,
105: N_("Invalidate the specified cache") },
106: { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN,
107: N_("Use separate cache for each user")},
108: { NULL, 0, NULL, 0, NULL }
109: };
110:
111:
112: static const char doc[] = N_("Name Service Cache Daemon.");
113:
114:
115: static error_t parse_opt (int key, char *arg, struct argp_state *state);
116:
117:
118: static struct argp argp =
119: {
120: options, parse_opt, NULL, doc,
121: };
122:
123:
124: static bool get_stats;
125:
126: int
127: main (int argc, char **argv)
128: {
129: int remaining;
130:
131:
132: setlocale (LC_ALL, "");
133:
134: textdomain (PACKAGE);
135:
136:
137: nscd_selinux_enabled (&selinux_enabled);
138:
139:
140: argp_parse (&argp, argc, argv, 0, &remaining, NULL);
141:
142: if (remaining != argc)
143: {
144: error (0, 0, gettext ("wrong number of arguments"));
145: argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
146: exit (1);
147: }
148:
149:
150: if (nscd_parse_file (conffile, dbs) != 0)
151:
152:
153: error (EXIT_FAILURE, 0,
154: _("failure while reading configuration file; this is fatal"));
155:
156:
157: if (get_stats)
158:
159: receive_print_stats ();
160:
161:
162: if (check_pid (_PATH_NSCDPID))
163: error (EXIT_FAILURE, 0, _("already running"));
164:
165:
166: start_time = time (NULL);
167:
168:
169: pagesize_m1 = getpagesize () - 1;
170:
171:
172: if (go_background)
173: {
174: int i;
175:
176: pid_t pid = fork ();
177: if (pid == -1)
178: error (EXIT_FAILURE, errno, _("cannot fork"));
179: if (pid != 0)
180: exit (0);
181:
182: int nullfd = open (_PATH_DEVNULL, O_RDWR);
183: if (nullfd != -1)
184: {
185: struct stat64 st;
186:
187: if (fstat64 (nullfd, &st) == 0 && S_ISCHR (st.st_mode) != 0
188: #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
189: && st.st_rdev == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)
190: #endif
191: )
192: {
193:
194: (void) dup2 (nullfd, STDIN_FILENO);
195: (void) dup2 (nullfd, STDOUT_FILENO);
196: (void) dup2 (nullfd, STDERR_FILENO);
197:
198: if (nullfd > 2)
199: close (nullfd);
200: }
201: else
202: {
203:
204: close (nullfd);
205: nullfd = -1;
206: }
207: }
208: int min_close_fd = nullfd == -1 ? 0 : STDERR_FILENO + 1;
209:
210: DIR *d = opendir ("/proc/self/fd");
211: if (d != NULL)
212: {
213: struct dirent64 *dirent;
214: int dfdn = dirfd (d);
215:
216: while ((dirent = readdir64 (d)) != NULL)
217: {
218: char *endp;
219: long int fdn = strtol (dirent->d_name, &endp, 10);
220:
221: if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd)
222: close ((int) fdn);
223: }
224:
225: closedir (d);
226: }
227: else
228: for (i = min_close_fd; i < getdtablesize (); i++)
229: close (i);
230:
231: pid = fork ();
232: if (pid == -1)
233: error (EXIT_FAILURE, errno, _("cannot fork"));
234: if (pid != 0)
235: exit (0);
236:
237: setsid ();
238:
239: if (chdir ("/") != 0)
240: error (EXIT_FAILURE, errno,
241: _("cannot change current working directory to \"/\""));
242:
243: openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
244:
245: if (write_pid (_PATH_NSCDPID) < 0)
246: dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
247:
248: if (!init_logfile ())
249: dbg_log (_("Could not create log file"));
250:
251:
252: signal (SIGTTOU, SIG_IGN);
253: signal (SIGTTIN, SIG_IGN);
254: signal (SIGTSTP, SIG_IGN);
255: }
256: else
257:
258: paranoia = 0;
259:
260:
261: if (selinux_enabled)
262: nscd_avc_init ();
263:
264: signal (SIGINT, termination_handler);
265: signal (SIGQUIT, termination_handler);
266: signal (SIGTERM, termination_handler);
267: signal (SIGPIPE, SIG_IGN);
268:
269:
270: unlink (_PATH_NSCDSOCKET);
271:
272:
273: __nss_disable_nscd ();
274:
275:
276: nscd_init ();
277:
278:
279: start_threads ();
280:
281: return 0;
282: }
283:
284:
285:
286: static error_t
287: parse_opt (int key, char *arg, struct argp_state *state)
288: {
289: switch (key)
290: {
291: case 'd':
292: ++debug_level;
293: go_background = 0;
294: break;
295:
296: case 'f':
297: conffile = arg;
298: break;
299:
300: case 'K':
301: if (getuid () != 0)
302: error (4, 0, _("Only root is allowed to use this option!"));
303: {
304: int sock = nscd_open_socket ();
305:
306: if (sock == -1)
307: exit (EXIT_FAILURE);
308:
309: request_header req;
310: req.version = NSCD_VERSION;
311: req.type = SHUTDOWN;
312: req.key_len = 0;
313:
314: ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &req,
315: sizeof (request_header),
316: MSG_NOSIGNAL));
317: close (sock);
318: exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
319: }
320:
321: case 'g':
322: get_stats = true;
323: break;
324:
325: case 'i':
326: if (getuid () != 0)
327: error (4, 0, _("Only root is allowed to use this option!"));
328: else
329: {
330: int sock = nscd_open_socket ();
331:
332: if (sock == -1)
333: exit (EXIT_FAILURE);
334:
335: dbtype cnt;
336: for (cnt = pwddb; cnt < lastdb; ++cnt)
337: if (strcmp (arg, dbnames[cnt]) == 0)
338: break;
339:
340: if (cnt == lastdb)
341: return ARGP_ERR_UNKNOWN;
342:
343: size_t arg_len = strlen (arg) + 1;
344: struct
345: {
346: request_header req;
347: char arg[arg_len];
348: } reqdata;
349:
350: reqdata.req.key_len = strlen (arg) + 1;
351: reqdata.req.version = NSCD_VERSION;
352: reqdata.req.type = INVALIDATE;
353: memcpy (reqdata.arg, arg, arg_len);
354:
355: ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &reqdata,
356: sizeof (request_header)
357: + arg_len,
358: MSG_NOSIGNAL));
359:
360: if (nbytes != sizeof (request_header) + arg_len)
361: {
362: int err = errno;
363: close (sock);
364: error (EXIT_FAILURE, err, _("write incomplete"));
365: }
366:
367:
368:
369: int32_t resp = 0;
370: nbytes = TEMP_FAILURE_RETRY (read (sock, &resp, sizeof (resp)));
371: if (nbytes != 0 && nbytes != sizeof (resp))
372: {
373: int err = errno;
374: close (sock);
375: error (EXIT_FAILURE, err, _("cannot read invalidate ACK"));
376: }
377:
378: close (sock);
379:
380: if (resp != 0)
381: error (EXIT_FAILURE, resp, _("invalidation failed"));
382:
383: exit (0);
384: }
385:
386: case 't':
387: nthreads = atol (arg);
388: break;
389:
390: case 'S':
391: error (0, 0, _("secure services not implemented anymore"));
392: break;
393:
394: default:
395: return ARGP_ERR_UNKNOWN;
396: }
397:
398: return 0;
399: }
400:
401:
402: static void
403: print_version (FILE *stream, struct argp_state *state)
404: {
405: fprintf (stream, "nscd (GNU %s) %s\n", PACKAGE, VERSION);
406: fprintf (stream, gettext ("\
407: Copyright (C) %s Free Software Foundation, Inc.\n\
408: This is free software; see the source for copying conditions. There is NO\n\
409: warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
410: "), "2007");
411: fprintf (stream, gettext ("Written by %s.\n"),
412: "Thorsten Kukuk and Ulrich Drepper");
413: }
414:
415:
416:
417: int
418: nscd_open_socket (void)
419: {
420: struct sockaddr_un addr;
421: int sock;
422:
423: sock = socket (PF_UNIX, SOCK_STREAM, 0);
424: if (sock < 0)
425: return -1;
426:
427: addr.sun_family = AF_UNIX;
428: assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
429: strcpy (addr.sun_path, _PATH_NSCDSOCKET);
430: if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
431: {
432: close (sock);
433: return -1;
434: }
435:
436: return sock;
437: }
438:
439:
440:
441: void
442: termination_handler (int signum)
443: {
444: close_sockets ();
445:
446:
447: unlink (_PATH_NSCDSOCKET);
448:
449:
450: unlink (_PATH_NSCDPID);
451:
452:
453:
454:
455: for (int cnt = 0; cnt < lastdb; ++cnt)
456: {
457: if (!dbs[cnt].enabled)
458: continue;
459:
460:
461: dbs[cnt].head->timestamp = 0;
462:
463: if (dbs[cnt].persistent)
464:
465: msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
466: }
467:
468:
469: if (selinux_enabled)
470: nscd_avc_destroy ();
471:
472: _exit (EXIT_SUCCESS);
473: }
474:
475:
476: static int
477: check_pid (const char *file)
478: {
479: FILE *fp;
480:
481: fp = fopen (file, "r");
482: if (fp)
483: {
484: pid_t pid;
485: int n;
486:
487: n = fscanf (fp, "%d", &pid);
488: fclose (fp);
489:
490:
491:
492:
493:
494: if ((n != 1 || kill (pid, 0) == 0) && pid != getpid ())
495: return 1;
496: }
497:
498: return 0;
499: }
500:
501:
502:
503: static int
504: write_pid (const char *file)
505: {
506: FILE *fp;
507:
508: fp = fopen (file, "w");
509: if (fp == NULL)
510: return -1;
511:
512: fprintf (fp, "%d\n", getpid ());
513:
514: int result = fflush (fp) || ferror (fp) ? -1 : 0;
515:
516: fclose (fp);
517:
518: return result;
519: }