Updated to fedora-glibc-20090218T1534
[glibc/history.git] / nscd / nscd.c
blob3265ea8973edc31056531bd18fe8d4d06dde331e
1 /* Copyright (c) 1998-2008, 2009 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>
50 /* Get libc version number. */
51 #include <version.h>
53 #define PACKAGE _libc_intl_domainname
55 /* Structure used by main() thread to keep track of the number of
56 active threads. Used to limit how many threads it will create
57 and under a shutdown condition to wait till all in-progress
58 requests have finished before "turning off the lights". */
60 typedef struct
62 int num_active;
63 pthread_cond_t thread_exit_cv;
64 pthread_mutex_t mutex;
65 } thread_info_t;
67 thread_info_t thread_info;
69 int do_shutdown;
70 int disabled_passwd;
71 int disabled_group;
72 int go_background = 1;
74 static const char *conffile = _PATH_NSCDCONF;
76 time_t start_time;
78 uintptr_t pagesize_m1;
80 int paranoia;
81 time_t restart_time;
82 time_t restart_interval = RESTART_INTERVAL;
83 const char *oldcwd;
84 uid_t old_uid;
85 gid_t old_gid;
87 static int check_pid (const char *file);
88 static int write_pid (const char *file);
90 /* Name and version of program. */
91 static void print_version (FILE *stream, struct argp_state *state);
92 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
94 /* Function to print some extra text in the help message. */
95 static char *more_help (int key, const char *text, void *input);
97 /* Definitions of arguments for argp functions. */
98 static const struct argp_option options[] =
100 { "config-file", 'f', N_("NAME"), 0,
101 N_("Read configuration data from NAME") },
102 { "debug", 'd', NULL, 0,
103 N_("Do not fork and display messages on the current tty") },
104 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
105 { "shutdown", 'K', NULL, 0, N_("Shut the server down") },
106 { "statistics", 'g', NULL, 0, N_("Print current configuration statistics") },
107 { "invalidate", 'i', N_("TABLE"), 0,
108 N_("Invalidate the specified cache") },
109 { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN,
110 N_("Use separate cache for each user")},
111 { NULL, 0, NULL, 0, NULL }
114 /* Short description of program. */
115 static const char doc[] = N_("Name Service Cache Daemon.");
117 /* Prototype for option handler. */
118 static error_t parse_opt (int key, char *arg, struct argp_state *state);
120 /* Data structure to communicate with argp functions. */
121 static struct argp argp =
123 options, parse_opt, NULL, doc, NULL, more_help
126 /* True if only statistics are requested. */
127 static bool get_stats;
130 main (int argc, char **argv)
132 int remaining;
134 /* Set locale via LC_ALL. */
135 setlocale (LC_ALL, "");
136 /* Set the text message domain. */
137 textdomain (PACKAGE);
139 /* Determine if the kernel has SELinux support. */
140 nscd_selinux_enabled (&selinux_enabled);
142 /* Parse and process arguments. */
143 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
145 if (remaining != argc)
147 error (0, 0, gettext ("wrong number of arguments"));
148 argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
149 exit (1);
152 /* Read the configuration file. */
153 if (nscd_parse_file (conffile, dbs) != 0)
154 /* We couldn't read the configuration file. We don't start the
155 server. */
156 error (EXIT_FAILURE, 0,
157 _("failure while reading configuration file; this is fatal"));
159 /* Do we only get statistics? */
160 if (get_stats)
161 /* Does not return. */
162 receive_print_stats ();
164 /* Check if we are already running. */
165 if (check_pid (_PATH_NSCDPID))
166 error (EXIT_FAILURE, 0, _("already running"));
168 /* Remember when we started. */
169 start_time = time (NULL);
171 /* Determine page size. */
172 pagesize_m1 = getpagesize () - 1;
174 /* Behave like a daemon. */
175 if (go_background)
177 int i;
179 pid_t pid = fork ();
180 if (pid == -1)
181 error (EXIT_FAILURE, errno, _("cannot fork"));
182 if (pid != 0)
183 exit (0);
185 int nullfd = open (_PATH_DEVNULL, O_RDWR);
186 if (nullfd != -1)
188 struct stat64 st;
190 if (fstat64 (nullfd, &st) == 0 && S_ISCHR (st.st_mode) != 0
191 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
192 && st.st_rdev == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)
193 #endif
196 /* It is the /dev/null special device alright. */
197 (void) dup2 (nullfd, STDIN_FILENO);
198 (void) dup2 (nullfd, STDOUT_FILENO);
199 (void) dup2 (nullfd, STDERR_FILENO);
201 if (nullfd > 2)
202 close (nullfd);
204 else
206 /* Ugh, somebody is trying to play a trick on us. */
207 close (nullfd);
208 nullfd = -1;
211 int min_close_fd = nullfd == -1 ? 0 : STDERR_FILENO + 1;
213 DIR *d = opendir ("/proc/self/fd");
214 if (d != NULL)
216 struct dirent64 *dirent;
217 int dfdn = dirfd (d);
219 while ((dirent = readdir64 (d)) != NULL)
221 char *endp;
222 long int fdn = strtol (dirent->d_name, &endp, 10);
224 if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd)
225 close ((int) fdn);
228 closedir (d);
230 else
231 for (i = min_close_fd; i < getdtablesize (); i++)
232 close (i);
234 pid = fork ();
235 if (pid == -1)
236 error (EXIT_FAILURE, errno, _("cannot fork"));
237 if (pid != 0)
238 exit (0);
240 setsid ();
242 if (chdir ("/") != 0)
243 error (EXIT_FAILURE, errno,
244 _("cannot change current working directory to \"/\""));
246 openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
248 if (write_pid (_PATH_NSCDPID) < 0)
249 dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
251 if (!init_logfile ())
252 dbg_log (_("Could not create log file"));
254 /* Ignore job control signals. */
255 signal (SIGTTOU, SIG_IGN);
256 signal (SIGTTIN, SIG_IGN);
257 signal (SIGTSTP, SIG_IGN);
259 else
260 /* In foreground mode we are not paranoid. */
261 paranoia = 0;
263 /* Start the SELinux AVC. */
264 if (selinux_enabled)
265 nscd_avc_init ();
267 signal (SIGINT, termination_handler);
268 signal (SIGQUIT, termination_handler);
269 signal (SIGTERM, termination_handler);
270 signal (SIGPIPE, SIG_IGN);
272 /* Cleanup files created by a previous 'bind'. */
273 unlink (_PATH_NSCDSOCKET);
275 /* Make sure we do not get recursive calls. */
276 __nss_disable_nscd ();
278 /* Init databases. */
279 nscd_init ();
281 /* Handle incoming requests */
282 start_threads ();
284 return 0;
288 /* Handle program arguments. */
289 static error_t
290 parse_opt (int key, char *arg, struct argp_state *state)
292 switch (key)
294 case 'd':
295 ++debug_level;
296 go_background = 0;
297 break;
299 case 'f':
300 conffile = arg;
301 break;
303 case 'K':
304 if (getuid () != 0)
305 error (4, 0, _("Only root is allowed to use this option!"));
307 int sock = nscd_open_socket ();
309 if (sock == -1)
310 exit (EXIT_FAILURE);
312 request_header req;
313 req.version = NSCD_VERSION;
314 req.type = SHUTDOWN;
315 req.key_len = 0;
317 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &req,
318 sizeof (request_header),
319 MSG_NOSIGNAL));
320 close (sock);
321 exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
324 case 'g':
325 get_stats = true;
326 break;
328 case 'i':
329 if (getuid () != 0)
330 error (4, 0, _("Only root is allowed to use this option!"));
331 else
333 int sock = nscd_open_socket ();
335 if (sock == -1)
336 exit (EXIT_FAILURE);
338 dbtype cnt;
339 for (cnt = pwddb; cnt < lastdb; ++cnt)
340 if (strcmp (arg, dbnames[cnt]) == 0)
341 break;
343 if (cnt == lastdb)
345 argp_error (state, _("'%s' is not a known database"), arg);
346 return EINVAL;
349 size_t arg_len = strlen (arg) + 1;
350 struct
352 request_header req;
353 char arg[arg_len];
354 } reqdata;
356 reqdata.req.key_len = strlen (arg) + 1;
357 reqdata.req.version = NSCD_VERSION;
358 reqdata.req.type = INVALIDATE;
359 memcpy (reqdata.arg, arg, arg_len);
361 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &reqdata,
362 sizeof (request_header)
363 + arg_len,
364 MSG_NOSIGNAL));
366 if (nbytes != sizeof (request_header) + arg_len)
368 int err = errno;
369 close (sock);
370 error (EXIT_FAILURE, err, _("write incomplete"));
373 /* Wait for ack. Older nscd just closed the socket when
374 prune_cache finished, silently ignore that. */
375 int32_t resp = 0;
376 nbytes = TEMP_FAILURE_RETRY (read (sock, &resp, sizeof (resp)));
377 if (nbytes != 0 && nbytes != sizeof (resp))
379 int err = errno;
380 close (sock);
381 error (EXIT_FAILURE, err, _("cannot read invalidate ACK"));
384 close (sock);
386 if (resp != 0)
387 error (EXIT_FAILURE, resp, _("invalidation failed"));
389 exit (0);
392 case 't':
393 nthreads = atol (arg);
394 break;
396 case 'S':
397 error (0, 0, _("secure services not implemented anymore"));
398 break;
400 default:
401 return ARGP_ERR_UNKNOWN;
404 return 0;
407 /* Print bug-reporting information in the help message. */
408 static char *
409 more_help (int key, const char *text, void *input)
411 switch (key)
413 case ARGP_KEY_HELP_EXTRA:
414 /* We print some extra information. */
415 return strdup (gettext ("\
416 For bug reporting instructions, please see:\n\
417 <http://www.gnu.org/software/libc/bugs.html>.\n"));
418 default:
419 break;
421 return (char *) text;
424 /* Print the version information. */
425 static void
426 print_version (FILE *stream, struct argp_state *state)
428 fprintf (stream, "nscd (GNU %s) %s\n", PACKAGE, VERSION);
429 fprintf (stream, gettext ("\
430 Copyright (C) %s Free Software Foundation, Inc.\n\
431 This is free software; see the source for copying conditions. There is NO\n\
432 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
433 "), "2009");
434 fprintf (stream, gettext ("Written by %s.\n"),
435 "Thorsten Kukuk and Ulrich Drepper");
439 /* Create a socket connected to a name. */
441 nscd_open_socket (void)
443 struct sockaddr_un addr;
444 int sock;
446 sock = socket (PF_UNIX, SOCK_STREAM, 0);
447 if (sock < 0)
448 return -1;
450 addr.sun_family = AF_UNIX;
451 assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
452 strcpy (addr.sun_path, _PATH_NSCDSOCKET);
453 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
455 close (sock);
456 return -1;
459 return sock;
463 /* Cleanup. */
464 void
465 termination_handler (int signum)
467 close_sockets ();
469 /* Clean up the file created by 'bind'. */
470 unlink (_PATH_NSCDSOCKET);
472 /* Clean up pid file. */
473 unlink (_PATH_NSCDPID);
475 // XXX Terminate threads.
477 /* Synchronize memory. */
478 for (int cnt = 0; cnt < lastdb; ++cnt)
480 if (!dbs[cnt].enabled)
481 continue;
483 /* Make sure nobody keeps using the database. */
484 dbs[cnt].head->timestamp = 0;
486 if (dbs[cnt].persistent)
487 // XXX async OK?
488 msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
491 /* Shutdown the SELinux AVC. */
492 if (selinux_enabled)
493 nscd_avc_destroy ();
495 _exit (EXIT_SUCCESS);
498 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
499 static int
500 check_pid (const char *file)
502 FILE *fp;
504 fp = fopen (file, "r");
505 if (fp)
507 pid_t pid;
508 int n;
510 n = fscanf (fp, "%d", &pid);
511 fclose (fp);
513 /* If we cannot parse the file default to assuming nscd runs.
514 If the PID is alive, assume it is running. That all unless
515 the PID is the same as the current process' since tha latter
516 can mean we re-exec. */
517 if ((n != 1 || kill (pid, 0) == 0) && pid != getpid ())
518 return 1;
521 return 0;
524 /* Write the current process id to the file FILE.
525 Returns 0 if successful, -1 if not. */
526 static int
527 write_pid (const char *file)
529 FILE *fp;
531 fp = fopen (file, "w");
532 if (fp == NULL)
533 return -1;
535 fprintf (fp, "%d\n", getpid ());
537 int result = fflush (fp) || ferror (fp) ? -1 : 0;
539 fclose (fp);
541 return result;