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 /* The SIGHUP handler is extern to this file */
123 extern void sighup_handler(int signum
);
125 /* True if only statistics are requested. */
126 static bool get_stats
;
129 main (int argc
, char **argv
)
133 /* Set locale via LC_ALL. */
134 setlocale (LC_ALL
, "");
135 /* Set the text message domain. */
136 textdomain (PACKAGE
);
138 /* Determine if the kernel has SELinux support. */
139 nscd_selinux_enabled (&selinux_enabled
);
141 /* Parse and process arguments. */
142 argp_parse (&argp
, argc
, argv
, 0, &remaining
, NULL
);
144 if (remaining
!= argc
)
146 error (0, 0, gettext ("wrong number of arguments"));
147 argp_help (&argp
, stdout
, ARGP_HELP_SEE
, program_invocation_short_name
);
151 /* Read the configuration file. */
152 if (nscd_parse_file (conffile
, dbs
) != 0)
153 /* We couldn't read the configuration file. We don't start the
155 error (EXIT_FAILURE
, 0,
156 _("failure while reading configuration file; this is fatal"));
158 /* Do we only get statistics? */
160 /* Does not return. */
161 receive_print_stats ();
163 /* Check if we are already running. */
164 if (check_pid (_PATH_NSCDPID
))
165 error (EXIT_FAILURE
, 0, _("already running"));
167 /* Remember when we started. */
168 start_time
= time (NULL
);
170 /* Determine page size. */
171 pagesize_m1
= getpagesize () - 1;
173 /* Behave like a daemon. */
180 error (EXIT_FAILURE
, errno
, _("cannot fork"));
184 int nullfd
= open (_PATH_DEVNULL
, O_RDWR
);
189 if (fstat64 (nullfd
, &st
) == 0 && S_ISCHR (st
.st_mode
) != 0
190 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
191 && st
.st_rdev
== makedev (DEV_NULL_MAJOR
, DEV_NULL_MINOR
)
195 /* It is the /dev/null special device alright. */
196 (void) dup2 (nullfd
, STDIN_FILENO
);
197 (void) dup2 (nullfd
, STDOUT_FILENO
);
198 (void) dup2 (nullfd
, STDERR_FILENO
);
205 /* Ugh, somebody is trying to play a trick on us. */
210 int min_close_fd
= nullfd
== -1 ? 0 : STDERR_FILENO
+ 1;
212 DIR *d
= opendir ("/proc/self/fd");
215 struct dirent64
*dirent
;
216 int dfdn
= dirfd (d
);
218 while ((dirent
= readdir64 (d
)) != NULL
)
221 long int fdn
= strtol (dirent
->d_name
, &endp
, 10);
223 if (*endp
== '\0' && fdn
!= dfdn
&& fdn
>= min_close_fd
)
230 for (i
= min_close_fd
; i
< getdtablesize (); i
++)
235 error (EXIT_FAILURE
, errno
, _("cannot fork"));
241 if (chdir ("/") != 0)
242 error (EXIT_FAILURE
, errno
,
243 _("cannot change current working cirectory to \"/\""));
245 openlog ("nscd", LOG_CONS
| LOG_ODELAY
, LOG_DAEMON
);
247 if (write_pid (_PATH_NSCDPID
) < 0)
248 dbg_log ("%s: %s", _PATH_NSCDPID
, strerror (errno
));
250 if (!init_logfile ())
251 dbg_log (_("Could not create log file"));
253 /* Ignore job control signals. */
254 signal (SIGTTOU
, SIG_IGN
);
255 signal (SIGTTIN
, SIG_IGN
);
256 signal (SIGTSTP
, SIG_IGN
);
259 /* In foreground mode we are not paranoid. */
262 /* Start the SELinux AVC. */
266 signal (SIGINT
, termination_handler
);
267 signal (SIGQUIT
, termination_handler
);
268 signal (SIGTERM
, termination_handler
);
269 signal (SIGHUP
, sighup_handler
);
270 signal (SIGPIPE
, SIG_IGN
);
272 /* Cleanup files created by a previous 'bind'. */
273 unlink (_PATH_NSCDSOCKET
);
275 /* Make sure we do not get recursive calls. */
276 __nss_disable_nscd ();
278 /* Init databases. */
281 /* Handle incoming requests */
288 /* Handle program arguments. */
290 parse_opt (int key
, char *arg
, struct argp_state
*state
)
305 error (4, 0, _("Only root is allowed to use this option!"));
307 int sock
= nscd_open_socket ();
314 req
.version
= NSCD_VERSION
;
317 nbytes
= TEMP_FAILURE_RETRY (send (sock
, &req
,
318 sizeof (request_header
),
321 exit (nbytes
!= sizeof (request_header
) ? EXIT_FAILURE
: EXIT_SUCCESS
);
330 error (4, 0, _("Only root is allowed to use this option!"));
333 int sock
= nscd_open_socket ();
339 if (strcmp (arg
, "passwd") == 0)
340 req
.key_len
= sizeof "passwd";
341 else if (strcmp (arg
, "group") == 0)
342 req
.key_len
= sizeof "group";
343 else if (strcmp (arg
, "hosts") == 0)
344 req
.key_len
= sizeof "hosts";
346 return ARGP_ERR_UNKNOWN
;
348 req
.version
= NSCD_VERSION
;
349 req
.type
= INVALIDATE
;
352 iov
[0].iov_base
= &req
;
353 iov
[0].iov_len
= sizeof (req
);
354 iov
[1].iov_base
= arg
;
355 iov
[1].iov_len
= req
.key_len
;
357 ssize_t nbytes
= TEMP_FAILURE_RETRY (writev (sock
, iov
, 2));
359 if (nbytes
!= iov
[0].iov_len
+ iov
[1].iov_len
)
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"));
386 nthreads
= atol (arg
);
390 error (0, 0, _("secure services not implemented anymore"));
394 return ARGP_ERR_UNKNOWN
;
400 /* Print the version information. */
402 print_version (FILE *stream
, struct argp_state
*state
)
404 fprintf (stream
, "nscd (GNU %s) %s\n", PACKAGE
, VERSION
);
405 fprintf (stream
, gettext ("\
406 Copyright (C) %s Free Software Foundation, Inc.\n\
407 This is free software; see the source for copying conditions. There is NO\n\
408 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
410 fprintf (stream
, gettext ("Written by %s.\n"),
411 "Thorsten Kukuk and Ulrich Drepper");
415 /* Create a socket connected to a name. */
417 nscd_open_socket (void)
419 struct sockaddr_un addr
;
422 sock
= socket (PF_UNIX
, SOCK_STREAM
, 0);
426 addr
.sun_family
= AF_UNIX
;
427 assert (sizeof (addr
.sun_path
) >= sizeof (_PATH_NSCDSOCKET
));
428 strcpy (addr
.sun_path
, _PATH_NSCDSOCKET
);
429 if (connect (sock
, (struct sockaddr
*) &addr
, sizeof (addr
)) < 0)
441 termination_handler (int signum
)
445 /* Clean up the file created by 'bind'. */
446 unlink (_PATH_NSCDSOCKET
);
448 /* Clean up pid file. */
449 unlink (_PATH_NSCDPID
);
451 // XXX Terminate threads.
453 /* Synchronize memory. */
454 for (int cnt
= 0; cnt
< lastdb
; ++cnt
)
456 if (!dbs
[cnt
].enabled
)
459 /* Make sure nobody keeps using the database. */
460 dbs
[cnt
].head
->timestamp
= 0;
462 if (dbs
[cnt
].persistent
)
464 msync (dbs
[cnt
].head
, dbs
[cnt
].memsize
, MS_ASYNC
);
467 /* Shutdown the SELinux AVC. */
471 _exit (EXIT_SUCCESS
);
474 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
476 check_pid (const char *file
)
480 fp
= fopen (file
, "r");
486 n
= fscanf (fp
, "%d", &pid
);
489 /* If we cannot parse the file default to assuming nscd runs.
490 If the PID is alive, assume it is running. That all unless
491 the PID is the same as the current process' since tha latter
492 can mean we re-exec. */
493 if ((n
!= 1 || kill (pid
, 0) == 0) && pid
!= getpid ())
500 /* Write the current process id to the file FILE.
501 Returns 0 if successful, -1 if not. */
503 write_pid (const char *file
)
507 fp
= fopen (file
, "w");
511 fprintf (fp
, "%d\n", getpid ());
513 int result
= fflush (fp
) || ferror (fp
) ? -1 : 0;