(nscd_gethst_r): Make sure resultbuf->h_addr_list addresses are
[kopensolaris-gnu/glibc.git] / nscd / connections.c
1 /* Inner loops of cache daemon.
2    Copyright (C) 1998, 1999 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 };
66
67 /* The control data structures for the services.  */
68 static struct database dbs[lastdb] =
69 {
70   [pwddb] = {
71     lock: PTHREAD_RWLOCK_INITIALIZER,
72     enabled: 0,
73     check_file: 1,
74     filename: "/etc/passwd",
75     module: 211,
76     disabled_iov: &pwd_iov_disabled,
77     postimeout: 3600,
78     negtimeout: 20
79   },
80   [grpdb] = {
81     lock: PTHREAD_RWLOCK_INITIALIZER,
82     enabled: 0,
83     check_file: 1,
84     filename: "/etc/group",
85     module: 211,
86     disabled_iov: &grp_iov_disabled,
87     postimeout: 3600,
88     negtimeout: 60
89   },
90   [hstdb] = {
91     lock: PTHREAD_RWLOCK_INITIALIZER,
92     enabled: 0,
93     check_file: 1,
94     filename: "/etc/hosts",
95     module: 211,
96     disabled_iov: &hst_iov_disabled,
97     postimeout: 3600,
98     negtimeout: 20
99   }
100 };
101
102 /* Number of seconds between two cache pruning runs.  */
103 #define CACHE_PRUNE_INTERVAL    15
104
105 /* Number of threads to use.  */
106 int nthreads = -1;
107
108 /* Socket for incoming connections.  */
109 static int sock;
110
111
112 /* Initialize database information structures.  */
113 void
114 nscd_init (const char *conffile)
115 {
116   struct sockaddr_un sock_addr;
117   size_t cnt;
118
119   /* Read the configuration file.  */
120   if (nscd_parse_file (conffile, dbs) != 0)
121     {
122       /* We couldn't read the configuration file.  Disable all services
123          by shutting down the srever.  */
124       dbg_log (_("cannot read configuration file; this is fatal"));
125       exit (1);
126     }
127   if (nthreads == -1)
128     /* No configuration for this value, assume a default.  */
129     nthreads = 2 * lastdb;
130
131   for (cnt = 0; cnt < lastdb; ++cnt)
132     if (dbs[cnt].enabled)
133       {
134         pthread_rwlock_init (&dbs[cnt].lock, NULL);
135
136         dbs[cnt].array = (struct hashentry **)
137           calloc (dbs[cnt].module, sizeof (struct hashentry *));
138         if (dbs[cnt].array == NULL)
139           error (EXIT_FAILURE, errno, "while allocating cache");
140
141         if (dbs[cnt].check_file)
142           {
143             /* We need the modification date of the file.  */
144             struct stat st;
145
146             if (stat (dbs[cnt].filename, &st) < 0)
147               {
148                 char buf[128];
149                 /* We cannot stat() the file, disable file checking.  */
150                 dbg_log (_("cannot stat() file `%s': %s"),
151                          dbs[cnt].filename,
152                          strerror_r (errno, buf, sizeof (buf)));
153                 dbs[cnt].check_file = 0;
154               }
155             else
156               dbs[cnt].file_mtime = st.st_mtime;
157           }
158       }
159
160   /* Create the socket.  */
161   sock = socket (AF_UNIX, SOCK_STREAM, 0);
162   if (sock < 0)
163     {
164       dbg_log (_("cannot open socket: %s"), strerror (errno));
165       exit (1);
166     }
167   /* Bind a name to the socket.  */
168   sock_addr.sun_family = AF_UNIX;
169   strcpy (sock_addr.sun_path, _PATH_NSCDSOCKET);
170   if (bind (sock, (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
171     {
172       dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
173       exit (1);
174     }
175
176   /* Set permissions for the socket.  */
177   chmod (_PATH_NSCDSOCKET, 0666);
178
179   /* Set the socket up to accept connections.  */
180   if (listen (sock, SOMAXCONN) < 0)
181     {
182       dbg_log (_("cannot enable socket to accept connections: %s"),
183                strerror (errno));
184       exit (1);
185     }
186 }
187
188
189 /* Close the connections.  */
190 void
191 close_sockets (void)
192 {
193   close (sock);
194 }
195
196
197 /* Handle new request.  */
198 static void
199 handle_request (int fd, request_header *req, void *key, uid_t uid)
200 {
201   if (debug_level > 0)
202     dbg_log (_("handle_request: request received (Version = %d)"),
203              req->version);
204
205   if (req->version != NSCD_VERSION)
206     {
207       dbg_log (_("\
208 cannot handle old request version %d; current version is %d"),
209                req->version, NSCD_VERSION);
210       return;
211     }
212
213   if (req->type >= GETPWBYNAME && req->type <= LASTDBREQ)
214     {
215       struct hashentry *cached;
216       struct database *db = &dbs[serv2db[req->type]];
217
218       if (debug_level > 0)
219         {
220           if (req->type == GETHOSTBYADDR || req->type == GETHOSTBYADDRv6)
221             {
222               char buf[INET6_ADDRSTRLEN];
223
224               dbg_log ("\t%s (%s)", serv2str[req->type],
225                        inet_ntop (req->type == GETHOSTBYADDR
226                                   ? AF_INET : AF_INET6,
227                                   key, buf, sizeof (buf)));
228             }
229           else
230             dbg_log ("\t%s (%s)", serv2str[req->type], key);
231         }
232
233       /* Is this service enabled?  */
234       if (!db->enabled)
235         {
236           /* No, sent the prepared record.  */
237           if (TEMP_FAILURE_RETRY (write (fd, db->disabled_iov->iov_base,
238                                          db->disabled_iov->iov_len))
239               != db->disabled_iov->iov_len)
240             {
241               /* We have problems sending the result.  */
242               char buf[256];
243               dbg_log (_("cannot write result: %s"),
244                        strerror_r (errno, buf, sizeof (buf)));
245             }
246
247           return;
248         }
249
250       /* Be sure we can read the data.  */
251       pthread_rwlock_rdlock (&db->lock);
252
253       /* See whether we can handle it from the cache.  */
254       cached = (struct hashentry *) cache_search (req->type, key, req->key_len,
255                                                   db, uid);
256       if (cached != NULL)
257         {
258           /* Hurray it's in the cache.  */
259           if (TEMP_FAILURE_RETRY (write (fd, cached->packet, cached->total))
260               != cached->total)
261             {
262               /* We have problems sending the result.  */
263               char buf[256];
264               dbg_log (_("cannot write result: %s"),
265                        strerror_r (errno, buf, sizeof (buf)));
266             }
267
268           pthread_rwlock_unlock (&db->lock);
269
270           return;
271         }
272
273       pthread_rwlock_unlock (&db->lock);
274     }
275   else
276     if (debug_level > 0)
277       dbg_log ("\t%s", serv2str[req->type]);
278
279   /* Handle the request.  */
280   switch (req->type)
281     {
282     case GETPWBYNAME:
283       addpwbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
284       break;
285
286     case GETPWBYUID:
287       addpwbyuid (&dbs[serv2db[req->type]], fd, req, key, uid);
288       break;
289
290     case GETGRBYNAME:
291       addgrbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
292       break;
293
294     case GETGRBYGID:
295       addgrbygid (&dbs[serv2db[req->type]], fd, req, key, uid);
296       break;
297
298     case GETHOSTBYNAME:
299       addhstbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
300       break;
301
302     case GETHOSTBYNAMEv6:
303       addhstbynamev6 (&dbs[serv2db[req->type]], fd, req, key, uid);
304       break;
305
306     case GETHOSTBYADDR:
307       addhstbyaddr (&dbs[serv2db[req->type]], fd, req, key, uid);
308       break;
309
310     case GETHOSTBYADDRv6:
311       addhstbyaddrv6 (&dbs[serv2db[req->type]], fd, req, key, uid);
312       break;
313
314     case GETSTAT:
315     case SHUTDOWN:
316       /* Accept shutdown and getstat only from root */
317       if (secure_in_use && uid == 0)
318         {
319           if (req->type == GETSTAT)
320             send_stats (fd, dbs);
321           else
322             termination_handler (0);
323         }
324       else
325         {
326           struct ucred caller;
327           socklen_t optlen = sizeof (caller);
328
329           if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
330             {
331               char buf[256];
332
333               dbg_log (_("error getting callers id: %s"),
334                        strerror_r (errno, buf, sizeof (buf)));
335             }
336           else
337             if (caller.uid == 0)
338               {
339                 if (req->type == GETSTAT)
340                   send_stats (fd, dbs);
341                 else
342                   termination_handler (0);
343               }
344         }
345       break;
346
347     default:
348       abort ();
349     }
350 }
351
352
353 /* This is the main loop.  It is replicated in different threads but the
354    `poll' call makes sure only one thread handles an incoming connection.  */
355 static void *
356 __attribute__ ((__noreturn__))
357 nscd_run (void *p)
358 {
359   int my_number = (int) p;
360   struct pollfd conn;
361   int run_prune = my_number < lastdb && dbs[my_number].enabled;
362   time_t now = time (NULL);
363   time_t next_prune = now + CACHE_PRUNE_INTERVAL;
364   int timeout = run_prune ? 1000 * (next_prune - now) : -1;
365
366   conn.fd = sock;
367   conn.events = POLLRDNORM;
368
369   while (1)
370     {
371       int nr = poll (&conn, 1, timeout);
372
373       if (nr == 0)
374         {
375           /* The `poll' call timed out.  It's time to clean up the cache.  */
376           assert (my_number < lastdb);
377           now = time (NULL);
378           prune_cache (&dbs[my_number], now);
379           next_prune = now + CACHE_PRUNE_INTERVAL;
380           timeout = 1000 * (next_prune - now);
381           continue;
382         }
383
384       /* We have a new incoming connection.  */
385       if (conn.revents & (POLLRDNORM|POLLERR|POLLHUP|POLLNVAL))
386         {
387           /* Accept the connection.  */
388           int fd = accept (conn.fd, NULL, NULL);
389           request_header req;
390           char buf[256];
391           uid_t uid = 0;
392
393           if (fd < 0)
394             {
395               dbg_log (_("while accepting connection: %s"),
396                        strerror_r (errno, buf, sizeof (buf)));
397               continue;
398             }
399
400           /* Now read the request.  */
401           if (TEMP_FAILURE_RETRY (read (fd, &req, sizeof (req)))
402               != sizeof (req))
403             {
404               dbg_log (_("short read while reading request: %s"),
405                        strerror_r (errno, buf, sizeof (buf)));
406               close (fd);
407               continue;
408             }
409
410           if (secure_in_use)
411             {
412               struct ucred caller;
413               socklen_t optlen = sizeof (caller);
414
415               if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED,
416                               &caller, &optlen) < 0)
417                 {
418                   dbg_log (_("error getting callers id: %s"),
419                            strerror_r (errno, buf, sizeof (buf)));
420                   close (fd);
421                   continue;
422                 }
423
424               if (req.type < GETPWBYNAME || req.type > LASTDBREQ
425                   || secure[serv2db[req.type]])
426                 uid = caller.uid;
427             }
428
429           /* It should not be possible to crash the nscd with a silly
430              request (i.e., a terribly large key.  We limit the size
431              to 1kb.  */
432           if (req.key_len < 0 || req.key_len > 1024)
433             {
434               dbg_log (_("key length in request too long: %Zd"), req.key_len);
435               close (fd);
436               continue;
437             }
438           else
439             {
440               /* Get the key.  */
441               char keybuf[req.key_len];
442
443               if (TEMP_FAILURE_RETRY (read (fd, keybuf, req.key_len))
444                   != req.key_len)
445                 {
446                   dbg_log (_("short read while reading request key: %s"),
447                            strerror_r (errno, buf, sizeof (buf)));
448                   close (fd);
449                   continue;
450                 }
451
452               /* Phew, we got all the data, now process it.  */
453               handle_request (fd, &req, keybuf, uid);
454
455               /* We are done.  */
456               close (fd);
457             }
458         }
459
460       if (run_prune)
461         {
462           now = time (NULL);
463           timeout = now < next_prune ? 1000 * (next_prune - now) : 0;
464         }
465     }
466 }
467
468
469 /* Start all the threads we want.  The initial process is thread no. 1.  */
470 void
471 start_threads (void)
472 {
473   int i;
474   pthread_attr_t attr;
475   pthread_t th;
476
477   pthread_attr_init (&attr);
478   pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
479
480   /* We allow less than LASTDB threads only for debugging.  */
481   if (debug_level == 0)
482     nthreads = MAX (nthreads, lastdb);
483
484   for (i = 1; i < nthreads; ++i)
485     pthread_create (&th, &attr, nscd_run, (void *) i);
486
487   pthread_attr_destroy (&attr);
488
489   nscd_run ((void *) 0);
490 }