Updated to fedora-glibc-20070221T1011
[glibc.git] / nscd / nscd.c
blob3257e056899582851fcd77da2daa106dc86fecbb
1 /* Copyright (c) 1998-2006, 2007 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 version 2 as
7 published by the Free Software Foundation.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
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>
49 /* Get libc version number. */
50 #include <version.h>
52 #define PACKAGE _libc_intl_domainname
54 /* Structure used by main() thread to keep track of the number of
55 active threads. Used to limit how many threads it will create
56 and under a shutdown condition to wait till all in-progress
57 requests have finished before "turning off the lights". */
59 typedef struct
61 int num_active;
62 pthread_cond_t thread_exit_cv;
63 pthread_mutex_t mutex;
64 } thread_info_t;
66 thread_info_t thread_info;
68 int do_shutdown;
69 int disabled_passwd;
70 int disabled_group;
71 int go_background = 1;
73 static const char *conffile = _PATH_NSCDCONF;
75 time_t start_time;
77 uintptr_t pagesize_m1;
79 int paranoia;
80 time_t restart_time;
81 time_t restart_interval = RESTART_INTERVAL;
82 const char *oldcwd;
83 uid_t old_uid;
84 gid_t old_gid;
86 static int check_pid (const char *file);
87 static int write_pid (const char *file);
89 /* Name and version of program. */
90 static void print_version (FILE *stream, struct argp_state *state);
91 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
93 /* Definitions of arguments for argp functions. */
94 static const struct argp_option options[] =
96 { "config-file", 'f', N_("NAME"), 0,
97 N_("Read configuration data from NAME") },
98 { "debug", 'd', NULL, 0,
99 N_("Do not fork and display messages on the current tty") },
100 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
101 { "shutdown", 'K', NULL, 0, N_("Shut the server down") },
102 { "statistic", 'g', NULL, 0, N_("Print current configuration statistic") },
103 { "invalidate", 'i', N_("TABLE"), 0,
104 N_("Invalidate the specified cache") },
105 { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN,
106 N_("Use separate cache for each user")},
107 { NULL, 0, NULL, 0, NULL }
110 /* Short description of program. */
111 static const char doc[] = N_("Name Service Cache Daemon.");
113 /* Prototype for option handler. */
114 static error_t parse_opt (int key, char *arg, struct argp_state *state);
116 /* Data structure to communicate with argp functions. */
117 static struct argp argp =
119 options, parse_opt, NULL, doc,
122 /* The SIGHUP handler is extern to this file */
123 extern void sighup_handler(int signum);
125 /* True if only statistics are requested. */
126 static bool get_stats;
129 main (int argc, char **argv)
131 int remaining;
133 /* Set locale via LC_ALL. */
134 setlocale (LC_ALL, "");
135 /* Set the text message domain. */
136 textdomain (PACKAGE);
138 /* Determine if the kernel has SELinux support. */
139 nscd_selinux_enabled (&selinux_enabled);
141 /* Parse and process arguments. */
142 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
144 if (remaining != argc)
146 error (0, 0, gettext ("wrong number of arguments"));
147 argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
148 exit (1);
151 /* Read the configuration file. */
152 if (nscd_parse_file (conffile, dbs) != 0)
153 /* We couldn't read the configuration file. We don't start the
154 server. */
155 error (EXIT_FAILURE, 0,
156 _("failure while reading configuration file; this is fatal"));
158 /* Do we only get statistics? */
159 if (get_stats)
160 /* Does not return. */
161 receive_print_stats ();
163 /* Check if we are already running. */
164 if (check_pid (_PATH_NSCDPID))
165 error (EXIT_FAILURE, 0, _("already running"));
167 /* Remember when we started. */
168 start_time = time (NULL);
170 /* Determine page size. */
171 pagesize_m1 = getpagesize () - 1;
173 /* Behave like a daemon. */
174 if (go_background)
176 int i;
178 pid_t pid = fork ();
179 if (pid == -1)
180 error (EXIT_FAILURE, errno, _("cannot fork"));
181 if (pid != 0)
182 exit (0);
184 int nullfd = open (_PATH_DEVNULL, O_RDWR);
185 if (nullfd != -1)
187 struct stat64 st;
189 if (fstat64 (nullfd, &st) == 0 && S_ISCHR (st.st_mode) != 0
190 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
191 && st.st_rdev == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)
192 #endif
195 /* It is the /dev/null special device alright. */
196 (void) dup2 (nullfd, STDIN_FILENO);
197 (void) dup2 (nullfd, STDOUT_FILENO);
198 (void) dup2 (nullfd, STDERR_FILENO);
200 if (nullfd > 2)
201 close (nullfd);
203 else
205 /* Ugh, somebody is trying to play a trick on us. */
206 close (nullfd);
207 nullfd = -1;
210 int min_close_fd = nullfd == -1 ? 0 : STDERR_FILENO + 1;
212 DIR *d = opendir ("/proc/self/fd");
213 if (d != NULL)
215 struct dirent64 *dirent;
216 int dfdn = dirfd (d);
218 while ((dirent = readdir64 (d)) != NULL)
220 char *endp;
221 long int fdn = strtol (dirent->d_name, &endp, 10);
223 if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd)
224 close ((int) fdn);
227 closedir (d);
229 else
230 for (i = min_close_fd; i < getdtablesize (); i++)
231 close (i);
233 pid = fork ();
234 if (pid == -1)
235 error (EXIT_FAILURE, errno, _("cannot fork"));
236 if (pid != 0)
237 exit (0);
239 setsid ();
241 if (chdir ("/") != 0)
242 error (EXIT_FAILURE, errno,
243 _("cannot change current working directory to \"/\""));
245 openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
247 if (write_pid (_PATH_NSCDPID) < 0)
248 dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
250 if (!init_logfile ())
251 dbg_log (_("Could not create log file"));
253 /* Ignore job control signals. */
254 signal (SIGTTOU, SIG_IGN);
255 signal (SIGTTIN, SIG_IGN);
256 signal (SIGTSTP, SIG_IGN);
258 else
259 /* In foreground mode we are not paranoid. */
260 paranoia = 0;
262 /* Start the SELinux AVC. */
263 if (selinux_enabled)
264 nscd_avc_init ();
266 signal (SIGINT, termination_handler);
267 signal (SIGQUIT, termination_handler);
268 signal (SIGTERM, termination_handler);
269 signal (SIGHUP, sighup_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)
344 return ARGP_ERR_UNKNOWN;
346 size_t arg_len = strlen (arg) + 1;
347 struct
349 request_header req;
350 char arg[arg_len];
351 } reqdata;
353 reqdata.req.key_len = strlen (arg) + 1;
354 reqdata.req.version = NSCD_VERSION;
355 reqdata.req.type = INVALIDATE;
356 memcpy (reqdata.arg, arg, arg_len);
358 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &reqdata,
359 sizeof (request_header)
360 + arg_len,
361 MSG_NOSIGNAL));
363 if (nbytes != sizeof (request_header) + arg_len)
365 int err = errno;
366 close (sock);
367 error (EXIT_FAILURE, err, _("write incomplete"));
370 /* Wait for ack. Older nscd just closed the socket when
371 prune_cache finished, silently ignore that. */
372 int32_t resp = 0;
373 nbytes = TEMP_FAILURE_RETRY (read (sock, &resp, sizeof (resp)));
374 if (nbytes != 0 && nbytes != sizeof (resp))
376 int err = errno;
377 close (sock);
378 error (EXIT_FAILURE, err, _("cannot read invalidate ACK"));
381 close (sock);
383 if (resp != 0)
384 error (EXIT_FAILURE, resp, _("invalidation failed"));
386 exit (0);
389 case 't':
390 nthreads = atol (arg);
391 break;
393 case 'S':
394 error (0, 0, _("secure services not implemented anymore"));
395 break;
397 default:
398 return ARGP_ERR_UNKNOWN;
401 return 0;
404 /* Print the version information. */
405 static void
406 print_version (FILE *stream, struct argp_state *state)
408 fprintf (stream, "nscd (GNU %s) %s\n", PACKAGE, VERSION);
409 fprintf (stream, gettext ("\
410 Copyright (C) %s Free Software Foundation, Inc.\n\
411 This is free software; see the source for copying conditions. There is NO\n\
412 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
413 "), "2007");
414 fprintf (stream, gettext ("Written by %s.\n"),
415 "Thorsten Kukuk and Ulrich Drepper");
419 /* Create a socket connected to a name. */
421 nscd_open_socket (void)
423 struct sockaddr_un addr;
424 int sock;
426 sock = socket (PF_UNIX, SOCK_STREAM, 0);
427 if (sock < 0)
428 return -1;
430 addr.sun_family = AF_UNIX;
431 assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
432 strcpy (addr.sun_path, _PATH_NSCDSOCKET);
433 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
435 close (sock);
436 return -1;
439 return sock;
443 /* Cleanup. */
444 void
445 termination_handler (int signum)
447 close_sockets ();
449 /* Clean up the file created by 'bind'. */
450 unlink (_PATH_NSCDSOCKET);
452 /* Clean up pid file. */
453 unlink (_PATH_NSCDPID);
455 // XXX Terminate threads.
457 /* Synchronize memory. */
458 for (int cnt = 0; cnt < lastdb; ++cnt)
460 if (!dbs[cnt].enabled)
461 continue;
463 /* Make sure nobody keeps using the database. */
464 dbs[cnt].head->timestamp = 0;
466 if (dbs[cnt].persistent)
467 // XXX async OK?
468 msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
471 /* Shutdown the SELinux AVC. */
472 if (selinux_enabled)
473 nscd_avc_destroy ();
475 _exit (EXIT_SUCCESS);
478 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
479 static int
480 check_pid (const char *file)
482 FILE *fp;
484 fp = fopen (file, "r");
485 if (fp)
487 pid_t pid;
488 int n;
490 n = fscanf (fp, "%d", &pid);
491 fclose (fp);
493 /* If we cannot parse the file default to assuming nscd runs.
494 If the PID is alive, assume it is running. That all unless
495 the PID is the same as the current process' since tha latter
496 can mean we re-exec. */
497 if ((n != 1 || kill (pid, 0) == 0) && pid != getpid ())
498 return 1;
501 return 0;
504 /* Write the current process id to the file FILE.
505 Returns 0 if successful, -1 if not. */
506 static int
507 write_pid (const char *file)
509 FILE *fp;
511 fp = fopen (file, "w");
512 if (fp == NULL)
513 return -1;
515 fprintf (fp, "%d\n", getpid ());
517 int result = fflush (fp) || ferror (fp) ? -1 : 0;
519 fclose (fp);
521 return result;