Define _DIRENT_MATCHES_DIRENT64 in bsd4.4/bits/dirent.h
[glibc.git] / nscd / nscd.c
blob79fb32f327af814e64294598f763325078dc8aaa
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 /* Make sure we do not get recursive calls. */
309 __nss_disable_nscd (register_traced_file);
311 /* Init databases. */
312 nscd_init ();
314 /* Start the SELinux AVC. */
315 if (selinux_enabled)
316 nscd_avc_init ();
318 /* Handle incoming requests */
319 start_threads ();
321 return 0;
325 /* Handle program arguments. */
326 static error_t
327 parse_opt (int key, char *arg, struct argp_state *state)
329 switch (key)
331 case 'd':
332 ++debug_level;
333 run_mode = RUN_DEBUG;
334 break;
336 case 'F':
337 run_mode = RUN_FOREGROUND;
338 break;
340 case 'f':
341 conffile = arg;
342 break;
344 case 'K':
345 if (getuid () != 0)
346 error (4, 0, _("Only root is allowed to use this option!"));
348 int sock = nscd_open_socket ();
350 if (sock == -1)
351 exit (EXIT_FAILURE);
353 request_header req;
354 req.version = NSCD_VERSION;
355 req.type = SHUTDOWN;
356 req.key_len = 0;
358 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &req,
359 sizeof (request_header),
360 MSG_NOSIGNAL));
361 close (sock);
362 exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
365 case 'g':
366 get_stats = true;
367 break;
369 case 'i':
370 if (getuid () != 0)
371 error (4, 0, _("Only root is allowed to use this option!"));
372 else
374 int sock = nscd_open_socket ();
376 if (sock == -1)
377 exit (EXIT_FAILURE);
379 dbtype cnt;
380 for (cnt = pwddb; cnt < lastdb; ++cnt)
381 if (strcmp (arg, dbnames[cnt]) == 0)
382 break;
384 if (cnt == lastdb)
386 argp_error (state, _("'%s' is not a known database"), arg);
387 return EINVAL;
390 size_t arg_len = strlen (arg) + 1;
391 struct
393 request_header req;
394 char arg[arg_len];
395 } reqdata;
397 reqdata.req.key_len = strlen (arg) + 1;
398 reqdata.req.version = NSCD_VERSION;
399 reqdata.req.type = INVALIDATE;
400 memcpy (reqdata.arg, arg, arg_len);
402 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &reqdata,
403 sizeof (request_header)
404 + arg_len,
405 MSG_NOSIGNAL));
407 if (nbytes != sizeof (request_header) + arg_len)
409 int err = errno;
410 close (sock);
411 error (EXIT_FAILURE, err, _("write incomplete"));
414 /* Wait for ack. Older nscd just closed the socket when
415 prune_cache finished, silently ignore that. */
416 int32_t resp = 0;
417 nbytes = TEMP_FAILURE_RETRY (read (sock, &resp, sizeof (resp)));
418 if (nbytes != 0 && nbytes != sizeof (resp))
420 int err = errno;
421 close (sock);
422 error (EXIT_FAILURE, err, _("cannot read invalidate ACK"));
425 close (sock);
427 if (resp != 0)
428 error (EXIT_FAILURE, resp, _("invalidation failed"));
430 exit (0);
433 case 't':
434 nthreads = atol (arg);
435 break;
437 case 'S':
438 error (0, 0, _("secure services not implemented anymore"));
439 break;
441 default:
442 return ARGP_ERR_UNKNOWN;
445 return 0;
448 /* Print bug-reporting information in the help message. */
449 static char *
450 more_help (int key, const char *text, void *input)
452 switch (key)
454 case ARGP_KEY_HELP_EXTRA:
455 /* We print some extra information. */
456 return strdup (gettext ("\
457 For bug reporting instructions, please see:\n\
458 <http://www.gnu.org/software/libc/bugs.html>.\n"));
459 default:
460 break;
462 return (char *) text;
465 /* Print the version information. */
466 static void
467 print_version (FILE *stream, struct argp_state *state)
469 fprintf (stream, "nscd (GNU %s) %s\n", PACKAGE, VERSION);
470 fprintf (stream, gettext ("\
471 Copyright (C) %s Free Software Foundation, Inc.\n\
472 This is free software; see the source for copying conditions. There is NO\n\
473 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
474 "), "2012");
475 fprintf (stream, gettext ("Written by %s.\n"),
476 "Thorsten Kukuk and Ulrich Drepper");
480 /* Create a socket connected to a name. */
482 nscd_open_socket (void)
484 struct sockaddr_un addr;
485 int sock;
487 sock = socket (PF_UNIX, SOCK_STREAM, 0);
488 if (sock < 0)
489 return -1;
491 addr.sun_family = AF_UNIX;
492 assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
493 strcpy (addr.sun_path, _PATH_NSCDSOCKET);
494 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
496 close (sock);
497 return -1;
500 return sock;
504 /* Cleanup. */
505 void
506 termination_handler (int signum)
508 close_sockets ();
510 /* Clean up the file created by 'bind'. */
511 unlink (_PATH_NSCDSOCKET);
513 /* Clean up pid file. */
514 unlink (_PATH_NSCDPID);
516 // XXX Terminate threads.
518 /* Synchronize memory. */
519 for (int cnt = 0; cnt < lastdb; ++cnt)
521 if (!dbs[cnt].enabled || dbs[cnt].head == NULL)
522 continue;
524 /* Make sure nobody keeps using the database. */
525 dbs[cnt].head->timestamp = 0;
527 if (dbs[cnt].persistent)
528 // XXX async OK?
529 msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
532 _exit (EXIT_SUCCESS);
535 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
536 static int
537 check_pid (const char *file)
539 FILE *fp;
541 fp = fopen (file, "r");
542 if (fp)
544 pid_t pid;
545 int n;
547 n = fscanf (fp, "%d", &pid);
548 fclose (fp);
550 /* If we cannot parse the file default to assuming nscd runs.
551 If the PID is alive, assume it is running. That all unless
552 the PID is the same as the current process' since tha latter
553 can mean we re-exec. */
554 if ((n != 1 || kill (pid, 0) == 0) && pid != getpid ())
555 return 1;
558 return 0;
561 /* Write the current process id to the file FILE.
562 Returns 0 if successful, -1 if not. */
563 static int
564 write_pid (const char *file)
566 FILE *fp;
568 fp = fopen (file, "w");
569 if (fp == NULL)
570 return -1;
572 fprintf (fp, "%d\n", getpid ());
574 int result = fflush (fp) || ferror (fp) ? -1 : 0;
576 fclose (fp);
578 return result;