1 /* Inner loops of cache daemon.
2 Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
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 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 #include <arpa/inet.h>
29 #include <sys/param.h>
31 #include <sys/socket.h>
39 /* Mapping of request type to database. */
40 static const dbtype serv2db
[LASTDBREQ
+ 1] =
42 [GETPWBYNAME
] = pwddb
,
44 [GETGRBYNAME
] = grpdb
,
46 [GETHOSTBYNAME
] = hstdb
,
47 [GETHOSTBYNAMEv6
] = hstdb
,
48 [GETHOSTBYADDR
] = hstdb
,
49 [GETHOSTBYADDRv6
] = hstdb
,
52 /* Map request type to a string. */
53 const char *serv2str
[LASTREQ
] =
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"
68 /* The control data structures for the services. */
69 static struct database dbs
[lastdb
] =
72 lock
: PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
,
75 filename
: "/etc/passwd",
77 disabled_iov
: &pwd_iov_disabled
,
82 lock
: PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
,
85 filename
: "/etc/group",
87 disabled_iov
: &grp_iov_disabled
,
92 lock
: PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
,
95 filename
: "/etc/hosts",
97 disabled_iov
: &hst_iov_disabled
,
103 /* Number of seconds between two cache pruning runs. */
104 #define CACHE_PRUNE_INTERVAL 15
106 /* Number of threads to use. */
109 /* Socket for incoming connections. */
113 /* Initialize database information structures. */
115 nscd_init (const char *conffile
)
117 struct sockaddr_un sock_addr
;
120 /* Read the configuration file. */
121 if (nscd_parse_file (conffile
, dbs
) != 0)
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"));
129 /* No configuration for this value, assume a default. */
130 nthreads
= 2 * lastdb
;
132 for (cnt
= 0; cnt
< lastdb
; ++cnt
)
133 if (dbs
[cnt
].enabled
)
135 pthread_rwlock_init (&dbs
[cnt
].lock
, NULL
);
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");
142 if (dbs
[cnt
].check_file
)
144 /* We need the modification date of the file. */
147 if (stat (dbs
[cnt
].filename
, &st
) < 0)
150 /* We cannot stat() the file, disable file checking. */
151 dbg_log (_("cannot stat() file `%s': %s"),
153 strerror_r (errno
, buf
, sizeof (buf
)));
154 dbs
[cnt
].check_file
= 0;
157 dbs
[cnt
].file_mtime
= st
.st_mtime
;
161 /* Create the socket. */
162 sock
= socket (AF_UNIX
, SOCK_STREAM
, 0);
165 dbg_log (_("cannot open socket: %s"), strerror (errno
));
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)
173 dbg_log ("%s: %s", _PATH_NSCDSOCKET
, strerror (errno
));
177 /* Set permissions for the socket. */
178 chmod (_PATH_NSCDSOCKET
, 0666);
180 /* Set the socket up to accept connections. */
181 if (listen (sock
, SOMAXCONN
) < 0)
183 dbg_log (_("cannot enable socket to accept connections: %s"),
190 /* Close the connections. */
198 invalidate_cache (char *key
)
202 if (strcmp (key
, "passwd") == 0)
204 else if (strcmp (key
, "group") == 0)
206 else if (__builtin_expect (strcmp (key
, "hosts"), 0) == 0)
211 if (dbs
[number
].enabled
)
212 prune_cache (&dbs
[number
], LONG_MAX
);
216 /* Handle new request. */
218 handle_request (int fd
, request_header
*req
, void *key
, uid_t uid
)
220 if (__builtin_expect (debug_level
, 0) > 0)
221 dbg_log (_("handle_request: request received (Version = %d)"),
224 if (__builtin_expect (req
->version
, NSCD_VERSION
) != NSCD_VERSION
)
228 cannot handle old request version %d; current version is %d"),
229 req
->version
, NSCD_VERSION
);
233 if (__builtin_expect (req
->type
, GETPWBYNAME
) >= GETPWBYNAME
234 && __builtin_expect (req
->type
, LASTDBREQ
) <= LASTDBREQ
)
236 struct hashentry
*cached
;
237 struct database
*db
= &dbs
[serv2db
[req
->type
]];
239 if (__builtin_expect (debug_level
, 0) > 0)
241 if (req
->type
== GETHOSTBYADDR
|| req
->type
== GETHOSTBYADDRv6
)
243 char buf
[INET6_ADDRSTRLEN
];
245 dbg_log ("\t%s (%s)", serv2str
[req
->type
],
246 inet_ntop (req
->type
== GETHOSTBYADDR
247 ? AF_INET
: AF_INET6
,
248 key
, buf
, sizeof (buf
)));
251 dbg_log ("\t%s (%s)", serv2str
[req
->type
], (char *)key
);
254 /* Is this service enabled? */
257 /* No, sent the prepared record. */
258 if (TEMP_FAILURE_RETRY (write (fd
, db
->disabled_iov
->iov_base
,
259 db
->disabled_iov
->iov_len
))
260 != db
->disabled_iov
->iov_len
261 && __builtin_expect (debug_level
, 0) > 0)
263 /* We have problems sending the result. */
265 dbg_log (_("cannot write result: %s"),
266 strerror_r (errno
, buf
, sizeof (buf
)));
272 /* Be sure we can read the data. */
273 pthread_rwlock_rdlock (&db
->lock
);
275 /* See whether we can handle it from the cache. */
276 cached
= (struct hashentry
*) cache_search (req
->type
, key
, req
->key_len
,
280 /* Hurray it's in the cache. */
281 if (TEMP_FAILURE_RETRY (write (fd
, cached
->packet
, cached
->total
))
283 && __builtin_expect (debug_level
, 0) > 0)
285 /* We have problems sending the result. */
287 dbg_log (_("cannot write result: %s"),
288 strerror_r (errno
, buf
, sizeof (buf
)));
291 pthread_rwlock_unlock (&db
->lock
);
296 pthread_rwlock_unlock (&db
->lock
);
298 else if (__builtin_expect (debug_level
, 0) > 0)
300 if (req
->type
== INVALIDATE
)
301 dbg_log ("\t%s (%s)", serv2str
[req
->type
], (char *)key
);
303 dbg_log ("\t%s", serv2str
[req
->type
]);
306 /* Handle the request. */
310 addpwbyname (&dbs
[serv2db
[req
->type
]], fd
, req
, key
, uid
);
314 addpwbyuid (&dbs
[serv2db
[req
->type
]], fd
, req
, key
, uid
);
318 addgrbyname (&dbs
[serv2db
[req
->type
]], fd
, req
, key
, uid
);
322 addgrbygid (&dbs
[serv2db
[req
->type
]], fd
, req
, key
, uid
);
326 addhstbyname (&dbs
[serv2db
[req
->type
]], fd
, req
, key
, uid
);
329 case GETHOSTBYNAMEv6
:
330 addhstbynamev6 (&dbs
[serv2db
[req
->type
]], fd
, req
, key
, uid
);
334 addhstbyaddr (&dbs
[serv2db
[req
->type
]], fd
, req
, key
, uid
);
337 case GETHOSTBYADDRv6
:
338 addhstbyaddrv6 (&dbs
[serv2db
[req
->type
]], fd
, req
, key
, uid
);
344 /* Accept shutdown, getstat and invalidate only from root */
345 if (secure_in_use
&& uid
== 0)
347 if (req
->type
== GETSTAT
)
348 send_stats (fd
, dbs
);
349 else if (req
->type
== INVALIDATE
)
350 invalidate_cache (key
);
352 termination_handler (0);
357 socklen_t optlen
= sizeof (caller
);
359 /* Some systems have no SO_PEERCRED implementation. They don't
360 care about security so we don't as well. */
362 if (getsockopt (fd
, SOL_SOCKET
, SO_PEERCRED
, &caller
, &optlen
) < 0)
366 dbg_log (_("error getting callers id: %s"),
367 strerror_r (errno
, buf
, sizeof (buf
)));
373 if (req
->type
== GETSTAT
)
374 send_stats (fd
, dbs
);
375 else if (req
->type
== INVALIDATE
)
376 invalidate_cache (key
);
378 termination_handler (0);
384 /* Ignore the command, it's nothing we know. */
390 /* This is the main loop. It is replicated in different threads but the
391 `poll' call makes sure only one thread handles an incoming connection. */
393 __attribute__ ((__noreturn__
))
396 long int my_number
= (long int) p
;
398 int run_prune
= my_number
< lastdb
&& dbs
[my_number
].enabled
;
399 time_t now
= time (NULL
);
400 time_t next_prune
= now
+ CACHE_PRUNE_INTERVAL
;
401 int timeout
= run_prune
? 1000 * (next_prune
- now
) : -1;
404 conn
.events
= POLLRDNORM
;
408 int nr
= poll (&conn
, 1, timeout
);
412 /* The `poll' call timed out. It's time to clean up the cache. */
413 assert (my_number
< lastdb
);
415 prune_cache (&dbs
[my_number
], now
);
416 next_prune
= now
+ CACHE_PRUNE_INTERVAL
;
417 timeout
= 1000 * (next_prune
- now
);
421 /* We have a new incoming connection. */
422 if (conn
.revents
& (POLLRDNORM
|POLLERR
|POLLHUP
|POLLNVAL
))
424 /* Accept the connection. */
425 int fd
= accept (conn
.fd
, NULL
, NULL
);
430 if (__builtin_expect (fd
, 0) < 0)
432 dbg_log (_("while accepting connection: %s"),
433 strerror_r (errno
, buf
, sizeof (buf
)));
437 /* Now read the request. */
438 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd
, &req
,
443 dbg_log (_("short read while reading request: %s"),
444 strerror_r (errno
, buf
, sizeof (buf
)));
449 /* Some systems have no SO_PEERCRED implementation. They don't
450 care about security so we don't as well. */
455 socklen_t optlen
= sizeof (caller
);
457 if (getsockopt (fd
, SOL_SOCKET
, SO_PEERCRED
,
458 &caller
, &optlen
) < 0)
460 dbg_log (_("error getting callers id: %s"),
461 strerror_r (errno
, buf
, sizeof (buf
)));
466 if (req
.type
< GETPWBYNAME
|| req
.type
> LASTDBREQ
467 || secure
[serv2db
[req
.type
]])
472 /* It should not be possible to crash the nscd with a silly
473 request (i.e., a terribly large key). We limit the size
475 if (__builtin_expect (req
.key_len
, 1) < 0
476 || __builtin_expect (req
.key_len
, 1) > 1024)
479 dbg_log (_("key length in request too long: %d"), req
.key_len
);
486 char keybuf
[req
.key_len
];
488 if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd
, keybuf
,
493 dbg_log (_("short read while reading request key: %s"),
494 strerror_r (errno
, buf
, sizeof (buf
)));
499 /* Phew, we got all the data, now process it. */
500 handle_request (fd
, &req
, keybuf
, uid
);
510 timeout
= now
< next_prune
? 1000 * (next_prune
- now
) : 0;
516 /* Start all the threads we want. The initial process is thread no. 1. */
524 pthread_attr_init (&attr
);
525 pthread_attr_setdetachstate (&attr
, PTHREAD_CREATE_DETACHED
);
527 /* We allow less than LASTDB threads only for debugging. */
528 if (debug_level
== 0)
529 nthreads
= MAX (nthreads
, lastdb
);
531 for (i
= 1; i
< nthreads
; ++i
)
532 pthread_create (&th
, &attr
, nscd_run
, (void *) i
);
534 pthread_attr_destroy (&attr
);
536 nscd_run ((void *) 0);