Simplify _ELF_DYNAMIC_DO_RELOC after combining the old two defs.
[glibc.git] / nscd / nscd.c
blob9cd7273bbf7b8219d7fc2dda3ceb71b0317c5d5b
1 /* Copyright (c) 1998-2011, 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;
74 int go_background = 1;
76 static const char *conffile = _PATH_NSCDCONF;
78 time_t start_time;
80 uintptr_t pagesize_m1;
82 int paranoia;
83 time_t restart_time;
84 time_t restart_interval = RESTART_INTERVAL;
85 const char *oldcwd;
86 uid_t old_uid;
87 gid_t old_gid;
89 static int check_pid (const char *file);
90 static int write_pid (const char *file);
92 /* Name and version of program. */
93 static void print_version (FILE *stream, struct argp_state *state);
94 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
96 /* Function to print some extra text in the help message. */
97 static char *more_help (int key, const char *text, void *input);
99 /* Definitions of arguments for argp functions. */
100 static const struct argp_option options[] =
102 { "config-file", 'f', N_("NAME"), 0,
103 N_("Read configuration data from NAME") },
104 { "debug", 'd', NULL, 0,
105 N_("Do not fork and display messages on the current tty") },
106 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
107 { "shutdown", 'K', NULL, 0, N_("Shut the server down") },
108 { "statistics", 'g', NULL, 0, N_("Print current configuration statistics") },
109 { "invalidate", 'i', N_("TABLE"), 0,
110 N_("Invalidate the specified cache") },
111 { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN,
112 N_("Use separate cache for each user")},
113 { NULL, 0, NULL, 0, NULL }
116 /* Short description of program. */
117 static const char doc[] = N_("Name Service Cache Daemon.");
119 /* Prototype for option handler. */
120 static error_t parse_opt (int key, char *arg, struct argp_state *state);
122 /* Data structure to communicate with argp functions. */
123 static struct argp argp =
125 options, parse_opt, NULL, doc, NULL, more_help
128 /* True if only statistics are requested. */
129 static bool get_stats;
132 main (int argc, char **argv)
134 int remaining;
136 /* Set locale via LC_ALL. */
137 setlocale (LC_ALL, "");
138 /* Set the text message domain. */
139 textdomain (PACKAGE);
141 /* Determine if the kernel has SELinux support. */
142 nscd_selinux_enabled (&selinux_enabled);
144 /* Parse and process arguments. */
145 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
147 if (remaining != argc)
149 error (0, 0, gettext ("wrong number of arguments"));
150 argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
151 exit (1);
154 /* Read the configuration file. */
155 if (nscd_parse_file (conffile, dbs) != 0)
156 /* We couldn't read the configuration file. We don't start the
157 server. */
158 error (EXIT_FAILURE, 0,
159 _("failure while reading configuration file; this is fatal"));
161 /* Do we only get statistics? */
162 if (get_stats)
163 /* Does not return. */
164 receive_print_stats ();
166 /* Check if we are already running. */
167 if (check_pid (_PATH_NSCDPID))
168 error (EXIT_FAILURE, 0, _("already running"));
170 /* Remember when we started. */
171 start_time = time (NULL);
173 /* Determine page size. */
174 pagesize_m1 = getpagesize () - 1;
176 /* Behave like a daemon. */
177 if (go_background)
179 int i;
181 pid_t pid = fork ();
182 if (pid == -1)
183 error (EXIT_FAILURE, errno, _("cannot fork"));
184 if (pid != 0)
185 exit (0);
187 int nullfd = open (_PATH_DEVNULL, O_RDWR);
188 if (nullfd != -1)
190 struct stat64 st;
192 if (fstat64 (nullfd, &st) == 0 && S_ISCHR (st.st_mode) != 0
193 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
194 && st.st_rdev == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)
195 #endif
198 /* It is the /dev/null special device alright. */
199 (void) dup2 (nullfd, STDIN_FILENO);
200 (void) dup2 (nullfd, STDOUT_FILENO);
201 (void) dup2 (nullfd, STDERR_FILENO);
203 if (nullfd > 2)
204 close (nullfd);
206 else
208 /* Ugh, somebody is trying to play a trick on us. */
209 close (nullfd);
210 nullfd = -1;
213 int min_close_fd = nullfd == -1 ? 0 : STDERR_FILENO + 1;
215 DIR *d = opendir ("/proc/self/fd");
216 if (d != NULL)
218 struct dirent64 *dirent;
219 int dfdn = dirfd (d);
221 while ((dirent = readdir64 (d)) != NULL)
223 char *endp;
224 long int fdn = strtol (dirent->d_name, &endp, 10);
226 if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd)
227 close ((int) fdn);
230 closedir (d);
232 else
233 for (i = min_close_fd; i < getdtablesize (); i++)
234 close (i);
236 pid = fork ();
237 if (pid == -1)
238 error (EXIT_FAILURE, errno, _("cannot fork"));
239 if (pid != 0)
240 exit (0);
242 setsid ();
244 if (chdir ("/") != 0)
245 error (EXIT_FAILURE, errno,
246 _("cannot change current working directory to \"/\""));
248 openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
250 if (write_pid (_PATH_NSCDPID) < 0)
251 dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
253 if (!init_logfile ())
254 dbg_log (_("Could not create log file"));
256 /* Ignore job control signals. */
257 signal (SIGTTOU, SIG_IGN);
258 signal (SIGTTIN, SIG_IGN);
259 signal (SIGTSTP, SIG_IGN);
261 else
262 /* In foreground mode we are not paranoid. */
263 paranoia = 0;
265 signal (SIGINT, termination_handler);
266 signal (SIGQUIT, termination_handler);
267 signal (SIGTERM, termination_handler);
268 signal (SIGPIPE, SIG_IGN);
270 /* Cleanup files created by a previous 'bind'. */
271 unlink (_PATH_NSCDSOCKET);
273 #ifdef HAVE_INOTIFY
274 /* Use inotify to recognize changed files. */
275 inotify_fd = inotify_init1 (IN_NONBLOCK);
276 # ifndef __ASSUME_IN_NONBLOCK
277 if (inotify_fd == -1 && errno == ENOSYS)
279 inotify_fd = inotify_init ();
280 if (inotify_fd != -1)
281 fcntl (inotify_fd, F_SETFL, O_RDONLY | O_NONBLOCK);
283 # endif
284 #endif
286 /* Make sure we do not get recursive calls. */
287 __nss_disable_nscd (register_traced_file);
289 /* Init databases. */
290 nscd_init ();
292 /* Start the SELinux AVC. */
293 if (selinux_enabled)
294 nscd_avc_init ();
296 /* Handle incoming requests */
297 start_threads ();
299 return 0;
303 /* Handle program arguments. */
304 static error_t
305 parse_opt (int key, char *arg, struct argp_state *state)
307 switch (key)
309 case 'd':
310 ++debug_level;
311 go_background = 0;
312 break;
314 case 'f':
315 conffile = arg;
316 break;
318 case 'K':
319 if (getuid () != 0)
320 error (4, 0, _("Only root is allowed to use this option!"));
322 int sock = nscd_open_socket ();
324 if (sock == -1)
325 exit (EXIT_FAILURE);
327 request_header req;
328 req.version = NSCD_VERSION;
329 req.type = SHUTDOWN;
330 req.key_len = 0;
332 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &req,
333 sizeof (request_header),
334 MSG_NOSIGNAL));
335 close (sock);
336 exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
339 case 'g':
340 get_stats = true;
341 break;
343 case 'i':
344 if (getuid () != 0)
345 error (4, 0, _("Only root is allowed to use this option!"));
346 else
348 int sock = nscd_open_socket ();
350 if (sock == -1)
351 exit (EXIT_FAILURE);
353 dbtype cnt;
354 for (cnt = pwddb; cnt < lastdb; ++cnt)
355 if (strcmp (arg, dbnames[cnt]) == 0)
356 break;
358 if (cnt == lastdb)
360 argp_error (state, _("'%s' is not a known database"), arg);
361 return EINVAL;
364 size_t arg_len = strlen (arg) + 1;
365 struct
367 request_header req;
368 char arg[arg_len];
369 } reqdata;
371 reqdata.req.key_len = strlen (arg) + 1;
372 reqdata.req.version = NSCD_VERSION;
373 reqdata.req.type = INVALIDATE;
374 memcpy (reqdata.arg, arg, arg_len);
376 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &reqdata,
377 sizeof (request_header)
378 + arg_len,
379 MSG_NOSIGNAL));
381 if (nbytes != sizeof (request_header) + arg_len)
383 int err = errno;
384 close (sock);
385 error (EXIT_FAILURE, err, _("write incomplete"));
388 /* Wait for ack. Older nscd just closed the socket when
389 prune_cache finished, silently ignore that. */
390 int32_t resp = 0;
391 nbytes = TEMP_FAILURE_RETRY (read (sock, &resp, sizeof (resp)));
392 if (nbytes != 0 && nbytes != sizeof (resp))
394 int err = errno;
395 close (sock);
396 error (EXIT_FAILURE, err, _("cannot read invalidate ACK"));
399 close (sock);
401 if (resp != 0)
402 error (EXIT_FAILURE, resp, _("invalidation failed"));
404 exit (0);
407 case 't':
408 nthreads = atol (arg);
409 break;
411 case 'S':
412 error (0, 0, _("secure services not implemented anymore"));
413 break;
415 default:
416 return ARGP_ERR_UNKNOWN;
419 return 0;
422 /* Print bug-reporting information in the help message. */
423 static char *
424 more_help (int key, const char *text, void *input)
426 switch (key)
428 case ARGP_KEY_HELP_EXTRA:
429 /* We print some extra information. */
430 return strdup (gettext ("\
431 For bug reporting instructions, please see:\n\
432 <http://www.gnu.org/software/libc/bugs.html>.\n"));
433 default:
434 break;
436 return (char *) text;
439 /* Print the version information. */
440 static void
441 print_version (FILE *stream, struct argp_state *state)
443 fprintf (stream, "nscd (GNU %s) %s\n", PACKAGE, VERSION);
444 fprintf (stream, gettext ("\
445 Copyright (C) %s Free Software Foundation, Inc.\n\
446 This is free software; see the source for copying conditions. There is NO\n\
447 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
448 "), "2012");
449 fprintf (stream, gettext ("Written by %s.\n"),
450 "Thorsten Kukuk and Ulrich Drepper");
454 /* Create a socket connected to a name. */
456 nscd_open_socket (void)
458 struct sockaddr_un addr;
459 int sock;
461 sock = socket (PF_UNIX, SOCK_STREAM, 0);
462 if (sock < 0)
463 return -1;
465 addr.sun_family = AF_UNIX;
466 assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
467 strcpy (addr.sun_path, _PATH_NSCDSOCKET);
468 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
470 close (sock);
471 return -1;
474 return sock;
478 /* Cleanup. */
479 void
480 termination_handler (int signum)
482 close_sockets ();
484 /* Clean up the file created by 'bind'. */
485 unlink (_PATH_NSCDSOCKET);
487 /* Clean up pid file. */
488 unlink (_PATH_NSCDPID);
490 // XXX Terminate threads.
492 /* Synchronize memory. */
493 for (int cnt = 0; cnt < lastdb; ++cnt)
495 if (!dbs[cnt].enabled || dbs[cnt].head == NULL)
496 continue;
498 /* Make sure nobody keeps using the database. */
499 dbs[cnt].head->timestamp = 0;
501 if (dbs[cnt].persistent)
502 // XXX async OK?
503 msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
506 _exit (EXIT_SUCCESS);
509 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
510 static int
511 check_pid (const char *file)
513 FILE *fp;
515 fp = fopen (file, "r");
516 if (fp)
518 pid_t pid;
519 int n;
521 n = fscanf (fp, "%d", &pid);
522 fclose (fp);
524 /* If we cannot parse the file default to assuming nscd runs.
525 If the PID is alive, assume it is running. That all unless
526 the PID is the same as the current process' since tha latter
527 can mean we re-exec. */
528 if ((n != 1 || kill (pid, 0) == 0) && pid != getpid ())
529 return 1;
532 return 0;
535 /* Write the current process id to the file FILE.
536 Returns 0 if successful, -1 if not. */
537 static int
538 write_pid (const char *file)
540 FILE *fp;
542 fp = fopen (file, "w");
543 if (fp == NULL)
544 return -1;
546 fprintf (fp, "%d\n", getpid ());
548 int result = fflush (fp) || ferror (fp) ? -1 : 0;
550 fclose (fp);
552 return result;