Include <kernel-features.h> explicitly where required.
[glibc.git] / nscd / nscd.c
bloba4c71e90e201c5097f6c7a40b2e83b2f83b51157
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 /* Structure used by main() thread to keep track of the number of
61 active threads. Used to limit how many threads it will create
62 and under a shutdown condition to wait till all in-progress
63 requests have finished before "turning off the lights". */
65 typedef struct
67 int num_active;
68 pthread_cond_t thread_exit_cv;
69 pthread_mutex_t mutex;
70 } thread_info_t;
72 thread_info_t thread_info;
74 int do_shutdown;
75 int disabled_passwd;
76 int disabled_group;
78 typedef enum
80 /* Running in background as daemon. */
81 RUN_DAEMONIZE,
82 /* Running in foreground but otherwise behave like a daemon,
83 i.e., detach from terminal and use syslog. This allows
84 better integration with services like systemd. */
85 RUN_FOREGROUND,
86 /* Run in foreground in debug mode. */
87 RUN_DEBUG
88 } run_modes;
90 static run_modes run_mode = RUN_DAEMONIZE;
92 static const char *conffile = _PATH_NSCDCONF;
94 time_t start_time;
96 uintptr_t pagesize_m1;
98 int paranoia;
99 time_t restart_time;
100 time_t restart_interval = RESTART_INTERVAL;
101 const char *oldcwd;
102 uid_t old_uid;
103 gid_t old_gid;
105 static int check_pid (const char *file);
106 static int write_pid (const char *file);
107 static int monitor_child (int fd);
109 /* Name and version of program. */
110 static void print_version (FILE *stream, struct argp_state *state);
111 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
113 /* Function to print some extra text in the help message. */
114 static char *more_help (int key, const char *text, void *input);
116 /* Definitions of arguments for argp functions. */
117 static const struct argp_option options[] =
119 { "config-file", 'f', N_("NAME"), 0,
120 N_("Read configuration data from NAME") },
121 { "debug", 'd', NULL, 0,
122 N_("Do not fork and display messages on the current tty") },
123 { "foreground", 'F', NULL, 0,
124 N_("Do not fork, but otherwise behave like a daemon") },
125 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
126 { "shutdown", 'K', NULL, 0, N_("Shut the server down") },
127 { "statistics", 'g', NULL, 0, N_("Print current configuration statistics") },
128 { "invalidate", 'i', N_("TABLE"), 0,
129 N_("Invalidate the specified cache") },
130 { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN,
131 N_("Use separate cache for each user")},
132 { NULL, 0, NULL, 0, NULL }
135 /* Short description of program. */
136 static const char doc[] = N_("Name Service Cache Daemon.");
138 /* Prototype for option handler. */
139 static error_t parse_opt (int key, char *arg, struct argp_state *state);
141 /* Data structure to communicate with argp functions. */
142 static struct argp argp =
144 options, parse_opt, NULL, doc, NULL, more_help
147 /* True if only statistics are requested. */
148 static bool get_stats;
149 static int parent_fd = -1;
152 main (int argc, char **argv)
154 int remaining;
156 /* Set locale via LC_ALL. */
157 setlocale (LC_ALL, "");
158 /* Set the text message domain. */
159 textdomain (PACKAGE);
161 /* Determine if the kernel has SELinux support. */
162 nscd_selinux_enabled (&selinux_enabled);
164 /* Parse and process arguments. */
165 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
167 if (remaining != argc)
169 error (0, 0, gettext ("wrong number of arguments"));
170 argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
171 exit (1);
174 /* Read the configuration file. */
175 if (nscd_parse_file (conffile, dbs) != 0)
176 /* We couldn't read the configuration file. We don't start the
177 server. */
178 error (EXIT_FAILURE, 0,
179 _("failure while reading configuration file; this is fatal"));
181 /* Do we only get statistics? */
182 if (get_stats)
183 /* Does not return. */
184 receive_print_stats ();
186 /* Check if we are already running. */
187 if (check_pid (_PATH_NSCDPID))
188 error (EXIT_FAILURE, 0, _("already running"));
190 /* Remember when we started. */
191 start_time = time (NULL);
193 /* Determine page size. */
194 pagesize_m1 = getpagesize () - 1;
196 if (run_mode == RUN_DAEMONIZE || run_mode == RUN_FOREGROUND)
198 int i;
199 pid_t pid;
201 /* Behave like a daemon. */
202 if (run_mode == RUN_DAEMONIZE)
204 int fd[2];
206 if (pipe (fd) != 0)
207 error (EXIT_FAILURE, errno,
208 _("cannot create a pipe to talk to the child"));
210 pid = fork ();
211 if (pid == -1)
212 error (EXIT_FAILURE, errno, _("cannot fork"));
213 if (pid != 0)
215 /* The parent only reads from the child. */
216 close (fd[1]);
217 exit (monitor_child (fd[0]));
219 else
221 /* The child only writes to the parent. */
222 close (fd[0]);
223 parent_fd = fd[1];
227 int nullfd = open (_PATH_DEVNULL, O_RDWR);
228 if (nullfd != -1)
230 struct stat64 st;
232 if (fstat64 (nullfd, &st) == 0 && S_ISCHR (st.st_mode) != 0
233 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
234 && st.st_rdev == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)
235 #endif
238 /* It is the /dev/null special device alright. */
239 (void) dup2 (nullfd, STDIN_FILENO);
240 (void) dup2 (nullfd, STDOUT_FILENO);
241 (void) dup2 (nullfd, STDERR_FILENO);
243 if (nullfd > 2)
244 close (nullfd);
246 else
248 /* Ugh, somebody is trying to play a trick on us. */
249 close (nullfd);
250 nullfd = -1;
253 int min_close_fd = nullfd == -1 ? 0 : STDERR_FILENO + 1;
255 DIR *d = opendir ("/proc/self/fd");
256 if (d != NULL)
258 struct dirent64 *dirent;
259 int dfdn = dirfd (d);
261 while ((dirent = readdir64 (d)) != NULL)
263 char *endp;
264 long int fdn = strtol (dirent->d_name, &endp, 10);
266 if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd
267 && fdn != parent_fd)
268 close ((int) fdn);
271 closedir (d);
273 else
274 for (i = min_close_fd; i < getdtablesize (); i++)
275 if (i != parent_fd)
276 close (i);
278 setsid ();
280 if (chdir ("/") != 0)
281 do_exit (EXIT_FAILURE, errno,
282 _("cannot change current working directory to \"/\""));
284 openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
286 if (write_pid (_PATH_NSCDPID) < 0)
287 dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
289 if (!init_logfile ())
290 dbg_log (_("Could not create log file"));
292 /* Ignore job control signals. */
293 signal (SIGTTOU, SIG_IGN);
294 signal (SIGTTIN, SIG_IGN);
295 signal (SIGTSTP, SIG_IGN);
297 else
298 /* In debug mode we are not paranoid. */
299 paranoia = 0;
301 signal (SIGINT, termination_handler);
302 signal (SIGQUIT, termination_handler);
303 signal (SIGTERM, termination_handler);
304 signal (SIGPIPE, SIG_IGN);
306 /* Cleanup files created by a previous 'bind'. */
307 unlink (_PATH_NSCDSOCKET);
309 #ifdef HAVE_INOTIFY
310 /* Use inotify to recognize changed files. */
311 inotify_fd = inotify_init1 (IN_NONBLOCK);
312 # ifndef __ASSUME_IN_NONBLOCK
313 if (inotify_fd == -1 && errno == ENOSYS)
315 inotify_fd = inotify_init ();
316 if (inotify_fd != -1)
317 fcntl (inotify_fd, F_SETFL, O_RDONLY | O_NONBLOCK);
319 # endif
320 #endif
322 #ifdef USE_NSCD
323 /* Make sure we do not get recursive calls. */
324 __nss_disable_nscd (register_traced_file);
325 #endif
327 /* Init databases. */
328 nscd_init ();
330 /* Start the SELinux AVC. */
331 if (selinux_enabled)
332 nscd_avc_init ();
334 /* Handle incoming requests */
335 start_threads ();
337 return 0;
341 /* Handle program arguments. */
342 static error_t
343 parse_opt (int key, char *arg, struct argp_state *state)
345 switch (key)
347 case 'd':
348 ++debug_level;
349 run_mode = RUN_DEBUG;
350 break;
352 case 'F':
353 run_mode = RUN_FOREGROUND;
354 break;
356 case 'f':
357 conffile = arg;
358 break;
360 case 'K':
361 if (getuid () != 0)
362 error (4, 0, _("Only root is allowed to use this option!"));
364 int sock = nscd_open_socket ();
366 if (sock == -1)
367 exit (EXIT_FAILURE);
369 request_header req;
370 req.version = NSCD_VERSION;
371 req.type = SHUTDOWN;
372 req.key_len = 0;
374 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &req,
375 sizeof (request_header),
376 MSG_NOSIGNAL));
377 close (sock);
378 exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
381 case 'g':
382 get_stats = true;
383 break;
385 case 'i':
386 if (getuid () != 0)
387 error (4, 0, _("Only root is allowed to use this option!"));
388 else
390 int sock = nscd_open_socket ();
392 if (sock == -1)
393 exit (EXIT_FAILURE);
395 dbtype cnt;
396 for (cnt = pwddb; cnt < lastdb; ++cnt)
397 if (strcmp (arg, dbnames[cnt]) == 0)
398 break;
400 if (cnt == lastdb)
402 argp_error (state, _("'%s' is not a known database"), arg);
403 return EINVAL;
406 size_t arg_len = strlen (arg) + 1;
407 struct
409 request_header req;
410 char arg[arg_len];
411 } reqdata;
413 reqdata.req.key_len = strlen (arg) + 1;
414 reqdata.req.version = NSCD_VERSION;
415 reqdata.req.type = INVALIDATE;
416 memcpy (reqdata.arg, arg, arg_len);
418 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &reqdata,
419 sizeof (request_header)
420 + arg_len,
421 MSG_NOSIGNAL));
423 if (nbytes != sizeof (request_header) + arg_len)
425 int err = errno;
426 close (sock);
427 error (EXIT_FAILURE, err, _("write incomplete"));
430 /* Wait for ack. Older nscd just closed the socket when
431 prune_cache finished, silently ignore that. */
432 int32_t resp = 0;
433 nbytes = TEMP_FAILURE_RETRY (read (sock, &resp, sizeof (resp)));
434 if (nbytes != 0 && nbytes != sizeof (resp))
436 int err = errno;
437 close (sock);
438 error (EXIT_FAILURE, err, _("cannot read invalidate ACK"));
441 close (sock);
443 if (resp != 0)
444 error (EXIT_FAILURE, resp, _("invalidation failed"));
446 exit (0);
449 case 't':
450 nthreads = atol (arg);
451 break;
453 case 'S':
454 error (0, 0, _("secure services not implemented anymore"));
455 break;
457 default:
458 return ARGP_ERR_UNKNOWN;
461 return 0;
464 /* Print bug-reporting information in the help message. */
465 static char *
466 more_help (int key, const char *text, void *input)
468 char *tables, *tp = NULL;
470 switch (key)
472 case ARGP_KEY_HELP_EXTRA:
474 dbtype cnt;
476 tables = xmalloc (sizeof (dbnames) + 1);
477 for (cnt = 0; cnt < lastdb; cnt++)
479 strcat (tables, dbnames[cnt]);
480 strcat (tables, " ");
484 /* We print some extra information. */
485 if (asprintf (&tp, gettext ("\
486 Supported tables:\n\
487 %s\n\
489 For bug reporting instructions, please see:\n\
490 %s.\n\
491 "), tables, REPORT_BUGS_TO) < 0)
492 tp = NULL;
493 free (tables);
494 return tp;
496 default:
497 break;
500 return (char *) text;
503 /* Print the version information. */
504 static void
505 print_version (FILE *stream, struct argp_state *state)
507 fprintf (stream, "nscd %s%s\n", PKGVERSION, VERSION);
508 fprintf (stream, gettext ("\
509 Copyright (C) %s Free Software Foundation, Inc.\n\
510 This is free software; see the source for copying conditions. There is NO\n\
511 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
512 "), "2014");
513 fprintf (stream, gettext ("Written by %s.\n"),
514 "Thorsten Kukuk and Ulrich Drepper");
518 /* Create a socket connected to a name. */
520 nscd_open_socket (void)
522 struct sockaddr_un addr;
523 int sock;
525 sock = socket (PF_UNIX, SOCK_STREAM, 0);
526 if (sock < 0)
527 return -1;
529 addr.sun_family = AF_UNIX;
530 assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
531 strcpy (addr.sun_path, _PATH_NSCDSOCKET);
532 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
534 close (sock);
535 return -1;
538 return sock;
542 /* Cleanup. */
543 void
544 termination_handler (int signum)
546 close_sockets ();
548 /* Clean up the file created by 'bind'. */
549 unlink (_PATH_NSCDSOCKET);
551 /* Clean up pid file. */
552 unlink (_PATH_NSCDPID);
554 // XXX Terminate threads.
556 /* Synchronize memory. */
557 for (int cnt = 0; cnt < lastdb; ++cnt)
559 if (!dbs[cnt].enabled || dbs[cnt].head == NULL)
560 continue;
562 /* Make sure nobody keeps using the database. */
563 dbs[cnt].head->timestamp = 0;
565 if (dbs[cnt].persistent)
566 // XXX async OK?
567 msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
570 _exit (EXIT_SUCCESS);
573 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
574 static int
575 check_pid (const char *file)
577 FILE *fp;
579 fp = fopen (file, "r");
580 if (fp)
582 pid_t pid;
583 int n;
585 n = fscanf (fp, "%d", &pid);
586 fclose (fp);
588 /* If we cannot parse the file default to assuming nscd runs.
589 If the PID is alive, assume it is running. That all unless
590 the PID is the same as the current process' since tha latter
591 can mean we re-exec. */
592 if ((n != 1 || kill (pid, 0) == 0) && pid != getpid ())
593 return 1;
596 return 0;
599 /* Write the current process id to the file FILE.
600 Returns 0 if successful, -1 if not. */
601 static int
602 write_pid (const char *file)
604 FILE *fp;
606 fp = fopen (file, "w");
607 if (fp == NULL)
608 return -1;
610 fprintf (fp, "%d\n", getpid ());
612 int result = fflush (fp) || ferror (fp) ? -1 : 0;
614 fclose (fp);
616 return result;
619 static int
620 monitor_child (int fd)
622 int child_ret = 0;
623 int ret = read (fd, &child_ret, sizeof (child_ret));
625 /* The child terminated with an error, either via exit or some other abnormal
626 method, like a segfault. */
627 if (ret <= 0 || child_ret != 0)
629 int err = wait (&child_ret);
631 if (err < 0)
633 fprintf (stderr, _("wait failed"));
634 return 1;
637 fprintf (stderr, _("child exited with status %d"),
638 WEXITSTATUS (child_ret));
639 if (WIFSIGNALED (child_ret))
640 fprintf (stderr, _(", terminated by signal %d.\n"),
641 WTERMSIG (child_ret));
642 else
643 fprintf (stderr, ".\n");
646 /* We have the child status, so exit with that code. */
647 close (fd);
649 return child_ret;
652 void
653 do_exit (int child_ret, int errnum, const char *format, ...)
655 if (parent_fd != -1)
657 int ret = write (parent_fd, &child_ret, sizeof (child_ret));
658 assert (ret == sizeof (child_ret));
659 close (parent_fd);
662 if (format != NULL)
664 /* Emulate error() since we don't have a va_list variant for it. */
665 va_list argp;
667 fflush (stdout);
669 fprintf (stderr, "%s: ", program_invocation_name);
671 va_start (argp, format);
672 vfprintf (stderr, format, argp);
673 va_end (argp);
675 fprintf (stderr, ": %s\n", strerror (errnum));
676 fflush (stderr);
679 /* Finally, exit. */
680 exit (child_ret);
683 void
684 notify_parent (int child_ret)
686 if (parent_fd == -1)
687 return;
689 int ret = write (parent_fd, &child_ret, sizeof (child_ret));
690 assert (ret == sizeof (child_ret));
691 close (parent_fd);
692 parent_fd = -1;