Fix a typo in ChangeLog
[glibc.git] / nscd / nscd.c
blobbee9ed49ff747306d78f409ff709c8ed607c24b7
1 /* Copyright (c) 1998-2012 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>
43 #include "dbg_log.h"
44 #include "nscd.h"
45 #include "selinux.h"
46 #include "../nss/nsswitch.h"
47 #include <device-nrs.h>
48 #ifdef HAVE_INOTIFY
49 # include <sys/inotify.h>
50 #endif
52 /* Get libc version number. */
53 #include <version.h>
55 #define PACKAGE _libc_intl_domainname
57 /* Structure used by main() thread to keep track of the number of
58 active threads. Used to limit how many threads it will create
59 and under a shutdown condition to wait till all in-progress
60 requests have finished before "turning off the lights". */
62 typedef struct
64 int num_active;
65 pthread_cond_t thread_exit_cv;
66 pthread_mutex_t mutex;
67 } thread_info_t;
69 thread_info_t thread_info;
71 int do_shutdown;
72 int disabled_passwd;
73 int disabled_group;
75 typedef enum
77 /* Running in background as daemon. */
78 RUN_DAEMONIZE,
79 /* Running in foreground but otherwise behave like a daemon,
80 i.e., detach from terminal and use syslog. This allows
81 better integration with services like systemd. */
82 RUN_FOREGROUND,
83 /* Run in foreground in debug mode. */
84 RUN_DEBUG
85 } run_modes;
87 static run_modes run_mode = RUN_DAEMONIZE;
89 static const char *conffile = _PATH_NSCDCONF;
91 time_t start_time;
93 uintptr_t pagesize_m1;
95 int paranoia;
96 time_t restart_time;
97 time_t restart_interval = RESTART_INTERVAL;
98 const char *oldcwd;
99 uid_t old_uid;
100 gid_t old_gid;
102 static int check_pid (const char *file);
103 static int write_pid (const char *file);
105 /* Name and version of program. */
106 static void print_version (FILE *stream, struct argp_state *state);
107 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
109 /* Function to print some extra text in the help message. */
110 static char *more_help (int key, const char *text, void *input);
112 /* Definitions of arguments for argp functions. */
113 static const struct argp_option options[] =
115 { "config-file", 'f', N_("NAME"), 0,
116 N_("Read configuration data from NAME") },
117 { "debug", 'd', NULL, 0,
118 N_("Do not fork and display messages on the current tty") },
119 { "foreground", 'F', NULL, 0,
120 N_("Do not fork, but otherwise behave like a daemon") },
121 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
122 { "shutdown", 'K', NULL, 0, N_("Shut the server down") },
123 { "statistics", 'g', NULL, 0, N_("Print current configuration statistics") },
124 { "invalidate", 'i', N_("TABLE"), 0,
125 N_("Invalidate the specified cache") },
126 { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN,
127 N_("Use separate cache for each user")},
128 { NULL, 0, NULL, 0, NULL }
131 /* Short description of program. */
132 static const char doc[] = N_("Name Service Cache Daemon.");
134 /* Prototype for option handler. */
135 static error_t parse_opt (int key, char *arg, struct argp_state *state);
137 /* Data structure to communicate with argp functions. */
138 static struct argp argp =
140 options, parse_opt, NULL, doc, NULL, more_help
143 /* True if only statistics are requested. */
144 static bool get_stats;
147 main (int argc, char **argv)
149 int remaining;
151 /* Set locale via LC_ALL. */
152 setlocale (LC_ALL, "");
153 /* Set the text message domain. */
154 textdomain (PACKAGE);
156 /* Determine if the kernel has SELinux support. */
157 nscd_selinux_enabled (&selinux_enabled);
159 /* Parse and process arguments. */
160 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
162 if (remaining != argc)
164 error (0, 0, gettext ("wrong number of arguments"));
165 argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
166 exit (1);
169 /* Read the configuration file. */
170 if (nscd_parse_file (conffile, dbs) != 0)
171 /* We couldn't read the configuration file. We don't start the
172 server. */
173 error (EXIT_FAILURE, 0,
174 _("failure while reading configuration file; this is fatal"));
176 /* Do we only get statistics? */
177 if (get_stats)
178 /* Does not return. */
179 receive_print_stats ();
181 /* Check if we are already running. */
182 if (check_pid (_PATH_NSCDPID))
183 error (EXIT_FAILURE, 0, _("already running"));
185 /* Remember when we started. */
186 start_time = time (NULL);
188 /* Determine page size. */
189 pagesize_m1 = getpagesize () - 1;
191 if (run_mode == RUN_DAEMONIZE || run_mode == RUN_FOREGROUND)
193 int i;
194 pid_t pid;
196 /* Behave like a daemon. */
197 if (run_mode == RUN_DAEMONIZE)
199 pid = fork ();
200 if (pid == -1)
201 error (EXIT_FAILURE, errno, _("cannot fork"));
202 if (pid != 0)
203 exit (0);
206 int nullfd = open (_PATH_DEVNULL, O_RDWR);
207 if (nullfd != -1)
209 struct stat64 st;
211 if (fstat64 (nullfd, &st) == 0 && S_ISCHR (st.st_mode) != 0
212 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
213 && st.st_rdev == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)
214 #endif
217 /* It is the /dev/null special device alright. */
218 (void) dup2 (nullfd, STDIN_FILENO);
219 (void) dup2 (nullfd, STDOUT_FILENO);
220 (void) dup2 (nullfd, STDERR_FILENO);
222 if (nullfd > 2)
223 close (nullfd);
225 else
227 /* Ugh, somebody is trying to play a trick on us. */
228 close (nullfd);
229 nullfd = -1;
232 int min_close_fd = nullfd == -1 ? 0 : STDERR_FILENO + 1;
234 DIR *d = opendir ("/proc/self/fd");
235 if (d != NULL)
237 struct dirent64 *dirent;
238 int dfdn = dirfd (d);
240 while ((dirent = readdir64 (d)) != NULL)
242 char *endp;
243 long int fdn = strtol (dirent->d_name, &endp, 10);
245 if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd)
246 close ((int) fdn);
249 closedir (d);
251 else
252 for (i = min_close_fd; i < getdtablesize (); i++)
253 close (i);
255 if (run_mode == RUN_DAEMONIZE)
257 pid = fork ();
258 if (pid == -1)
259 error (EXIT_FAILURE, errno, _("cannot fork"));
260 if (pid != 0)
261 exit (0);
264 setsid ();
266 if (chdir ("/") != 0)
267 error (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 switch (key)
456 case ARGP_KEY_HELP_EXTRA:
457 /* We print some extra information. */
458 return strdup (gettext ("\
459 For bug reporting instructions, please see:\n\
460 <http://www.gnu.org/software/libc/bugs.html>.\n"));
461 default:
462 break;
464 return (char *) text;
467 /* Print the version information. */
468 static void
469 print_version (FILE *stream, struct argp_state *state)
471 fprintf (stream, "nscd (GNU %s) %s\n", PACKAGE, VERSION);
472 fprintf (stream, gettext ("\
473 Copyright (C) %s Free Software Foundation, Inc.\n\
474 This is free software; see the source for copying conditions. There is NO\n\
475 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
476 "), "2012");
477 fprintf (stream, gettext ("Written by %s.\n"),
478 "Thorsten Kukuk and Ulrich Drepper");
482 /* Create a socket connected to a name. */
484 nscd_open_socket (void)
486 struct sockaddr_un addr;
487 int sock;
489 sock = socket (PF_UNIX, SOCK_STREAM, 0);
490 if (sock < 0)
491 return -1;
493 addr.sun_family = AF_UNIX;
494 assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
495 strcpy (addr.sun_path, _PATH_NSCDSOCKET);
496 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
498 close (sock);
499 return -1;
502 return sock;
506 /* Cleanup. */
507 void
508 termination_handler (int signum)
510 close_sockets ();
512 /* Clean up the file created by 'bind'. */
513 unlink (_PATH_NSCDSOCKET);
515 /* Clean up pid file. */
516 unlink (_PATH_NSCDPID);
518 // XXX Terminate threads.
520 /* Synchronize memory. */
521 for (int cnt = 0; cnt < lastdb; ++cnt)
523 if (!dbs[cnt].enabled || dbs[cnt].head == NULL)
524 continue;
526 /* Make sure nobody keeps using the database. */
527 dbs[cnt].head->timestamp = 0;
529 if (dbs[cnt].persistent)
530 // XXX async OK?
531 msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
534 _exit (EXIT_SUCCESS);
537 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
538 static int
539 check_pid (const char *file)
541 FILE *fp;
543 fp = fopen (file, "r");
544 if (fp)
546 pid_t pid;
547 int n;
549 n = fscanf (fp, "%d", &pid);
550 fclose (fp);
552 /* If we cannot parse the file default to assuming nscd runs.
553 If the PID is alive, assume it is running. That all unless
554 the PID is the same as the current process' since tha latter
555 can mean we re-exec. */
556 if ((n != 1 || kill (pid, 0) == 0) && pid != getpid ())
557 return 1;
560 return 0;
563 /* Write the current process id to the file FILE.
564 Returns 0 if successful, -1 if not. */
565 static int
566 write_pid (const char *file)
568 FILE *fp;
570 fp = fopen (file, "w");
571 if (fp == NULL)
572 return -1;
574 fprintf (fp, "%d\n", getpid ());
576 int result = fflush (fp) || ferror (fp) ? -1 : 0;
578 fclose (fp);
580 return result;