Cleanup nscd.c
[platform/upstream/linaro-glibc.git] / nscd / nscd.c
1 /* Copyright (c) 1998-2012 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
4
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.
9
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.
14
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/>.  */
17
18 /* nscd - Name Service Cache Daemon. Caches passwd, group, and hosts.  */
19
20 #include <argp.h>
21 #include <assert.h>
22 #include <dirent.h>
23 #include <errno.h>
24 #include <error.h>
25 #include <fcntl.h>
26 #include <libintl.h>
27 #include <locale.h>
28 #include <paths.h>
29 #include <pthread.h>
30 #include <signal.h>
31 #include <stdbool.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <syslog.h>
36 #include <unistd.h>
37 #include <sys/mman.h>
38 #include <sys/socket.h>
39 #include <sys/stat.h>
40 #include <sys/uio.h>
41 #include <sys/un.h>
42
43 #include "dbg_log.h"
44 #include "nscd.h"
45 #include "selinux.h"
46 #include "../nss/nsswitch.h"
47 #include <device-nrs.h>
48 #ifdef HAVE_INOTIFY
49 # include <sys/inotify.h>
50 #endif
51
52 /* Get libc version number.  */
53 #include <version.h>
54
55 #define PACKAGE _libc_intl_domainname
56
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".  */
61
62 typedef struct
63 {
64   int             num_active;
65   pthread_cond_t  thread_exit_cv;
66   pthread_mutex_t mutex;
67 } thread_info_t;
68
69 thread_info_t thread_info;
70
71 int do_shutdown;
72 int disabled_passwd;
73 int disabled_group;
74
75 typedef enum
76 {
77   /* Running in background as daemon.  */
78   RUN_DAEMONIZE,
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.  */
82   RUN_FOREGROUND,
83   /* Run in foreground in debug mode.  */
84   RUN_DEBUG
85 } run_modes;
86
87 static run_modes run_mode = RUN_DAEMONIZE;
88
89 static const char *conffile = _PATH_NSCDCONF;
90
91 time_t start_time;
92
93 uintptr_t pagesize_m1;
94
95 int paranoia;
96 time_t restart_time;
97 time_t restart_interval = RESTART_INTERVAL;
98 const char *oldcwd;
99 uid_t old_uid;
100 gid_t old_gid;
101
102 static int check_pid (const char *file);
103 static int write_pid (const char *file);
104
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;
108
109 /* Function to print some extra text in the help message.  */
110 static char *more_help (int key, const char *text, void *input);
111
112 /* Definitions of arguments for argp functions.  */
113 static const struct argp_option options[] =
114 {
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 }
129 };
130
131 /* Short description of program.  */
132 static const char doc[] = N_("Name Service Cache Daemon.");
133
134 /* Prototype for option handler.  */
135 static error_t parse_opt (int key, char *arg, struct argp_state *state);
136
137 /* Data structure to communicate with argp functions.  */
138 static struct argp argp =
139 {
140   options, parse_opt, NULL, doc, NULL, more_help
141 };
142
143 /* True if only statistics are requested.  */
144 static bool get_stats;
145
146 int
147 main (int argc, char **argv)
148 {
149   int remaining;
150
151   /* Set locale via LC_ALL.  */
152   setlocale (LC_ALL, "");
153   /* Set the text message domain.  */
154   textdomain (PACKAGE);
155
156   /* Determine if the kernel has SELinux support.  */
157   nscd_selinux_enabled (&selinux_enabled);
158
159   /* Parse and process arguments.  */
160   argp_parse (&argp, argc, argv, 0, &remaining, NULL);
161
162   if (remaining != argc)
163     {
164       error (0, 0, gettext ("wrong number of arguments"));
165       argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
166       exit (1);
167     }
168
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
172        server.  */
173     error (EXIT_FAILURE, 0,
174            _("failure while reading configuration file; this is fatal"));
175
176   /* Do we only get statistics?  */
177   if (get_stats)
178     /* Does not return.  */
179     receive_print_stats ();
180
181   /* Check if we are already running. */
182   if (check_pid (_PATH_NSCDPID))
183     error (EXIT_FAILURE, 0, _("already running"));
184
185   /* Remember when we started.  */
186   start_time = time (NULL);
187
188   /* Determine page size.  */
189   pagesize_m1 = getpagesize () - 1;
190
191   if (run_mode == RUN_DAEMONIZE || run_mode == RUN_FOREGROUND)
192     {
193       int i;
194       pid_t pid;
195
196       /* Behave like a daemon.  */
197       if (run_mode == RUN_DAEMONIZE)
198         {
199           pid = fork ();
200           if (pid == -1)
201             error (EXIT_FAILURE, errno, _("cannot fork"));
202           if (pid != 0)
203             exit (0);
204         }
205
206       int nullfd = open (_PATH_DEVNULL, O_RDWR);
207       if (nullfd != -1)
208         {
209           struct stat64 st;
210
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)
214 #endif
215               )
216             {
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);
221
222               if (nullfd > 2)
223                 close (nullfd);
224             }
225           else
226             {
227               /* Ugh, somebody is trying to play a trick on us.  */
228               close (nullfd);
229               nullfd = -1;
230             }
231         }
232       int min_close_fd = nullfd == -1 ? 0 : STDERR_FILENO + 1;
233
234       DIR *d = opendir ("/proc/self/fd");
235       if (d != NULL)
236         {
237           struct dirent64 *dirent;
238           int dfdn = dirfd (d);
239
240           while ((dirent = readdir64 (d)) != NULL)
241             {
242               char *endp;
243               long int fdn = strtol (dirent->d_name, &endp, 10);
244
245               if (*endp == '\0' && fdn != dfdn && fdn >= min_close_fd)
246                 close ((int) fdn);
247             }
248
249           closedir (d);
250         }
251       else
252         for (i = min_close_fd; i < getdtablesize (); i++)
253           close (i);
254
255       if (run_mode == RUN_DAEMONIZE)
256         {
257           pid = fork ();
258           if (pid == -1)
259             error (EXIT_FAILURE, errno, _("cannot fork"));
260           if (pid != 0)
261             exit (0);
262         }
263
264       setsid ();
265
266       if (chdir ("/") != 0)
267         error (EXIT_FAILURE, errno,
268                _("cannot change current working directory to \"/\""));
269
270       openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
271
272       if (write_pid (_PATH_NSCDPID) < 0)
273         dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
274
275       if (!init_logfile ())
276         dbg_log (_("Could not create log file"));
277
278       /* Ignore job control signals.  */
279       signal (SIGTTOU, SIG_IGN);
280       signal (SIGTTIN, SIG_IGN);
281       signal (SIGTSTP, SIG_IGN);
282     }
283   else
284     /* In debug mode we are not paranoid.  */
285     paranoia = 0;
286
287   signal (SIGINT, termination_handler);
288   signal (SIGQUIT, termination_handler);
289   signal (SIGTERM, termination_handler);
290   signal (SIGPIPE, SIG_IGN);
291
292   /* Cleanup files created by a previous 'bind'.  */
293   unlink (_PATH_NSCDSOCKET);
294
295 #ifdef HAVE_INOTIFY
296   /* Use inotify to recognize changed files.  */
297   inotify_fd = inotify_init1 (IN_NONBLOCK);
298 # ifndef __ASSUME_IN_NONBLOCK
299   if (inotify_fd == -1 && errno == ENOSYS)
300     {
301       inotify_fd = inotify_init ();
302       if (inotify_fd != -1)
303         fcntl (inotify_fd, F_SETFL, O_RDONLY | O_NONBLOCK);
304     }
305 # endif
306 #endif
307
308   /* Make sure we do not get recursive calls.  */
309   __nss_disable_nscd (register_traced_file);
310
311   /* Init databases.  */
312   nscd_init ();
313
314   /* Start the SELinux AVC.  */
315   if (selinux_enabled)
316     nscd_avc_init ();
317
318   /* Handle incoming requests */
319   start_threads ();
320
321   return 0;
322 }
323
324
325 /* Handle program arguments.  */
326 static error_t
327 parse_opt (int key, char *arg, struct argp_state *state)
328 {
329   switch (key)
330     {
331     case 'd':
332       ++debug_level;
333       run_mode = RUN_DEBUG;
334       break;
335
336     case 'F':
337       run_mode = RUN_FOREGROUND;
338       break;
339
340     case 'f':
341       conffile = arg;
342       break;
343
344     case 'K':
345       if (getuid () != 0)
346         error (4, 0, _("Only root is allowed to use this option!"));
347       {
348         int sock = nscd_open_socket ();
349
350         if (sock == -1)
351           exit (EXIT_FAILURE);
352
353         request_header req;
354         req.version = NSCD_VERSION;
355         req.type = SHUTDOWN;
356         req.key_len = 0;
357
358         ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &req,
359                                                    sizeof (request_header),
360                                                    MSG_NOSIGNAL));
361         close (sock);
362         exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
363       }
364
365     case 'g':
366       get_stats = true;
367       break;
368
369     case 'i':
370       if (getuid () != 0)
371         error (4, 0, _("Only root is allowed to use this option!"));
372       else
373         {
374           int sock = nscd_open_socket ();
375
376           if (sock == -1)
377             exit (EXIT_FAILURE);
378
379           dbtype cnt;
380           for (cnt = pwddb; cnt < lastdb; ++cnt)
381             if (strcmp (arg, dbnames[cnt]) == 0)
382               break;
383
384           if (cnt == lastdb)
385             {
386               argp_error (state, _("'%s' is not a known database"), arg);
387               return EINVAL;
388             }
389
390           size_t arg_len = strlen (arg) + 1;
391           struct
392           {
393             request_header req;
394             char arg[arg_len];
395           } reqdata;
396
397           reqdata.req.key_len = strlen (arg) + 1;
398           reqdata.req.version = NSCD_VERSION;
399           reqdata.req.type = INVALIDATE;
400           memcpy (reqdata.arg, arg, arg_len);
401
402           ssize_t nbytes = TEMP_FAILURE_RETRY (send (sock, &reqdata,
403                                                      sizeof (request_header)
404                                                      + arg_len,
405                                                      MSG_NOSIGNAL));
406
407           if (nbytes != sizeof (request_header) + arg_len)
408             {
409               int err = errno;
410               close (sock);
411               error (EXIT_FAILURE, err, _("write incomplete"));
412             }
413
414           /* Wait for ack.  Older nscd just closed the socket when
415              prune_cache finished, silently ignore that.  */
416           int32_t resp = 0;
417           nbytes = TEMP_FAILURE_RETRY (read (sock, &resp, sizeof (resp)));
418           if (nbytes != 0 && nbytes != sizeof (resp))
419             {
420               int err = errno;
421               close (sock);
422               error (EXIT_FAILURE, err, _("cannot read invalidate ACK"));
423             }
424
425           close (sock);
426
427           if (resp != 0)
428             error (EXIT_FAILURE, resp, _("invalidation failed"));
429
430           exit (0);
431         }
432
433     case 't':
434       nthreads = atol (arg);
435       break;
436
437     case 'S':
438       error (0, 0, _("secure services not implemented anymore"));
439       break;
440
441     default:
442       return ARGP_ERR_UNKNOWN;
443     }
444
445   return 0;
446 }
447
448 /* Print bug-reporting information in the help message.  */
449 static char *
450 more_help (int key, const char *text, void *input)
451 {
452   switch (key)
453     {
454     case ARGP_KEY_HELP_EXTRA:
455       /* We print some extra information.  */
456       return strdup (gettext ("\
457 For bug reporting instructions, please see:\n\
458 <http://www.gnu.org/software/libc/bugs.html>.\n"));
459     default:
460       break;
461     }
462   return (char *) text;
463 }
464
465 /* Print the version information.  */
466 static void
467 print_version (FILE *stream, struct argp_state *state)
468 {
469   fprintf (stream, "nscd (GNU %s) %s\n", PACKAGE, VERSION);
470   fprintf (stream, gettext ("\
471 Copyright (C) %s Free Software Foundation, Inc.\n\
472 This is free software; see the source for copying conditions.  There is NO\n\
473 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
474 "), "2012");
475   fprintf (stream, gettext ("Written by %s.\n"),
476            "Thorsten Kukuk and Ulrich Drepper");
477 }
478
479
480 /* Create a socket connected to a name.  */
481 int
482 nscd_open_socket (void)
483 {
484   struct sockaddr_un addr;
485   int sock;
486
487   sock = socket (PF_UNIX, SOCK_STREAM, 0);
488   if (sock < 0)
489     return -1;
490
491   addr.sun_family = AF_UNIX;
492   assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
493   strcpy (addr.sun_path, _PATH_NSCDSOCKET);
494   if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
495     {
496       close (sock);
497       return -1;
498     }
499
500   return sock;
501 }
502
503
504 /* Cleanup.  */
505 void
506 termination_handler (int signum)
507 {
508   close_sockets ();
509
510   /* Clean up the file created by 'bind'.  */
511   unlink (_PATH_NSCDSOCKET);
512
513   /* Clean up pid file.  */
514   unlink (_PATH_NSCDPID);
515
516   // XXX Terminate threads.
517
518   /* Synchronize memory.  */
519   for (int cnt = 0; cnt < lastdb; ++cnt)
520     {
521       if (!dbs[cnt].enabled || dbs[cnt].head == NULL)
522         continue;
523
524       /* Make sure nobody keeps using the database.  */
525       dbs[cnt].head->timestamp = 0;
526
527       if (dbs[cnt].persistent)
528         // XXX async OK?
529         msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
530     }
531
532   _exit (EXIT_SUCCESS);
533 }
534
535 /* Returns 1 if the process in pid file FILE is running, 0 if not.  */
536 static int
537 check_pid (const char *file)
538 {
539   FILE *fp;
540
541   fp = fopen (file, "r");
542   if (fp)
543     {
544       pid_t pid;
545       int n;
546
547       n = fscanf (fp, "%d", &pid);
548       fclose (fp);
549
550       /* If we cannot parse the file default to assuming nscd runs.
551          If the PID is alive, assume it is running.  That all unless
552          the PID is the same as the current process' since tha latter
553          can mean we re-exec.  */
554       if ((n != 1 || kill (pid, 0) == 0) && pid != getpid ())
555         return 1;
556     }
557
558   return 0;
559 }
560
561 /* Write the current process id to the file FILE.
562    Returns 0 if successful, -1 if not.  */
563 static int
564 write_pid (const char *file)
565 {
566   FILE *fp;
567
568   fp = fopen (file, "w");
569   if (fp == NULL)
570     return -1;
571
572   fprintf (fp, "%d\n", getpid ());
573
574   int result = fflush (fp) || ferror (fp) ? -1 : 0;
575
576   fclose (fp);
577
578   return result;
579 }