1 /* Copyright (c) 1998-2003, 2004 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
20 /* nscd - Name Service Cache Daemon. Caches passwd, group, and hosts. */
40 #include <sys/socket.h>
48 #include "../nss/nsswitch.h"
49 #include <device-nrs.h>
51 /* Get libc version number. */
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". */
64 pthread_cond_t thread_exit_cv;
65 pthread_mutex_t mutex;
68 thread_info_t thread_info;
73 int go_background = 1;
76 static const char *conffile = _PATH_NSCDCONF;
80 uintptr_t pagesize_m1;
82 static int check_pid (const char *file);
83 static int write_pid (const char *file);
85 /* Name and version of program. */
86 static void print_version (FILE *stream, struct argp_state *state);
87 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
89 /* Definitions of arguments for argp functions. */
90 static const struct argp_option options[] =
92 { "config-file", 'f', N_("NAME"), 0,
93 N_("Read configuration data from NAME") },
94 { "debug", 'd', NULL, 0,
95 N_("Do not fork and display messages on the current tty") },
96 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
97 { "shutdown", 'K', NULL, 0, N_("Shut the server down") },
98 { "statistic", 'g', NULL, 0, N_("Print current configuration statistic") },
99 { "invalidate", 'i', N_("TABLE"), 0,
100 N_("Invalidate the specified cache") },
101 { "secure", 'S', N_("TABLE,yes"), 0, N_("Use separate cache for each user")},
102 { NULL, 0, NULL, 0, NULL }
105 /* Short description of program. */
106 static const char doc[] = N_("Name Service Cache Daemon.");
108 /* Prototype for option handler. */
109 static error_t parse_opt (int key, char *arg, struct argp_state *state);
111 /* Data structure to communicate with argp functions. */
112 static struct argp argp =
114 options, parse_opt, NULL, doc,
117 /* True if only statistics are requested. */
118 static bool get_stats;
121 main (int argc, char **argv)
125 /* Set locale via LC_ALL. */
126 setlocale (LC_ALL, "");
127 /* Set the text message domain. */
128 textdomain (PACKAGE);
130 /* Determine if the kernel has SELinux support. */
131 nscd_selinux_enabled (&selinux_enabled);
133 /* Parse and process arguments. */
134 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
136 if (remaining != argc)
138 error (0, 0, gettext ("wrong number of arguments"));
139 argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
143 /* Read the configuration file. */
144 if (nscd_parse_file (conffile, dbs) != 0)
146 /* We couldn't read the configuration file. We don't start the
148 dbg_log (_("cannot read configuration file; this is fatal"));
152 /* Do we only get statistics? */
154 /* Does not return. */
155 receive_print_stats ();
157 /* Check if we are already running. */
158 if (check_pid (_PATH_NSCDPID))
159 error (EXIT_FAILURE, 0, _("already running"));
161 /* Remember when we started. */
162 start_time = time (NULL);
164 /* Determine page size. */
165 pagesize_m1 = getpagesize () - 1;
167 /* Behave like a daemon. */
174 error (EXIT_FAILURE, errno, _("cannot fork"));
178 int nullfd = open (_PATH_DEVNULL, O_RDWR);
183 if (fstat64 (nullfd, &st) == 0 && S_ISCHR (st.st_mode) != 0
184 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
185 && st.st_rdev == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)
189 /* It is the /dev/null special device alright. */
190 (void) dup2 (nullfd, STDIN_FILENO);
191 (void) dup2 (nullfd, STDOUT_FILENO);
192 (void) dup2 (nullfd, STDERR_FILENO);
199 /* Ugh, somebody is trying to play a trick on us. */
204 int min_close_fd = nullfd == -1 ? 0 : STDERR_FILENO + 1;
206 DIR *d = opendir ("/proc/self/fd");
209 struct dirent64 *dirent;
210 int dfdn = dirfd (d);
212 while ((dirent = readdir64 (d)) != NULL)
215 long int fdn = strtol (dirent->d_name, &endp, 10);
217 if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd)
224 for (i = min_close_fd; i < getdtablesize (); i++)
229 error (EXIT_FAILURE, errno, _("cannot fork"));
237 openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
239 if (write_pid (_PATH_NSCDPID) < 0)
240 dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
242 if (!init_logfile ())
243 dbg_log (_("Could not create log file"));
245 /* Ignore job control signals. */
246 signal (SIGTTOU, SIG_IGN);
247 signal (SIGTTIN, SIG_IGN);
248 signal (SIGTSTP, SIG_IGN);
251 /* Start the SELinux AVC. */
255 signal (SIGINT, termination_handler);
256 signal (SIGQUIT, termination_handler);
257 signal (SIGTERM, termination_handler);
258 signal (SIGPIPE, SIG_IGN);
260 /* Cleanup files created by a previous 'bind'. */
261 unlink (_PATH_NSCDSOCKET);
263 /* Make sure we do not get recursive calls. */
264 __nss_disable_nscd ();
266 /* Init databases. */
269 /* Handle incoming requests */
276 /* Handle program arguments. */
278 parse_opt (int key, char *arg, struct argp_state *state)
293 error (EXIT_FAILURE, 0, _("Only root is allowed to use this option!"));
295 int sock = nscd_open_socket ();
302 req.version = NSCD_VERSION;
305 nbytes = TEMP_FAILURE_RETRY (write (sock, &req,
306 sizeof (request_header)));
308 exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
317 error (EXIT_FAILURE, 0, _("Only root is allowed to use this option!"));
320 int sock = nscd_open_socket ();
329 if (strcmp (arg, "passwd") == 0)
330 req.key_len = sizeof "passwd";
331 else if (strcmp (arg, "group") == 0)
332 req.key_len = sizeof "group";
333 else if (strcmp (arg, "hosts") == 0)
334 req.key_len = sizeof "hosts";
336 return ARGP_ERR_UNKNOWN;
338 req.version = NSCD_VERSION;
339 req.type = INVALIDATE;
341 iov[0].iov_base = &req;
342 iov[0].iov_len = sizeof (req);
343 iov[1].iov_base = arg;
344 iov[1].iov_len = req.key_len;
346 nbytes = TEMP_FAILURE_RETRY (writev (sock, iov, 2));
350 exit (nbytes != iov[0].iov_len + iov[1].iov_len
351 ? EXIT_FAILURE : EXIT_SUCCESS);
355 nthreads = atol (arg);
359 if (strcmp (arg, "passwd,yes") == 0)
360 secure_in_use = dbs[pwddb].secure = 1;
361 else if (strcmp (arg, "group,yes") == 0)
362 secure_in_use = dbs[grpdb].secure = 1;
363 else if (strcmp (arg, "hosts,yes") == 0)
364 secure_in_use = dbs[hstdb].secure = 1;
368 return ARGP_ERR_UNKNOWN;
374 /* Print the version information. */
376 print_version (FILE *stream, struct argp_state *state)
378 fprintf (stream, "nscd (GNU %s) %s\n", PACKAGE, VERSION);
379 fprintf (stream, gettext ("\
380 Copyright (C) %s Free Software Foundation, Inc.\n\
381 This is free software; see the source for copying conditions. There is NO\n\
382 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
384 fprintf (stream, gettext ("Written by %s.\n"),
385 "Thorsten Kukuk and Ulrich Drepper");
389 /* Create a socket connected to a name. */
391 nscd_open_socket (void)
393 struct sockaddr_un addr;
396 sock = socket (PF_UNIX, SOCK_STREAM, 0);
400 addr.sun_family = AF_UNIX;
401 assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
402 strcpy (addr.sun_path, _PATH_NSCDSOCKET);
403 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
414 termination_handler (int signum)
418 /* Clean up the file created by 'bind'. */
419 unlink (_PATH_NSCDSOCKET);
421 /* Clean up pid file. */
422 unlink (_PATH_NSCDPID);
424 // XXX Terminate threads.
426 /* Synchronize memory. */
427 for (int cnt = 0; cnt < lastdb; ++cnt)
428 if (dbs[cnt].persistent)
430 msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
432 /* Shutdown the SELinux AVC. */
436 _exit (EXIT_SUCCESS);
439 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
441 check_pid (const char *file)
445 fp = fopen (file, "r");
451 n = fscanf (fp, "%d", &pid);
454 if (n != 1 || kill (pid, 0) == 0)
461 /* Write the current process id to the file FILE.
462 Returns 0 if successful, -1 if not. */
464 write_pid (const char *file)
468 fp = fopen (file, "w");
472 fprintf (fp, "%d\n", getpid ());
473 if (fflush (fp) || ferror (fp))
482 /* This is an ugly hack which prevents getaddrinfo from being dragged
483 into nscd. There currently is no special getaddrinfo version for
484 use in nscd. In case it should be necessary such a version must be
485 created and this dummy version should be removed. */