(invalidate_cache): Don't invalidate a cache if it is not enabled.
[kopensolaris-gnu/glibc.git] / nscd / connections.c
1 /* Inner loops of cache daemon.
2    Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the GNU C Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 #include <assert.h>
22 #include <error.h>
23 #include <errno.h>
24 #include <pthread.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <libintl.h>
28 #include <arpa/inet.h>
29 #include <sys/param.h>
30 #include <sys/poll.h>
31 #include <sys/socket.h>
32 #include <sys/stat.h>
33 #include <sys/un.h>
34
35 #include "nscd.h"
36 #include "dbg_log.h"
37
38
39 /* Mapping of request type to database.  */
40 static const dbtype serv2db[LASTDBREQ + 1] =
41 {
42   [GETPWBYNAME] = pwddb,
43   [GETPWBYUID] = pwddb,
44   [GETGRBYNAME] = grpdb,
45   [GETGRBYGID] = grpdb,
46   [GETHOSTBYNAME] = hstdb,
47   [GETHOSTBYNAMEv6] = hstdb,
48   [GETHOSTBYADDR] = hstdb,
49   [GETHOSTBYADDRv6] = hstdb,
50 };
51
52 /* Map request type to a string.  */
53 const char *serv2str[LASTREQ] =
54 {
55   [GETPWBYNAME] = "GETPWBYNAME",
56   [GETPWBYUID] = "GETPWBYUID",
57   [GETGRBYNAME] = "GETGRBYNAME",
58   [GETGRBYGID] = "GETGRBYGID",
59   [GETHOSTBYNAME] = "GETHOSTBYNAME",
60   [GETHOSTBYNAMEv6] = "GETHOSTBYNAMEv6",
61   [GETHOSTBYADDR] = "GETHOSTBYADDR",
62   [GETHOSTBYADDRv6] = "GETHOSTBYADDRv6",
63   [SHUTDOWN] = "SHUTDOWN",
64   [GETSTAT] = "GETSTAT",
65   [INVALIDATE] = "INVALIDATE"
66 };
67
68 /* The control data structures for the services.  */
69 static struct database dbs[lastdb] =
70 {
71   [pwddb] = {
72     lock: PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
73     enabled: 0,
74     check_file: 1,
75     filename: "/etc/passwd",
76     module: 211,
77     disabled_iov: &pwd_iov_disabled,
78     postimeout: 3600,
79     negtimeout: 20
80   },
81   [grpdb] = {
82     lock: PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
83     enabled: 0,
84     check_file: 1,
85     filename: "/etc/group",
86     module: 211,
87     disabled_iov: &grp_iov_disabled,
88     postimeout: 3600,
89     negtimeout: 60
90   },
91   [hstdb] = {
92     lock: PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
93     enabled: 0,
94     check_file: 1,
95     filename: "/etc/hosts",
96     module: 211,
97     disabled_iov: &hst_iov_disabled,
98     postimeout: 3600,
99     negtimeout: 20
100   }
101 };
102
103 /* Number of seconds between two cache pruning runs.  */
104 #define CACHE_PRUNE_INTERVAL    15
105
106 /* Number of threads to use.  */
107 int nthreads = -1;
108
109 /* Socket for incoming connections.  */
110 static int sock;
111
112
113 /* Initialize database information structures.  */
114 void
115 nscd_init (const char *conffile)
116 {
117   struct sockaddr_un sock_addr;
118   size_t cnt;
119
120   /* Read the configuration file.  */
121   if (nscd_parse_file (conffile, dbs) != 0)
122     {
123       /* We couldn't read the configuration file.  Disable all services
124          by shutting down the srever.  */
125       dbg_log (_("cannot read configuration file; this is fatal"));
126       exit (1);
127     }
128   if (nthreads == -1)
129     /* No configuration for this value, assume a default.  */
130     nthreads = 2 * lastdb;
131
132   for (cnt = 0; cnt < lastdb; ++cnt)
133     if (dbs[cnt].enabled)
134       {
135         pthread_rwlock_init (&dbs[cnt].lock, NULL);
136
137         dbs[cnt].array = (struct hashentry **)
138           calloc (dbs[cnt].module, sizeof (struct hashentry *));
139         if (dbs[cnt].array == NULL)
140           error (EXIT_FAILURE, errno, "while allocating cache");
141
142         if (dbs[cnt].check_file)
143           {
144             /* We need the modification date of the file.  */
145             struct stat st;
146
147             if (stat (dbs[cnt].filename, &st) < 0)
148               {
149                 char buf[128];
150                 /* We cannot stat() the file, disable file checking.  */
151                 dbg_log (_("cannot stat() file `%s': %s"),
152                          dbs[cnt].filename,
153                          strerror_r (errno, buf, sizeof (buf)));
154                 dbs[cnt].check_file = 0;
155               }
156             else
157               dbs[cnt].file_mtime = st.st_mtime;
158           }
159       }
160
161   /* Create the socket.  */
162   sock = socket (AF_UNIX, SOCK_STREAM, 0);
163   if (sock < 0)
164     {
165       dbg_log (_("cannot open socket: %s"), strerror (errno));
166       exit (1);
167     }
168   /* Bind a name to the socket.  */
169   sock_addr.sun_family = AF_UNIX;
170   strcpy (sock_addr.sun_path, _PATH_NSCDSOCKET);
171   if (bind (sock, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
172     {
173       dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
174       exit (1);
175     }
176
177   /* Set permissions for the socket.  */
178   chmod (_PATH_NSCDSOCKET, 0666);
179
180   /* Set the socket up to accept connections.  */
181   if (listen (sock, SOMAXCONN) < 0)
182     {
183       dbg_log (_("cannot enable socket to accept connections: %s"),
184                strerror (errno));
185       exit (1);
186     }
187 }
188
189
190 /* Close the connections.  */
191 void
192 close_sockets (void)
193 {
194   close (sock);
195 }
196
197 static void
198 invalidate_cache (char *key)
199 {
200   dbtype number;
201
202   if (strcmp (key, "passwd") == 0)
203     number = pwddb;
204   else if (strcmp (key, "group") == 0)
205     number = grpdb;
206   else if (strcmp (key, "hosts") == 0)
207     number = hstdb;
208   else return;
209
210   if (dbs[number].enabled)
211     prune_cache (&dbs[number], LONG_MAX);
212 }
213
214
215 /* Handle new request.  */
216 static void
217 handle_request (int fd, request_header *req, void *key, uid_t uid)
218 {
219   if (debug_level > 0)
220     dbg_log (_("handle_request: request received (Version = %d)"),
221              req->version);
222
223   if (req->version != NSCD_VERSION)
224     {
225       dbg_log (_("\
226 cannot handle old request version %d; current version is %d"),
227                req->version, NSCD_VERSION);
228       return;
229     }
230
231   if (req->type >= GETPWBYNAME && req->type <= LASTDBREQ)
232     {
233       struct hashentry *cached;
234       struct database *db = &dbs[serv2db[req->type]];
235
236       if (debug_level > 0)
237         {
238           if (req->type == GETHOSTBYADDR || req->type == GETHOSTBYADDRv6)
239             {
240               char buf[INET6_ADDRSTRLEN];
241
242               dbg_log ("\t%s (%s)", serv2str[req->type],
243                        inet_ntop (req->type == GETHOSTBYADDR
244                                   ? AF_INET : AF_INET6,
245                                   key, buf, sizeof (buf)));
246             }
247           else
248             dbg_log ("\t%s (%s)", serv2str[req->type], key);
249         }
250
251       /* Is this service enabled?  */
252       if (!db->enabled)
253         {
254           /* No, sent the prepared record.  */
255           if (TEMP_FAILURE_RETRY (write (fd, db->disabled_iov->iov_base,
256                                          db->disabled_iov->iov_len))
257               != db->disabled_iov->iov_len)
258             {
259               /* We have problems sending the result.  */
260               char buf[256];
261               dbg_log (_("cannot write result: %s"),
262                        strerror_r (errno, buf, sizeof (buf)));
263             }
264
265           return;
266         }
267
268       /* Be sure we can read the data.  */
269       pthread_rwlock_rdlock (&db->lock);
270
271       /* See whether we can handle it from the cache.  */
272       cached = (struct hashentry *) cache_search (req->type, key, req->key_len,
273                                                   db, uid);
274       if (cached != NULL)
275         {
276           /* Hurray it's in the cache.  */
277           if (TEMP_FAILURE_RETRY (write (fd, cached->packet, cached->total))
278               != cached->total)
279             {
280               /* We have problems sending the result.  */
281               char buf[256];
282               dbg_log (_("cannot write result: %s"),
283                        strerror_r (errno, buf, sizeof (buf)));
284             }
285
286           pthread_rwlock_unlock (&db->lock);
287
288           return;
289         }
290
291       pthread_rwlock_unlock (&db->lock);
292     }
293   else if (debug_level > 0)
294     {
295       if (req->type == INVALIDATE)
296         dbg_log ("\t%s (%s)", serv2str[req->type], key);
297       else
298         dbg_log ("\t%s", serv2str[req->type]);
299     }
300
301   /* Handle the request.  */
302   switch (req->type)
303     {
304     case GETPWBYNAME:
305       addpwbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
306       break;
307
308     case GETPWBYUID:
309       addpwbyuid (&dbs[serv2db[req->type]], fd, req, key, uid);
310       break;
311
312     case GETGRBYNAME:
313       addgrbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
314       break;
315
316     case GETGRBYGID:
317       addgrbygid (&dbs[serv2db[req->type]], fd, req, key, uid);
318       break;
319
320     case GETHOSTBYNAME:
321       addhstbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
322       break;
323
324     case GETHOSTBYNAMEv6:
325       addhstbynamev6 (&dbs[serv2db[req->type]], fd, req, key, uid);
326       break;
327
328     case GETHOSTBYADDR:
329       addhstbyaddr (&dbs[serv2db[req->type]], fd, req, key, uid);
330       break;
331
332     case GETHOSTBYADDRv6:
333       addhstbyaddrv6 (&dbs[serv2db[req->type]], fd, req, key, uid);
334       break;
335
336     case GETSTAT:
337     case SHUTDOWN:
338     case INVALIDATE:
339       /* Accept shutdown, getstat and invalidate only from root */
340       if (secure_in_use && uid == 0)
341         {
342           if (req->type == GETSTAT)
343             send_stats (fd, dbs);
344           else if (req->type == INVALIDATE)
345             invalidate_cache (key);
346           else
347             termination_handler (0);
348         }
349       else
350         {
351           struct ucred caller;
352           socklen_t optlen = sizeof (caller);
353
354           /* Some systems have no SO_PEERCRED implementation.  They don't
355              care about security so we don't as well.  */
356 #ifdef SO_PEERCRED
357           if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
358             {
359               char buf[256];
360
361               dbg_log (_("error getting callers id: %s"),
362                        strerror_r (errno, buf, sizeof (buf)));
363             }
364           else
365             if (caller.uid == 0)
366 #endif
367               {
368                 if (req->type == GETSTAT)
369                   send_stats (fd, dbs);
370                 else if (req->type == INVALIDATE)
371                   invalidate_cache (key);
372                 else
373                   termination_handler (0);
374               }
375         }
376       break;
377
378     default:
379       /* Ignore the command, it's nothing we know.  */
380       break;
381     }
382 }
383
384
385 /* This is the main loop.  It is replicated in different threads but the
386    `poll' call makes sure only one thread handles an incoming connection.  */
387 static void *
388 __attribute__ ((__noreturn__))
389 nscd_run (void *p)
390 {
391   long int my_number = (long int) p;
392   struct pollfd conn;
393   int run_prune = my_number < lastdb && dbs[my_number].enabled;
394   time_t now = time (NULL);
395   time_t next_prune = now + CACHE_PRUNE_INTERVAL;
396   int timeout = run_prune ? 1000 * (next_prune - now) : -1;
397
398   conn.fd = sock;
399   conn.events = POLLRDNORM;
400
401   while (1)
402     {
403       int nr = poll (&conn, 1, timeout);
404
405       if (nr == 0)
406         {
407           /* The `poll' call timed out.  It's time to clean up the cache.  */
408           assert (my_number < lastdb);
409           now = time (NULL);
410           prune_cache (&dbs[my_number], now);
411           next_prune = now + CACHE_PRUNE_INTERVAL;
412           timeout = 1000 * (next_prune - now);
413           continue;
414         }
415
416       /* We have a new incoming connection.  */
417       if (conn.revents & (POLLRDNORM|POLLERR|POLLHUP|POLLNVAL))
418         {
419           /* Accept the connection.  */
420           int fd = accept (conn.fd, NULL, NULL);
421           request_header req;
422           char buf[256];
423           uid_t uid = 0;
424
425           if (fd < 0)
426             {
427               dbg_log (_("while accepting connection: %s"),
428                        strerror_r (errno, buf, sizeof (buf)));
429               continue;
430             }
431
432           /* Now read the request.  */
433           if (TEMP_FAILURE_RETRY (read (fd, &req, sizeof (req)))
434               != sizeof (req))
435             {
436               dbg_log (_("short read while reading request: %s"),
437                        strerror_r (errno, buf, sizeof (buf)));
438               close (fd);
439               continue;
440             }
441
442           /* Some systems have no SO_PEERCRED implementation.  They don't
443              care about security so we don't as well.  */
444 #ifdef SO_PEERCRED
445           if (secure_in_use)
446             {
447               struct ucred caller;
448               socklen_t optlen = sizeof (caller);
449
450               if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED,
451                               &caller, &optlen) < 0)
452                 {
453                   dbg_log (_("error getting callers id: %s"),
454                            strerror_r (errno, buf, sizeof (buf)));
455                   close (fd);
456                   continue;
457                 }
458
459               if (req.type < GETPWBYNAME || req.type > LASTDBREQ
460                   || secure[serv2db[req.type]])
461                 uid = caller.uid;
462             }
463 #endif
464
465           /* It should not be possible to crash the nscd with a silly
466              request (i.e., a terribly large key).  We limit the size
467              to 1kb.  */
468           if (req.key_len < 0 || req.key_len > 1024)
469             {
470               dbg_log (_("key length in request too long: %zd"), req.key_len);
471               close (fd);
472               continue;
473             }
474           else
475             {
476               /* Get the key.  */
477               char keybuf[req.key_len];
478
479               if (TEMP_FAILURE_RETRY (read (fd, keybuf, req.key_len))
480                   != req.key_len)
481                 {
482                   dbg_log (_("short read while reading request key: %s"),
483                            strerror_r (errno, buf, sizeof (buf)));
484                   close (fd);
485                   continue;
486                 }
487
488               /* Phew, we got all the data, now process it.  */
489               handle_request (fd, &req, keybuf, uid);
490
491               /* We are done.  */
492               close (fd);
493             }
494         }
495
496       if (run_prune)
497         {
498           now = time (NULL);
499           timeout = now < next_prune ? 1000 * (next_prune - now) : 0;
500         }
501     }
502 }
503
504
505 /* Start all the threads we want.  The initial process is thread no. 1.  */
506 void
507 start_threads (void)
508 {
509   long int i;
510   pthread_attr_t attr;
511   pthread_t th;
512
513   pthread_attr_init (&attr);
514   pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
515
516   /* We allow less than LASTDB threads only for debugging.  */
517   if (debug_level == 0)
518     nthreads = MAX (nthreads, lastdb);
519
520   for (i = 1; i < nthreads; ++i)
521     pthread_create (&th, &attr, nscd_run, (void *) i);
522
523   pthread_attr_destroy (&attr);
524
525   nscd_run ((void *) 0);
526 }