Avoid warning from shifting
[glibc.git] / nscd / nscd.c
blobbe693c9d5c57f9b5081657be7cad2909780b3c48
1 /* Copyright (c) 1998-2008, 2009, 2010, 2011 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, write to the Free Software Foundation,
17 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19 /* nscd - Name Service Cache Daemon. Caches passwd, group, and hosts. */
21 #include <argp.h>
22 #include <assert.h>
23 #include <dirent.h>
24 #include <errno.h>
25 #include <error.h>
26 #include <fcntl.h>
27 #include <libintl.h>
28 #include <locale.h>
29 #include <paths.h>
30 #include <pthread.h>
31 #include <signal.h>
32 #include <stdbool.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <syslog.h>
37 #include <unistd.h>
38 #include <sys/mman.h>
39 #include <sys/socket.h>
40 #include <sys/stat.h>
41 #include <sys/uio.h>
42 #include <sys/un.h>
44 #include "dbg_log.h"
45 #include "nscd.h"
46 #include "selinux.h"
47 #include "../nss/nsswitch.h"
48 #include <device-nrs.h>
49 #ifdef HAVE_INOTIFY
50 # include <sys/inotify.h>
51 #endif
53 /* Get libc version number. */
54 #include <version.h>
56 #define PACKAGE _libc_intl_domainname
58 /* Structure used by main() thread to keep track of the number of
59 active threads. Used to limit how many threads it will create
60 and under a shutdown condition to wait till all in-progress
61 requests have finished before "turning off the lights". */
63 typedef struct
65 int num_active;
66 pthread_cond_t thread_exit_cv;
67 pthread_mutex_t mutex;
68 } thread_info_t;
70 thread_info_t thread_info;
72 int do_shutdown;
73 int disabled_passwd;
74 int disabled_group;
75 int go_background = 1;
77 static const char *conffile = _PATH_NSCDCONF;
79 time_t start_time;
81 uintptr_t pagesize_m1;
83 int paranoia;
84 time_t restart_time;
85 time_t restart_interval = RESTART_INTERVAL;
86 const char *oldcwd;
87 uid_t old_uid;
88 gid_t old_gid;
90 static int check_pid (const char *file);
91 static int write_pid (const char *file);
93 /* Name and version of program. */
94 static void print_version (FILE *stream, struct argp_state *state);
95 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
97 /* Function to print some extra text in the help message. */
98 static char *more_help (int key, const char *text, void *input);
100 /* Definitions of arguments for argp functions. */
101 static const struct argp_option options[] =
103 { "config-file", 'f', N_("NAME"), 0,
104 N_("Read configuration data from NAME") },
105 { "debug", 'd', NULL, 0,
106 N_("Do not fork and display messages on the current tty") },
107 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
108 { "shutdown", 'K', NULL, 0, N_("Shut the server down") },
109 { "statistics", 'g', NULL, 0, N_("Print current configuration statistics") },
110 { "invalidate", 'i', N_("TABLE"), 0,
111 N_("Invalidate the specified cache") },
112 { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN,
113 N_("Use separate cache for each user")},
114 { NULL, 0, NULL, 0, NULL }
117 /* Short description of program. */
118 static const char doc[] = N_("Name Service Cache Daemon.");
120 /* Prototype for option handler. */
121 static error_t parse_opt (int key, char *arg, struct argp_state *state);
123 /* Data structure to communicate with argp functions. */
124 static struct argp argp =
126 options, parse_opt, NULL, doc, NULL, more_help
129 /* True if only statistics are requested. */
130 static bool get_stats;
133 main (int argc, char **argv)
135 int remaining;
137 /* Set locale via LC_ALL. */
138 setlocale (LC_ALL, "");
139 /* Set the text message domain. */
140 textdomain (PACKAGE);
142 /* Determine if the kernel has SELinux support. */
143 nscd_selinux_enabled (&selinux_enabled);
145 /* Parse and process arguments. */
146 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
148 if (remaining != argc)
150 error (0, 0, gettext ("wrong number of arguments"));
151 argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
152 exit (1);
155 /* Read the configuration file. */
156 if (nscd_parse_file (conffile, dbs) != 0)
157 /* We couldn't read the configuration file. We don't start the
158 server. */
159 error (EXIT_FAILURE, 0,
160 _("failure while reading configuration file; this is fatal"));
162 /* Do we only get statistics? */
163 if (get_stats)
164 /* Does not return. */
165 receive_print_stats ();
167 /* Check if we are already running. */
168 if (check_pid (_PATH_NSCDPID))
169 error (EXIT_FAILURE, 0, _("already running"));
171 /* Remember when we started. */
172 start_time = time (NULL);
174 /* Determine page size. */
175 pagesize_m1 = getpagesize () - 1;
177 /* Behave like a daemon. */
178 if (go_background)
180 int i;
182 pid_t pid = fork ();
183 if (pid == -1)
184 error (EXIT_FAILURE, errno, _("cannot fork"));
185 if (pid != 0)
186 exit (0);
188 int nullfd = open (_PATH_DEVNULL, O_RDWR);
189 if (nullfd != -1)
191 struct stat64 st;
193 if (fstat64 (nullfd, &st) == 0 && S_ISCHR (st.st_mode) != 0
194 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
195 && st.st_rdev == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)
196 #endif
199 /* It is the /dev/null special device alright. */
200 (void) dup2 (nullfd, STDIN_FILENO);
201 (void) dup2 (nullfd, STDOUT_FILENO);
202 (void) dup2 (nullfd, STDERR_FILENO);
204 if (nullfd > 2)
205 close (nullfd);
207 else
209 /* Ugh, somebody is trying to play a trick on us. */
210 close (nullfd);
211 nullfd = -1;
214 int min_close_fd = nullfd == -1 ? 0 : STDERR_FILENO + 1;
216 DIR *d = opendir ("/proc/self/fd");
217 if (d != NULL)
219 struct dirent64 *dirent;
220 int dfdn = dirfd (d);
222 while ((dirent = readdir64 (d)) != NULL)
224 char *endp;
225 long int fdn = strtol (dirent->d_name, &endp, 10);
227 if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd)
228 close ((int) fdn);
231 closedir (d);
233 else
234 for (i = min_close_fd; i < getdtablesize (); i++)
235 close (i);
237 pid = fork ();
238 if (pid == -1)
239 error (EXIT_FAILURE, errno, _("cannot fork"));
240 if (pid != 0)
241 exit (0);
243 setsid ();
245 if (chdir ("/") != 0)
246 error (EXIT_FAILURE, errno,
247 _("cannot change current working directory to \"/\""));
249 openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
251 if (write_pid (_PATH_NSCDPID) < 0)
252 dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
254 if (!init_logfile ())
255 dbg_log (_("Could not create log file"));
257 /* Ignore job control signals. */
258 signal (SIGTTOU, SIG_IGN);
259 signal (SIGTTIN, SIG_IGN);
260 signal (SIGTSTP, SIG_IGN);
262 else
263 /* In foreground mode we are not paranoid. */
264 paranoia = 0;
266 signal (SIGINT, termination_handler);
267 signal (SIGQUIT, termination_handler);
268 signal (SIGTERM, termination_handler);
269 signal (SIGPIPE, SIG_IGN);
271 /* Cleanup files created by a previous 'bind'. */
272 unlink (_PATH_NSCDSOCKET);
274 #ifdef HAVE_INOTIFY
275 /* Use inotify to recognize changed files. */
276 inotify_fd = inotify_init1 (IN_NONBLOCK);
277 # ifndef __ASSUME_IN_NONBLOCK
278 if (inotify_fd == -1 && errno == ENOSYS)
280 inotify_fd = inotify_init ();
281 if (inotify_fd != -1)
282 fcntl (inotify_fd, F_SETFL, O_RDONLY | O_NONBLOCK);
284 # endif
285 #endif
287 /* Make sure we do not get recursive calls. */
288 __nss_disable_nscd (register_traced_file);
290 /* Init databases. */
291 nscd_init ();
293 /* Start the SELinux AVC. */
294 if (selinux_enabled)
295 nscd_avc_init ();
297 /* Handle incoming requests */
298 start_threads ();
300 return 0;
304 /* Handle program arguments. */
305 static error_t
306 parse_opt (int key, char *arg, struct argp_state *state)
308 switch (key)
310 case 'd':
311 ++debug_level;
312 go_background = 0;
313 break;
315 case 'f':
316 conffile = arg;
317 break;
319 case 'K':
320 if (getuid () != 0)
321 error (4, 0, _("Only root is allowed to use this option!"));
323 int sock = nscd_open_socket ();
325 if (sock == -1)
326 exit (EXIT_FAILURE);
328 request_header req;
329 req.version = NSCD_VERSION;
330 req.type = SHUTDOWN;
331 req.key_len = 0;
333 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &req,
334 sizeof (request_header),
335 MSG_NOSIGNAL));
336 close (sock);
337 exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
340 case 'g':
341 get_stats = true;
342 break;
344 case 'i':
345 if (getuid () != 0)
346 error (4, 0, _("Only root is allowed to use this option!"));
347 else
349 int sock = nscd_open_socket ();
351 if (sock == -1)
352 exit (EXIT_FAILURE);
354 dbtype cnt;
355 for (cnt = pwddb; cnt < lastdb; ++cnt)
356 if (strcmp (arg, dbnames[cnt]) == 0)
357 break;
359 if (cnt == lastdb)
361 argp_error (state, _("'%s' is not a known database"), arg);
362 return EINVAL;
365 size_t arg_len = strlen (arg) + 1;
366 struct
368 request_header req;
369 char arg[arg_len];
370 } reqdata;
372 reqdata.req.key_len = strlen (arg) + 1;
373 reqdata.req.version = NSCD_VERSION;
374 reqdata.req.type = INVALIDATE;
375 memcpy (reqdata.arg, arg, arg_len);
377 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &reqdata,
378 sizeof (request_header)
379 + arg_len,
380 MSG_NOSIGNAL));
382 if (nbytes != sizeof (request_header) + arg_len)
384 int err = errno;
385 close (sock);
386 error (EXIT_FAILURE, err, _("write incomplete"));
389 /* Wait for ack. Older nscd just closed the socket when
390 prune_cache finished, silently ignore that. */
391 int32_t resp = 0;
392 nbytes = TEMP_FAILURE_RETRY (read (sock, &resp, sizeof (resp)));
393 if (nbytes != 0 && nbytes != sizeof (resp))
395 int err = errno;
396 close (sock);
397 error (EXIT_FAILURE, err, _("cannot read invalidate ACK"));
400 close (sock);
402 if (resp != 0)
403 error (EXIT_FAILURE, resp, _("invalidation failed"));
405 exit (0);
408 case 't':
409 nthreads = atol (arg);
410 break;
412 case 'S':
413 error (0, 0, _("secure services not implemented anymore"));
414 break;
416 default:
417 return ARGP_ERR_UNKNOWN;
420 return 0;
423 /* Print bug-reporting information in the help message. */
424 static char *
425 more_help (int key, const char *text, void *input)
427 switch (key)
429 case ARGP_KEY_HELP_EXTRA:
430 /* We print some extra information. */
431 return strdup (gettext ("\
432 For bug reporting instructions, please see:\n\
433 <http://www.gnu.org/software/libc/bugs.html>.\n"));
434 default:
435 break;
437 return (char *) text;
440 /* Print the version information. */
441 static void
442 print_version (FILE *stream, struct argp_state *state)
444 fprintf (stream, "nscd (GNU %s) %s\n", PACKAGE, VERSION);
445 fprintf (stream, gettext ("\
446 Copyright (C) %s Free Software Foundation, Inc.\n\
447 This is free software; see the source for copying conditions. There is NO\n\
448 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
449 "), "2011");
450 fprintf (stream, gettext ("Written by %s.\n"),
451 "Thorsten Kukuk and Ulrich Drepper");
455 /* Create a socket connected to a name. */
457 nscd_open_socket (void)
459 struct sockaddr_un addr;
460 int sock;
462 sock = socket (PF_UNIX, SOCK_STREAM, 0);
463 if (sock < 0)
464 return -1;
466 addr.sun_family = AF_UNIX;
467 assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
468 strcpy (addr.sun_path, _PATH_NSCDSOCKET);
469 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
471 close (sock);
472 return -1;
475 return sock;
479 /* Cleanup. */
480 void
481 termination_handler (int signum)
483 close_sockets ();
485 /* Clean up the file created by 'bind'. */
486 unlink (_PATH_NSCDSOCKET);
488 /* Clean up pid file. */
489 unlink (_PATH_NSCDPID);
491 // XXX Terminate threads.
493 /* Synchronize memory. */
494 for (int cnt = 0; cnt < lastdb; ++cnt)
496 if (!dbs[cnt].enabled || dbs[cnt].head == NULL)
497 continue;
499 /* Make sure nobody keeps using the database. */
500 dbs[cnt].head->timestamp = 0;
502 if (dbs[cnt].persistent)
503 // XXX async OK?
504 msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
507 _exit (EXIT_SUCCESS);
510 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
511 static int
512 check_pid (const char *file)
514 FILE *fp;
516 fp = fopen (file, "r");
517 if (fp)
519 pid_t pid;
520 int n;
522 n = fscanf (fp, "%d", &pid);
523 fclose (fp);
525 /* If we cannot parse the file default to assuming nscd runs.
526 If the PID is alive, assume it is running. That all unless
527 the PID is the same as the current process' since tha latter
528 can mean we re-exec. */
529 if ((n != 1 || kill (pid, 0) == 0) && pid != getpid ())
530 return 1;
533 return 0;
536 /* Write the current process id to the file FILE.
537 Returns 0 if successful, -1 if not. */
538 static int
539 write_pid (const char *file)
541 FILE *fp;
543 fp = fopen (file, "w");
544 if (fp == NULL)
545 return -1;
547 fprintf (fp, "%d\n", getpid ());
549 int result = fflush (fp) || ferror (fp) ? -1 : 0;
551 fclose (fp);
553 return result;