Require autoconf 2.69
[glibc.git] / nscd / nscd.c
blob7131ead8cbd65c7f3aaf5f75f3336bf803623804
1 /* Copyright (c) 1998-2014 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; version 2 of the License, or
8 (at your option) any later version.
10 This program 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
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, see <http://www.gnu.org/licenses/>. */
18 /* nscd - Name Service Cache Daemon. Caches passwd, group, and hosts. */
20 #include <argp.h>
21 #include <assert.h>
22 #include <dirent.h>
23 #include <errno.h>
24 #include <error.h>
25 #include <fcntl.h>
26 #include <libintl.h>
27 #include <locale.h>
28 #include <paths.h>
29 #include <pthread.h>
30 #include <signal.h>
31 #include <stdbool.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <syslog.h>
36 #include <unistd.h>
37 #include <sys/mman.h>
38 #include <sys/socket.h>
39 #include <sys/stat.h>
40 #include <sys/uio.h>
41 #include <sys/un.h>
42 #include <sys/wait.h>
43 #include <stdarg.h>
45 #include "dbg_log.h"
46 #include "nscd.h"
47 #include "selinux.h"
48 #include "../nss/nsswitch.h"
49 #include <device-nrs.h>
50 #ifdef HAVE_INOTIFY
51 # include <sys/inotify.h>
52 #endif
53 #include <kernel-features.h>
55 /* Get libc version number. */
56 #include <version.h>
58 #define PACKAGE _libc_intl_domainname
60 int do_shutdown;
61 int disabled_passwd;
62 int disabled_group;
64 typedef enum
66 /* Running in background as daemon. */
67 RUN_DAEMONIZE,
68 /* Running in foreground but otherwise behave like a daemon,
69 i.e., detach from terminal and use syslog. This allows
70 better integration with services like systemd. */
71 RUN_FOREGROUND,
72 /* Run in foreground in debug mode. */
73 RUN_DEBUG
74 } run_modes;
76 static run_modes run_mode = RUN_DAEMONIZE;
78 static const char *conffile = _PATH_NSCDCONF;
80 time_t start_time;
82 uintptr_t pagesize_m1;
84 int paranoia;
85 time_t restart_time;
86 time_t restart_interval = RESTART_INTERVAL;
87 const char *oldcwd;
88 uid_t old_uid;
89 gid_t old_gid;
91 static int check_pid (const char *file);
92 static int write_pid (const char *file);
93 static int monitor_child (int fd);
95 /* Name and version of program. */
96 static void print_version (FILE *stream, struct argp_state *state);
97 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
99 /* Function to print some extra text in the help message. */
100 static char *more_help (int key, const char *text, void *input);
102 /* Definitions of arguments for argp functions. */
103 static const struct argp_option options[] =
105 { "config-file", 'f', N_("NAME"), 0,
106 N_("Read configuration data from NAME") },
107 { "debug", 'd', NULL, 0,
108 N_("Do not fork and display messages on the current tty") },
109 { "foreground", 'F', NULL, 0,
110 N_("Do not fork, but otherwise behave like a daemon") },
111 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
112 { "shutdown", 'K', NULL, 0, N_("Shut the server down") },
113 { "statistics", 'g', NULL, 0, N_("Print current configuration statistics") },
114 { "invalidate", 'i', N_("TABLE"), 0,
115 N_("Invalidate the specified cache") },
116 { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN,
117 N_("Use separate cache for each user")},
118 { NULL, 0, NULL, 0, NULL }
121 /* Short description of program. */
122 static const char doc[] = N_("Name Service Cache Daemon.");
124 /* Prototype for option handler. */
125 static error_t parse_opt (int key, char *arg, struct argp_state *state);
127 /* Data structure to communicate with argp functions. */
128 static struct argp argp =
130 options, parse_opt, NULL, doc, NULL, more_help
133 /* True if only statistics are requested. */
134 static bool get_stats;
135 static int parent_fd = -1;
138 main (int argc, char **argv)
140 int remaining;
142 /* Set locale via LC_ALL. */
143 setlocale (LC_ALL, "");
144 /* Set the text message domain. */
145 textdomain (PACKAGE);
147 /* Determine if the kernel has SELinux support. */
148 nscd_selinux_enabled (&selinux_enabled);
150 /* Parse and process arguments. */
151 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
153 if (remaining != argc)
155 error (0, 0, gettext ("wrong number of arguments"));
156 argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
157 exit (1);
160 /* Read the configuration file. */
161 if (nscd_parse_file (conffile, dbs) != 0)
162 /* We couldn't read the configuration file. We don't start the
163 server. */
164 error (EXIT_FAILURE, 0,
165 _("failure while reading configuration file; this is fatal"));
167 /* Do we only get statistics? */
168 if (get_stats)
169 /* Does not return. */
170 receive_print_stats ();
172 /* Check if we are already running. */
173 if (check_pid (_PATH_NSCDPID))
174 error (EXIT_FAILURE, 0, _("already running"));
176 /* Remember when we started. */
177 start_time = time (NULL);
179 /* Determine page size. */
180 pagesize_m1 = getpagesize () - 1;
182 if (run_mode == RUN_DAEMONIZE || run_mode == RUN_FOREGROUND)
184 int i;
185 pid_t pid;
187 /* Behave like a daemon. */
188 if (run_mode == RUN_DAEMONIZE)
190 int fd[2];
192 if (pipe (fd) != 0)
193 error (EXIT_FAILURE, errno,
194 _("cannot create a pipe to talk to the child"));
196 pid = fork ();
197 if (pid == -1)
198 error (EXIT_FAILURE, errno, _("cannot fork"));
199 if (pid != 0)
201 /* The parent only reads from the child. */
202 close (fd[1]);
203 exit (monitor_child (fd[0]));
205 else
207 /* The child only writes to the parent. */
208 close (fd[0]);
209 parent_fd = fd[1];
213 int nullfd = open (_PATH_DEVNULL, O_RDWR);
214 if (nullfd != -1)
216 struct stat64 st;
218 if (fstat64 (nullfd, &st) == 0 && S_ISCHR (st.st_mode) != 0
219 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
220 && st.st_rdev == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)
221 #endif
224 /* It is the /dev/null special device alright. */
225 (void) dup2 (nullfd, STDIN_FILENO);
226 (void) dup2 (nullfd, STDOUT_FILENO);
227 (void) dup2 (nullfd, STDERR_FILENO);
229 if (nullfd > 2)
230 close (nullfd);
232 else
234 /* Ugh, somebody is trying to play a trick on us. */
235 close (nullfd);
236 nullfd = -1;
239 int min_close_fd = nullfd == -1 ? 0 : STDERR_FILENO + 1;
241 DIR *d = opendir ("/proc/self/fd");
242 if (d != NULL)
244 struct dirent64 *dirent;
245 int dfdn = dirfd (d);
247 while ((dirent = readdir64 (d)) != NULL)
249 char *endp;
250 long int fdn = strtol (dirent->d_name, &endp, 10);
252 if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd
253 && fdn != parent_fd)
254 close ((int) fdn);
257 closedir (d);
259 else
260 for (i = min_close_fd; i < getdtablesize (); i++)
261 if (i != parent_fd)
262 close (i);
264 setsid ();
266 if (chdir ("/") != 0)
267 do_exit (EXIT_FAILURE, errno,
268 _("cannot change current working directory to \"/\""));
270 openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
272 if (write_pid (_PATH_NSCDPID) < 0)
273 dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
275 if (!init_logfile ())
276 dbg_log (_("Could not create log file"));
278 /* Ignore job control signals. */
279 signal (SIGTTOU, SIG_IGN);
280 signal (SIGTTIN, SIG_IGN);
281 signal (SIGTSTP, SIG_IGN);
283 else
284 /* In debug mode we are not paranoid. */
285 paranoia = 0;
287 signal (SIGINT, termination_handler);
288 signal (SIGQUIT, termination_handler);
289 signal (SIGTERM, termination_handler);
290 signal (SIGPIPE, SIG_IGN);
292 /* Cleanup files created by a previous 'bind'. */
293 unlink (_PATH_NSCDSOCKET);
295 #ifdef HAVE_INOTIFY
296 /* Use inotify to recognize changed files. */
297 inotify_fd = inotify_init1 (IN_NONBLOCK);
298 # ifndef __ASSUME_IN_NONBLOCK
299 if (inotify_fd == -1 && errno == ENOSYS)
301 inotify_fd = inotify_init ();
302 if (inotify_fd != -1)
303 fcntl (inotify_fd, F_SETFL, O_RDONLY | O_NONBLOCK);
305 # endif
306 #endif
308 #ifdef USE_NSCD
309 /* Make sure we do not get recursive calls. */
310 __nss_disable_nscd (register_traced_file);
311 #endif
313 /* Init databases. */
314 nscd_init ();
316 /* Start the SELinux AVC. */
317 if (selinux_enabled)
318 nscd_avc_init ();
320 /* Handle incoming requests */
321 start_threads ();
323 return 0;
327 /* Handle program arguments. */
328 static error_t
329 parse_opt (int key, char *arg, struct argp_state *state)
331 switch (key)
333 case 'd':
334 ++debug_level;
335 run_mode = RUN_DEBUG;
336 break;
338 case 'F':
339 run_mode = RUN_FOREGROUND;
340 break;
342 case 'f':
343 conffile = arg;
344 break;
346 case 'K':
347 if (getuid () != 0)
348 error (4, 0, _("Only root is allowed to use this option!"));
350 int sock = nscd_open_socket ();
352 if (sock == -1)
353 exit (EXIT_FAILURE);
355 request_header req;
356 req.version = NSCD_VERSION;
357 req.type = SHUTDOWN;
358 req.key_len = 0;
360 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &req,
361 sizeof (request_header),
362 MSG_NOSIGNAL));
363 close (sock);
364 exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
367 case 'g':
368 get_stats = true;
369 break;
371 case 'i':
372 if (getuid () != 0)
373 error (4, 0, _("Only root is allowed to use this option!"));
374 else
376 int sock = nscd_open_socket ();
378 if (sock == -1)
379 exit (EXIT_FAILURE);
381 dbtype cnt;
382 for (cnt = pwddb; cnt < lastdb; ++cnt)
383 if (strcmp (arg, dbnames[cnt]) == 0)
384 break;
386 if (cnt == lastdb)
388 argp_error (state, _("'%s' is not a known database"), arg);
389 return EINVAL;
392 size_t arg_len = strlen (arg) + 1;
393 struct
395 request_header req;
396 char arg[arg_len];
397 } reqdata;
399 reqdata.req.key_len = strlen (arg) + 1;
400 reqdata.req.version = NSCD_VERSION;
401 reqdata.req.type = INVALIDATE;
402 memcpy (reqdata.arg, arg, arg_len);
404 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &reqdata,
405 sizeof (request_header)
406 + arg_len,
407 MSG_NOSIGNAL));
409 if (nbytes != sizeof (request_header) + arg_len)
411 int err = errno;
412 close (sock);
413 error (EXIT_FAILURE, err, _("write incomplete"));
416 /* Wait for ack. Older nscd just closed the socket when
417 prune_cache finished, silently ignore that. */
418 int32_t resp = 0;
419 nbytes = TEMP_FAILURE_RETRY (read (sock, &resp, sizeof (resp)));
420 if (nbytes != 0 && nbytes != sizeof (resp))
422 int err = errno;
423 close (sock);
424 error (EXIT_FAILURE, err, _("cannot read invalidate ACK"));
427 close (sock);
429 if (resp != 0)
430 error (EXIT_FAILURE, resp, _("invalidation failed"));
432 exit (0);
435 case 't':
436 nthreads = atol (arg);
437 break;
439 case 'S':
440 error (0, 0, _("secure services not implemented anymore"));
441 break;
443 default:
444 return ARGP_ERR_UNKNOWN;
447 return 0;
450 /* Print bug-reporting information in the help message. */
451 static char *
452 more_help (int key, const char *text, void *input)
454 char *tables, *tp = NULL;
456 switch (key)
458 case ARGP_KEY_HELP_EXTRA:
460 dbtype cnt;
462 tables = xmalloc (sizeof (dbnames) + 1);
463 for (cnt = 0; cnt < lastdb; cnt++)
465 strcat (tables, dbnames[cnt]);
466 strcat (tables, " ");
470 /* We print some extra information. */
471 if (asprintf (&tp, gettext ("\
472 Supported tables:\n\
473 %s\n\
475 For bug reporting instructions, please see:\n\
476 %s.\n\
477 "), tables, REPORT_BUGS_TO) < 0)
478 tp = NULL;
479 free (tables);
480 return tp;
482 default:
483 break;
486 return (char *) text;
489 /* Print the version information. */
490 static void
491 print_version (FILE *stream, struct argp_state *state)
493 fprintf (stream, "nscd %s%s\n", PKGVERSION, VERSION);
494 fprintf (stream, gettext ("\
495 Copyright (C) %s Free Software Foundation, Inc.\n\
496 This is free software; see the source for copying conditions. There is NO\n\
497 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
498 "), "2014");
499 fprintf (stream, gettext ("Written by %s.\n"),
500 "Thorsten Kukuk and Ulrich Drepper");
504 /* Create a socket connected to a name. */
506 nscd_open_socket (void)
508 struct sockaddr_un addr;
509 int sock;
511 sock = socket (PF_UNIX, SOCK_STREAM, 0);
512 if (sock < 0)
513 return -1;
515 addr.sun_family = AF_UNIX;
516 assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
517 strcpy (addr.sun_path, _PATH_NSCDSOCKET);
518 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
520 close (sock);
521 return -1;
524 return sock;
528 /* Cleanup. */
529 void
530 termination_handler (int signum)
532 close_sockets ();
534 /* Clean up the file created by 'bind'. */
535 unlink (_PATH_NSCDSOCKET);
537 /* Clean up pid file. */
538 unlink (_PATH_NSCDPID);
540 // XXX Terminate threads.
542 /* Synchronize memory. */
543 for (int cnt = 0; cnt < lastdb; ++cnt)
545 if (!dbs[cnt].enabled || dbs[cnt].head == NULL)
546 continue;
548 /* Make sure nobody keeps using the database. */
549 dbs[cnt].head->timestamp = 0;
551 if (dbs[cnt].persistent)
552 // XXX async OK?
553 msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
556 _exit (EXIT_SUCCESS);
559 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
560 static int
561 check_pid (const char *file)
563 FILE *fp;
565 fp = fopen (file, "r");
566 if (fp)
568 pid_t pid;
569 int n;
571 n = fscanf (fp, "%d", &pid);
572 fclose (fp);
574 /* If we cannot parse the file default to assuming nscd runs.
575 If the PID is alive, assume it is running. That all unless
576 the PID is the same as the current process' since tha latter
577 can mean we re-exec. */
578 if ((n != 1 || kill (pid, 0) == 0) && pid != getpid ())
579 return 1;
582 return 0;
585 /* Write the current process id to the file FILE.
586 Returns 0 if successful, -1 if not. */
587 static int
588 write_pid (const char *file)
590 FILE *fp;
592 fp = fopen (file, "w");
593 if (fp == NULL)
594 return -1;
596 fprintf (fp, "%d\n", getpid ());
598 int result = fflush (fp) || ferror (fp) ? -1 : 0;
600 fclose (fp);
602 return result;
605 static int
606 monitor_child (int fd)
608 int child_ret = 0;
609 int ret = read (fd, &child_ret, sizeof (child_ret));
611 /* The child terminated with an error, either via exit or some other abnormal
612 method, like a segfault. */
613 if (ret <= 0 || child_ret != 0)
615 int status;
616 int err = wait (&status);
618 if (err < 0)
620 fprintf (stderr, _("'wait' failed\n"));
621 return 1;
624 if (WIFEXITED (status))
626 child_ret = WEXITSTATUS (status);
627 fprintf (stderr, _("child exited with status %d\n"), child_ret);
629 if (WIFSIGNALED (status))
631 child_ret = WTERMSIG (status);
632 fprintf (stderr, _("child terminated by signal %d\n"), child_ret);
636 /* We have the child status, so exit with that code. */
637 close (fd);
639 return child_ret;
642 void
643 do_exit (int child_ret, int errnum, const char *format, ...)
645 if (parent_fd != -1)
647 int ret = write (parent_fd, &child_ret, sizeof (child_ret));
648 assert (ret == sizeof (child_ret));
649 close (parent_fd);
652 if (format != NULL)
654 /* Emulate error() since we don't have a va_list variant for it. */
655 va_list argp;
657 fflush (stdout);
659 fprintf (stderr, "%s: ", program_invocation_name);
661 va_start (argp, format);
662 vfprintf (stderr, format, argp);
663 va_end (argp);
665 fprintf (stderr, ": %s\n", strerror (errnum));
666 fflush (stderr);
669 /* Finally, exit. */
670 exit (child_ret);
673 void
674 notify_parent (int child_ret)
676 if (parent_fd == -1)
677 return;
679 int ret = write (parent_fd, &child_ret, sizeof (child_ret));
680 assert (ret == sizeof (child_ret));
681 close (parent_fd);
682 parent_fd = -1;