(nscd_gethst_r): Make sure resultbuf->h_addr_list addresses are
[kopensolaris-gnu/glibc.git] / nscd / nscd.c
1 /* Copyright (c) 1998, 1999 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    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
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    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA. */
19
20 /* nscd - Name Service Cache Daemon. Caches passwd, group, and hosts.  */
21
22 #include <argp.h>
23 #include <assert.h>
24 #include <errno.h>
25 #include <error.h>
26 #include <libintl.h>
27 #include <locale.h>
28 #include <pthread.h>
29 #include <pwd.h>
30 #include <signal.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <syslog.h>
35 #include <unistd.h>
36 #include <sys/socket.h>
37 #include <sys/un.h>
38
39 #include "dbg_log.h"
40 #include "nscd.h"
41
42 /* Get libc version number.  */
43 #include <version.h>
44
45 #define PACKAGE _libc_intl_domainname
46
47 /* Structure used by main() thread to keep track of the number of
48    active threads.  Used to limit how many threads it will create
49    and under a shutdown condition to wait till all in-progress
50    requests have finished before "turning off the lights".  */
51
52 typedef struct
53 {
54   int             num_active;
55   pthread_cond_t  thread_exit_cv;
56   pthread_mutex_t mutex;
57 } thread_info_t;
58
59 thread_info_t thread_info;
60
61 int do_shutdown;
62 int disabled_passwd;
63 int disabled_group;
64 int go_background = 1;
65
66 int secure[lastdb];
67 int secure_in_use;
68 static const char *conffile = _PATH_NSCDCONF;
69
70 static int check_pid (const char *file);
71 static int write_pid (const char *file);
72
73 /* Name and version of program.  */
74 static void print_version (FILE *stream, struct argp_state *state);
75 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
76
77 /* Definitions of arguments for argp functions.  */
78 static const struct argp_option options[] =
79 {
80   { "config-file", 'f', N_("NAME"), 0,
81     N_("Read configuration data from NAME") },
82   { "debug", 'd', NULL, 0,
83     N_("Do not fork and display messages on the current tty") },
84   { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
85   { "shutdown", 'K', NULL, 0, N_("Shut the server down") },
86   { "statistic", 'g', NULL, 0, N_("Print current configuration statistic") },
87   { "secure", 'S', N_("TABLE,yes"), 0, N_("Use separate cache for each user")},
88   { NULL, 0, NULL, 0, NULL }
89 };
90
91 /* Short description of program.  */
92 static const char doc[] = N_("Name Service Cache Daemon.");
93
94 /* Prototype for option handler.  */
95 static error_t parse_opt __P ((int key, char *arg, struct argp_state *state));
96
97 /* Data structure to communicate with argp functions.  */
98 static struct argp argp =
99 {
100   options, parse_opt, NULL, doc,
101 };
102
103 int
104 main (int argc, char **argv)
105 {
106   int remaining;
107
108   /* Set locale via LC_ALL.  */
109   setlocale (LC_ALL, "");
110   /* Set the text message domain.  */
111   textdomain (PACKAGE);
112
113   /* Parse and process arguments.  */
114   argp_parse (&argp, argc, argv, 0, &remaining, NULL);
115
116   if (remaining != argc)
117     {
118       error (0, 0, gettext ("wrong number of arguments"));
119       argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
120       exit (EXIT_FAILURE);
121     }
122
123   /* Check if we are already running. */
124   if (check_pid (_PATH_NSCDPID))
125     error (EXIT_FAILURE, 0, _("already running"));
126
127   /* Behave like a daemon.  */
128   if (go_background)
129     {
130       int i;
131
132       if (fork ())
133         exit (0);
134
135       for (i = 0; i < getdtablesize (); i++)
136         close (i);
137
138       if (fork ())
139         exit (0);
140
141       chdir ("/");
142
143       openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
144
145       if (write_pid (_PATH_NSCDPID) < 0)
146         dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
147
148       /* Ignore job control signals.  */
149       signal (SIGTTOU, SIG_IGN);
150       signal (SIGTTIN, SIG_IGN);
151       signal (SIGTSTP, SIG_IGN);
152     }
153
154   signal (SIGINT, termination_handler);
155   signal (SIGQUIT, termination_handler);
156   signal (SIGTERM, termination_handler);
157   signal (SIGPIPE, SIG_IGN);
158
159   /* Cleanup files created by a previous `bind'.  */
160   unlink (_PATH_NSCDSOCKET);
161
162   /* Init databases.  */
163   nscd_init (conffile);
164
165   /* Handle incoming requests */
166   start_threads ();
167
168   return 0;
169 }
170
171
172 /* Handle program arguments.  */
173 static error_t
174 parse_opt (int key, char *arg, struct argp_state *state)
175 {
176   switch (key)
177     {
178     case 'd':
179       ++debug_level;
180       go_background = 0;
181       break;
182
183     case 'f':
184       conffile = arg;
185       break;
186
187     case 'K':
188       if (getuid () != 0)
189         error (EXIT_FAILURE, 0, _("Only root is allowed to use this option!"));
190       {
191         int sock = nscd_open_socket ();
192         request_header req;
193         ssize_t nbytes;
194
195         if (sock == -1)
196           exit (EXIT_FAILURE);
197
198         req.version = NSCD_VERSION;
199         req.type = SHUTDOWN;
200         req.key_len = 0;
201         nbytes = TEMP_FAILURE_RETRY (write (sock, &req,
202                                             sizeof (request_header)));
203         close (sock);
204         exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
205       }
206
207     case 'g':
208       if (getuid () != 0)
209         error (EXIT_FAILURE, 0, _("Only root is allowed to use this option!"));
210       receive_print_stats ();
211       /* Does not return.  */
212
213     case 't':
214       nthreads = atol (arg);
215       break;
216
217     case 'S':
218       if (strcmp (arg, "passwd,yes") == 0)
219         secure_in_use = secure[pwddb] = 1;
220       else if (strcmp (arg, "group,yes") == 0)
221         secure_in_use = secure[grpdb] = 1;
222       else if (strcmp (arg, "hosts,yes") == 0)
223         secure_in_use = secure[hstdb] = 1;
224       break;
225
226     default:
227       return ARGP_ERR_UNKNOWN;
228     }
229
230   return 0;
231 }
232
233 /* Print the version information.  */
234 static void
235 print_version (FILE *stream, struct argp_state *state)
236 {
237   fprintf (stream, "nscd (GNU %s) %s\n", PACKAGE, VERSION);
238   fprintf (stream, gettext ("\
239 Copyright (C) %s Free Software Foundation, Inc.\n\
240 This is free software; see the source for copying conditions.  There is NO\n\
241 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
242 "), "1999");
243   fprintf (stream, gettext ("Written by %s.\n"),
244            "Thorsten Kukuk and Ulrich Drepper");
245 }
246
247
248 /* Create a socket connected to a name.  */
249 int
250 nscd_open_socket (void)
251 {
252   struct sockaddr_un addr;
253   int sock;
254
255   sock = socket (PF_UNIX, SOCK_STREAM, 0);
256   if (sock < 0)
257     return -1;
258
259   addr.sun_family = AF_UNIX;
260   assert (sizeof (addr.sun_path) >= sizeof (_PATH_NSCDSOCKET));
261   strcpy (addr.sun_path, _PATH_NSCDSOCKET);
262   if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
263     {
264       close (sock);
265       return -1;
266     }
267
268   return sock;
269 }
270
271 /* Cleanup.  */
272 void
273 termination_handler (int signum)
274 {
275   close_sockets ();
276
277   /* Clean up the file created by `bind'.  */
278   unlink (_PATH_NSCDSOCKET);
279
280   /* Clean up pid file.  */
281   unlink (_PATH_NSCDPID);
282
283   exit (EXIT_SUCCESS);
284 }
285
286 /* Returns 1 if the process in pid file FILE is running, 0 if not.  */
287 static int
288 check_pid (const char *file)
289 {
290   FILE *fp;
291
292   fp = fopen (file, "r");
293   if (fp)
294     {
295       pid_t pid;
296       int n;
297
298       n = fscanf (fp, "%d", &pid);
299       fclose (fp);
300
301       if (n != 1 || kill (pid, 0) == 0)
302         return 1;
303     }
304
305   return 0;
306 }
307
308 /* Write the current process id to the file FILE.
309    Returns 0 if successful, -1 if not.  */
310 static int
311 write_pid (const char *file)
312 {
313   FILE *fp;
314
315   fp = fopen (file, "w");
316   if (fp == NULL)
317     return -1;
318
319   fprintf (fp, "%d\n", getpid ());
320   if (fflush (fp) || ferror (fp))
321     return -1;
322
323   fclose (fp);
324
325   return 0;
326 }