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>
53 #include <kernel-features.h>
55 /* Get libc version number. */
58 #define PACKAGE _libc_intl_domainname
60 /* Structure used by main() thread to keep track of the number of
61 active threads. Used to limit how many threads it will create
62 and under a shutdown condition to wait till all in-progress
63 requests have finished before "turning off the lights". */
68 pthread_cond_t thread_exit_cv
;
69 pthread_mutex_t mutex
;
72 thread_info_t thread_info
;
80 /* Running in background as daemon. */
82 /* Running in foreground but otherwise behave like a daemon,
83 i.e., detach from terminal and use syslog. This allows
84 better integration with services like systemd. */
86 /* Run in foreground in debug mode. */
90 static run_modes run_mode
= RUN_DAEMONIZE
;
92 static const char *conffile
= _PATH_NSCDCONF
;
96 uintptr_t pagesize_m1
;
100 time_t restart_interval
= RESTART_INTERVAL
;
105 static int check_pid (const char *file
);
106 static int write_pid (const char *file
);
107 static int monitor_child (int fd
);
109 /* Name and version of program. */
110 static void print_version (FILE *stream
, struct argp_state
*state
);
111 void (*argp_program_version_hook
) (FILE *, struct argp_state
*) = print_version
;
113 /* Function to print some extra text in the help message. */
114 static char *more_help (int key
, const char *text
, void *input
);
116 /* Definitions of arguments for argp functions. */
117 static const struct argp_option options
[] =
119 { "config-file", 'f', N_("NAME"), 0,
120 N_("Read configuration data from NAME") },
121 { "debug", 'd', NULL
, 0,
122 N_("Do not fork and display messages on the current tty") },
123 { "foreground", 'F', NULL
, 0,
124 N_("Do not fork, but otherwise behave like a daemon") },
125 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
126 { "shutdown", 'K', NULL
, 0, N_("Shut the server down") },
127 { "statistics", 'g', NULL
, 0, N_("Print current configuration statistics") },
128 { "invalidate", 'i', N_("TABLE"), 0,
129 N_("Invalidate the specified cache") },
130 { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN
,
131 N_("Use separate cache for each user")},
132 { NULL
, 0, NULL
, 0, NULL
}
135 /* Short description of program. */
136 static const char doc
[] = N_("Name Service Cache Daemon.");
138 /* Prototype for option handler. */
139 static error_t
parse_opt (int key
, char *arg
, struct argp_state
*state
);
141 /* Data structure to communicate with argp functions. */
142 static struct argp argp
=
144 options
, parse_opt
, NULL
, doc
, NULL
, more_help
147 /* True if only statistics are requested. */
148 static bool get_stats
;
149 static int parent_fd
= -1;
152 main (int argc
, char **argv
)
156 /* Set locale via LC_ALL. */
157 setlocale (LC_ALL
, "");
158 /* Set the text message domain. */
159 textdomain (PACKAGE
);
161 /* Determine if the kernel has SELinux support. */
162 nscd_selinux_enabled (&selinux_enabled
);
164 /* Parse and process arguments. */
165 argp_parse (&argp
, argc
, argv
, 0, &remaining
, NULL
);
167 if (remaining
!= argc
)
169 error (0, 0, gettext ("wrong number of arguments"));
170 argp_help (&argp
, stdout
, ARGP_HELP_SEE
, program_invocation_short_name
);
174 /* Read the configuration file. */
175 if (nscd_parse_file (conffile
, dbs
) != 0)
176 /* We couldn't read the configuration file. We don't start the
178 error (EXIT_FAILURE
, 0,
179 _("failure while reading configuration file; this is fatal"));
181 /* Do we only get statistics? */
183 /* Does not return. */
184 receive_print_stats ();
186 /* Check if we are already running. */
187 if (check_pid (_PATH_NSCDPID
))
188 error (EXIT_FAILURE
, 0, _("already running"));
190 /* Remember when we started. */
191 start_time
= time (NULL
);
193 /* Determine page size. */
194 pagesize_m1
= getpagesize () - 1;
196 if (run_mode
== RUN_DAEMONIZE
|| run_mode
== RUN_FOREGROUND
)
201 /* Behave like a daemon. */
202 if (run_mode
== RUN_DAEMONIZE
)
207 error (EXIT_FAILURE
, errno
,
208 _("cannot create a pipe to talk to the child"));
212 error (EXIT_FAILURE
, errno
, _("cannot fork"));
215 /* The parent only reads from the child. */
217 exit (monitor_child (fd
[0]));
221 /* The child only writes to the parent. */
227 int nullfd
= open (_PATH_DEVNULL
, O_RDWR
);
232 if (fstat64 (nullfd
, &st
) == 0 && S_ISCHR (st
.st_mode
) != 0
233 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
234 && st
.st_rdev
== makedev (DEV_NULL_MAJOR
, DEV_NULL_MINOR
)
238 /* It is the /dev/null special device alright. */
239 (void) dup2 (nullfd
, STDIN_FILENO
);
240 (void) dup2 (nullfd
, STDOUT_FILENO
);
241 (void) dup2 (nullfd
, STDERR_FILENO
);
248 /* Ugh, somebody is trying to play a trick on us. */
253 int min_close_fd
= nullfd
== -1 ? 0 : STDERR_FILENO
+ 1;
255 DIR *d
= opendir ("/proc/self/fd");
258 struct dirent64
*dirent
;
259 int dfdn
= dirfd (d
);
261 while ((dirent
= readdir64 (d
)) != NULL
)
264 long int fdn
= strtol (dirent
->d_name
, &endp
, 10);
266 if (*endp
== '\0' && fdn
!= dfdn
&& fdn
>= min_close_fd
274 for (i
= min_close_fd
; i
< getdtablesize (); i
++)
280 if (chdir ("/") != 0)
281 do_exit (EXIT_FAILURE
, errno
,
282 _("cannot change current working directory to \"/\""));
284 openlog ("nscd", LOG_CONS
| LOG_ODELAY
, LOG_DAEMON
);
286 if (write_pid (_PATH_NSCDPID
) < 0)
287 dbg_log ("%s: %s", _PATH_NSCDPID
, strerror (errno
));
289 if (!init_logfile ())
290 dbg_log (_("Could not create log file"));
292 /* Ignore job control signals. */
293 signal (SIGTTOU
, SIG_IGN
);
294 signal (SIGTTIN
, SIG_IGN
);
295 signal (SIGTSTP
, SIG_IGN
);
298 /* In debug mode we are not paranoid. */
301 signal (SIGINT
, termination_handler
);
302 signal (SIGQUIT
, termination_handler
);
303 signal (SIGTERM
, termination_handler
);
304 signal (SIGPIPE
, SIG_IGN
);
306 /* Cleanup files created by a previous 'bind'. */
307 unlink (_PATH_NSCDSOCKET
);
310 /* Use inotify to recognize changed files. */
311 inotify_fd
= inotify_init1 (IN_NONBLOCK
);
312 # ifndef __ASSUME_IN_NONBLOCK
313 if (inotify_fd
== -1 && errno
== ENOSYS
)
315 inotify_fd
= inotify_init ();
316 if (inotify_fd
!= -1)
317 fcntl (inotify_fd
, F_SETFL
, O_RDONLY
| O_NONBLOCK
);
323 /* Make sure we do not get recursive calls. */
324 __nss_disable_nscd (register_traced_file
);
327 /* Init databases. */
330 /* Start the SELinux AVC. */
334 /* Handle incoming requests */
341 /* Handle program arguments. */
343 parse_opt (int key
, char *arg
, struct argp_state
*state
)
349 run_mode
= RUN_DEBUG
;
353 run_mode
= RUN_FOREGROUND
;
362 error (4, 0, _("Only root is allowed to use this option!"));
364 int sock
= nscd_open_socket ();
370 req
.version
= NSCD_VERSION
;
374 ssize_t nbytes
= TEMP_FAILURE_RETRY (send (sock
, &req
,
375 sizeof (request_header
),
378 exit (nbytes
!= sizeof (request_header
) ? EXIT_FAILURE
: EXIT_SUCCESS
);
387 error (4, 0, _("Only root is allowed to use this option!"));
390 int sock
= nscd_open_socket ();
396 for (cnt
= pwddb
; cnt
< lastdb
; ++cnt
)
397 if (strcmp (arg
, dbnames
[cnt
]) == 0)
402 argp_error (state
, _("'%s' is not a known database"), arg
);
406 size_t arg_len
= strlen (arg
) + 1;
413 reqdata
.req
.key_len
= strlen (arg
) + 1;
414 reqdata
.req
.version
= NSCD_VERSION
;
415 reqdata
.req
.type
= INVALIDATE
;
416 memcpy (reqdata
.arg
, arg
, arg_len
);
418 ssize_t nbytes
= TEMP_FAILURE_RETRY (send (sock
, &reqdata
,
419 sizeof (request_header
)
423 if (nbytes
!= sizeof (request_header
) + arg_len
)
427 error (EXIT_FAILURE
, err
, _("write incomplete"));
430 /* Wait for ack. Older nscd just closed the socket when
431 prune_cache finished, silently ignore that. */
433 nbytes
= TEMP_FAILURE_RETRY (read (sock
, &resp
, sizeof (resp
)));
434 if (nbytes
!= 0 && nbytes
!= sizeof (resp
))
438 error (EXIT_FAILURE
, err
, _("cannot read invalidate ACK"));
444 error (EXIT_FAILURE
, resp
, _("invalidation failed"));
450 nthreads
= atol (arg
);
454 error (0, 0, _("secure services not implemented anymore"));
458 return ARGP_ERR_UNKNOWN
;
464 /* Print bug-reporting information in the help message. */
466 more_help (int key
, const char *text
, void *input
)
468 char *tables
, *tp
= NULL
;
472 case ARGP_KEY_HELP_EXTRA
:
476 tables
= xmalloc (sizeof (dbnames
) + 1);
477 for (cnt
= 0; cnt
< lastdb
; cnt
++)
479 strcat (tables
, dbnames
[cnt
]);
480 strcat (tables
, " ");
484 /* We print some extra information. */
485 if (asprintf (&tp
, gettext ("\
489 For bug reporting instructions, please see:\n\
491 "), tables
, REPORT_BUGS_TO
) < 0)
500 return (char *) text
;
503 /* Print the version information. */
505 print_version (FILE *stream
, struct argp_state
*state
)
507 fprintf (stream
, "nscd %s%s\n", PKGVERSION
, VERSION
);
508 fprintf (stream
, gettext ("\
509 Copyright (C) %s Free Software Foundation, Inc.\n\
510 This is free software; see the source for copying conditions. There is NO\n\
511 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
513 fprintf (stream
, gettext ("Written by %s.\n"),
514 "Thorsten Kukuk and Ulrich Drepper");
518 /* Create a socket connected to a name. */
520 nscd_open_socket (void)
522 struct sockaddr_un addr
;
525 sock
= socket (PF_UNIX
, SOCK_STREAM
, 0);
529 addr
.sun_family
= AF_UNIX
;
530 assert (sizeof (addr
.sun_path
) >= sizeof (_PATH_NSCDSOCKET
));
531 strcpy (addr
.sun_path
, _PATH_NSCDSOCKET
);
532 if (connect (sock
, (struct sockaddr
*) &addr
, sizeof (addr
)) < 0)
544 termination_handler (int signum
)
548 /* Clean up the file created by 'bind'. */
549 unlink (_PATH_NSCDSOCKET
);
551 /* Clean up pid file. */
552 unlink (_PATH_NSCDPID
);
554 // XXX Terminate threads.
556 /* Synchronize memory. */
557 for (int cnt
= 0; cnt
< lastdb
; ++cnt
)
559 if (!dbs
[cnt
].enabled
|| dbs
[cnt
].head
== NULL
)
562 /* Make sure nobody keeps using the database. */
563 dbs
[cnt
].head
->timestamp
= 0;
565 if (dbs
[cnt
].persistent
)
567 msync (dbs
[cnt
].head
, dbs
[cnt
].memsize
, MS_ASYNC
);
570 _exit (EXIT_SUCCESS
);
573 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
575 check_pid (const char *file
)
579 fp
= fopen (file
, "r");
585 n
= fscanf (fp
, "%d", &pid
);
588 /* If we cannot parse the file default to assuming nscd runs.
589 If the PID is alive, assume it is running. That all unless
590 the PID is the same as the current process' since tha latter
591 can mean we re-exec. */
592 if ((n
!= 1 || kill (pid
, 0) == 0) && pid
!= getpid ())
599 /* Write the current process id to the file FILE.
600 Returns 0 if successful, -1 if not. */
602 write_pid (const char *file
)
606 fp
= fopen (file
, "w");
610 fprintf (fp
, "%d\n", getpid ());
612 int result
= fflush (fp
) || ferror (fp
) ? -1 : 0;
620 monitor_child (int fd
)
623 int ret
= read (fd
, &child_ret
, sizeof (child_ret
));
625 /* The child terminated with an error, either via exit or some other abnormal
626 method, like a segfault. */
627 if (ret
<= 0 || child_ret
!= 0)
629 int err
= wait (&child_ret
);
633 fprintf (stderr
, _("wait failed"));
637 fprintf (stderr
, _("child exited with status %d"),
638 WEXITSTATUS (child_ret
));
639 if (WIFSIGNALED (child_ret
))
640 fprintf (stderr
, _(", terminated by signal %d.\n"),
641 WTERMSIG (child_ret
));
643 fprintf (stderr
, ".\n");
646 /* We have the child status, so exit with that code. */
653 do_exit (int child_ret
, int errnum
, const char *format
, ...)
657 int ret
= write (parent_fd
, &child_ret
, sizeof (child_ret
));
658 assert (ret
== sizeof (child_ret
));
664 /* Emulate error() since we don't have a va_list variant for it. */
669 fprintf (stderr
, "%s: ", program_invocation_name
);
671 va_start (argp
, format
);
672 vfprintf (stderr
, format
, argp
);
675 fprintf (stderr
, ": %s\n", strerror (errnum
));
684 notify_parent (int child_ret
)
689 int ret
= write (parent_fd
, &child_ret
, sizeof (child_ret
));
690 assert (ret
== sizeof (child_ret
));