Update.
[glibc.git] / nscd / nscd.c
blob4586cf04c9ac8fdf4e1b75a9df959164a5e439db
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
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 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"), OPTION_HIDDEN,
102 N_("Use separate cache for each user")},
103 { NULL, 0, NULL, 0, NULL }
106 /* Short description of program. */
107 static const char doc[] = N_("Name Service Cache Daemon.");
109 /* Prototype for option handler. */
110 static error_t parse_opt (int key, char *arg, struct argp_state *state);
112 /* Data structure to communicate with argp functions. */
113 static struct argp argp =
115 options, parse_opt, NULL, doc,
118 /* True if only statistics are requested. */
119 static bool get_stats;
122 main (int argc, char **argv)
124 int remaining;
126 /* Set locale via LC_ALL. */
127 setlocale (LC_ALL, "");
128 /* Set the text message domain. */
129 textdomain (PACKAGE);
131 /* Determine if the kernel has SELinux support. */
132 nscd_selinux_enabled (&selinux_enabled);
134 /* Parse and process arguments. */
135 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
137 if (remaining != argc)
139 error (0, 0, gettext ("wrong number of arguments"));
140 argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
141 exit (EXIT_FAILURE);
144 /* Read the configuration file. */
145 if (nscd_parse_file (conffile, dbs) != 0)
147 /* We couldn't read the configuration file. We don't start the
148 server. */
149 dbg_log (_("cannot read configuration file; this is fatal"));
150 exit (1);
153 /* Do we only get statistics? */
154 if (get_stats)
155 /* Does not return. */
156 receive_print_stats ();
158 /* Check if we are already running. */
159 if (check_pid (_PATH_NSCDPID))
160 error (EXIT_FAILURE, 0, _("already running"));
162 /* Remember when we started. */
163 start_time = time (NULL);
165 /* Determine page size. */
166 pagesize_m1 = getpagesize () - 1;
168 /* Behave like a daemon. */
169 if (go_background)
171 int i;
173 pid_t pid = fork ();
174 if (pid == -1)
175 error (EXIT_FAILURE, errno, _("cannot fork"));
176 if (pid != 0)
177 exit (0);
179 int nullfd = open (_PATH_DEVNULL, O_RDWR);
180 if (nullfd != -1)
182 struct stat64 st;
184 if (fstat64 (nullfd, &st) == 0 && S_ISCHR (st.st_mode) != 0
185 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
186 && st.st_rdev == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)
187 #endif
190 /* It is the /dev/null special device alright. */
191 (void) dup2 (nullfd, STDIN_FILENO);
192 (void) dup2 (nullfd, STDOUT_FILENO);
193 (void) dup2 (nullfd, STDERR_FILENO);
195 if (nullfd > 2)
196 close (nullfd);
198 else
200 /* Ugh, somebody is trying to play a trick on us. */
201 close (nullfd);
202 nullfd = -1;
205 int min_close_fd = nullfd == -1 ? 0 : STDERR_FILENO + 1;
207 DIR *d = opendir ("/proc/self/fd");
208 if (d != NULL)
210 struct dirent64 *dirent;
211 int dfdn = dirfd (d);
213 while ((dirent = readdir64 (d)) != NULL)
215 char *endp;
216 long int fdn = strtol (dirent->d_name, &endp, 10);
218 if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd)
219 close ((int) fdn);
222 closedir (d);
224 else
225 for (i = min_close_fd; i < getdtablesize (); i++)
226 close (i);
228 pid = fork ();
229 if (pid == -1)
230 error (EXIT_FAILURE, errno, _("cannot fork"));
231 if (pid != 0)
232 exit (0);
234 setsid ();
236 chdir ("/");
238 openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
240 if (write_pid (_PATH_NSCDPID) < 0)
241 dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
243 if (!init_logfile ())
244 dbg_log (_("Could not create log file"));
246 /* Ignore job control signals. */
247 signal (SIGTTOU, SIG_IGN);
248 signal (SIGTTIN, SIG_IGN);
249 signal (SIGTSTP, SIG_IGN);
252 /* Start the SELinux AVC. */
253 if (selinux_enabled)
254 nscd_avc_init ();
256 signal (SIGINT, termination_handler);
257 signal (SIGQUIT, termination_handler);
258 signal (SIGTERM, termination_handler);
259 signal (SIGPIPE, SIG_IGN);
261 /* Cleanup files created by a previous 'bind'. */
262 unlink (_PATH_NSCDSOCKET);
264 /* Make sure we do not get recursive calls. */
265 __nss_disable_nscd ();
267 /* Init databases. */
268 nscd_init ();
270 /* Handle incoming requests */
271 start_threads ();
273 return 0;
277 /* Handle program arguments. */
278 static error_t
279 parse_opt (int key, char *arg, struct argp_state *state)
281 switch (key)
283 case 'd':
284 ++debug_level;
285 go_background = 0;
286 break;
288 case 'f':
289 conffile = arg;
290 break;
292 case 'K':
293 if (getuid () != 0)
294 error (EXIT_FAILURE, 0, _("Only root is allowed to use this option!"));
296 int sock = nscd_open_socket ();
297 request_header req;
298 ssize_t nbytes;
300 if (sock == -1)
301 exit (EXIT_FAILURE);
303 req.version = NSCD_VERSION;
304 req.type = SHUTDOWN;
305 req.key_len = 0;
306 nbytes = TEMP_FAILURE_RETRY (write (sock, &req,
307 sizeof (request_header)));
308 close (sock);
309 exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
312 case 'g':
313 get_stats = true;
314 break;
316 case 'i':
317 if (getuid () != 0)
318 error (EXIT_FAILURE, 0, _("Only root is allowed to use this option!"));
319 else
321 int sock = nscd_open_socket ();
323 if (sock == -1)
324 exit (EXIT_FAILURE);
326 request_header req;
327 ssize_t nbytes;
328 struct iovec iov[2];
330 if (strcmp (arg, "passwd") == 0)
331 req.key_len = sizeof "passwd";
332 else if (strcmp (arg, "group") == 0)
333 req.key_len = sizeof "group";
334 else if (strcmp (arg, "hosts") == 0)
335 req.key_len = sizeof "hosts";
336 else
337 return ARGP_ERR_UNKNOWN;
339 req.version = NSCD_VERSION;
340 req.type = INVALIDATE;
342 iov[0].iov_base = &req;
343 iov[0].iov_len = sizeof (req);
344 iov[1].iov_base = arg;
345 iov[1].iov_len = req.key_len;
347 nbytes = TEMP_FAILURE_RETRY (writev (sock, iov, 2));
349 close (sock);
351 exit (nbytes != iov[0].iov_len + iov[1].iov_len
352 ? EXIT_FAILURE : EXIT_SUCCESS);
355 case 't':
356 nthreads = atol (arg);
357 break;
359 case 'S':
360 #if 0
361 if (strcmp (arg, "passwd,yes") == 0)
362 secure_in_use = dbs[pwddb].secure = 1;
363 else if (strcmp (arg, "group,yes") == 0)
364 secure_in_use = dbs[grpdb].secure = 1;
365 else if (strcmp (arg, "hosts,yes") == 0)
366 secure_in_use = dbs[hstdb].secure = 1;
367 #else
368 error (0, 0, _("secure services not implemented anymore"));
369 #endif
370 break;
372 default:
373 return ARGP_ERR_UNKNOWN;
376 return 0;
379 /* Print the version information. */
380 static void
381 print_version (FILE *stream, struct argp_state *state)
383 fprintf (stream, "nscd (GNU %s) %s\n", PACKAGE, VERSION);
384 fprintf (stream, gettext ("\
385 Copyright (C) %s Free Software Foundation, Inc.\n\
386 This is free software; see the source for copying conditions. There is NO\n\
387 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
388 "), "2004");
389 fprintf (stream, gettext ("Written by %s.\n"),
390 "Thorsten Kukuk and Ulrich Drepper");
394 /* Create a socket connected to a name. */
396 nscd_open_socket (void)
398 struct sockaddr_un addr;
399 int sock;
401 sock = socket (PF_UNIX, SOCK_STREAM, 0);
402 if (sock < 0)
403 return -1;
405 addr.sun_family = AF_UNIX;
406 assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
407 strcpy (addr.sun_path, _PATH_NSCDSOCKET);
408 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
410 close (sock);
411 return -1;
414 return sock;
417 /* Cleanup. */
418 void
419 termination_handler (int signum)
421 close_sockets ();
423 /* Clean up the file created by 'bind'. */
424 unlink (_PATH_NSCDSOCKET);
426 /* Clean up pid file. */
427 unlink (_PATH_NSCDPID);
429 // XXX Terminate threads.
431 /* Synchronize memory. */
432 for (int cnt = 0; cnt < lastdb; ++cnt)
433 if (dbs[cnt].persistent)
434 // XXX async OK?
435 msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
437 /* Shutdown the SELinux AVC. */
438 if (selinux_enabled)
439 nscd_avc_destroy ();
441 _exit (EXIT_SUCCESS);
444 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
445 static int
446 check_pid (const char *file)
448 FILE *fp;
450 fp = fopen (file, "r");
451 if (fp)
453 pid_t pid;
454 int n;
456 n = fscanf (fp, "%d", &pid);
457 fclose (fp);
459 if (n != 1 || kill (pid, 0) == 0)
460 return 1;
463 return 0;
466 /* Write the current process id to the file FILE.
467 Returns 0 if successful, -1 if not. */
468 static int
469 write_pid (const char *file)
471 FILE *fp;
473 fp = fopen (file, "w");
474 if (fp == NULL)
475 return -1;
477 fprintf (fp, "%d\n", getpid ());
478 if (fflush (fp) || ferror (fp))
479 return -1;
481 fclose (fp);
483 return 0;
487 /* This is an ugly hack which prevents getaddrinfo from being dragged
488 into nscd. There currently is no special getaddrinfo version for
489 use in nscd. In case it should be necessary such a version must be
490 created and this dummy version should be removed. */
491 void
492 getaddrinfo (void)
494 abort ();