1 /* Copyright (c) 1998-2014 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 as published
7 by the Free Software Foundation; version 2 of the License, or
8 (at your option) any later version.
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.
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/>. */
18 /* nscd - Name Service Cache Daemon. Caches passwd, group, and hosts. */
38 #include <sys/socket.h>
48 #include "../nss/nsswitch.h"
49 #include <device-nrs.h>
51 # include <sys/inotify.h>
54 /* Get libc version number. */
57 #define PACKAGE _libc_intl_domainname
59 /* Structure used by main() thread to keep track of the number of
60 active threads. Used to limit how many threads it will create
61 and under a shutdown condition to wait till all in-progress
62 requests have finished before "turning off the lights". */
67 pthread_cond_t thread_exit_cv
;
68 pthread_mutex_t mutex
;
71 thread_info_t thread_info
;
79 /* Running in background as daemon. */
81 /* Running in foreground but otherwise behave like a daemon,
82 i.e., detach from terminal and use syslog. This allows
83 better integration with services like systemd. */
85 /* Run in foreground in debug mode. */
89 static run_modes run_mode
= RUN_DAEMONIZE
;
91 static const char *conffile
= _PATH_NSCDCONF
;
95 uintptr_t pagesize_m1
;
99 time_t restart_interval
= RESTART_INTERVAL
;
104 static int check_pid (const char *file
);
105 static int write_pid (const char *file
);
106 static int monitor_child (int fd
);
108 /* Name and version of program. */
109 static void print_version (FILE *stream
, struct argp_state
*state
);
110 void (*argp_program_version_hook
) (FILE *, struct argp_state
*) = print_version
;
112 /* Function to print some extra text in the help message. */
113 static char *more_help (int key
, const char *text
, void *input
);
115 /* Definitions of arguments for argp functions. */
116 static const struct argp_option options
[] =
118 { "config-file", 'f', N_("NAME"), 0,
119 N_("Read configuration data from NAME") },
120 { "debug", 'd', NULL
, 0,
121 N_("Do not fork and display messages on the current tty") },
122 { "foreground", 'F', NULL
, 0,
123 N_("Do not fork, but otherwise behave like a daemon") },
124 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
125 { "shutdown", 'K', NULL
, 0, N_("Shut the server down") },
126 { "statistics", 'g', NULL
, 0, N_("Print current configuration statistics") },
127 { "invalidate", 'i', N_("TABLE"), 0,
128 N_("Invalidate the specified cache") },
129 { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN
,
130 N_("Use separate cache for each user")},
131 { NULL
, 0, NULL
, 0, NULL
}
134 /* Short description of program. */
135 static const char doc
[] = N_("Name Service Cache Daemon.");
137 /* Prototype for option handler. */
138 static error_t
parse_opt (int key
, char *arg
, struct argp_state
*state
);
140 /* Data structure to communicate with argp functions. */
141 static struct argp argp
=
143 options
, parse_opt
, NULL
, doc
, NULL
, more_help
146 /* True if only statistics are requested. */
147 static bool get_stats
;
148 static int parent_fd
= -1;
151 main (int argc
, char **argv
)
155 /* Set locale via LC_ALL. */
156 setlocale (LC_ALL
, "");
157 /* Set the text message domain. */
158 textdomain (PACKAGE
);
160 /* Determine if the kernel has SELinux support. */
161 nscd_selinux_enabled (&selinux_enabled
);
163 /* Parse and process arguments. */
164 argp_parse (&argp
, argc
, argv
, 0, &remaining
, NULL
);
166 if (remaining
!= argc
)
168 error (0, 0, gettext ("wrong number of arguments"));
169 argp_help (&argp
, stdout
, ARGP_HELP_SEE
, program_invocation_short_name
);
173 /* Read the configuration file. */
174 if (nscd_parse_file (conffile
, dbs
) != 0)
175 /* We couldn't read the configuration file. We don't start the
177 error (EXIT_FAILURE
, 0,
178 _("failure while reading configuration file; this is fatal"));
180 /* Do we only get statistics? */
182 /* Does not return. */
183 receive_print_stats ();
185 /* Check if we are already running. */
186 if (check_pid (_PATH_NSCDPID
))
187 error (EXIT_FAILURE
, 0, _("already running"));
189 /* Remember when we started. */
190 start_time
= time (NULL
);
192 /* Determine page size. */
193 pagesize_m1
= getpagesize () - 1;
195 if (run_mode
== RUN_DAEMONIZE
|| run_mode
== RUN_FOREGROUND
)
200 /* Behave like a daemon. */
201 if (run_mode
== RUN_DAEMONIZE
)
206 error (EXIT_FAILURE
, errno
,
207 _("cannot create a pipe to talk to the child"));
211 error (EXIT_FAILURE
, errno
, _("cannot fork"));
214 /* The parent only reads from the child. */
216 exit (monitor_child (fd
[0]));
220 /* The child only writes to the parent. */
226 int nullfd
= open (_PATH_DEVNULL
, O_RDWR
);
231 if (fstat64 (nullfd
, &st
) == 0 && S_ISCHR (st
.st_mode
) != 0
232 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
233 && st
.st_rdev
== makedev (DEV_NULL_MAJOR
, DEV_NULL_MINOR
)
237 /* It is the /dev/null special device alright. */
238 (void) dup2 (nullfd
, STDIN_FILENO
);
239 (void) dup2 (nullfd
, STDOUT_FILENO
);
240 (void) dup2 (nullfd
, STDERR_FILENO
);
247 /* Ugh, somebody is trying to play a trick on us. */
252 int min_close_fd
= nullfd
== -1 ? 0 : STDERR_FILENO
+ 1;
254 DIR *d
= opendir ("/proc/self/fd");
257 struct dirent64
*dirent
;
258 int dfdn
= dirfd (d
);
260 while ((dirent
= readdir64 (d
)) != NULL
)
263 long int fdn
= strtol (dirent
->d_name
, &endp
, 10);
265 if (*endp
== '\0' && fdn
!= dfdn
&& fdn
>= min_close_fd
273 for (i
= min_close_fd
; i
< getdtablesize (); i
++)
279 if (chdir ("/") != 0)
280 do_exit (EXIT_FAILURE
, errno
,
281 _("cannot change current working directory to \"/\""));
283 openlog ("nscd", LOG_CONS
| LOG_ODELAY
, LOG_DAEMON
);
285 if (write_pid (_PATH_NSCDPID
) < 0)
286 dbg_log ("%s: %s", _PATH_NSCDPID
, strerror (errno
));
288 if (!init_logfile ())
289 dbg_log (_("Could not create log file"));
291 /* Ignore job control signals. */
292 signal (SIGTTOU
, SIG_IGN
);
293 signal (SIGTTIN
, SIG_IGN
);
294 signal (SIGTSTP
, SIG_IGN
);
297 /* In debug mode we are not paranoid. */
300 signal (SIGINT
, termination_handler
);
301 signal (SIGQUIT
, termination_handler
);
302 signal (SIGTERM
, termination_handler
);
303 signal (SIGPIPE
, SIG_IGN
);
305 /* Cleanup files created by a previous 'bind'. */
306 unlink (_PATH_NSCDSOCKET
);
309 /* Use inotify to recognize changed files. */
310 inotify_fd
= inotify_init1 (IN_NONBLOCK
);
311 # ifndef __ASSUME_IN_NONBLOCK
312 if (inotify_fd
== -1 && errno
== ENOSYS
)
314 inotify_fd
= inotify_init ();
315 if (inotify_fd
!= -1)
316 fcntl (inotify_fd
, F_SETFL
, O_RDONLY
| O_NONBLOCK
);
322 /* Make sure we do not get recursive calls. */
323 __nss_disable_nscd (register_traced_file
);
326 /* Init databases. */
329 /* Start the SELinux AVC. */
333 /* Handle incoming requests */
340 /* Handle program arguments. */
342 parse_opt (int key
, char *arg
, struct argp_state
*state
)
348 run_mode
= RUN_DEBUG
;
352 run_mode
= RUN_FOREGROUND
;
361 error (4, 0, _("Only root is allowed to use this option!"));
363 int sock
= nscd_open_socket ();
369 req
.version
= NSCD_VERSION
;
373 ssize_t nbytes
= TEMP_FAILURE_RETRY (send (sock
, &req
,
374 sizeof (request_header
),
377 exit (nbytes
!= sizeof (request_header
) ? EXIT_FAILURE
: EXIT_SUCCESS
);
386 error (4, 0, _("Only root is allowed to use this option!"));
389 int sock
= nscd_open_socket ();
395 for (cnt
= pwddb
; cnt
< lastdb
; ++cnt
)
396 if (strcmp (arg
, dbnames
[cnt
]) == 0)
401 argp_error (state
, _("'%s' is not a known database"), arg
);
405 size_t arg_len
= strlen (arg
) + 1;
412 reqdata
.req
.key_len
= strlen (arg
) + 1;
413 reqdata
.req
.version
= NSCD_VERSION
;
414 reqdata
.req
.type
= INVALIDATE
;
415 memcpy (reqdata
.arg
, arg
, arg_len
);
417 ssize_t nbytes
= TEMP_FAILURE_RETRY (send (sock
, &reqdata
,
418 sizeof (request_header
)
422 if (nbytes
!= sizeof (request_header
) + arg_len
)
426 error (EXIT_FAILURE
, err
, _("write incomplete"));
429 /* Wait for ack. Older nscd just closed the socket when
430 prune_cache finished, silently ignore that. */
432 nbytes
= TEMP_FAILURE_RETRY (read (sock
, &resp
, sizeof (resp
)));
433 if (nbytes
!= 0 && nbytes
!= sizeof (resp
))
437 error (EXIT_FAILURE
, err
, _("cannot read invalidate ACK"));
443 error (EXIT_FAILURE
, resp
, _("invalidation failed"));
449 nthreads
= atol (arg
);
453 error (0, 0, _("secure services not implemented anymore"));
457 return ARGP_ERR_UNKNOWN
;
463 /* Print bug-reporting information in the help message. */
465 more_help (int key
, const char *text
, void *input
)
467 char *tables
, *tp
= NULL
;
471 case ARGP_KEY_HELP_EXTRA
:
475 tables
= xmalloc (sizeof (dbnames
) + 1);
476 for (cnt
= 0; cnt
< lastdb
; cnt
++)
478 strcat (tables
, dbnames
[cnt
]);
479 strcat (tables
, " ");
483 /* We print some extra information. */
484 if (asprintf (&tp
, gettext ("\
488 For bug reporting instructions, please see:\n\
490 "), tables
, REPORT_BUGS_TO
) < 0)
499 return (char *) text
;
502 /* Print the version information. */
504 print_version (FILE *stream
, struct argp_state
*state
)
506 fprintf (stream
, "nscd %s%s\n", PKGVERSION
, VERSION
);
507 fprintf (stream
, gettext ("\
508 Copyright (C) %s Free Software Foundation, Inc.\n\
509 This is free software; see the source for copying conditions. There is NO\n\
510 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
512 fprintf (stream
, gettext ("Written by %s.\n"),
513 "Thorsten Kukuk and Ulrich Drepper");
517 /* Create a socket connected to a name. */
519 nscd_open_socket (void)
521 struct sockaddr_un addr
;
524 sock
= socket (PF_UNIX
, SOCK_STREAM
, 0);
528 addr
.sun_family
= AF_UNIX
;
529 assert (sizeof (addr
.sun_path
) >= sizeof (_PATH_NSCDSOCKET
));
530 strcpy (addr
.sun_path
, _PATH_NSCDSOCKET
);
531 if (connect (sock
, (struct sockaddr
*) &addr
, sizeof (addr
)) < 0)
543 termination_handler (int signum
)
547 /* Clean up the file created by 'bind'. */
548 unlink (_PATH_NSCDSOCKET
);
550 /* Clean up pid file. */
551 unlink (_PATH_NSCDPID
);
553 // XXX Terminate threads.
555 /* Synchronize memory. */
556 for (int cnt
= 0; cnt
< lastdb
; ++cnt
)
558 if (!dbs
[cnt
].enabled
|| dbs
[cnt
].head
== NULL
)
561 /* Make sure nobody keeps using the database. */
562 dbs
[cnt
].head
->timestamp
= 0;
564 if (dbs
[cnt
].persistent
)
566 msync (dbs
[cnt
].head
, dbs
[cnt
].memsize
, MS_ASYNC
);
569 _exit (EXIT_SUCCESS
);
572 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
574 check_pid (const char *file
)
578 fp
= fopen (file
, "r");
584 n
= fscanf (fp
, "%d", &pid
);
587 /* If we cannot parse the file default to assuming nscd runs.
588 If the PID is alive, assume it is running. That all unless
589 the PID is the same as the current process' since tha latter
590 can mean we re-exec. */
591 if ((n
!= 1 || kill (pid
, 0) == 0) && pid
!= getpid ())
598 /* Write the current process id to the file FILE.
599 Returns 0 if successful, -1 if not. */
601 write_pid (const char *file
)
605 fp
= fopen (file
, "w");
609 fprintf (fp
, "%d\n", getpid ());
611 int result
= fflush (fp
) || ferror (fp
) ? -1 : 0;
619 monitor_child (int fd
)
622 int ret
= read (fd
, &child_ret
, sizeof (child_ret
));
624 /* The child terminated with an error, either via exit or some other abnormal
625 method, like a segfault. */
626 if (ret
<= 0 || child_ret
!= 0)
628 int err
= wait (&child_ret
);
632 fprintf (stderr
, _("wait failed"));
636 fprintf (stderr
, _("child exited with status %d"),
637 WEXITSTATUS (child_ret
));
638 if (WIFSIGNALED (child_ret
))
639 fprintf (stderr
, _(", terminated by signal %d.\n"),
640 WTERMSIG (child_ret
));
642 fprintf (stderr
, ".\n");
645 /* We have the child status, so exit with that code. */
652 do_exit (int child_ret
, int errnum
, const char *format
, ...)
656 int ret
= write (parent_fd
, &child_ret
, sizeof (child_ret
));
657 assert (ret
== sizeof (child_ret
));
663 /* Emulate error() since we don't have a va_list variant for it. */
668 fprintf (stderr
, "%s: ", program_invocation_name
);
670 va_start (argp
, format
);
671 vfprintf (stderr
, format
, argp
);
674 fprintf (stderr
, ": %s\n", strerror (errnum
));
683 notify_parent (int child_ret
)
688 int ret
= write (parent_fd
, &child_ret
, sizeof (child_ret
));
689 assert (ret
== sizeof (child_ret
));