1 /* Copyright (c) 1998-2003, 2004, 2005 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library 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 GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 /* nscd - Name Service Cache Daemon. Caches passwd, group, and hosts. */
40 #include <sys/socket.h>
48 #include "../nss/nsswitch.h"
49 #include <device-nrs.h>
51 /* Get libc version number. */
54 #define PACKAGE _libc_intl_domainname
56 /* Structure used by main() thread to keep track of the number of
57 active threads. Used to limit how many threads it will create
58 and under a shutdown condition to wait till all in-progress
59 requests have finished before "turning off the lights". */
64 pthread_cond_t thread_exit_cv
;
65 pthread_mutex_t mutex
;
68 thread_info_t thread_info
;
73 int go_background
= 1;
76 static const char *conffile
= _PATH_NSCDCONF
;
80 uintptr_t pagesize_m1
;
84 time_t restart_interval
= RESTART_INTERVAL
;
89 static int check_pid (const char *file
);
90 static int write_pid (const char *file
);
92 /* Name and version of program. */
93 static void print_version (FILE *stream
, struct argp_state
*state
);
94 void (*argp_program_version_hook
) (FILE *, struct argp_state
*) = print_version
;
96 /* Definitions of arguments for argp functions. */
97 static const struct argp_option options
[] =
99 { "config-file", 'f', N_("NAME"), 0,
100 N_("Read configuration data from NAME") },
101 { "debug", 'd', NULL
, 0,
102 N_("Do not fork and display messages on the current tty") },
103 { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
104 { "shutdown", 'K', NULL
, 0, N_("Shut the server down") },
105 { "statistic", 'g', NULL
, 0, N_("Print current configuration statistic") },
106 { "invalidate", 'i', N_("TABLE"), 0,
107 N_("Invalidate the specified cache") },
108 { "secure", 'S', N_("TABLE,yes"), OPTION_HIDDEN
,
109 N_("Use separate cache for each user")},
110 { NULL
, 0, NULL
, 0, NULL
}
113 /* Short description of program. */
114 static const char doc
[] = N_("Name Service Cache Daemon.");
116 /* Prototype for option handler. */
117 static error_t
parse_opt (int key
, char *arg
, struct argp_state
*state
);
119 /* Data structure to communicate with argp functions. */
120 static struct argp argp
=
122 options
, parse_opt
, NULL
, doc
,
125 /* The SIGHUP handler is extern to this file */
126 extern void sighup_handler(int signum
);
128 /* True if only statistics are requested. */
129 static bool get_stats
;
132 main (int argc
, char **argv
)
136 /* Set locale via LC_ALL. */
137 setlocale (LC_ALL
, "");
138 /* Set the text message domain. */
139 textdomain (PACKAGE
);
141 /* Determine if the kernel has SELinux support. */
142 nscd_selinux_enabled (&selinux_enabled
);
144 /* Parse and process arguments. */
145 argp_parse (&argp
, argc
, argv
, 0, &remaining
, NULL
);
147 if (remaining
!= argc
)
149 error (0, 0, gettext ("wrong number of arguments"));
150 argp_help (&argp
, stdout
, ARGP_HELP_SEE
, program_invocation_short_name
);
154 /* Read the configuration file. */
155 if (nscd_parse_file (conffile
, dbs
) != 0)
157 /* We couldn't read the configuration file. We don't start the
159 dbg_log (_("cannot read configuration file; this is fatal"));
163 /* Do we only get statistics? */
165 /* Does not return. */
166 receive_print_stats ();
168 /* Check if we are already running. */
169 if (check_pid (_PATH_NSCDPID
))
170 error (EXIT_FAILURE
, 0, _("already running"));
172 /* Remember when we started. */
173 start_time
= time (NULL
);
175 /* Determine page size. */
176 pagesize_m1
= getpagesize () - 1;
178 /* Behave like a daemon. */
185 error (EXIT_FAILURE
, errno
, _("cannot fork"));
189 int nullfd
= open (_PATH_DEVNULL
, O_RDWR
);
194 if (fstat64 (nullfd
, &st
) == 0 && S_ISCHR (st
.st_mode
) != 0
195 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
196 && st
.st_rdev
== makedev (DEV_NULL_MAJOR
, DEV_NULL_MINOR
)
200 /* It is the /dev/null special device alright. */
201 (void) dup2 (nullfd
, STDIN_FILENO
);
202 (void) dup2 (nullfd
, STDOUT_FILENO
);
203 (void) dup2 (nullfd
, STDERR_FILENO
);
210 /* Ugh, somebody is trying to play a trick on us. */
215 int min_close_fd
= nullfd
== -1 ? 0 : STDERR_FILENO
+ 1;
217 DIR *d
= opendir ("/proc/self/fd");
220 struct dirent64
*dirent
;
221 int dfdn
= dirfd (d
);
223 while ((dirent
= readdir64 (d
)) != NULL
)
226 long int fdn
= strtol (dirent
->d_name
, &endp
, 10);
228 if (*endp
== '\0' && fdn
!= dfdn
&& fdn
>= min_close_fd
)
235 for (i
= min_close_fd
; i
< getdtablesize (); i
++)
240 error (EXIT_FAILURE
, errno
, _("cannot fork"));
248 openlog ("nscd", LOG_CONS
| LOG_ODELAY
, LOG_DAEMON
);
250 if (write_pid (_PATH_NSCDPID
) < 0)
251 dbg_log ("%s: %s", _PATH_NSCDPID
, strerror (errno
));
253 if (!init_logfile ())
254 dbg_log (_("Could not create log file"));
256 /* Ignore job control signals. */
257 signal (SIGTTOU
, SIG_IGN
);
258 signal (SIGTTIN
, SIG_IGN
);
259 signal (SIGTSTP
, SIG_IGN
);
262 /* In foreground mode we are not paranoid. */
265 /* Start the SELinux AVC. */
269 signal (SIGINT
, termination_handler
);
270 signal (SIGQUIT
, termination_handler
);
271 signal (SIGTERM
, termination_handler
);
272 signal (SIGHUP
, sighup_handler
);
273 signal (SIGPIPE
, SIG_IGN
);
275 /* Cleanup files created by a previous 'bind'. */
276 unlink (_PATH_NSCDSOCKET
);
278 /* Make sure we do not get recursive calls. */
279 __nss_disable_nscd ();
281 /* Init databases. */
284 /* Handle incoming requests */
291 /* Handle program arguments. */
293 parse_opt (int key
, char *arg
, struct argp_state
*state
)
308 error (4, 0, _("Only root is allowed to use this option!"));
310 int sock
= nscd_open_socket ();
317 req
.version
= NSCD_VERSION
;
320 nbytes
= TEMP_FAILURE_RETRY (write (sock
, &req
,
321 sizeof (request_header
)));
323 exit (nbytes
!= sizeof (request_header
) ? EXIT_FAILURE
: EXIT_SUCCESS
);
332 error (4, 0, _("Only root is allowed to use this option!"));
335 int sock
= nscd_open_socket ();
344 if (strcmp (arg
, "passwd") == 0)
345 req
.key_len
= sizeof "passwd";
346 else if (strcmp (arg
, "group") == 0)
347 req
.key_len
= sizeof "group";
348 else if (strcmp (arg
, "hosts") == 0)
349 req
.key_len
= sizeof "hosts";
351 return ARGP_ERR_UNKNOWN
;
353 req
.version
= NSCD_VERSION
;
354 req
.type
= INVALIDATE
;
356 iov
[0].iov_base
= &req
;
357 iov
[0].iov_len
= sizeof (req
);
358 iov
[1].iov_base
= arg
;
359 iov
[1].iov_len
= req
.key_len
;
361 nbytes
= TEMP_FAILURE_RETRY (writev (sock
, iov
, 2));
365 exit (nbytes
!= iov
[0].iov_len
+ iov
[1].iov_len
366 ? EXIT_FAILURE
: EXIT_SUCCESS
);
370 nthreads
= atol (arg
);
375 if (strcmp (arg
, "passwd,yes") == 0)
376 secure_in_use
= dbs
[pwddb
].secure
= 1;
377 else if (strcmp (arg
, "group,yes") == 0)
378 secure_in_use
= dbs
[grpdb
].secure
= 1;
379 else if (strcmp (arg
, "hosts,yes") == 0)
380 secure_in_use
= dbs
[hstdb
].secure
= 1;
382 error (0, 0, _("secure services not implemented anymore"));
387 return ARGP_ERR_UNKNOWN
;
393 /* Print the version information. */
395 print_version (FILE *stream
, struct argp_state
*state
)
397 fprintf (stream
, "nscd (GNU %s) %s\n", PACKAGE
, VERSION
);
398 fprintf (stream
, gettext ("\
399 Copyright (C) %s Free Software Foundation, Inc.\n\
400 This is free software; see the source for copying conditions. There is NO\n\
401 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
403 fprintf (stream
, gettext ("Written by %s.\n"),
404 "Thorsten Kukuk and Ulrich Drepper");
408 /* Create a socket connected to a name. */
410 nscd_open_socket (void)
412 struct sockaddr_un addr
;
415 sock
= socket (PF_UNIX
, SOCK_STREAM
, 0);
419 addr
.sun_family
= AF_UNIX
;
420 assert (sizeof (addr
.sun_path
) >= sizeof (_PATH_NSCDSOCKET
));
421 strcpy (addr
.sun_path
, _PATH_NSCDSOCKET
);
422 if (connect (sock
, (struct sockaddr
*) &addr
, sizeof (addr
)) < 0)
434 termination_handler (int signum
)
438 /* Clean up the file created by 'bind'. */
439 unlink (_PATH_NSCDSOCKET
);
441 /* Clean up pid file. */
442 unlink (_PATH_NSCDPID
);
444 // XXX Terminate threads.
446 /* Synchronize memory. */
447 for (int cnt
= 0; cnt
< lastdb
; ++cnt
)
449 if (!dbs
[cnt
].enabled
)
452 /* Make sure nobody keeps using the database. */
453 dbs
[cnt
].head
->timestamp
= 0;
455 if (dbs
[cnt
].persistent
)
457 msync (dbs
[cnt
].head
, dbs
[cnt
].memsize
, MS_ASYNC
);
460 /* Shutdown the SELinux AVC. */
464 _exit (EXIT_SUCCESS
);
467 /* Returns 1 if the process in pid file FILE is running, 0 if not. */
469 check_pid (const char *file
)
473 fp
= fopen (file
, "r");
479 n
= fscanf (fp
, "%d", &pid
);
482 /* If we cannot parse the file default to assuming nscd runs.
483 If the PID is alive, assume it is running. That all unless
484 the PID is the same as the current process' since tha latter
485 can mean we re-exec. */
486 if ((n
!= 1 || kill (pid
, 0) == 0) && pid
!= getpid ())
493 /* Write the current process id to the file FILE.
494 Returns 0 if successful, -1 if not. */
496 write_pid (const char *file
)
500 fp
= fopen (file
, "w");
504 fprintf (fp
, "%d\n", getpid ());
505 if (fflush (fp
) || ferror (fp
))