Updated to fedora-glibc-20050721T0814
[glibc.git] / nscd / nscd.c
blob4d14f06ecff9a803b848d2e6e523ef872f3cf3f7
1 /* Copyright (c) 1998-2003, 2004, 2005 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library 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 GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
20 /* nscd - Name Service Cache Daemon. Caches passwd, group, and hosts. */
22 #include <argp.h>
23 #include <assert.h>
24 #include <dirent.h>
25 #include <errno.h>
26 #include <error.h>
27 #include <fcntl.h>
28 #include <libintl.h>
29 #include <locale.h>
30 #include <paths.h>
31 #include <pthread.h>
32 #include <signal.h>
33 #include <stdbool.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <syslog.h>
38 #include <unistd.h>
39 #include <sys/mman.h>
40 #include <sys/socket.h>
41 #include <sys/stat.h>
42 #include <sys/uio.h>
43 #include <sys/un.h>
45 #include "dbg_log.h"
46 #include "nscd.h"
47 #include "selinux.h"
48 #include "../nss/nsswitch.h"
49 #include <device-nrs.h>
51 /* Get libc version number. */
52 #include <version.h>
54 #define PACKAGE _libc_intl_domainname
56 /* Structure used by main() thread to keep track of the number of
57 active threads. Used to limit how many threads it will create
58 and under a shutdown condition to wait till all in-progress
59 requests have finished before "turning off the lights". */
61 typedef struct
63 int num_active;
64 pthread_cond_t thread_exit_cv;
65 pthread_mutex_t mutex;
66 } thread_info_t;
68 thread_info_t thread_info;
70 int do_shutdown;
71 int disabled_passwd;
72 int disabled_group;
73 int go_background = 1;
75 int secure_in_use;
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 /* Definitions of arguments for argp functions. */
97 static const struct argp_option options[] =
99 { "config-file", 'f', N_("NAME"), 0,
100 N_("Read configuration data from NAME") },
101 { "debug", 'd', NULL, 0,
102 N_("Do not fork and display messages on the current tty") },
103 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
104 { "shutdown", 'K', NULL, 0, N_("Shut the server down") },
105 { "statistic", 'g', NULL, 0, N_("Print current configuration statistic") },
106 { "invalidate", 'i', N_("TABLE"), 0,
107 N_("Invalidate the specified cache") },
108 { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN,
109 N_("Use separate cache for each user")},
110 { NULL, 0, NULL, 0, NULL }
113 /* Short description of program. */
114 static const char doc[] = N_("Name Service Cache Daemon.");
116 /* Prototype for option handler. */
117 static error_t parse_opt (int key, char *arg, struct argp_state *state);
119 /* Data structure to communicate with argp functions. */
120 static struct argp argp =
122 options, parse_opt, NULL, doc,
125 /* The SIGHUP handler is extern to this file */
126 extern void sighup_handler(int signum);
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)
157 /* We couldn't read the configuration file. We don't start the
158 server. */
159 dbg_log (_("cannot read configuration file; this is fatal"));
160 exit (1);
163 /* Do we only get statistics? */
164 if (get_stats)
165 /* Does not return. */
166 receive_print_stats ();
168 /* Check if we are already running. */
169 if (check_pid (_PATH_NSCDPID))
170 error (EXIT_FAILURE, 0, _("already running"));
172 /* Remember when we started. */
173 start_time = time (NULL);
175 /* Determine page size. */
176 pagesize_m1 = getpagesize () - 1;
178 /* Behave like a daemon. */
179 if (go_background)
181 int i;
183 pid_t pid = fork ();
184 if (pid == -1)
185 error (EXIT_FAILURE, errno, _("cannot fork"));
186 if (pid != 0)
187 exit (0);
189 int nullfd = open (_PATH_DEVNULL, O_RDWR);
190 if (nullfd != -1)
192 struct stat64 st;
194 if (fstat64 (nullfd, &st) == 0 && S_ISCHR (st.st_mode) != 0
195 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
196 && st.st_rdev == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)
197 #endif
200 /* It is the /dev/null special device alright. */
201 (void) dup2 (nullfd, STDIN_FILENO);
202 (void) dup2 (nullfd, STDOUT_FILENO);
203 (void) dup2 (nullfd, STDERR_FILENO);
205 if (nullfd > 2)
206 close (nullfd);
208 else
210 /* Ugh, somebody is trying to play a trick on us. */
211 close (nullfd);
212 nullfd = -1;
215 int min_close_fd = nullfd == -1 ? 0 : STDERR_FILENO + 1;
217 DIR *d = opendir ("/proc/self/fd");
218 if (d != NULL)
220 struct dirent64 *dirent;
221 int dfdn = dirfd (d);
223 while ((dirent = readdir64 (d)) != NULL)
225 char *endp;
226 long int fdn = strtol (dirent->d_name, &endp, 10);
228 if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd)
229 close ((int) fdn);
232 closedir (d);
234 else
235 for (i = min_close_fd; i < getdtablesize (); i++)
236 close (i);
238 pid = fork ();
239 if (pid == -1)
240 error (EXIT_FAILURE, errno, _("cannot fork"));
241 if (pid != 0)
242 exit (0);
244 setsid ();
246 if (chdir ("/") != 0)
247 error (EXIT_FAILURE, errno,
248 _("cannot change current working cirectory to \"/\""));
250 openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
252 if (write_pid (_PATH_NSCDPID) < 0)
253 dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
255 if (!init_logfile ())
256 dbg_log (_("Could not create log file"));
258 /* Ignore job control signals. */
259 signal (SIGTTOU, SIG_IGN);
260 signal (SIGTTIN, SIG_IGN);
261 signal (SIGTSTP, SIG_IGN);
263 else
264 /* In foreground mode we are not paranoid. */
265 paranoia = 0;
267 /* Start the SELinux AVC. */
268 if (selinux_enabled)
269 nscd_avc_init ();
271 signal (SIGINT, termination_handler);
272 signal (SIGQUIT, termination_handler);
273 signal (SIGTERM, termination_handler);
274 signal (SIGHUP, sighup_handler);
275 signal (SIGPIPE, SIG_IGN);
277 /* Cleanup files created by a previous 'bind'. */
278 unlink (_PATH_NSCDSOCKET);
280 /* Make sure we do not get recursive calls. */
281 __nss_disable_nscd ();
283 /* Init databases. */
284 nscd_init ();
286 /* Handle incoming requests */
287 start_threads ();
289 return 0;
293 /* Handle program arguments. */
294 static error_t
295 parse_opt (int key, char *arg, struct argp_state *state)
297 switch (key)
299 case 'd':
300 ++debug_level;
301 go_background = 0;
302 break;
304 case 'f':
305 conffile = arg;
306 break;
308 case 'K':
309 if (getuid () != 0)
310 error (4, 0, _("Only root is allowed to use this option!"));
312 int sock = nscd_open_socket ();
313 request_header req;
314 ssize_t nbytes;
316 if (sock == -1)
317 exit (EXIT_FAILURE);
319 req.version = NSCD_VERSION;
320 req.type = SHUTDOWN;
321 req.key_len = 0;
322 nbytes = TEMP_FAILURE_RETRY (write (sock, &req,
323 sizeof (request_header)));
324 close (sock);
325 exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
328 case 'g':
329 get_stats = true;
330 break;
332 case 'i':
333 if (getuid () != 0)
334 error (4, 0, _("Only root is allowed to use this option!"));
335 else
337 int sock = nscd_open_socket ();
339 if (sock == -1)
340 exit (EXIT_FAILURE);
342 request_header req;
343 ssize_t nbytes;
344 struct iovec iov[2];
346 if (strcmp (arg, "passwd") == 0)
347 req.key_len = sizeof "passwd";
348 else if (strcmp (arg, "group") == 0)
349 req.key_len = sizeof "group";
350 else if (strcmp (arg, "hosts") == 0)
351 req.key_len = sizeof "hosts";
352 else
353 return ARGP_ERR_UNKNOWN;
355 req.version = NSCD_VERSION;
356 req.type = INVALIDATE;
358 iov[0].iov_base = &req;
359 iov[0].iov_len = sizeof (req);
360 iov[1].iov_base = arg;
361 iov[1].iov_len = req.key_len;
363 nbytes = TEMP_FAILURE_RETRY (writev (sock, iov, 2));
365 close (sock);
367 exit (nbytes != iov[0].iov_len + iov[1].iov_len
368 ? EXIT_FAILURE : EXIT_SUCCESS);
371 case 't':
372 nthreads = atol (arg);
373 break;
375 case 'S':
376 #if 0
377 if (strcmp (arg, "passwd,yes") == 0)
378 secure_in_use = dbs[pwddb].secure = 1;
379 else if (strcmp (arg, "group,yes") == 0)
380 secure_in_use = dbs[grpdb].secure = 1;
381 else if (strcmp (arg, "hosts,yes") == 0)
382 secure_in_use = dbs[hstdb].secure = 1;
383 #else
384 error (0, 0, _("secure services not implemented anymore"));
385 #endif
386 break;
388 default:
389 return ARGP_ERR_UNKNOWN;
392 return 0;
395 /* Print the version information. */
396 static void
397 print_version (FILE *stream, struct argp_state *state)
399 fprintf (stream, "nscd (GNU %s) %s\n", PACKAGE, VERSION);
400 fprintf (stream, gettext ("\
401 Copyright (C) %s Free Software Foundation, Inc.\n\
402 This is free software; see the source for copying conditions. There is NO\n\
403 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
404 "), "2005");
405 fprintf (stream, gettext ("Written by %s.\n"),
406 "Thorsten Kukuk and Ulrich Drepper");
410 /* Create a socket connected to a name. */
412 nscd_open_socket (void)
414 struct sockaddr_un addr;
415 int sock;
417 sock = socket (PF_UNIX, SOCK_STREAM, 0);
418 if (sock < 0)
419 return -1;
421 addr.sun_family = AF_UNIX;
422 assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
423 strcpy (addr.sun_path, _PATH_NSCDSOCKET);
424 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
426 close (sock);
427 return -1;
430 return sock;
434 /* Cleanup. */
435 void
436 termination_handler (int signum)
438 close_sockets ();
440 /* Clean up the file created by 'bind'. */
441 unlink (_PATH_NSCDSOCKET);
443 /* Clean up pid file. */
444 unlink (_PATH_NSCDPID);
446 // XXX Terminate threads.
448 /* Synchronize memory. */
449 for (int cnt = 0; cnt < lastdb; ++cnt)
451 if (!dbs[cnt].enabled)
452 continue;
454 /* Make sure nobody keeps using the database. */
455 dbs[cnt].head->timestamp = 0;
457 if (dbs[cnt].persistent)
458 // XXX async OK?
459 msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
462 /* Shutdown the SELinux AVC. */
463 if (selinux_enabled)
464 nscd_avc_destroy ();
466 _exit (EXIT_SUCCESS);
469 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
470 static int
471 check_pid (const char *file)
473 FILE *fp;
475 fp = fopen (file, "r");
476 if (fp)
478 pid_t pid;
479 int n;
481 n = fscanf (fp, "%d", &pid);
482 fclose (fp);
484 /* If we cannot parse the file default to assuming nscd runs.
485 If the PID is alive, assume it is running. That all unless
486 the PID is the same as the current process' since tha latter
487 can mean we re-exec. */
488 if ((n != 1 || kill (pid, 0) == 0) && pid != getpid ())
489 return 1;
492 return 0;
495 /* Write the current process id to the file FILE.
496 Returns 0 if successful, -1 if not. */
497 static int
498 write_pid (const char *file)
500 FILE *fp;
502 fp = fopen (file, "w");
503 if (fp == NULL)
504 return -1;
506 fprintf (fp, "%d\n", getpid ());
507 if (fflush (fp) || ferror (fp))
508 return -1;
510 fclose (fp);
512 return 0;