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>
46 #include "../nss/nsswitch.h"
47 #include <device-nrs.h>
49 # include <sys/inotify.h>
52 /* Get libc version number. */
55 #define PACKAGE _libc_intl_domainname
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". */
65 pthread_cond_t thread_exit_cv
;
66 pthread_mutex_t mutex
;
69 thread_info_t thread_info
;
77 /* Running in background as daemon. */
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. */
83 /* Run in foreground in debug mode. */
87 static run_modes run_mode
= RUN_DAEMONIZE
;
89 static const char *conffile
= _PATH_NSCDCONF
;
93 uintptr_t pagesize_m1
;
97 time_t restart_interval
= RESTART_INTERVAL
;
102 static int check_pid (const char *file
);
103 static int write_pid (const char *file
);
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
;
109 /* Function to print some extra text in the help message. */
110 static char *more_help (int key
, const char *text
, void *input
);
112 /* Definitions of arguments for argp functions. */
113 static const struct argp_option options
[] =
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
}
131 /* Short description of program. */
132 static const char doc
[] = N_("Name Service Cache Daemon.");
134 /* Prototype for option handler. */
135 static error_t
parse_opt (int key
, char *arg
, struct argp_state
*state
);
137 /* Data structure to communicate with argp functions. */
138 static struct argp argp
=
140 options
, parse_opt
, NULL
, doc
, NULL
, more_help
143 /* True if only statistics are requested. */
144 static bool get_stats
;
147 main (int argc
, char **argv
)
151 /* Set locale via LC_ALL. */
152 setlocale (LC_ALL
, "");
153 /* Set the text message domain. */
154 textdomain (PACKAGE
);
156 /* Determine if the kernel has SELinux support. */
157 nscd_selinux_enabled (&selinux_enabled
);
159 /* Parse and process arguments. */
160 argp_parse (&argp
, argc
, argv
, 0, &remaining
, NULL
);
162 if (remaining
!= argc
)
164 error (0, 0, gettext ("wrong number of arguments"));
165 argp_help (&argp
, stdout
, ARGP_HELP_SEE
, program_invocation_short_name
);
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
173 error (EXIT_FAILURE
, 0,
174 _("failure while reading configuration file; this is fatal"));
176 /* Do we only get statistics? */
178 /* Does not return. */
179 receive_print_stats ();
181 /* Check if we are already running. */
182 if (check_pid (_PATH_NSCDPID
))
183 error (EXIT_FAILURE
, 0, _("already running"));
185 /* Remember when we started. */
186 start_time
= time (NULL
);
188 /* Determine page size. */
189 pagesize_m1
= getpagesize () - 1;
191 if (run_mode
== RUN_DAEMONIZE
|| run_mode
== RUN_FOREGROUND
)
196 /* Behave like a daemon. */
197 if (run_mode
== RUN_DAEMONIZE
)
201 error (EXIT_FAILURE
, errno
, _("cannot fork"));
206 int nullfd
= open (_PATH_DEVNULL
, O_RDWR
);
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
)
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
);
227 /* Ugh, somebody is trying to play a trick on us. */
232 int min_close_fd
= nullfd
== -1 ? 0 : STDERR_FILENO
+ 1;
234 DIR *d
= opendir ("/proc/self/fd");
237 struct dirent64
*dirent
;
238 int dfdn
= dirfd (d
);
240 while ((dirent
= readdir64 (d
)) != NULL
)
243 long int fdn
= strtol (dirent
->d_name
, &endp
, 10);
245 if (*endp
== '\0' && fdn
!= dfdn
&& fdn
>= min_close_fd
)
252 for (i
= min_close_fd
; i
< getdtablesize (); i
++)
257 if (chdir ("/") != 0)
258 error (EXIT_FAILURE
, errno
,
259 _("cannot change current working directory to \"/\""));
261 openlog ("nscd", LOG_CONS
| LOG_ODELAY
, LOG_DAEMON
);
263 if (write_pid (_PATH_NSCDPID
) < 0)
264 dbg_log ("%s: %s", _PATH_NSCDPID
, strerror (errno
));
266 if (!init_logfile ())
267 dbg_log (_("Could not create log file"));
269 /* Ignore job control signals. */
270 signal (SIGTTOU
, SIG_IGN
);
271 signal (SIGTTIN
, SIG_IGN
);
272 signal (SIGTSTP
, SIG_IGN
);
275 /* In debug mode we are not paranoid. */
278 signal (SIGINT
, termination_handler
);
279 signal (SIGQUIT
, termination_handler
);
280 signal (SIGTERM
, termination_handler
);
281 signal (SIGPIPE
, SIG_IGN
);
283 /* Cleanup files created by a previous 'bind'. */
284 unlink (_PATH_NSCDSOCKET
);
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
)
292 inotify_fd
= inotify_init ();
293 if (inotify_fd
!= -1)
294 fcntl (inotify_fd
, F_SETFL
, O_RDONLY
| O_NONBLOCK
);
300 /* Make sure we do not get recursive calls. */
301 __nss_disable_nscd (register_traced_file
);
304 /* Init databases. */
307 /* Start the SELinux AVC. */
311 /* Handle incoming requests */
318 /* Handle program arguments. */
320 parse_opt (int key
, char *arg
, struct argp_state
*state
)
326 run_mode
= RUN_DEBUG
;
330 run_mode
= RUN_FOREGROUND
;
339 error (4, 0, _("Only root is allowed to use this option!"));
341 int sock
= nscd_open_socket ();
347 req
.version
= NSCD_VERSION
;
351 ssize_t nbytes
= TEMP_FAILURE_RETRY (send (sock
, &req
,
352 sizeof (request_header
),
355 exit (nbytes
!= sizeof (request_header
) ? EXIT_FAILURE
: EXIT_SUCCESS
);
364 error (4, 0, _("Only root is allowed to use this option!"));
367 int sock
= nscd_open_socket ();
373 for (cnt
= pwddb
; cnt
< lastdb
; ++cnt
)
374 if (strcmp (arg
, dbnames
[cnt
]) == 0)
379 argp_error (state
, _("'%s' is not a known database"), arg
);
383 size_t arg_len
= strlen (arg
) + 1;
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
);
395 ssize_t nbytes
= TEMP_FAILURE_RETRY (send (sock
, &reqdata
,
396 sizeof (request_header
)
400 if (nbytes
!= sizeof (request_header
) + arg_len
)
404 error (EXIT_FAILURE
, err
, _("write incomplete"));
407 /* Wait for ack. Older nscd just closed the socket when
408 prune_cache finished, silently ignore that. */
410 nbytes
= TEMP_FAILURE_RETRY (read (sock
, &resp
, sizeof (resp
)));
411 if (nbytes
!= 0 && nbytes
!= sizeof (resp
))
415 error (EXIT_FAILURE
, err
, _("cannot read invalidate ACK"));
421 error (EXIT_FAILURE
, resp
, _("invalidation failed"));
427 nthreads
= atol (arg
);
431 error (0, 0, _("secure services not implemented anymore"));
435 return ARGP_ERR_UNKNOWN
;
441 /* Print bug-reporting information in the help message. */
443 more_help (int key
, const char *text
, void *input
)
445 char *tables
, *tp
= NULL
;
449 case ARGP_KEY_HELP_EXTRA
:
453 tables
= xmalloc (sizeof (dbnames
) + 1);
454 for (cnt
= 0; cnt
< lastdb
; cnt
++)
456 strcat (tables
, dbnames
[cnt
]);
457 strcat (tables
, " ");
461 /* We print some extra information. */
462 if (asprintf (&tp
, gettext ("\
466 For bug reporting instructions, please see:\n\
468 "), tables
, REPORT_BUGS_TO
) < 0)
477 return (char *) text
;
480 /* Print the version information. */
482 print_version (FILE *stream
, struct argp_state
*state
)
484 fprintf (stream
, "nscd %s%s\n", PKGVERSION
, VERSION
);
485 fprintf (stream
, gettext ("\
486 Copyright (C) %s Free Software Foundation, Inc.\n\
487 This is free software; see the source for copying conditions. There is NO\n\
488 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
490 fprintf (stream
, gettext ("Written by %s.\n"),
491 "Thorsten Kukuk and Ulrich Drepper");
495 /* Create a socket connected to a name. */
497 nscd_open_socket (void)
499 struct sockaddr_un addr
;
502 sock
= socket (PF_UNIX
, SOCK_STREAM
, 0);
506 addr
.sun_family
= AF_UNIX
;
507 assert (sizeof (addr
.sun_path
) >= sizeof (_PATH_NSCDSOCKET
));
508 strcpy (addr
.sun_path
, _PATH_NSCDSOCKET
);
509 if (connect (sock
, (struct sockaddr
*) &addr
, sizeof (addr
)) < 0)
521 termination_handler (int signum
)
525 /* Clean up the file created by 'bind'. */
526 unlink (_PATH_NSCDSOCKET
);
528 /* Clean up pid file. */
529 unlink (_PATH_NSCDPID
);
531 // XXX Terminate threads.
533 /* Synchronize memory. */
534 for (int cnt
= 0; cnt
< lastdb
; ++cnt
)
536 if (!dbs
[cnt
].enabled
|| dbs
[cnt
].head
== NULL
)
539 /* Make sure nobody keeps using the database. */
540 dbs
[cnt
].head
->timestamp
= 0;
542 if (dbs
[cnt
].persistent
)
544 msync (dbs
[cnt
].head
, dbs
[cnt
].memsize
, MS_ASYNC
);
547 _exit (EXIT_SUCCESS
);
550 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
552 check_pid (const char *file
)
556 fp
= fopen (file
, "r");
562 n
= fscanf (fp
, "%d", &pid
);
565 /* If we cannot parse the file default to assuming nscd runs.
566 If the PID is alive, assume it is running. That all unless
567 the PID is the same as the current process' since tha latter
568 can mean we re-exec. */
569 if ((n
!= 1 || kill (pid
, 0) == 0) && pid
!= getpid ())
576 /* Write the current process id to the file FILE.
577 Returns 0 if successful, -1 if not. */
579 write_pid (const char *file
)
583 fp
= fopen (file
, "w");
587 fprintf (fp
, "%d\n", getpid ());
589 int result
= fflush (fp
) || ferror (fp
) ? -1 : 0;