]> git.ipfire.org Git - thirdparty/glibc.git/blame - nscd/nscd.c
Update copyright notices with scripts/update-copyrights
[thirdparty/glibc.git] / nscd / nscd.c
CommitLineData
d4697bc9 1/* Copyright (c) 1998-2014 Free Software Foundation, Inc.
d67281a7 2 This file is part of the GNU C Library.
a1c542bf 3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
d67281a7 4
43bc8ac6 5 This program is free software; you can redistribute it and/or modify
2e2efe65
RM
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.
d67281a7 9
43bc8ac6 10 This program is distributed in the hope that it will be useful,
d67281a7 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
43bc8ac6
UD
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
d67281a7 14
43bc8ac6 15 You should have received a copy of the GNU General Public License
59ba27a6 16 along with this program; if not, see <http://www.gnu.org/licenses/>. */
d67281a7 17
67479a70 18/* nscd - Name Service Cache Daemon. Caches passwd, group, and hosts. */
d67281a7 19
4d06461a 20#include <argp.h>
67479a70 21#include <assert.h>
d4397629 22#include <dirent.h>
d67281a7 23#include <errno.h>
4d06461a 24#include <error.h>
d4397629 25#include <fcntl.h>
d67281a7
UD
26#include <libintl.h>
27#include <locale.h>
d4397629 28#include <paths.h>
d67281a7 29#include <pthread.h>
d67281a7 30#include <signal.h>
a12ce44f 31#include <stdbool.h>
d67281a7
UD
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <syslog.h>
4c223a7c 36#include <unistd.h>
a95a08b4 37#include <sys/mman.h>
d67281a7 38#include <sys/socket.h>
d4397629 39#include <sys/stat.h>
ead07d01 40#include <sys/uio.h>
d67281a7
UD
41#include <sys/un.h>
42
43#include "dbg_log.h"
44#include "nscd.h"
74a30a58 45#include "selinux.h"
ef4d5b32 46#include "../nss/nsswitch.h"
d4397629 47#include <device-nrs.h>
319b9ad4
UD
48#ifdef HAVE_INOTIFY
49# include <sys/inotify.h>
50#endif
d67281a7
UD
51
52/* Get libc version number. */
53#include <version.h>
54
55#define PACKAGE _libc_intl_domainname
56
57/* Structure used by main() thread to keep track of the number of
58 active threads. Used to limit how many threads it will create
59 and under a shutdown condition to wait till all in-progress
60 requests have finished before "turning off the lights". */
61
62typedef struct
63{
64 int num_active;
65 pthread_cond_t thread_exit_cv;
66 pthread_mutex_t mutex;
67} thread_info_t;
68
69thread_info_t thread_info;
70
a1c542bf
UD
71int do_shutdown;
72int disabled_passwd;
73int disabled_group;
bb90b80b 74
edfe0dbe 75typedef enum
bb90b80b 76{
edfe0dbe
AJ
77 /* Running in background as daemon. */
78 RUN_DAEMONIZE,
bb90b80b
AJ
79 /* Running in foreground but otherwise behave like a daemon,
80 i.e., detach from terminal and use syslog. This allows
81 better integration with services like systemd. */
82 RUN_FOREGROUND,
bb90b80b
AJ
83 /* Run in foreground in debug mode. */
84 RUN_DEBUG
edfe0dbe
AJ
85} run_modes;
86
87static run_modes run_mode = RUN_DAEMONIZE;
a1c542bf 88
67479a70 89static const char *conffile = _PATH_NSCDCONF;
d67281a7 90
c86e6aec
UD
91time_t start_time;
92
3418007e
UD
93uintptr_t pagesize_m1;
94
4401d759
UD
95int paranoia;
96time_t restart_time;
97time_t restart_interval = RESTART_INTERVAL;
98const char *oldcwd;
99uid_t old_uid;
100gid_t old_gid;
101
d67281a7
UD
102static int check_pid (const char *file);
103static int write_pid (const char *file);
d67281a7 104
4d06461a
UD
105/* Name and version of program. */
106static void print_version (FILE *stream, struct argp_state *state);
107void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
108
cbbcaf23
UD
109/* Function to print some extra text in the help message. */
110static char *more_help (int key, const char *text, void *input);
111
4d06461a
UD
112/* Definitions of arguments for argp functions. */
113static const struct argp_option options[] =
114{
115 { "config-file", 'f', N_("NAME"), 0,
116 N_("Read configuration data from NAME") },
117 { "debug", 'd', NULL, 0,
118 N_("Do not fork and display messages on the current tty") },
bb90b80b 119 { "foreground", 'F', NULL, 0,
edfe0dbe 120 N_("Do not fork, but otherwise behave like a daemon") },
67479a70 121 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
4d06461a 122 { "shutdown", 'K', NULL, 0, N_("Shut the server down") },
1d20f7f8 123 { "statistics", 'g', NULL, 0, N_("Print current configuration statistics") },
756409c4
UD
124 { "invalidate", 'i', N_("TABLE"), 0,
125 N_("Invalidate the specified cache") },
3c12b91a
UD
126 { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN,
127 N_("Use separate cache for each user")},
4d06461a
UD
128 { NULL, 0, NULL, 0, NULL }
129};
130
131/* Short description of program. */
67a96999 132static const char doc[] = N_("Name Service Cache Daemon.");
4d06461a
UD
133
134/* Prototype for option handler. */
d8cf93f4 135static error_t parse_opt (int key, char *arg, struct argp_state *state);
4d06461a
UD
136
137/* Data structure to communicate with argp functions. */
138static struct argp argp =
139{
cbbcaf23 140 options, parse_opt, NULL, doc, NULL, more_help
4d06461a
UD
141};
142
a12ce44f
UD
143/* True if only statistics are requested. */
144static bool get_stats;
145
d67281a7
UD
146int
147main (int argc, char **argv)
148{
4d06461a 149 int remaining;
d67281a7
UD
150
151 /* Set locale via LC_ALL. */
152 setlocale (LC_ALL, "");
153 /* Set the text message domain. */
154 textdomain (PACKAGE);
155
74a30a58
UD
156 /* Determine if the kernel has SELinux support. */
157 nscd_selinux_enabled (&selinux_enabled);
158
4d06461a
UD
159 /* Parse and process arguments. */
160 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
161
14e9dd67 162 if (remaining != argc)
d67281a7 163 {
4d06461a
UD
164 error (0, 0, gettext ("wrong number of arguments"));
165 argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
64d64de6 166 exit (1);
d67281a7
UD
167 }
168
a12ce44f
UD
169 /* Read the configuration file. */
170 if (nscd_parse_file (conffile, dbs) != 0)
4fb5ab74
UD
171 /* We couldn't read the configuration file. We don't start the
172 server. */
173 error (EXIT_FAILURE, 0,
174 _("failure while reading configuration file; this is fatal"));
a12ce44f
UD
175
176 /* Do we only get statistics? */
177 if (get_stats)
178 /* Does not return. */
179 receive_print_stats ();
180
d67281a7
UD
181 /* Check if we are already running. */
182 if (check_pid (_PATH_NSCDPID))
67479a70 183 error (EXIT_FAILURE, 0, _("already running"));
d67281a7 184
c86e6aec
UD
185 /* Remember when we started. */
186 start_time = time (NULL);
187
3418007e
UD
188 /* Determine page size. */
189 pagesize_m1 = getpagesize () - 1;
190
91d8d69e 191 if (run_mode == RUN_DAEMONIZE || run_mode == RUN_FOREGROUND)
d67281a7 192 {
6c202c68 193 int i;
bb90b80b 194 pid_t pid;
6c202c68 195
bb90b80b
AJ
196 /* Behave like a daemon. */
197 if (run_mode == RUN_DAEMONIZE)
198 {
199 pid = fork ();
200 if (pid == -1)
201 error (EXIT_FAILURE, errno, _("cannot fork"));
202 if (pid != 0)
203 exit (0);
204 }
6c202c68 205
d4397629
UD
206 int nullfd = open (_PATH_DEVNULL, O_RDWR);
207 if (nullfd != -1)
208 {
209 struct stat64 st;
210
211 if (fstat64 (nullfd, &st) == 0 && S_ISCHR (st.st_mode) != 0
212#if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
213 && st.st_rdev == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)
214#endif
215 )
216 {
217 /* It is the /dev/null special device alright. */
218 (void) dup2 (nullfd, STDIN_FILENO);
219 (void) dup2 (nullfd, STDOUT_FILENO);
220 (void) dup2 (nullfd, STDERR_FILENO);
221
222 if (nullfd > 2)
223 close (nullfd);
224 }
225 else
226 {
227 /* Ugh, somebody is trying to play a trick on us. */
228 close (nullfd);
229 nullfd = -1;
230 }
231 }
232 int min_close_fd = nullfd == -1 ? 0 : STDERR_FILENO + 1;
233
234 DIR *d = opendir ("/proc/self/fd");
235 if (d != NULL)
236 {
237 struct dirent64 *dirent;
238 int dfdn = dirfd (d);
239
240 while ((dirent = readdir64 (d)) != NULL)
241 {
242 char *endp;
4c5dd2a2 243 long int fdn = strtol (dirent->d_name, &endp, 10);
d4397629
UD
244
245 if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd)
246 close ((int) fdn);
247 }
248
249 closedir (d);
250 }
251 else
252 for (i = min_close_fd; i < getdtablesize (); i++)
253 close (i);
6c202c68 254
adcf0e4a
UD
255 setsid ();
256
be686f18
UD
257 if (chdir ("/") != 0)
258 error (EXIT_FAILURE, errno,
3a4e0609 259 _("cannot change current working directory to \"/\""));
6c202c68 260
d67281a7
UD
261 openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
262
d67281a7 263 if (write_pid (_PATH_NSCDPID) < 0)
561470e0 264 dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
d67281a7 265
f4047366
UD
266 if (!init_logfile ())
267 dbg_log (_("Could not create log file"));
268
67479a70 269 /* Ignore job control signals. */
d67281a7
UD
270 signal (SIGTTOU, SIG_IGN);
271 signal (SIGTTIN, SIG_IGN);
272 signal (SIGTSTP, SIG_IGN);
273 }
4401d759 274 else
bb90b80b 275 /* In debug mode we are not paranoid. */
4401d759 276 paranoia = 0;
6c202c68
UD
277
278 signal (SIGINT, termination_handler);
279 signal (SIGQUIT, termination_handler);
280 signal (SIGTERM, termination_handler);
281 signal (SIGPIPE, SIG_IGN);
282
230c3e1e 283 /* Cleanup files created by a previous 'bind'. */
d67281a7
UD
284 unlink (_PATH_NSCDSOCKET);
285
319b9ad4
UD
286#ifdef HAVE_INOTIFY
287 /* Use inotify to recognize changed files. */
288 inotify_fd = inotify_init1 (IN_NONBLOCK);
289# ifndef __ASSUME_IN_NONBLOCK
290 if (inotify_fd == -1 && errno == ENOSYS)
291 {
292 inotify_fd = inotify_init ();
293 if (inotify_fd != -1)
294 fcntl (inotify_fd, F_SETFL, O_RDONLY | O_NONBLOCK);
295 }
296# endif
297#endif
298
3cc3ef96 299#ifdef USE_NSCD
ef4d5b32 300 /* Make sure we do not get recursive calls. */
319b9ad4 301 __nss_disable_nscd (register_traced_file);
3cc3ef96 302#endif
ef4d5b32 303
67479a70 304 /* Init databases. */
a12ce44f 305 nscd_init ();
d67281a7 306
a9ae54a1
AS
307 /* Start the SELinux AVC. */
308 if (selinux_enabled)
309 nscd_avc_init ();
310
d67281a7 311 /* Handle incoming requests */
67479a70 312 start_threads ();
d67281a7
UD
313
314 return 0;
315}
316
4d06461a
UD
317
318/* Handle program arguments. */
319static error_t
320parse_opt (int key, char *arg, struct argp_state *state)
321{
322 switch (key)
323 {
324 case 'd':
67479a70 325 ++debug_level;
bb90b80b
AJ
326 run_mode = RUN_DEBUG;
327 break;
328
329 case 'F':
330 run_mode = RUN_FOREGROUND;
4d06461a 331 break;
67479a70 332
4d06461a
UD
333 case 'f':
334 conffile = arg;
335 break;
67479a70 336
4d06461a
UD
337 case 'K':
338 if (getuid () != 0)
64d64de6 339 error (4, 0, _("Only root is allowed to use this option!"));
4d06461a 340 {
67479a70 341 int sock = nscd_open_socket ();
4d06461a
UD
342
343 if (sock == -1)
344 exit (EXIT_FAILURE);
345
8c6d1043 346 request_header req;
4d06461a
UD
347 req.version = NSCD_VERSION;
348 req.type = SHUTDOWN;
349 req.key_len = 0;
8c6d1043
UD
350
351 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &req,
352 sizeof (request_header),
353 MSG_NOSIGNAL));
4d06461a 354 close (sock);
67479a70 355 exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
4d06461a 356 }
67479a70 357
4d06461a 358 case 'g':
a12ce44f
UD
359 get_stats = true;
360 break;
67479a70 361
756409c4
UD
362 case 'i':
363 if (getuid () != 0)
64d64de6 364 error (4, 0, _("Only root is allowed to use this option!"));
756409c4
UD
365 else
366 {
367 int sock = nscd_open_socket ();
756409c4
UD
368
369 if (sock == -1)
370 exit (EXIT_FAILURE);
371
b21fa963
UD
372 dbtype cnt;
373 for (cnt = pwddb; cnt < lastdb; ++cnt)
374 if (strcmp (arg, dbnames[cnt]) == 0)
375 break;
376
377 if (cnt == lastdb)
251fe50c
RM
378 {
379 argp_error (state, _("'%s' is not a known database"), arg);
380 return EINVAL;
381 }
756409c4 382
8c6d1043
UD
383 size_t arg_len = strlen (arg) + 1;
384 struct
385 {
386 request_header req;
387 char arg[arg_len];
388 } reqdata;
756409c4 389
8c6d1043
UD
390 reqdata.req.key_len = strlen (arg) + 1;
391 reqdata.req.version = NSCD_VERSION;
392 reqdata.req.type = INVALIDATE;
393 memcpy (reqdata.arg, arg, arg_len);
ead07d01 394
8c6d1043
UD
395 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &reqdata,
396 sizeof (request_header)
397 + arg_len,
398 MSG_NOSIGNAL));
902c4291 399
8c6d1043 400 if (nbytes != sizeof (request_header) + arg_len)
902c4291
UD
401 {
402 int err = errno;
403 close (sock);
404 error (EXIT_FAILURE, err, _("write incomplete"));
405 }
406
407 /* Wait for ack. Older nscd just closed the socket when
408 prune_cache finished, silently ignore that. */
409 int32_t resp = 0;
410 nbytes = TEMP_FAILURE_RETRY (read (sock, &resp, sizeof (resp)));
411 if (nbytes != 0 && nbytes != sizeof (resp))
412 {
413 int err = errno;
414 close (sock);
415 error (EXIT_FAILURE, err, _("cannot read invalidate ACK"));
416 }
756409c4
UD
417
418 close (sock);
419
902c4291
UD
420 if (resp != 0)
421 error (EXIT_FAILURE, resp, _("invalidation failed"));
422
423 exit (0);
756409c4
UD
424 }
425
67479a70
UD
426 case 't':
427 nthreads = atol (arg);
428 break;
429
a1c542bf 430 case 'S':
3c12b91a 431 error (0, 0, _("secure services not implemented anymore"));
a1c542bf
UD
432 break;
433
4d06461a
UD
434 default:
435 return ARGP_ERR_UNKNOWN;
436 }
67479a70 437
4d06461a
UD
438 return 0;
439}
440
cbbcaf23
UD
441/* Print bug-reporting information in the help message. */
442static char *
443more_help (int key, const char *text, void *input)
444{
8b748aed 445 char *tp = NULL;
cbbcaf23
UD
446 switch (key)
447 {
448 case ARGP_KEY_HELP_EXTRA:
449 /* We print some extra information. */
8b748aed 450 if (asprintf (&tp, gettext ("\
cbbcaf23 451For bug reporting instructions, please see:\n\
8b748aed
JM
452%s.\n"), REPORT_BUGS_TO) < 0)
453 return NULL;
454 return tp;
cbbcaf23
UD
455 default:
456 break;
457 }
458 return (char *) text;
459}
460
4d06461a
UD
461/* Print the version information. */
462static void
463print_version (FILE *stream, struct argp_state *state)
464{
8b748aed 465 fprintf (stream, "nscd %s%s\n", PKGVERSION, VERSION);
4d06461a
UD
466 fprintf (stream, gettext ("\
467Copyright (C) %s Free Software Foundation, Inc.\n\
468This is free software; see the source for copying conditions. There is NO\n\
469warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
0549fbba 470"), "2013");
67479a70
UD
471 fprintf (stream, gettext ("Written by %s.\n"),
472 "Thorsten Kukuk and Ulrich Drepper");
4d06461a
UD
473}
474
475
67479a70 476/* Create a socket connected to a name. */
d67281a7 477int
67479a70 478nscd_open_socket (void)
d67281a7
UD
479{
480 struct sockaddr_un addr;
481 int sock;
482
483 sock = socket (PF_UNIX, SOCK_STREAM, 0);
484 if (sock < 0)
485 return -1;
486
487 addr.sun_family = AF_UNIX;
67479a70 488 assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
d67281a7
UD
489 strcpy (addr.sun_path, _PATH_NSCDSOCKET);
490 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
491 {
492 close (sock);
493 return -1;
494 }
495
496 return sock;
497}
498
4401d759 499
d67281a7 500/* Cleanup. */
67479a70 501void
d67281a7
UD
502termination_handler (int signum)
503{
504 close_sockets ();
505
230c3e1e 506 /* Clean up the file created by 'bind'. */
d67281a7
UD
507 unlink (_PATH_NSCDSOCKET);
508
509 /* Clean up pid file. */
510 unlink (_PATH_NSCDPID);
511
a95a08b4
UD
512 // XXX Terminate threads.
513
514 /* Synchronize memory. */
515 for (int cnt = 0; cnt < lastdb; ++cnt)
74fef3bb 516 {
feb1eb0b 517 if (!dbs[cnt].enabled || dbs[cnt].head == NULL)
6aa10807
UD
518 continue;
519
74fef3bb
UD
520 /* Make sure nobody keeps using the database. */
521 dbs[cnt].head->timestamp = 0;
522
523 if (dbs[cnt].persistent)
524 // XXX async OK?
525 msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
526 }
a95a08b4 527
230c3e1e 528 _exit (EXIT_SUCCESS);
d67281a7
UD
529}
530
d67281a7
UD
531/* Returns 1 if the process in pid file FILE is running, 0 if not. */
532static int
533check_pid (const char *file)
534{
535 FILE *fp;
536
537 fp = fopen (file, "r");
538 if (fp)
539 {
540 pid_t pid;
67479a70 541 int n;
d67281a7 542
67479a70 543 n = fscanf (fp, "%d", &pid);
d67281a7
UD
544 fclose (fp);
545
4401d759
UD
546 /* If we cannot parse the file default to assuming nscd runs.
547 If the PID is alive, assume it is running. That all unless
548 the PID is the same as the current process' since tha latter
549 can mean we re-exec. */
550 if ((n != 1 || kill (pid, 0) == 0) && pid != getpid ())
561470e0 551 return 1;
d67281a7
UD
552 }
553
554 return 0;
555}
556
557/* Write the current process id to the file FILE.
558 Returns 0 if successful, -1 if not. */
559static int
560write_pid (const char *file)
561{
562 FILE *fp;
563
564 fp = fopen (file, "w");
565 if (fp == NULL)
566 return -1;
567
568 fprintf (fp, "%d\n", getpid ());
0292b0dd
UD
569
570 int result = fflush (fp) || ferror (fp) ? -1 : 0;
d67281a7
UD
571
572 fclose (fp);
573
0292b0dd 574 return result;
d67281a7 575}