1 /* Copyright (c) 1998-2003, 2004, 2005, 2006 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 version 2 as
7 published by the Free Software Foundation.
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, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
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 /* Get libc version number. */
52 #define PACKAGE _libc_intl_domainname
54 /* Structure used by main() thread to keep track of the number of
55 active threads. Used to limit how many threads it will create
56 and under a shutdown condition to wait till all in-progress
57 requests have finished before "turning off the lights". */
62 pthread_cond_t thread_exit_cv
;
63 pthread_mutex_t mutex
;
66 thread_info_t thread_info
;
71 int go_background
= 1;
73 static const char *conffile
= _PATH_NSCDCONF
;
77 uintptr_t pagesize_m1
;
81 time_t restart_interval
= RESTART_INTERVAL
;
86 static int check_pid (const char *file
);
87 static int write_pid (const char *file
);
89 /* Name and version of program. */
90 static void print_version (FILE *stream
, struct argp_state
*state
);
91 void (*argp_program_version_hook
) (FILE *, struct argp_state
*) = print_version
;
93 /* Definitions of arguments for argp functions. */
94 static const struct argp_option options
[] =
96 { "config-file", 'f', N_("NAME"), 0,
97 N_("Read configuration data from NAME") },
98 { "debug", 'd', NULL
, 0,
99 N_("Do not fork and display messages on the current tty") },
100 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
101 { "shutdown", 'K', NULL
, 0, N_("Shut the server down") },
102 { "statistic", 'g', NULL
, 0, N_("Print current configuration statistic") },
103 { "invalidate", 'i', N_("TABLE"), 0,
104 N_("Invalidate the specified cache") },
105 { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN
,
106 N_("Use separate cache for each user")},
107 { NULL
, 0, NULL
, 0, NULL
}
110 /* Short description of program. */
111 static const char doc
[] = N_("Name Service Cache Daemon.");
113 /* Prototype for option handler. */
114 static error_t
parse_opt (int key
, char *arg
, struct argp_state
*state
);
116 /* Data structure to communicate with argp functions. */
117 static struct argp argp
=
119 options
, parse_opt
, NULL
, doc
,
122 /* True if only statistics are requested. */
123 static bool get_stats
;
126 main (int argc
, char **argv
)
130 /* Set locale via LC_ALL. */
131 setlocale (LC_ALL
, "");
132 /* Set the text message domain. */
133 textdomain (PACKAGE
);
135 /* Determine if the kernel has SELinux support. */
136 nscd_selinux_enabled (&selinux_enabled
);
138 /* Parse and process arguments. */
139 argp_parse (&argp
, argc
, argv
, 0, &remaining
, NULL
);
141 if (remaining
!= argc
)
143 error (0, 0, gettext ("wrong number of arguments"));
144 argp_help (&argp
, stdout
, ARGP_HELP_SEE
, program_invocation_short_name
);
148 /* Read the configuration file. */
149 if (nscd_parse_file (conffile
, dbs
) != 0)
150 /* We couldn't read the configuration file. We don't start the
152 error (EXIT_FAILURE
, 0,
153 _("failure while reading configuration file; this is fatal"));
155 /* Do we only get statistics? */
157 /* Does not return. */
158 receive_print_stats ();
160 /* Check if we are already running. */
161 if (check_pid (_PATH_NSCDPID
))
162 error (EXIT_FAILURE
, 0, _("already running"));
164 /* Remember when we started. */
165 start_time
= time (NULL
);
167 /* Determine page size. */
168 pagesize_m1
= getpagesize () - 1;
170 /* Behave like a daemon. */
177 error (EXIT_FAILURE
, errno
, _("cannot fork"));
181 int nullfd
= open (_PATH_DEVNULL
, O_RDWR
);
186 if (fstat64 (nullfd
, &st
) == 0 && S_ISCHR (st
.st_mode
) != 0
187 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
188 && st
.st_rdev
== makedev (DEV_NULL_MAJOR
, DEV_NULL_MINOR
)
192 /* It is the /dev/null special device alright. */
193 (void) dup2 (nullfd
, STDIN_FILENO
);
194 (void) dup2 (nullfd
, STDOUT_FILENO
);
195 (void) dup2 (nullfd
, STDERR_FILENO
);
202 /* Ugh, somebody is trying to play a trick on us. */
207 int min_close_fd
= nullfd
== -1 ? 0 : STDERR_FILENO
+ 1;
209 DIR *d
= opendir ("/proc/self/fd");
212 struct dirent64
*dirent
;
213 int dfdn
= dirfd (d
);
215 while ((dirent
= readdir64 (d
)) != NULL
)
218 long int fdn
= strtol (dirent
->d_name
, &endp
, 10);
220 if (*endp
== '\0' && fdn
!= dfdn
&& fdn
>= min_close_fd
)
227 for (i
= min_close_fd
; i
< getdtablesize (); i
++)
232 error (EXIT_FAILURE
, errno
, _("cannot fork"));
238 if (chdir ("/") != 0)
239 error (EXIT_FAILURE
, errno
,
240 _("cannot change current working cirectory to \"/\""));
242 openlog ("nscd", LOG_CONS
| LOG_ODELAY
, LOG_DAEMON
);
244 if (write_pid (_PATH_NSCDPID
) < 0)
245 dbg_log ("%s: %s", _PATH_NSCDPID
, strerror (errno
));
247 if (!init_logfile ())
248 dbg_log (_("Could not create log file"));
250 /* Ignore job control signals. */
251 signal (SIGTTOU
, SIG_IGN
);
252 signal (SIGTTIN
, SIG_IGN
);
253 signal (SIGTSTP
, SIG_IGN
);
256 /* In foreground mode we are not paranoid. */
259 /* Start the SELinux AVC. */
263 signal (SIGINT
, termination_handler
);
264 signal (SIGQUIT
, termination_handler
);
265 signal (SIGTERM
, termination_handler
);
266 signal (SIGPIPE
, SIG_IGN
);
268 /* Cleanup files created by a previous 'bind'. */
269 unlink (_PATH_NSCDSOCKET
);
271 /* Make sure we do not get recursive calls. */
272 __nss_disable_nscd ();
274 /* Init databases. */
277 /* Handle incoming requests */
284 /* Handle program arguments. */
286 parse_opt (int key
, char *arg
, struct argp_state
*state
)
301 error (4, 0, _("Only root is allowed to use this option!"));
303 int sock
= nscd_open_socket ();
310 req
.version
= NSCD_VERSION
;
313 nbytes
= TEMP_FAILURE_RETRY (send (sock
, &req
,
314 sizeof (request_header
),
317 exit (nbytes
!= sizeof (request_header
) ? EXIT_FAILURE
: EXIT_SUCCESS
);
326 error (4, 0, _("Only root is allowed to use this option!"));
329 int sock
= nscd_open_socket ();
338 if (strcmp (arg
, "passwd") == 0)
339 req
.key_len
= sizeof "passwd";
340 else if (strcmp (arg
, "group") == 0)
341 req
.key_len
= sizeof "group";
342 else if (strcmp (arg
, "hosts") == 0)
343 req
.key_len
= sizeof "hosts";
345 return ARGP_ERR_UNKNOWN
;
347 req
.version
= NSCD_VERSION
;
348 req
.type
= INVALIDATE
;
350 iov
[0].iov_base
= &req
;
351 iov
[0].iov_len
= sizeof (req
);
352 iov
[1].iov_base
= arg
;
353 iov
[1].iov_len
= req
.key_len
;
355 nbytes
= TEMP_FAILURE_RETRY (writev (sock
, iov
, 2));
359 exit (nbytes
!= iov
[0].iov_len
+ iov
[1].iov_len
360 ? EXIT_FAILURE
: EXIT_SUCCESS
);
364 nthreads
= atol (arg
);
368 error (0, 0, _("secure services not implemented anymore"));
372 return ARGP_ERR_UNKNOWN
;
378 /* Print the version information. */
380 print_version (FILE *stream
, struct argp_state
*state
)
382 fprintf (stream
, "nscd (GNU %s) %s\n", PACKAGE
, VERSION
);
383 fprintf (stream
, gettext ("\
384 Copyright (C) %s Free Software Foundation, Inc.\n\
385 This is free software; see the source for copying conditions. There is NO\n\
386 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
388 fprintf (stream
, gettext ("Written by %s.\n"),
389 "Thorsten Kukuk and Ulrich Drepper");
393 /* Create a socket connected to a name. */
395 nscd_open_socket (void)
397 struct sockaddr_un addr
;
400 sock
= socket (PF_UNIX
, SOCK_STREAM
, 0);
404 addr
.sun_family
= AF_UNIX
;
405 assert (sizeof (addr
.sun_path
) >= sizeof (_PATH_NSCDSOCKET
));
406 strcpy (addr
.sun_path
, _PATH_NSCDSOCKET
);
407 if (connect (sock
, (struct sockaddr
*) &addr
, sizeof (addr
)) < 0)
419 termination_handler (int signum
)
423 /* Clean up the file created by 'bind'. */
424 unlink (_PATH_NSCDSOCKET
);
426 /* Clean up pid file. */
427 unlink (_PATH_NSCDPID
);
429 // XXX Terminate threads.
431 /* Synchronize memory. */
432 for (int cnt
= 0; cnt
< lastdb
; ++cnt
)
434 if (!dbs
[cnt
].enabled
)
437 /* Make sure nobody keeps using the database. */
438 dbs
[cnt
].head
->timestamp
= 0;
440 if (dbs
[cnt
].persistent
)
442 msync (dbs
[cnt
].head
, dbs
[cnt
].memsize
, MS_ASYNC
);
445 /* Shutdown the SELinux AVC. */
449 _exit (EXIT_SUCCESS
);
452 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
454 check_pid (const char *file
)
458 fp
= fopen (file
, "r");
464 n
= fscanf (fp
, "%d", &pid
);
467 /* If we cannot parse the file default to assuming nscd runs.
468 If the PID is alive, assume it is running. That all unless
469 the PID is the same as the current process' since tha latter
470 can mean we re-exec. */
471 if ((n
!= 1 || kill (pid
, 0) == 0) && pid
!= getpid ())
478 /* Write the current process id to the file FILE.
479 Returns 0 if successful, -1 if not. */
481 write_pid (const char *file
)
485 fp
= fopen (file
, "w");
489 fprintf (fp
, "%d\n", getpid ());
491 int result
= fflush (fp
) || ferror (fp
) ? -1 : 0;