]> git.ipfire.org Git - thirdparty/glibc.git/blob - nscd/nscd.c
Revert "nscd: don't fork twice"
[thirdparty/glibc.git] / nscd / nscd.c
1 /* Copyright (c) 1998-2013 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
4
5 This program is free software; you can redistribute it and/or modify
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.
9
10 This program 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
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, see <http://www.gnu.org/licenses/>. */
17
18 /* nscd - Name Service Cache Daemon. Caches passwd, group, and hosts. */
19
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>
42
43 #include "dbg_log.h"
44 #include "nscd.h"
45 #include "selinux.h"
46 #include "../nss/nsswitch.h"
47 #include <device-nrs.h>
48 #ifdef HAVE_INOTIFY
49 # include <sys/inotify.h>
50 #endif
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
62 typedef struct
63 {
64 int num_active;
65 pthread_cond_t thread_exit_cv;
66 pthread_mutex_t mutex;
67 } thread_info_t;
68
69 thread_info_t thread_info;
70
71 int do_shutdown;
72 int disabled_passwd;
73 int disabled_group;
74
75 typedef enum
76 {
77 /* Running in background as daemon. */
78 RUN_DAEMONIZE,
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,
83 /* Run in foreground in debug mode. */
84 RUN_DEBUG
85 } run_modes;
86
87 static run_modes run_mode = RUN_DAEMONIZE;
88
89 static const char *conffile = _PATH_NSCDCONF;
90
91 time_t start_time;
92
93 uintptr_t pagesize_m1;
94
95 int paranoia;
96 time_t restart_time;
97 time_t restart_interval = RESTART_INTERVAL;
98 const char *oldcwd;
99 uid_t old_uid;
100 gid_t old_gid;
101
102 static int check_pid (const char *file);
103 static int write_pid (const char *file);
104
105 /* Name and version of program. */
106 static void print_version (FILE *stream, struct argp_state *state);
107 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
108
109 /* Function to print some extra text in the help message. */
110 static char *more_help (int key, const char *text, void *input);
111
112 /* Definitions of arguments for argp functions. */
113 static 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") },
119 { "foreground", 'F', NULL, 0,
120 N_("Do not fork, but otherwise behave like a daemon") },
121 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
122 { "shutdown", 'K', NULL, 0, N_("Shut the server down") },
123 { "statistics", 'g', NULL, 0, N_("Print current configuration statistics") },
124 { "invalidate", 'i', N_("TABLE"), 0,
125 N_("Invalidate the specified cache") },
126 { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN,
127 N_("Use separate cache for each user")},
128 { NULL, 0, NULL, 0, NULL }
129 };
130
131 /* Short description of program. */
132 static const char doc[] = N_("Name Service Cache Daemon.");
133
134 /* Prototype for option handler. */
135 static error_t parse_opt (int key, char *arg, struct argp_state *state);
136
137 /* Data structure to communicate with argp functions. */
138 static struct argp argp =
139 {
140 options, parse_opt, NULL, doc, NULL, more_help
141 };
142
143 /* True if only statistics are requested. */
144 static bool get_stats;
145
146 int
147 main (int argc, char **argv)
148 {
149 int remaining;
150
151 /* Set locale via LC_ALL. */
152 setlocale (LC_ALL, "");
153 /* Set the text message domain. */
154 textdomain (PACKAGE);
155
156 /* Determine if the kernel has SELinux support. */
157 nscd_selinux_enabled (&selinux_enabled);
158
159 /* Parse and process arguments. */
160 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
161
162 if (remaining != argc)
163 {
164 error (0, 0, gettext ("wrong number of arguments"));
165 argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
166 exit (1);
167 }
168
169 /* Read the configuration file. */
170 if (nscd_parse_file (conffile, dbs) != 0)
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"));
175
176 /* Do we only get statistics? */
177 if (get_stats)
178 /* Does not return. */
179 receive_print_stats ();
180
181 /* Check if we are already running. */
182 if (check_pid (_PATH_NSCDPID))
183 error (EXIT_FAILURE, 0, _("already running"));
184
185 /* Remember when we started. */
186 start_time = time (NULL);
187
188 /* Determine page size. */
189 pagesize_m1 = getpagesize () - 1;
190
191 if (run_mode == RUN_DAEMONIZE || run_mode == RUN_FOREGROUND)
192 {
193 int i;
194 pid_t pid;
195
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 }
205
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;
243 long int fdn = strtol (dirent->d_name, &endp, 10);
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);
254
255 if (run_mode == RUN_DAEMONIZE)
256 {
257 pid = fork ();
258 if (pid == -1)
259 error (EXIT_FAILURE, errno, _("cannot fork"));
260 if (pid != 0)
261 exit (0);
262 }
263
264 setsid ();
265
266 if (chdir ("/") != 0)
267 error (EXIT_FAILURE, errno,
268 _("cannot change current working directory to \"/\""));
269
270 openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
271
272 if (write_pid (_PATH_NSCDPID) < 0)
273 dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
274
275 if (!init_logfile ())
276 dbg_log (_("Could not create log file"));
277
278 /* Ignore job control signals. */
279 signal (SIGTTOU, SIG_IGN);
280 signal (SIGTTIN, SIG_IGN);
281 signal (SIGTSTP, SIG_IGN);
282 }
283 else
284 /* In debug mode we are not paranoid. */
285 paranoia = 0;
286
287 signal (SIGINT, termination_handler);
288 signal (SIGQUIT, termination_handler);
289 signal (SIGTERM, termination_handler);
290 signal (SIGPIPE, SIG_IGN);
291
292 /* Cleanup files created by a previous 'bind'. */
293 unlink (_PATH_NSCDSOCKET);
294
295 #ifdef HAVE_INOTIFY
296 /* Use inotify to recognize changed files. */
297 inotify_fd = inotify_init1 (IN_NONBLOCK);
298 # ifndef __ASSUME_IN_NONBLOCK
299 if (inotify_fd == -1 && errno == ENOSYS)
300 {
301 inotify_fd = inotify_init ();
302 if (inotify_fd != -1)
303 fcntl (inotify_fd, F_SETFL, O_RDONLY | O_NONBLOCK);
304 }
305 # endif
306 #endif
307
308 #ifdef USE_NSCD
309 /* Make sure we do not get recursive calls. */
310 __nss_disable_nscd (register_traced_file);
311 #endif
312
313 /* Init databases. */
314 nscd_init ();
315
316 /* Start the SELinux AVC. */
317 if (selinux_enabled)
318 nscd_avc_init ();
319
320 /* Handle incoming requests */
321 start_threads ();
322
323 return 0;
324 }
325
326
327 /* Handle program arguments. */
328 static error_t
329 parse_opt (int key, char *arg, struct argp_state *state)
330 {
331 switch (key)
332 {
333 case 'd':
334 ++debug_level;
335 run_mode = RUN_DEBUG;
336 break;
337
338 case 'F':
339 run_mode = RUN_FOREGROUND;
340 break;
341
342 case 'f':
343 conffile = arg;
344 break;
345
346 case 'K':
347 if (getuid () != 0)
348 error (4, 0, _("Only root is allowed to use this option!"));
349 {
350 int sock = nscd_open_socket ();
351
352 if (sock == -1)
353 exit (EXIT_FAILURE);
354
355 request_header req;
356 req.version = NSCD_VERSION;
357 req.type = SHUTDOWN;
358 req.key_len = 0;
359
360 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &req,
361 sizeof (request_header),
362 MSG_NOSIGNAL));
363 close (sock);
364 exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
365 }
366
367 case 'g':
368 get_stats = true;
369 break;
370
371 case 'i':
372 if (getuid () != 0)
373 error (4, 0, _("Only root is allowed to use this option!"));
374 else
375 {
376 int sock = nscd_open_socket ();
377
378 if (sock == -1)
379 exit (EXIT_FAILURE);
380
381 dbtype cnt;
382 for (cnt = pwddb; cnt < lastdb; ++cnt)
383 if (strcmp (arg, dbnames[cnt]) == 0)
384 break;
385
386 if (cnt == lastdb)
387 {
388 argp_error (state, _("'%s' is not a known database"), arg);
389 return EINVAL;
390 }
391
392 size_t arg_len = strlen (arg) + 1;
393 struct
394 {
395 request_header req;
396 char arg[arg_len];
397 } reqdata;
398
399 reqdata.req.key_len = strlen (arg) + 1;
400 reqdata.req.version = NSCD_VERSION;
401 reqdata.req.type = INVALIDATE;
402 memcpy (reqdata.arg, arg, arg_len);
403
404 ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &reqdata,
405 sizeof (request_header)
406 + arg_len,
407 MSG_NOSIGNAL));
408
409 if (nbytes != sizeof (request_header) + arg_len)
410 {
411 int err = errno;
412 close (sock);
413 error (EXIT_FAILURE, err, _("write incomplete"));
414 }
415
416 /* Wait for ack. Older nscd just closed the socket when
417 prune_cache finished, silently ignore that. */
418 int32_t resp = 0;
419 nbytes = TEMP_FAILURE_RETRY (read (sock, &resp, sizeof (resp)));
420 if (nbytes != 0 && nbytes != sizeof (resp))
421 {
422 int err = errno;
423 close (sock);
424 error (EXIT_FAILURE, err, _("cannot read invalidate ACK"));
425 }
426
427 close (sock);
428
429 if (resp != 0)
430 error (EXIT_FAILURE, resp, _("invalidation failed"));
431
432 exit (0);
433 }
434
435 case 't':
436 nthreads = atol (arg);
437 break;
438
439 case 'S':
440 error (0, 0, _("secure services not implemented anymore"));
441 break;
442
443 default:
444 return ARGP_ERR_UNKNOWN;
445 }
446
447 return 0;
448 }
449
450 /* Print bug-reporting information in the help message. */
451 static char *
452 more_help (int key, const char *text, void *input)
453 {
454 char *tp = NULL;
455 switch (key)
456 {
457 case ARGP_KEY_HELP_EXTRA:
458 /* We print some extra information. */
459 if (asprintf (&tp, gettext ("\
460 For bug reporting instructions, please see:\n\
461 %s.\n"), REPORT_BUGS_TO) < 0)
462 return NULL;
463 return tp;
464 default:
465 break;
466 }
467 return (char *) text;
468 }
469
470 /* Print the version information. */
471 static void
472 print_version (FILE *stream, struct argp_state *state)
473 {
474 fprintf (stream, "nscd %s%s\n", PKGVERSION, VERSION);
475 fprintf (stream, gettext ("\
476 Copyright (C) %s Free Software Foundation, Inc.\n\
477 This is free software; see the source for copying conditions. There is NO\n\
478 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
479 "), "2013");
480 fprintf (stream, gettext ("Written by %s.\n"),
481 "Thorsten Kukuk and Ulrich Drepper");
482 }
483
484
485 /* Create a socket connected to a name. */
486 int
487 nscd_open_socket (void)
488 {
489 struct sockaddr_un addr;
490 int sock;
491
492 sock = socket (PF_UNIX, SOCK_STREAM, 0);
493 if (sock < 0)
494 return -1;
495
496 addr.sun_family = AF_UNIX;
497 assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
498 strcpy (addr.sun_path, _PATH_NSCDSOCKET);
499 if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
500 {
501 close (sock);
502 return -1;
503 }
504
505 return sock;
506 }
507
508
509 /* Cleanup. */
510 void
511 termination_handler (int signum)
512 {
513 close_sockets ();
514
515 /* Clean up the file created by 'bind'. */
516 unlink (_PATH_NSCDSOCKET);
517
518 /* Clean up pid file. */
519 unlink (_PATH_NSCDPID);
520
521 // XXX Terminate threads.
522
523 /* Synchronize memory. */
524 for (int cnt = 0; cnt < lastdb; ++cnt)
525 {
526 if (!dbs[cnt].enabled || dbs[cnt].head == NULL)
527 continue;
528
529 /* Make sure nobody keeps using the database. */
530 dbs[cnt].head->timestamp = 0;
531
532 if (dbs[cnt].persistent)
533 // XXX async OK?
534 msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
535 }
536
537 _exit (EXIT_SUCCESS);
538 }
539
540 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
541 static int
542 check_pid (const char *file)
543 {
544 FILE *fp;
545
546 fp = fopen (file, "r");
547 if (fp)
548 {
549 pid_t pid;
550 int n;
551
552 n = fscanf (fp, "%d", &pid);
553 fclose (fp);
554
555 /* If we cannot parse the file default to assuming nscd runs.
556 If the PID is alive, assume it is running. That all unless
557 the PID is the same as the current process' since tha latter
558 can mean we re-exec. */
559 if ((n != 1 || kill (pid, 0) == 0) && pid != getpid ())
560 return 1;
561 }
562
563 return 0;
564 }
565
566 /* Write the current process id to the file FILE.
567 Returns 0 if successful, -1 if not. */
568 static int
569 write_pid (const char *file)
570 {
571 FILE *fp;
572
573 fp = fopen (file, "w");
574 if (fp == NULL)
575 return -1;
576
577 fprintf (fp, "%d\n", getpid ());
578
579 int result = fflush (fp) || ferror (fp) ? -1 : 0;
580
581 fclose (fp);
582
583 return result;
584 }