1 /* Copyright (c) 1998-2023 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published
6 by the Free Software Foundation; version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, see <https://www.gnu.org/licenses/>. */
17 /* nscd - Name Service Cache Daemon. Caches passwd, group, and hosts. */
37 #include <sys/socket.h>
47 #include "../nss/nsswitch.h"
48 #include <device-nrs.h>
50 # include <sys/inotify.h>
52 #include <kernel-features.h>
54 /* Get libc version number. */
57 #define PACKAGE _libc_intl_domainname
65 /* Running in background as daemon. */
67 /* Running in foreground but otherwise behave like a daemon,
68 i.e., detach from terminal and use syslog. This allows
69 better integration with services like systemd. */
71 /* Run in foreground in debug mode. */
75 static run_modes run_mode
= RUN_DAEMONIZE
;
77 static const char *conffile
= _PATH_NSCDCONF
;
79 static const char *print_cache
= NULL
;
83 uintptr_t pagesize_m1
;
87 time_t restart_interval
= RESTART_INTERVAL
;
92 static int check_pid (const char *file
);
93 static int write_pid (const char *file
);
94 static int monitor_child (int fd
);
96 /* Name and version of program. */
97 static void print_version (FILE *stream
, struct argp_state
*state
);
98 void (*argp_program_version_hook
) (FILE *, struct argp_state
*) = print_version
;
100 /* Function to print some extra text in the help message. */
101 static char *more_help (int key
, const char *text
, void *input
);
103 /* Definitions of arguments for argp functions. */
104 static const struct argp_option options
[] =
106 { "config-file", 'f', N_("NAME"), 0,
107 N_("Read configuration data from NAME") },
108 { "debug", 'd', NULL
, 0,
109 N_("Do not fork and display messages on the current tty") },
110 { "print", 'p', N_("NAME"), 0,
111 N_("Print contents of the offline cache file NAME") },
112 { "foreground", 'F', NULL
, 0,
113 N_("Do not fork, but otherwise behave like a daemon") },
114 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
115 { "shutdown", 'K', NULL
, 0, N_("Shut the server down") },
116 { "statistics", 'g', NULL
, 0, N_("Print current configuration statistics") },
117 { "invalidate", 'i', N_("TABLE"), 0,
118 N_("Invalidate the specified cache") },
119 { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN
,
120 N_("Use separate cache for each user")},
121 { NULL
, 0, NULL
, 0, NULL
}
124 /* Short description of program. */
125 static const char doc
[] = N_("Name Service Cache Daemon.");
127 /* Prototype for option handler. */
128 static error_t
parse_opt (int key
, char *arg
, struct argp_state
*state
);
130 /* Data structure to communicate with argp functions. */
131 static struct argp argp
=
133 options
, parse_opt
, NULL
, doc
, NULL
, more_help
136 /* True if only statistics are requested. */
137 static bool get_stats
;
138 static int parent_fd
= -1;
141 main (int argc
, char **argv
)
145 /* Set locale via LC_ALL. */
146 setlocale (LC_ALL
, "");
147 /* Set the text message domain. */
148 textdomain (PACKAGE
);
150 /* Determine if the kernel has SELinux support. */
151 nscd_selinux_enabled (&selinux_enabled
);
153 /* Parse and process arguments. */
154 argp_parse (&argp
, argc
, argv
, 0, &remaining
, NULL
);
156 if (remaining
!= argc
)
158 error (0, 0, gettext ("wrong number of arguments"));
159 argp_help (&argp
, stdout
, ARGP_HELP_SEE
, program_invocation_short_name
);
163 /* Print the contents of the indicated cache file. */
164 if (print_cache
!= NULL
)
165 /* Does not return. */
166 nscd_print_cache (print_cache
);
168 /* Read the configuration file. */
169 if (nscd_parse_file (conffile
, dbs
) != 0)
170 /* We couldn't read the configuration file. We don't start the
172 error (EXIT_FAILURE
, 0,
173 _("failure while reading configuration file; this is fatal"));
175 /* Do we only get statistics? */
177 /* Does not return. */
178 receive_print_stats ();
180 /* Check if we are already running. */
181 if (check_pid (_PATH_NSCDPID
))
182 error (EXIT_FAILURE
, 0, _("already running"));
184 /* Remember when we started. */
185 start_time
= time (NULL
);
187 /* Determine page size. */
188 pagesize_m1
= getpagesize () - 1;
190 if (run_mode
== RUN_DAEMONIZE
|| run_mode
== RUN_FOREGROUND
)
195 /* Behave like a daemon. */
196 if (run_mode
== RUN_DAEMONIZE
)
201 error (EXIT_FAILURE
, errno
,
202 _("cannot create a pipe to talk to the child"));
206 error (EXIT_FAILURE
, errno
, _("cannot fork"));
209 /* The parent only reads from the child. */
211 exit (monitor_child (fd
[0]));
215 /* The child only writes to the parent. */
221 int nullfd
= open (_PATH_DEVNULL
, O_RDWR
);
226 if (fstat64 (nullfd
, &st
) == 0 && S_ISCHR (st
.st_mode
) != 0
227 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
228 && st
.st_rdev
== makedev (DEV_NULL_MAJOR
, DEV_NULL_MINOR
)
232 /* It is the /dev/null special device alright. */
233 (void) dup2 (nullfd
, STDIN_FILENO
);
234 (void) dup2 (nullfd
, STDOUT_FILENO
);
235 (void) dup2 (nullfd
, STDERR_FILENO
);
242 /* Ugh, somebody is trying to play a trick on us. */
247 int min_close_fd
= nullfd
== -1 ? 0 : STDERR_FILENO
+ 1;
249 DIR *d
= opendir ("/proc/self/fd");
252 struct dirent64
*dirent
;
253 int dfdn
= dirfd (d
);
255 while ((dirent
= readdir64 (d
)) != NULL
)
258 long int fdn
= strtol (dirent
->d_name
, &endp
, 10);
260 if (*endp
== '\0' && fdn
!= dfdn
&& fdn
>= min_close_fd
268 for (i
= min_close_fd
; i
< getdtablesize (); i
++)
274 if (chdir ("/") != 0)
275 do_exit (EXIT_FAILURE
, errno
,
276 _("cannot change current working directory to \"/\""));
278 openlog ("nscd", LOG_CONS
| LOG_ODELAY
, LOG_DAEMON
);
280 if (write_pid (_PATH_NSCDPID
) < 0)
281 dbg_log ("%s: %s", _PATH_NSCDPID
, strerror (errno
));
283 if (!init_logfile ())
284 dbg_log (_("Could not create log file"));
286 /* Ignore job control signals. */
287 signal (SIGTTOU
, SIG_IGN
);
288 signal (SIGTTIN
, SIG_IGN
);
289 signal (SIGTSTP
, SIG_IGN
);
292 /* In debug mode we are not paranoid. */
295 signal (SIGINT
, termination_handler
);
296 signal (SIGQUIT
, termination_handler
);
297 signal (SIGTERM
, termination_handler
);
298 signal (SIGPIPE
, SIG_IGN
);
300 /* Cleanup files created by a previous 'bind'. */
301 unlink (_PATH_NSCDSOCKET
);
304 /* Use inotify to recognize changed files. */
305 inotify_fd
= inotify_init1 (IN_NONBLOCK
);
306 # ifndef __ASSUME_IN_NONBLOCK
307 if (inotify_fd
== -1 && errno
== ENOSYS
)
309 inotify_fd
= inotify_init ();
310 if (inotify_fd
!= -1)
311 fcntl (inotify_fd
, F_SETFL
, O_RDONLY
| O_NONBLOCK
);
317 /* Make sure we do not get recursive calls. */
318 __nss_disable_nscd (register_traced_file
);
321 /* Init databases. */
324 /* Start the SELinux AVC. */
328 /* Handle incoming requests */
335 static void __attribute__ ((noreturn
))
336 invalidate_db (const char *dbname
)
338 int sock
= nscd_open_socket ();
343 size_t dbname_len
= strlen (dbname
) + 1;
344 size_t reqlen
= sizeof (request_header
) + dbname_len
;
349 } *reqdata
= alloca (reqlen
);
351 reqdata
->req
.key_len
= dbname_len
;
352 reqdata
->req
.version
= NSCD_VERSION
;
353 reqdata
->req
.type
= INVALIDATE
;
354 memcpy (reqdata
->dbname
, dbname
, dbname_len
);
356 ssize_t nbytes
= TEMP_FAILURE_RETRY (send (sock
, reqdata
, reqlen
,
359 if (nbytes
!= reqlen
)
363 error (EXIT_FAILURE
, err
, _("write incomplete"));
366 /* Wait for ack. Older nscd just closed the socket when
367 prune_cache finished, silently ignore that. */
369 nbytes
= TEMP_FAILURE_RETRY (read (sock
, &resp
, sizeof (resp
)));
370 if (nbytes
!= 0 && nbytes
!= sizeof (resp
))
374 error (EXIT_FAILURE
, err
, _("cannot read invalidate ACK"));
380 error (EXIT_FAILURE
, resp
, _("invalidation failed"));
385 static void __attribute__ ((noreturn
))
388 int sock
= nscd_open_socket ();
394 req
.version
= NSCD_VERSION
;
398 ssize_t nbytes
= TEMP_FAILURE_RETRY (send (sock
, &req
, sizeof req
,
401 exit (nbytes
!= sizeof (request_header
) ? EXIT_FAILURE
: EXIT_SUCCESS
);
404 /* Handle program arguments. */
406 parse_opt (int key
, char *arg
, struct argp_state
*state
)
412 run_mode
= RUN_DEBUG
;
420 run_mode
= RUN_FOREGROUND
;
429 error (4, 0, _("Only root is allowed to use this option!"));
440 /* Validate the database name. */
443 for (cnt
= pwddb
; cnt
< lastdb
; ++cnt
)
444 if (strcmp (arg
, dbnames
[cnt
]) == 0)
449 argp_error (state
, _("'%s' is not a known database"), arg
);
454 error (4, 0, _("Only root is allowed to use this option!"));
460 nthreads
= atol (arg
);
464 error (0, 0, _("secure services not implemented anymore"));
468 return ARGP_ERR_UNKNOWN
;
474 /* Print bug-reporting information in the help message. */
476 more_help (int key
, const char *text
, void *input
)
480 case ARGP_KEY_HELP_EXTRA
:
482 /* We print some extra information. */
484 char *tables
= xstrdup (dbnames
[0]);
485 for (dbtype i
= 1; i
< lastdb
; ++i
)
488 if (asprintf (&more_tables
, "%s %s", tables
, dbnames
[i
]) < 0)
491 if (more_tables
== NULL
)
493 tables
= more_tables
;
497 if (asprintf (&tp
, gettext ("\
501 For bug reporting instructions, please see:\n\
503 "), tables
, REPORT_BUGS_TO
) < 0)
513 return (char *) text
;
516 /* Print the version information. */
518 print_version (FILE *stream
, struct argp_state
*state
)
520 fprintf (stream
, "nscd %s%s\n", PKGVERSION
, VERSION
);
521 fprintf (stream
, gettext ("\
522 Copyright (C) %s Free Software Foundation, Inc.\n\
523 This is free software; see the source for copying conditions. There is NO\n\
524 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
526 fprintf (stream
, gettext ("Written by %s.\n"),
527 "Thorsten Kukuk and Ulrich Drepper");
531 /* Create a socket connected to a name. */
533 nscd_open_socket (void)
535 struct sockaddr_un addr
;
538 sock
= socket (PF_UNIX
, SOCK_STREAM
, 0);
542 addr
.sun_family
= AF_UNIX
;
543 assert (sizeof (addr
.sun_path
) >= sizeof (_PATH_NSCDSOCKET
));
544 strcpy (addr
.sun_path
, _PATH_NSCDSOCKET
);
545 if (connect (sock
, (struct sockaddr
*) &addr
, sizeof (addr
)) < 0)
557 termination_handler (int signum
)
561 /* Clean up the file created by 'bind'. */
562 unlink (_PATH_NSCDSOCKET
);
564 /* Clean up pid file. */
565 unlink (_PATH_NSCDPID
);
567 // XXX Terminate threads.
569 /* Synchronize memory. */
570 for (int cnt
= 0; cnt
< lastdb
; ++cnt
)
572 if (!dbs
[cnt
].enabled
|| dbs
[cnt
].head
== NULL
)
575 /* Make sure nobody keeps using the database. */
576 dbs
[cnt
].head
->timestamp
= 0;
578 if (dbs
[cnt
].persistent
)
580 msync (dbs
[cnt
].head
, dbs
[cnt
].memsize
, MS_ASYNC
);
583 _exit (EXIT_SUCCESS
);
586 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
588 check_pid (const char *file
)
592 fp
= fopen (file
, "r");
598 n
= fscanf (fp
, "%d", &pid
);
601 /* If we cannot parse the file default to assuming nscd runs.
602 If the PID is alive, assume it is running. That all unless
603 the PID is the same as the current process' since the latter
604 can mean we re-exec. */
605 if ((n
!= 1 || kill (pid
, 0) == 0) && pid
!= getpid ())
612 /* Write the current process id to the file FILE.
613 Returns 0 if successful, -1 if not. */
615 write_pid (const char *file
)
619 fp
= fopen (file
, "w");
623 fprintf (fp
, "%d\n", getpid ());
625 int result
= fflush (fp
) || ferror (fp
) ? -1 : 0;
633 monitor_child (int fd
)
636 int ret
= read (fd
, &child_ret
, sizeof (child_ret
));
638 /* The child terminated with an error, either via exit or some other abnormal
639 method, like a segfault. */
640 if (ret
<= 0 || child_ret
!= 0)
643 int err
= wait (&status
);
647 fprintf (stderr
, _("'wait' failed\n"));
651 if (WIFEXITED (status
))
653 child_ret
= WEXITSTATUS (status
);
654 fprintf (stderr
, _("child exited with status %d\n"), child_ret
);
656 if (WIFSIGNALED (status
))
658 child_ret
= WTERMSIG (status
);
659 fprintf (stderr
, _("child terminated by signal %d\n"), child_ret
);
663 /* We have the child status, so exit with that code. */
670 do_exit (int child_ret
, int errnum
, const char *format
, ...)
674 int ret
__attribute__ ((unused
));
675 ret
= write (parent_fd
, &child_ret
, sizeof (child_ret
));
676 assert (ret
== sizeof (child_ret
));
682 /* Emulate error() since we don't have a va_list variant for it. */
687 fprintf (stderr
, "%s: ", program_invocation_name
);
689 va_start (argp
, format
);
690 vfprintf (stderr
, format
, argp
);
693 fprintf (stderr
, ": %s\n", strerror (errnum
));
702 notify_parent (int child_ret
)
707 int ret
__attribute__ ((unused
));
708 ret
= write (parent_fd
, &child_ret
, sizeof (child_ret
));
709 assert (ret
== sizeof (child_ret
));