Use statvfs64() for pathconf(_PC_NAME_MAX).
[glibc.git] / nscd / nscd.c
blob56803785e187fa26840315c31d09fa4ab2bcac2f
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
54 /* Get libc version number. */
55 #include <version.h>
57 #define PACKAGE _libc_intl_domainname
59 /* Structure used by main() thread to keep track of the number of
60 active threads. Used to limit how many threads it will create
61 and under a shutdown condition to wait till all in-progress
62 requests have finished before "turning off the lights". */
64 typedef struct
66 int num_active;
67 pthread_cond_t thread_exit_cv;
68 pthread_mutex_t mutex;
69 } thread_info_t;
71 thread_info_t thread_info;
73 int do_shutdown;
74 int disabled_passwd;
75 int disabled_group;
77 typedef enum
79 /* Running in background as daemon. */
80 RUN_DAEMONIZE,
81 /* Running in foreground but otherwise behave like a daemon,
82 i.e., detach from terminal and use syslog. This allows
83 better integration with services like systemd. */
84 RUN_FOREGROUND,
85 /* Run in foreground in debug mode. */
86 RUN_DEBUG
87 } run_modes;
89 static run_modes run_mode = RUN_DAEMONIZE;
91 static const char *conffile = _PATH_NSCDCONF;
93 time_t start_time;
95 uintptr_t pagesize_m1;
97 int paranoia;
98 time_t restart_time;
99 time_t restart_interval = RESTART_INTERVAL;
100 const char *oldcwd;
101 uid_t old_uid;
102 gid_t old_gid;
104 static int check_pid (const char *file);
105 static int write_pid (const char *file);
106 static int monitor_child (int fd);
108 /* Name and version of program. */
109 static void print_version (FILE *stream, struct argp_state *state);
110 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
112 /* Function to print some extra text in the help message. */
113 static char *more_help (int key, const char *text, void *input);
115 /* Definitions of arguments for argp functions. */
116 static const struct argp_option options[] =
118 { "config-file", 'f', N_("NAME"), 0,
119 N_("Read configuration data from NAME") },
120 { "debug", 'd', NULL, 0,
121 N_("Do not fork and display messages on the current tty") },
122 { "foreground", 'F', NULL, 0,
123 N_("Do not fork, but otherwise behave like a daemon") },
124 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
125 { "shutdown", 'K', NULL, 0, N_("Shut the server down") },
126 { "statistics", 'g', NULL, 0, N_("Print current configuration statistics") },
127 { "invalidate", 'i', N_("TABLE"), 0,
128 N_("Invalidate the specified cache") },
129 { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN,
130 N_("Use separate cache for each user")},
131 { NULL, 0, NULL, 0, NULL }
134 /* Short description of program. */
135 static const char doc[] = N_("Name Service Cache Daemon.");
137 /* Prototype for option handler. */
138 static error_t parse_opt (int key, char *arg, struct argp_state *state);
140 /* Data structure to communicate with argp functions. */
141 static struct argp argp =
143 options, parse_opt, NULL, doc, NULL, more_help
146 /* True if only statistics are requested. */
147 static bool get_stats;
148 static int parent_fd = -1;
151 main (int argc, char **argv)
153 int remaining;
155 /* Set locale via LC_ALL. */
156 setlocale (LC_ALL, "");
157 /* Set the text message domain. */
158 textdomain (PACKAGE);
160 /* Determine if the kernel has SELinux support. */
161 nscd_selinux_enabled (&selinux_enabled);
163 /* Parse and process arguments. */
164 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
166 if (remaining != argc)
168 error (0, 0, gettext ("wrong number of arguments"));
169 argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
170 exit (1);
173 /* Read the configuration file. */
174 if (nscd_parse_file (conffile, dbs) != 0)
175 /* We couldn't read the configuration file. We don't start the
176 server. */
177 error (EXIT_FAILURE, 0,
178 _("failure while reading configuration file; this is fatal"));
180 /* Do we only get statistics? */
181 if (get_stats)
182 /* Does not return. */
183 receive_print_stats ();
185 /* Check if we are already running. */
186 if (check_pid (_PATH_NSCDPID))
187 error (EXIT_FAILURE, 0, _("already running"));
189 /* Remember when we started. */
190 start_time = time (NULL);
192 /* Determine page size. */
193 pagesize_m1 = getpagesize () - 1;
195 if (run_mode == RUN_DAEMONIZE || run_mode == RUN_FOREGROUND)
197 int i;
198 pid_t pid;
200 /* Behave like a daemon. */
201 if (run_mode == RUN_DAEMONIZE)
203 int fd[2];
205 if (pipe (fd) != 0)
206 error (EXIT_FAILURE, errno,
207 _("cannot create a pipe to talk to the child"));
209 pid = fork ();
210 if (pid == -1)
211 error (EXIT_FAILURE, errno, _("cannot fork"));
212 if (pid != 0)
214 /* The parent only reads from the child. */
215 close (fd[1]);
216 exit (monitor_child (fd[0]));
218 else
220 /* The child only writes to the parent. */
221 close (fd[0]);
222 parent_fd = fd[1];
226 int nullfd = open (_PATH_DEVNULL, O_RDWR);
227 if (nullfd != -1)
229 struct stat64 st;
231 if (fstat64 (nullfd, &st) == 0 && S_ISCHR (st.st_mode) != 0
232 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
233 && st.st_rdev == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)
234 #endif
237 /* It is the /dev/null special device alright. */
238 (void) dup2 (nullfd, STDIN_FILENO);
239 (void) dup2 (nullfd, STDOUT_FILENO);
240 (void) dup2 (nullfd, STDERR_FILENO);
242 if (nullfd > 2)
243 close (nullfd);
245 else
247 /* Ugh, somebody is trying to play a trick on us. */
248 close (nullfd);
249 nullfd = -1;
252 int min_close_fd = nullfd == -1 ? 0 : STDERR_FILENO + 1;
254 DIR *d = opendir ("/proc/self/fd");
255 if (d != NULL)
257 struct dirent64 *dirent;
258 int dfdn = dirfd (d);
260 while ((dirent = readdir64 (d)) != NULL)
262 char *endp;
263 long int fdn = strtol (dirent->d_name, &endp, 10);
265 if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd
266 && fdn != parent_fd)
267 close ((int) fdn);
270 closedir (d);
272 else
273 for (i = min_close_fd; i < getdtablesize (); i++)
274 if (i != parent_fd)
275 close (i);
277 setsid ();
279 if (chdir ("/") != 0)
280 do_exit (EXIT_FAILURE, errno,
281 _("cannot change current working directory to \"/\""));
283 openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
285 if (write_pid (_PATH_NSCDPID) < 0)
286 dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
288 if (!init_logfile ())
289 dbg_log (_("Could not create log file"));
291 /* Ignore job control signals. */
292 signal (SIGTTOU, SIG_IGN);
293 signal (SIGTTIN, SIG_IGN);
294 signal (SIGTSTP, SIG_IGN);
296 else
297 /* In debug mode we are not paranoid. */
298 paranoia = 0;
300 signal (SIGINT, termination_handler);
301 signal (SIGQUIT, termination_handler);
302 signal (SIGTERM, termination_handler);
303 signal (SIGPIPE, SIG_IGN);
305 /* Cleanup files created by a previous 'bind'. */
306 unlink (_PATH_NSCDSOCKET);
308 #ifdef HAVE_INOTIFY
309 /* Use inotify to recognize changed files. */
310 inotify_fd = inotify_init1 (IN_NONBLOCK);
311 # ifndef __ASSUME_IN_NONBLOCK
312 if (inotify_fd == -1 && errno == ENOSYS)
314 inotify_fd = inotify_init ();
315 if (inotify_fd != -1)
316 fcntl (inotify_fd, F_SETFL, O_RDONLY | O_NONBLOCK);
318 # endif
319 #endif
321 #ifdef USE_NSCD
322 /* Make sure we do not get recursive calls. */
323 __nss_disable_nscd (register_traced_file);
324 #endif
326 /* Init databases. */
327 nscd_init ();
329 /* Start the SELinux AVC. */
330 if (selinux_enabled)
331 nscd_avc_init ();
333 /* Handle incoming requests */
334 start_threads ();
336 return 0;
340 /* Handle program arguments. */
341 static error_t
342 parse_opt (int key, char *arg, struct argp_state *state)
344 switch (key)
346 case 'd':
347 ++debug_level;
348 run_mode = RUN_DEBUG;
349 break;
351 case 'F':
352 run_mode = RUN_FOREGROUND;
353 break;
355 case 'f':
356 conffile = arg;
357 break;
359 case 'K':
360 if (getuid () != 0)
361 error (4, 0, _("Only root is allowed to use this option!"));
363 int sock = nscd_open_socket ();
365 if (sock == -1)
366 exit (EXIT_FAILURE);
368 request_header req;
369 req.version = NSCD_VERSION;
370 req.type = SHUTDOWN;
371 req.key_len = 0;
373 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &req,
374 sizeof (request_header),
375 MSG_NOSIGNAL));
376 close (sock);
377 exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
380 case 'g':
381 get_stats = true;
382 break;
384 case 'i':
385 if (getuid () != 0)
386 error (4, 0, _("Only root is allowed to use this option!"));
387 else
389 int sock = nscd_open_socket ();
391 if (sock == -1)
392 exit (EXIT_FAILURE);
394 dbtype cnt;
395 for (cnt = pwddb; cnt < lastdb; ++cnt)
396 if (strcmp (arg, dbnames[cnt]) == 0)
397 break;
399 if (cnt == lastdb)
401 argp_error (state, _("'%s' is not a known database"), arg);
402 return EINVAL;
405 size_t arg_len = strlen (arg) + 1;
406 struct
408 request_header req;
409 char arg[arg_len];
410 } reqdata;
412 reqdata.req.key_len = strlen (arg) + 1;
413 reqdata.req.version = NSCD_VERSION;
414 reqdata.req.type = INVALIDATE;
415 memcpy (reqdata.arg, arg, arg_len);
417 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &reqdata,
418 sizeof (request_header)
419 + arg_len,
420 MSG_NOSIGNAL));
422 if (nbytes != sizeof (request_header) + arg_len)
424 int err = errno;
425 close (sock);
426 error (EXIT_FAILURE, err, _("write incomplete"));
429 /* Wait for ack. Older nscd just closed the socket when
430 prune_cache finished, silently ignore that. */
431 int32_t resp = 0;
432 nbytes = TEMP_FAILURE_RETRY (read (sock, &resp, sizeof (resp)));
433 if (nbytes != 0 && nbytes != sizeof (resp))
435 int err = errno;
436 close (sock);
437 error (EXIT_FAILURE, err, _("cannot read invalidate ACK"));
440 close (sock);
442 if (resp != 0)
443 error (EXIT_FAILURE, resp, _("invalidation failed"));
445 exit (0);
448 case 't':
449 nthreads = atol (arg);
450 break;
452 case 'S':
453 error (0, 0, _("secure services not implemented anymore"));
454 break;
456 default:
457 return ARGP_ERR_UNKNOWN;
460 return 0;
463 /* Print bug-reporting information in the help message. */
464 static char *
465 more_help (int key, const char *text, void *input)
467 char *tables, *tp = NULL;
469 switch (key)
471 case ARGP_KEY_HELP_EXTRA:
473 dbtype cnt;
475 tables = xmalloc (sizeof (dbnames) + 1);
476 for (cnt = 0; cnt < lastdb; cnt++)
478 strcat (tables, dbnames[cnt]);
479 strcat (tables, " ");
483 /* We print some extra information. */
484 if (asprintf (&tp, gettext ("\
485 Supported tables:\n\
486 %s\n\
488 For bug reporting instructions, please see:\n\
489 %s.\n\
490 "), tables, REPORT_BUGS_TO) < 0)
491 tp = NULL;
492 free (tables);
493 return tp;
495 default:
496 break;
499 return (char *) text;
502 /* Print the version information. */
503 static void
504 print_version (FILE *stream, struct argp_state *state)
506 fprintf (stream, "nscd %s%s\n", PKGVERSION, VERSION);
507 fprintf (stream, gettext ("\
508 Copyright (C) %s Free Software Foundation, Inc.\n\
509 This is free software; see the source for copying conditions. There is NO\n\
510 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
511 "), "2014");
512 fprintf (stream, gettext ("Written by %s.\n"),
513 "Thorsten Kukuk and Ulrich Drepper");
517 /* Create a socket connected to a name. */
519 nscd_open_socket (void)
521 struct sockaddr_un addr;
522 int sock;
524 sock = socket (PF_UNIX, SOCK_STREAM, 0);
525 if (sock < 0)
526 return -1;
528 addr.sun_family = AF_UNIX;
529 assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
530 strcpy (addr.sun_path, _PATH_NSCDSOCKET);
531 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
533 close (sock);
534 return -1;
537 return sock;
541 /* Cleanup. */
542 void
543 termination_handler (int signum)
545 close_sockets ();
547 /* Clean up the file created by 'bind'. */
548 unlink (_PATH_NSCDSOCKET);
550 /* Clean up pid file. */
551 unlink (_PATH_NSCDPID);
553 // XXX Terminate threads.
555 /* Synchronize memory. */
556 for (int cnt = 0; cnt < lastdb; ++cnt)
558 if (!dbs[cnt].enabled || dbs[cnt].head == NULL)
559 continue;
561 /* Make sure nobody keeps using the database. */
562 dbs[cnt].head->timestamp = 0;
564 if (dbs[cnt].persistent)
565 // XXX async OK?
566 msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
569 _exit (EXIT_SUCCESS);
572 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
573 static int
574 check_pid (const char *file)
576 FILE *fp;
578 fp = fopen (file, "r");
579 if (fp)
581 pid_t pid;
582 int n;
584 n = fscanf (fp, "%d", &pid);
585 fclose (fp);
587 /* If we cannot parse the file default to assuming nscd runs.
588 If the PID is alive, assume it is running. That all unless
589 the PID is the same as the current process' since tha latter
590 can mean we re-exec. */
591 if ((n != 1 || kill (pid, 0) == 0) && pid != getpid ())
592 return 1;
595 return 0;
598 /* Write the current process id to the file FILE.
599 Returns 0 if successful, -1 if not. */
600 static int
601 write_pid (const char *file)
603 FILE *fp;
605 fp = fopen (file, "w");
606 if (fp == NULL)
607 return -1;
609 fprintf (fp, "%d\n", getpid ());
611 int result = fflush (fp) || ferror (fp) ? -1 : 0;
613 fclose (fp);
615 return result;
618 static int
619 monitor_child (int fd)
621 int child_ret = 0;
622 int ret = read (fd, &child_ret, sizeof (child_ret));
624 /* The child terminated with an error, either via exit or some other abnormal
625 method, like a segfault. */
626 if (ret <= 0 || child_ret != 0)
628 int err = wait (&child_ret);
630 if (err < 0)
632 fprintf (stderr, _("wait failed"));
633 return 1;
636 fprintf (stderr, _("child exited with status %d"),
637 WEXITSTATUS (child_ret));
638 if (WIFSIGNALED (child_ret))
639 fprintf (stderr, _(", terminated by signal %d.\n"),
640 WTERMSIG (child_ret));
641 else
642 fprintf (stderr, ".\n");
645 /* We have the child status, so exit with that code. */
646 close (fd);
648 return child_ret;
651 void
652 do_exit (int child_ret, int errnum, const char *format, ...)
654 if (parent_fd != -1)
656 int ret = write (parent_fd, &child_ret, sizeof (child_ret));
657 assert (ret == sizeof (child_ret));
658 close (parent_fd);
661 if (format != NULL)
663 /* Emulate error() since we don't have a va_list variant for it. */
664 va_list argp;
666 fflush (stdout);
668 fprintf (stderr, "%s: ", program_invocation_name);
670 va_start (argp, format);
671 vfprintf (stderr, format, argp);
672 va_end (argp);
674 fprintf (stderr, ": %s\n", strerror (errnum));
675 fflush (stderr);
678 /* Finally, exit. */
679 exit (child_ret);
682 void
683 notify_parent (int child_ret)
685 if (parent_fd == -1)
686 return;
688 int ret = write (parent_fd, &child_ret, sizeof (child_ret));
689 assert (ret == sizeof (child_ret));
690 close (parent_fd);
691 parent_fd = -1;