8158 Want named threads API
[unleashed.git] / usr / src / cmd / nscd / nscd_frontend.c
blob134da3f2802a911d2a306a2cffc1f63923ae9e42
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2012 Milan Jurik. All rights reserved.
25 * Copyright 2018 Joyent, Inc.
28 #include <stdlib.h>
29 #include <alloca.h>
30 #include <signal.h>
31 #include <sys/stat.h>
32 #include <unistd.h>
33 #include <pthread.h>
34 #include <time.h>
35 #include <errno.h>
36 #include <door.h>
37 #include <zone.h>
38 #include <resolv.h>
39 #include <sys/socket.h>
40 #include <net/route.h>
41 #include <string.h>
42 #include <net/if.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include "nscd_common.h"
46 #include "nscd_door.h"
47 #include "nscd_config.h"
48 #include "nscd_switch.h"
49 #include "nscd_log.h"
50 #include "nscd_selfcred.h"
51 #include "nscd_frontend.h"
52 #include "nscd_admin.h"
54 static void rts_mon(void);
55 static void keep_open_dns_socket(void);
57 extern nsc_ctx_t *cache_ctx_p[];
60 * Current active Configuration data for the frontend component
62 static nscd_cfg_global_frontend_t frontend_cfg_g;
63 static nscd_cfg_frontend_t *frontend_cfg;
65 static int max_servers = 0;
66 static int max_servers_set = 0;
67 static int per_user_is_on = 1;
69 static char *main_execname;
70 static char **main_argv;
71 extern int _whoami;
72 extern long activity;
73 extern mutex_t activity_lock;
75 static sema_t common_sema;
77 static thread_key_t lookup_state_key;
78 static mutex_t create_lock = DEFAULTMUTEX;
79 static int num_servers = 0;
80 static thread_key_t server_key;
83 * Bind a TSD value to a server thread. This enables the destructor to
84 * be called if/when this thread exits. This would be a programming
85 * error, but better safe than sorry.
87 /*ARGSUSED*/
88 static void *
89 server_tsd_bind(void *arg)
91 static void *value = 0;
93 (void) thr_setname(thr_self(), "server_tsd_bind");
95 /* disable cancellation to avoid hangs if server threads disappear */
96 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
97 (void) thr_setspecific(server_key, value);
98 (void) door_return(NULL, 0, NULL, 0);
100 /* make lint happy */
101 return (NULL);
105 * Server threads are created here.
107 /*ARGSUSED*/
108 static void
109 server_create(door_info_t *dip)
111 (void) mutex_lock(&create_lock);
112 if (++num_servers > max_servers) {
113 num_servers--;
114 (void) mutex_unlock(&create_lock);
115 return;
117 (void) mutex_unlock(&create_lock);
118 (void) thr_create(NULL, 0, server_tsd_bind, NULL,
119 THR_BOUND|THR_DETACHED, NULL);
123 * Server thread are destroyed here
125 /*ARGSUSED*/
126 static void
127 server_destroy(void *arg)
129 (void) mutex_lock(&create_lock);
130 num_servers--;
131 (void) mutex_unlock(&create_lock);
135 * get clearance
138 _nscd_get_clearance(sema_t *sema)
140 if (sema_trywait(&common_sema) == 0) {
141 (void) thr_setspecific(lookup_state_key, NULL);
142 return (0);
145 if (sema_trywait(sema) == 0) {
146 (void) thr_setspecific(lookup_state_key, (void*)1);
147 return (0);
150 return (1);
155 * release clearance
158 _nscd_release_clearance(sema_t *sema)
160 int which;
162 (void) thr_getspecific(lookup_state_key, (void**)&which);
163 if (which == 0) /* from common pool */ {
164 (void) sema_post(&common_sema);
165 return (0);
168 (void) sema_post(sema);
169 return (1);
172 static void
173 dozip(void)
175 /* not much here */
179 * _nscd_restart_if_cfgfile_changed()
180 * Restart if modification times of nsswitch.conf or resolv.conf have changed.
182 * If nsswitch.conf has changed then it is possible that sources for
183 * various backends have changed and therefore the current cached
184 * data may not be consistent with the new data sources. By
185 * restarting the cache will be cleared and the new configuration will
186 * be used.
188 * The check for resolv.conf is made as only the first call to
189 * res_gethostbyname() or res_getaddrbyname() causes a call to
190 * res_ninit() to occur which in turn parses resolv.conf. Therefore
191 * to benefit from changes to resolv.conf nscd must be restarted when
192 * resolv.conf is updated, removed or created. If res_getXbyY calls
193 * are removed from NSS then this check could be removed.
196 void
197 _nscd_restart_if_cfgfile_changed()
200 static mutex_t nsswitch_lock = DEFAULTMUTEX;
201 static timestruc_t last_nsswitch_check = { 0 };
202 static timestruc_t last_nsswitch_modified = { 0 };
203 static timestruc_t last_resolv_modified = { -1, 0 };
204 static mutex_t restarting_lock = DEFAULTMUTEX;
205 static int restarting = 0;
206 int restart = 0;
207 time_t now = time(NULL);
208 char *me = "_nscd_restart_if_cfgfile_changed";
210 #define FLAG_RESTART_REQUIRED if (restarting == 0) {\
211 (void) mutex_lock(&restarting_lock);\
212 if (restarting == 0) {\
213 restarting = 1;\
214 restart = 1;\
216 (void) mutex_unlock(&restarting_lock);\
219 if (restarting == 1)
220 return;
222 if (now - last_nsswitch_check.tv_sec < _NSC_FILE_CHECK_TIME)
223 return;
225 (void) mutex_lock(&nsswitch_lock);
227 if (now - last_nsswitch_check.tv_sec >= _NSC_FILE_CHECK_TIME) {
228 struct stat nss_buf;
229 struct stat res_buf;
231 last_nsswitch_check.tv_sec = now;
232 last_nsswitch_check.tv_nsec = 0;
234 (void) mutex_unlock(&nsswitch_lock); /* let others continue */
236 if (stat("/etc/nsswitch.conf", &nss_buf) < 0) {
237 return;
238 } else if (last_nsswitch_modified.tv_sec == 0) {
239 last_nsswitch_modified = nss_buf.st_mtim;
242 if (last_nsswitch_modified.tv_sec < nss_buf.st_mtim.tv_sec ||
243 (last_nsswitch_modified.tv_sec == nss_buf.st_mtim.tv_sec &&
244 last_nsswitch_modified.tv_nsec < nss_buf.st_mtim.tv_nsec)) {
245 FLAG_RESTART_REQUIRED;
248 if (restart == 0) {
249 if (stat("/etc/resolv.conf", &res_buf) < 0) {
250 /* Unable to stat file, were we previously? */
251 if (last_resolv_modified.tv_sec > 0) {
252 /* Yes, it must have been removed. */
253 FLAG_RESTART_REQUIRED;
254 } else if (last_resolv_modified.tv_sec == -1) {
255 /* No, then we've never seen it. */
256 last_resolv_modified.tv_sec = 0;
258 } else if (last_resolv_modified.tv_sec == -1) {
259 /* We've just started and file is present. */
260 last_resolv_modified = res_buf.st_mtim;
261 } else if (last_resolv_modified.tv_sec == 0) {
262 /* Wasn't there at start-up. */
263 FLAG_RESTART_REQUIRED;
264 } else if (last_resolv_modified.tv_sec <
265 res_buf.st_mtim.tv_sec ||
266 (last_resolv_modified.tv_sec ==
267 res_buf.st_mtim.tv_sec &&
268 last_resolv_modified.tv_nsec <
269 res_buf.st_mtim.tv_nsec)) {
270 FLAG_RESTART_REQUIRED;
274 if (restart == 1) {
275 char *fmri;
278 * if in self cred mode, kill the forker and
279 * child nscds
281 if (_nscd_is_self_cred_on(0, NULL)) {
282 _nscd_kill_forker();
283 _nscd_kill_all_children();
287 * time for restart
289 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_INFO)
290 (me, "nscd restart due to %s or %s change\n",
291 "/etc/nsswitch.conf", "resolv.conf");
293 * try to restart under smf
295 if ((fmri = getenv("SMF_FMRI")) == NULL) {
296 /* not running under smf - reexec */
297 (void) execv(main_execname, main_argv);
298 exit(1); /* just in case */
301 if (smf_restart_instance(fmri) == 0)
302 (void) sleep(10); /* wait a bit */
303 exit(1); /* give up waiting for resurrection */
306 } else
307 (void) mutex_unlock(&nsswitch_lock);
310 uid_t
311 _nscd_get_client_euid()
313 ucred_t *uc = NULL;
314 uid_t id;
315 char *me = "get_client_euid";
317 if (door_ucred(&uc) != 0) {
318 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
319 (me, "door_ucred: %s\n", strerror(errno));
320 return ((uid_t)-1);
323 id = ucred_geteuid(uc);
324 ucred_free(uc);
325 return (id);
329 * Check to see if the door client's euid is 0 or if it has required_priv
330 * privilege. Return 0 if yes, -1 otherwise.
331 * Supported values for required_priv are:
332 * - NSCD_ALL_PRIV: for all zones privileges
333 * - NSCD_READ_PRIV: for PRIV_FILE_DAC_READ privilege
336 _nscd_check_client_priv(int required_priv)
338 int rc = 0;
339 ucred_t *uc = NULL;
340 const priv_set_t *eset;
341 char *me = "_nscd_check_client_read_priv";
342 priv_set_t *zs; /* zone */
344 if (door_ucred(&uc) != 0) {
345 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
346 (me, "door_ucred: %s\n", strerror(errno));
347 return (-1);
350 if (ucred_geteuid(uc) == 0) {
351 ucred_free(uc);
352 return (0);
355 eset = ucred_getprivset(uc, PRIV_EFFECTIVE);
356 switch (required_priv) {
357 case NSCD_ALL_PRIV:
358 zs = priv_str_to_set("zone", ",", NULL);
359 if (!priv_isequalset(eset, zs)) {
360 _NSCD_LOG(NSCD_LOG_FRONT_END,
361 NSCD_LOG_LEVEL_ERROR)
362 (me, "missing all zones privileges\n");
363 rc = -1;
365 priv_freeset(zs);
366 break;
367 case NSCD_READ_PRIV:
368 if (!priv_ismember(eset, PRIV_FILE_DAC_READ))
369 rc = -1;
370 break;
371 default:
372 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
373 (me, "unknown required_priv: %d\n", required_priv);
374 rc = -1;
375 break;
377 ucred_free(uc);
378 return (rc);
381 static void
382 N2N_check_priv(
383 void *buf,
384 char *dc_str)
386 nss_pheader_t *phdr = (nss_pheader_t *)buf;
387 ucred_t *uc = NULL;
388 const priv_set_t *eset;
389 zoneid_t zoneid;
390 int errnum;
391 char *me = "N2N_check_priv";
393 if (door_ucred(&uc) != 0) {
394 errnum = errno;
395 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
396 (me, "door_ucred: %s\n", strerror(errno));
398 NSCD_SET_STATUS(phdr, NSS_ERROR, errnum);
399 return;
402 eset = ucred_getprivset(uc, PRIV_EFFECTIVE);
403 zoneid = ucred_getzoneid(uc);
405 if ((zoneid != GLOBAL_ZONEID && zoneid != getzoneid()) ||
406 eset != NULL ? !priv_ismember(eset, PRIV_SYS_ADMIN) :
407 ucred_geteuid(uc) != 0) {
409 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT)
410 (me, "%s call failed(cred): caller pid %d, uid %d, "
411 "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc),
412 ucred_getruid(uc), ucred_geteuid(uc), zoneid);
413 ucred_free(uc);
415 NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES);
416 return;
419 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
420 (me, "nscd received %s cmd from pid %d, uid %d, "
421 "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc),
422 ucred_getruid(uc), ucred_geteuid(uc), zoneid);
424 ucred_free(uc);
426 NSCD_SET_STATUS_SUCCESS(phdr);
429 void
430 _nscd_APP_check_cred(
431 void *buf,
432 pid_t *pidp,
433 char *dc_str,
434 int log_comp,
435 int log_level)
437 nss_pheader_t *phdr = (nss_pheader_t *)buf;
438 ucred_t *uc = NULL;
439 uid_t ruid;
440 uid_t euid;
441 pid_t pid;
442 int errnum;
443 char *me = "_nscd_APP_check_cred";
445 if (door_ucred(&uc) != 0) {
446 errnum = errno;
447 _NSCD_LOG(log_comp, NSCD_LOG_LEVEL_ERROR)
448 (me, "door_ucred: %s\n", strerror(errno));
450 NSCD_SET_STATUS(phdr, NSS_ERROR, errnum);
451 return;
454 NSCD_SET_STATUS_SUCCESS(phdr);
455 pid = ucred_getpid(uc);
456 if (NSS_PACKED_CRED_CHECK(buf, ruid = ucred_getruid(uc),
457 euid = ucred_geteuid(uc))) {
458 if (pidp != NULL) {
459 if (*pidp == (pid_t)-1)
460 *pidp = pid;
461 else if (*pidp != pid) {
462 NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES);
465 } else {
466 NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES);
469 ucred_free(uc);
471 if (NSCD_STATUS_IS_NOT_OK(phdr)) {
472 _NSCD_LOG(log_comp, log_level)
473 (me, "%s call failed: caller pid %d (input pid = %d), ruid %d, "
474 "euid %d, header ruid %d, header euid %d\n", dc_str,
475 pid, (pidp != NULL) ? *pidp : -1, ruid, euid,
476 ((nss_pheader_t *)(buf))->p_ruid,
477 ((nss_pheader_t *)(buf))->p_euid);
481 /* log error and return -1 when an invalid packed buffer header is found */
482 static int
483 pheader_error(nss_pheader_t *phdr, uint32_t call_number)
485 char *call_num_str;
487 switch (call_number) {
488 case NSCD_SEARCH:
489 call_num_str = "NSCD_SEARCH";
490 break;
491 case NSCD_SETENT:
492 call_num_str = "NSCD_SETENT";
493 break;
494 case NSCD_GETENT:
495 call_num_str = "NSCD_GETENT";
496 break;
497 case NSCD_ENDENT:
498 call_num_str = "NSCD_ENDENT";
499 break;
500 case NSCD_PUT:
501 call_num_str = "NSCD_PUT";
502 break;
503 case NSCD_GETHINTS:
504 call_num_str = "NSCD_GETHINTS";
505 break;
506 default:
507 call_num_str = "UNKNOWN";
508 break;
511 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT)
512 ("pheader_error", "call number %s: invalid packed buffer header\n",
513 call_num_str);
515 NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL);
516 return (-1);
520 * Validate the header of a getXbyY or setent/getent/endent request.
521 * Return 0 if good, -1 otherwise.
523 * A valid header looks like the following (size is arg_size, does
524 * not include the output area):
525 * +----------------------------------+ --
526 * | nss_pheader_t (header fixed part)| ^
527 * | | |
528 * | pbufsiz, dbd,off, key_off, | len = sizeof(nss_pheader_t)
529 * | data_off .... | |
530 * | | v
531 * +----------------------------------+ <----- dbd_off
532 * | dbd (database description) | ^
533 * | nss_dbd_t + up to 3 strings | |
534 * | length = sizeof(nss_dbd_t) + | len = key_off - dbd_off
535 * | length of 3 strings + | |
536 * | length of padding | |
537 * | (total length in multiple of 4) | v
538 * +----------------------------------+ <----- key_off
539 * | lookup key | ^
540 * | nss_XbyY_key_t, content varies, | |
541 * | based on database and lookup op | len = data_off - key_off
542 * | length = data_off - key_off | |
543 * | including padding, multiple of 4 | v
544 * +----------------------------------+ <----- data_off (= arg_size)
545 * | | ^
546 * | area to hold results | |
547 * | | len = data_len (= pbufsiz -
548 * | | | data_off)
549 * | | v
550 * +----------------------------------+ <----- pbufsiz
552 static int
553 validate_pheader(
554 void *argp,
555 size_t arg_size,
556 uint32_t call_number)
558 nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp;
559 nssuint_t l1, l2;
562 * current version is NSCD_HEADER_REV, length of the fixed part
563 * of the header must match the size of nss_pheader_t
565 if (phdr->p_version != NSCD_HEADER_REV ||
566 phdr->dbd_off != sizeof (nss_pheader_t))
567 return (pheader_error(phdr, call_number));
570 * buffer size and offsets must be in multiple of 4
572 if ((arg_size & 3) || (phdr->dbd_off & 3) || (phdr->key_off & 3) ||
573 (phdr->data_off & 3))
574 return (pheader_error(phdr, call_number));
577 * the input arg_size is the length of the request header
578 * and should be less than NSCD_PHDR_MAXLEN
580 if (phdr->data_off != arg_size || arg_size > NSCD_PHDR_MAXLEN)
581 return (pheader_error(phdr, call_number));
583 /* get length of the dbd area */
584 l1 = phdr->key_off - phdr-> dbd_off;
587 * dbd area may contain padding, so length of dbd should
588 * not be less than the length of the actual data
590 if (l1 < phdr->dbd_len)
591 return (pheader_error(phdr, call_number));
593 /* get length of the key area */
594 l2 = phdr->data_off - phdr->key_off;
597 * key area may contain padding, so length of key area should
598 * not be less than the length of the actual data
600 if (l2 < phdr->key_len)
601 return (pheader_error(phdr, call_number));
604 * length of fixed part + lengths of dbd and key area = length of
605 * the request header
607 if (sizeof (nss_pheader_t) + l1 + l2 != phdr->data_off)
608 return (pheader_error(phdr, call_number));
610 /* header length + data length = buffer length */
611 if (phdr->data_off + phdr->data_len != phdr->pbufsiz)
612 return (pheader_error(phdr, call_number));
614 return (0);
617 /* log error and return -1 when an invalid nscd to nscd buffer is found */
618 static int
619 N2Nbuf_error(nss_pheader_t *phdr, uint32_t call_number)
621 char *call_num_str;
623 switch (call_number) {
624 case NSCD_PING:
625 call_num_str = "NSCD_PING";
626 break;
628 case NSCD_IMHERE:
629 call_num_str = "NSCD_IMHERE";
630 break;
632 case NSCD_PULSE:
633 call_num_str = "NSCD_PULSE";
634 break;
636 case NSCD_FORK:
637 call_num_str = "NSCD_FORK";
638 break;
640 case NSCD_KILL:
641 call_num_str = "NSCD_KILL";
642 break;
644 case NSCD_REFRESH:
645 call_num_str = "NSCD_REFRESH";
646 break;
648 case NSCD_GETPUADMIN:
649 call_num_str = "NSCD_GETPUADMIN";
650 break;
652 case NSCD_GETADMIN:
653 call_num_str = "NSCD_GETADMIN";
654 break;
656 case NSCD_SETADMIN:
657 call_num_str = "NSCD_SETADMIN";
658 break;
660 case NSCD_KILLSERVER:
661 call_num_str = "NSCD_KILLSERVER";
662 break;
663 default:
664 call_num_str = "UNKNOWN";
665 break;
668 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT)
669 ("N2Nbuf_error", "call number %s: invalid N2N buffer\n", call_num_str);
671 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
672 NSCD_DOOR_BUFFER_CHECK_FAILED);
674 return (-1);
678 * Validate the buffer of an nscd to nscd request.
679 * Return 0 if good, -1 otherwise.
681 * A valid buffer looks like the following (size is arg_size):
682 * +----------------------------------+ --
683 * | nss_pheader_t (header fixed part)| ^
684 * | | |
685 * | pbufsiz, dbd,off, key_off, | len = sizeof(nss_pheader_t)
686 * | data_off .... | |
687 * | | v
688 * +----------------------------------+ <---dbd_off = key_off = data_off
689 * | | ^
690 * | input data/output data | |
691 * | OR no data | len = data_len (= pbufsiz -
692 * | | | data_off)
693 * | | | len could be zero
694 * | | v
695 * +----------------------------------+ <--- pbufsiz
697 static int
698 validate_N2Nbuf(
699 void *argp,
700 size_t arg_size,
701 uint32_t call_number)
703 nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp;
706 * current version is NSCD_HEADER_REV, length of the fixed part
707 * of the header must match the size of nss_pheader_t
709 if (phdr->p_version != NSCD_HEADER_REV ||
710 phdr->dbd_off != sizeof (nss_pheader_t))
711 return (N2Nbuf_error(phdr, call_number));
714 * There are no dbd and key data, so the dbd, key, data
715 * offsets should be equal
717 if (phdr->dbd_off != phdr->key_off ||
718 phdr->dbd_off != phdr->data_off)
719 return (N2Nbuf_error(phdr, call_number));
722 * the input arg_size is the buffer length and should
723 * be less or equal than NSCD_N2NBUF_MAXLEN
725 if (phdr->pbufsiz != arg_size || arg_size > NSCD_N2NBUF_MAXLEN)
726 return (N2Nbuf_error(phdr, call_number));
728 /* header length + data length = buffer length */
729 if (phdr->data_off + phdr->data_len != phdr->pbufsiz)
730 return (N2Nbuf_error(phdr, call_number));
732 return (0);
735 static void
736 lookup(char *argp, size_t arg_size)
738 nsc_lookup_args_t largs;
739 char space[NSCD_LOOKUP_BUFSIZE];
740 nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp;
742 NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr, space,
743 sizeof (space));
746 * make sure the first couple bytes of the data area is null,
747 * so that bad strings in the packed header stop here
749 (void) memset((char *)phdr + phdr->data_off, 0, 16);
751 (void) memset(&largs, 0, sizeof (largs));
752 largs.buffer = argp;
753 largs.bufsize = arg_size;
754 nsc_lookup(&largs, 0);
757 * only the PUN needs to keep track of the
758 * activity count to determine when to
759 * terminate itself
761 if (_whoami == NSCD_CHILD) {
762 (void) mutex_lock(&activity_lock);
763 ++activity;
764 (void) mutex_unlock(&activity_lock);
767 NSCD_SET_RETURN_ARG(phdr, arg_size);
768 (void) door_return(argp, arg_size, NULL, 0);
771 static void
772 getent(char *argp, size_t arg_size)
774 char space[NSCD_LOOKUP_BUFSIZE];
775 nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp;
777 NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr, space, sizeof (space));
779 nss_pgetent(argp, arg_size);
781 NSCD_SET_RETURN_ARG(phdr, arg_size);
782 (void) door_return(argp, arg_size, NULL, 0);
785 static int
786 is_db_per_user(void *buf, char *dblist)
788 nss_pheader_t *phdr = (nss_pheader_t *)buf;
789 nss_dbd_t *pdbd;
790 char *dbname, *dbn;
791 int len;
793 /* copy db name into a temp buffer */
794 pdbd = (nss_dbd_t *)((void *)((char *)buf + phdr->dbd_off));
795 dbname = (char *)pdbd + pdbd->o_name;
796 len = strlen(dbname);
797 dbn = alloca(len + 2);
798 (void) memcpy(dbn, dbname, len);
800 /* check if <dbname> + ',' can be found in the dblist string */
801 dbn[len] = ',';
802 dbn[len + 1] = '\0';
803 if (strstr(dblist, dbn) != NULL)
804 return (1);
807 * check if <dbname> can be found in the last part
808 * of the dblist string
810 dbn[len] = '\0';
811 if (strstr(dblist, dbn) != NULL)
812 return (1);
814 return (0);
818 * Check to see if all conditions are met for processing per-user
819 * requests. Returns 1 if yes, -1 if backend is not configured,
820 * 0 otherwise.
822 static int
823 need_per_user_door(void *buf, int whoami, uid_t uid, char **dblist)
825 nss_pheader_t *phdr = (nss_pheader_t *)buf;
827 NSCD_SET_STATUS_SUCCESS(phdr);
829 /* if already a per-user nscd, no need to get per-user door */
830 if (whoami == NSCD_CHILD)
831 return (0);
833 /* forker shouldn't be asked */
834 if (whoami == NSCD_FORKER) {
835 NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP);
836 return (0);
839 /* if door client is root, no need for a per-user door */
840 if (uid == 0)
841 return (0);
844 * if per-user lookup is not configured, no per-user
845 * door available
847 if (_nscd_is_self_cred_on(0, dblist) == 0)
848 return (-1);
851 * if per-user lookup is not configured for the db,
852 * don't bother
854 if (is_db_per_user(phdr, *dblist) == 0)
855 return (0);
857 return (1);
860 static void
861 if_selfcred_return_per_user_door(char *argp, size_t arg_size,
862 door_desc_t *dp, int whoami)
864 nss_pheader_t *phdr = (nss_pheader_t *)((void *)argp);
865 char *dblist;
866 int door = -1;
867 int rc = 0;
868 door_desc_t desc;
869 char *space;
870 int len;
873 * check to see if self-cred is configured and
874 * need to return an alternate PUN door
876 if (per_user_is_on == 1) {
877 rc = need_per_user_door(argp, whoami,
878 _nscd_get_client_euid(), &dblist);
879 if (rc == -1)
880 per_user_is_on = 0;
882 if (rc <= 0) {
884 * self-cred not configured, and no error detected,
885 * return to continue the door call processing
887 if (NSCD_STATUS_IS_OK(phdr))
888 return;
889 else
891 * configured but error detected,
892 * stop the door call processing
894 (void) door_return(argp, phdr->data_off, NULL, 0);
897 /* get the alternate PUN door */
898 _nscd_proc_alt_get(argp, &door);
899 if (NSCD_GET_STATUS(phdr) != NSS_ALTRETRY) {
900 (void) door_return(argp, phdr->data_off, NULL, 0);
903 /* return the alternate door descriptor */
904 len = strlen(dblist) + 1;
905 space = alloca(arg_size + len);
906 phdr->data_len = len;
907 (void) memcpy(space, phdr, arg_size);
908 (void) strncpy((char *)space + arg_size, dblist, len);
909 dp = &desc;
910 dp->d_attributes = DOOR_DESCRIPTOR;
911 dp->d_data.d_desc.d_descriptor = door;
912 arg_size += len;
913 (void) door_return(space, arg_size, dp, 1);
916 /*ARGSUSED*/
917 static void
918 switcher(void *cookie, char *argp, size_t arg_size,
919 door_desc_t *dp, uint_t n_desc)
921 int iam;
922 pid_t ent_pid = -1;
923 nss_pheader_t *phdr = (nss_pheader_t *)((void *)argp);
924 void *uptr;
925 int len;
926 size_t buflen;
927 int callnum;
928 char *me = "switcher";
930 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
931 (me, "switcher ...\n");
933 if (argp == DOOR_UNREF_DATA) {
934 (void) printf("Door Slam... exiting\n");
935 exit(0);
938 if (argp == NULL) { /* empty door call */
939 (void) door_return(NULL, 0, 0, 0); /* return the favor */
943 * need to restart if main nscd and config file(s) changed
945 if (_whoami == NSCD_MAIN)
946 _nscd_restart_if_cfgfile_changed();
948 if ((phdr->nsc_callnumber & NSCDV2CATMASK) == NSCD_CALLCAT_APP) {
950 /* make sure the packed buffer header is good */
951 if (validate_pheader(argp, arg_size,
952 phdr->nsc_callnumber) == -1)
953 (void) door_return(argp, arg_size, NULL, 0);
955 switch (phdr->nsc_callnumber) {
957 case NSCD_SEARCH:
959 /* if a fallback to main nscd, skip per-user setup */
960 if (phdr->p_status != NSS_ALTRETRY)
961 if_selfcred_return_per_user_door(argp, arg_size,
962 dp, _whoami);
963 lookup(argp, arg_size);
965 break;
967 case NSCD_SETENT:
969 _nscd_APP_check_cred(argp, &ent_pid, "NSCD_SETENT",
970 NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT);
971 if (NSCD_STATUS_IS_OK(phdr)) {
972 if_selfcred_return_per_user_door(argp, arg_size,
973 dp, _whoami);
974 nss_psetent(argp, arg_size, ent_pid);
976 break;
978 case NSCD_GETENT:
980 getent(argp, arg_size);
981 break;
983 case NSCD_ENDENT:
985 nss_pendent(argp, arg_size);
986 break;
988 case NSCD_PUT:
990 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
991 (me, "door call NSCD_PUT not supported yet\n");
993 NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP);
994 break;
996 case NSCD_GETHINTS:
998 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
999 (me, "door call NSCD_GETHINTS not supported yet\n");
1001 NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP);
1002 break;
1004 default:
1006 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1007 (me, "Unknown name service door call op %x\n",
1008 phdr->nsc_callnumber);
1010 NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL);
1011 break;
1014 (void) door_return(argp, arg_size, NULL, 0);
1017 iam = NSCD_MAIN;
1018 callnum = phdr->nsc_callnumber & ~NSCD_WHOAMI;
1019 if (callnum == NSCD_IMHERE ||
1020 callnum == NSCD_PULSE || callnum == NSCD_FORK)
1021 iam = phdr->nsc_callnumber & NSCD_WHOAMI;
1022 else
1023 callnum = phdr->nsc_callnumber;
1025 /* nscd -> nscd v2 calls */
1027 /* make sure the buffer is good */
1028 if (validate_N2Nbuf(argp, arg_size, callnum) == -1)
1029 (void) door_return(argp, arg_size, NULL, 0);
1031 switch (callnum) {
1033 case NSCD_PING:
1034 NSCD_SET_STATUS_SUCCESS(phdr);
1035 break;
1037 case NSCD_IMHERE:
1038 _nscd_proc_iamhere(argp, dp, n_desc, iam);
1039 break;
1041 case NSCD_PULSE:
1042 N2N_check_priv(argp, "NSCD_PULSE");
1043 if (NSCD_STATUS_IS_OK(phdr))
1044 _nscd_proc_pulse(argp, iam);
1045 break;
1047 case NSCD_FORK:
1048 N2N_check_priv(argp, "NSCD_FORK");
1049 if (NSCD_STATUS_IS_OK(phdr))
1050 _nscd_proc_fork(argp, iam);
1051 break;
1053 case NSCD_KILL:
1054 N2N_check_priv(argp, "NSCD_KILL");
1055 if (NSCD_STATUS_IS_OK(phdr))
1056 exit(0);
1057 break;
1059 case NSCD_REFRESH:
1060 N2N_check_priv(argp, "NSCD_REFRESH");
1061 if (NSCD_STATUS_IS_OK(phdr)) {
1062 if (_nscd_refresh() != NSCD_SUCCESS)
1063 exit(1);
1064 NSCD_SET_STATUS_SUCCESS(phdr);
1066 break;
1068 case NSCD_GETPUADMIN:
1070 if (_nscd_is_self_cred_on(0, NULL)) {
1071 _nscd_peruser_getadmin(argp, sizeof (nscd_admin_t));
1072 } else {
1073 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
1074 NSCD_SELF_CRED_NOT_CONFIGURED);
1076 break;
1078 case NSCD_GETADMIN:
1080 len = _nscd_door_getadmin((void *)argp);
1081 if (len == 0)
1082 break;
1084 /* size of door buffer not big enough, allocate one */
1085 NSCD_ALLOC_DOORBUF(NSCD_GETADMIN, len, uptr, buflen);
1087 /* copy packed header */
1088 *(nss_pheader_t *)uptr = *(nss_pheader_t *)((void *)argp);
1090 /* set new buffer size */
1091 ((nss_pheader_t *)uptr)->pbufsiz = buflen;
1093 /* try one more time */
1094 (void) _nscd_door_getadmin((void *)uptr);
1095 (void) door_return(uptr, buflen, NULL, 0);
1096 break;
1098 case NSCD_SETADMIN:
1099 N2N_check_priv(argp, "NSCD_SETADMIN");
1100 if (NSCD_STATUS_IS_OK(phdr))
1101 _nscd_door_setadmin(argp);
1102 break;
1104 case NSCD_KILLSERVER:
1105 N2N_check_priv(argp, "NSCD_KILLSERVER");
1106 if (NSCD_STATUS_IS_OK(phdr)) {
1107 /* also kill the forker nscd if one is running */
1108 _nscd_kill_forker();
1109 exit(0);
1111 break;
1113 default:
1114 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1115 (me, "Unknown name service door call op %d\n",
1116 phdr->nsc_callnumber);
1118 NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL);
1120 (void) door_return(argp, arg_size, NULL, 0);
1121 break;
1124 (void) door_return(argp, arg_size, NULL, 0);
1128 _nscd_setup_server(char *execname, char **argv)
1131 int fd;
1132 int errnum;
1133 int bind_failed = 0;
1134 mode_t old_mask;
1135 struct stat buf;
1136 sigset_t myset;
1137 struct sigaction action;
1138 char *me = "_nscd_setup_server";
1140 main_execname = execname;
1141 main_argv = argv;
1143 /* Any nscd process is to ignore SIGPIPE */
1144 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
1145 errnum = errno;
1146 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1147 (me, "signal (SIGPIPE): %s\n", strerror(errnum));
1148 return (-1);
1151 keep_open_dns_socket();
1154 * the max number of server threads should be fixed now, so
1155 * set flag to indicate that no in-flight change is allowed
1157 max_servers_set = 1;
1159 (void) thr_keycreate(&lookup_state_key, NULL);
1160 (void) sema_init(&common_sema, frontend_cfg_g.common_worker_threads,
1161 USYNC_THREAD, 0);
1163 /* Establish server thread pool */
1164 (void) door_server_create(server_create);
1165 if (thr_keycreate(&server_key, server_destroy) != 0) {
1166 errnum = errno;
1167 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1168 (me, "thr_keycreate (server thread): %s\n",
1169 strerror(errnum));
1170 return (-1);
1173 /* Create a door */
1174 if ((fd = door_create(switcher, NAME_SERVICE_DOOR_COOKIE,
1175 DOOR_UNREF | DOOR_NO_CANCEL)) < 0) {
1176 errnum = errno;
1177 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1178 (me, "door_create: %s\n", strerror(errnum));
1179 return (-1);
1182 /* if not main nscd, no more setup to do */
1183 if (_whoami != NSCD_MAIN)
1184 return (fd);
1186 /* bind to file system */
1187 if (is_system_labeled() && (getzoneid() == GLOBAL_ZONEID)) {
1188 if (stat(TSOL_NAME_SERVICE_DOOR, &buf) < 0) {
1189 int newfd;
1191 /* make sure the door will be readable by all */
1192 old_mask = umask(0);
1193 if ((newfd = creat(TSOL_NAME_SERVICE_DOOR, 0444)) < 0) {
1194 errnum = errno;
1195 _NSCD_LOG(NSCD_LOG_FRONT_END,
1196 NSCD_LOG_LEVEL_ERROR)
1197 (me, "Cannot create %s: %s\n",
1198 TSOL_NAME_SERVICE_DOOR,
1199 strerror(errnum));
1200 bind_failed = 1;
1202 /* rstore the old file mode creation mask */
1203 (void) umask(old_mask);
1204 (void) close(newfd);
1206 if (symlink(TSOL_NAME_SERVICE_DOOR, NAME_SERVICE_DOOR) != 0) {
1207 if (errno != EEXIST) {
1208 errnum = errno;
1209 _NSCD_LOG(NSCD_LOG_FRONT_END,
1210 NSCD_LOG_LEVEL_ERROR)
1211 (me, "Cannot symlink %s: %s\n",
1212 NAME_SERVICE_DOOR, strerror(errnum));
1213 bind_failed = 1;
1216 } else if (stat(NAME_SERVICE_DOOR, &buf) < 0) {
1217 int newfd;
1219 /* make sure the door will be readable by all */
1220 old_mask = umask(0);
1221 if ((newfd = creat(NAME_SERVICE_DOOR, 0444)) < 0) {
1222 errnum = errno;
1223 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1224 (me, "Cannot create %s: %s\n", NAME_SERVICE_DOOR,
1225 strerror(errnum));
1226 bind_failed = 1;
1228 /* rstore the old file mode creation mask */
1229 (void) umask(old_mask);
1230 (void) close(newfd);
1233 if (bind_failed == 1) {
1234 (void) door_revoke(fd);
1235 return (-1);
1238 if (fattach(fd, NAME_SERVICE_DOOR) < 0) {
1239 if ((errno != EBUSY) ||
1240 (fdetach(NAME_SERVICE_DOOR) < 0) ||
1241 (fattach(fd, NAME_SERVICE_DOOR) < 0)) {
1242 errnum = errno;
1243 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1244 (me, "fattach: %s\n", strerror(errnum));
1245 (void) door_revoke(fd);
1246 return (-1);
1251 * kick off routing socket monitor thread
1253 if (thr_create(NULL, NULL,
1254 (void *(*)(void *))rts_mon, 0, 0, NULL) != 0) {
1255 errnum = errno;
1256 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1257 (me, "thr_create (routing socket monitor): %s\n",
1258 strerror(errnum));
1260 (void) door_revoke(fd);
1261 return (-1);
1265 * set up signal handler for SIGHUP
1267 action.sa_handler = dozip;
1268 action.sa_flags = 0;
1269 (void) sigemptyset(&action.sa_mask);
1270 (void) sigemptyset(&myset);
1271 (void) sigaddset(&myset, SIGHUP);
1273 if (sigaction(SIGHUP, &action, NULL) < 0) {
1274 errnum = errno;
1275 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1276 (me, "sigaction (SIGHUP): %s\n", strerror(errnum));
1278 (void) door_revoke(fd);
1279 return (-1);
1282 return (fd);
1286 _nscd_setup_child_server(int did)
1289 int errnum;
1290 int fd;
1291 nscd_rc_t rc;
1292 char *me = "_nscd_setup_child_server";
1294 /* Re-establish our own server thread pool */
1295 (void) door_server_create(server_create);
1296 if (thr_keycreate(&server_key, server_destroy) != 0) {
1297 errnum = errno;
1298 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
1299 (me, "thr_keycreate failed: %s", strerror(errnum));
1300 return (-1);
1304 * Create a new door.
1305 * Keep DOOR_REFUSE_DESC (self-cred nscds don't fork)
1307 (void) close(did);
1308 if ((fd = door_create(switcher, NAME_SERVICE_DOOR_COOKIE,
1309 DOOR_REFUSE_DESC|DOOR_UNREF|DOOR_NO_CANCEL)) < 0) {
1310 errnum = errno;
1311 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
1312 (me, "door_create failed: %s", strerror(errnum));
1313 return (-1);
1317 * kick off routing socket monitor thread
1319 if (thr_create(NULL, NULL,
1320 (void *(*)(void *))rts_mon, 0, 0, NULL) != 0) {
1321 errnum = errno;
1322 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1323 (me, "thr_create (routing socket monitor): %s\n",
1324 strerror(errnum));
1325 (void) door_revoke(fd);
1326 return (-1);
1330 * start monitoring the states of the name service clients
1332 rc = _nscd_init_smf_monitor();
1333 if (rc != NSCD_SUCCESS) {
1334 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1335 (me, "unable to start the SMF monitor (rc = %d)\n", rc);
1337 (void) door_revoke(fd);
1338 return (-1);
1341 return (fd);
1344 nscd_rc_t
1345 _nscd_alloc_frontend_cfg()
1347 frontend_cfg = calloc(NSCD_NUM_DB, sizeof (nscd_cfg_frontend_t));
1348 if (frontend_cfg == NULL)
1349 return (NSCD_NO_MEMORY);
1351 return (NSCD_SUCCESS);
1355 /* ARGSUSED */
1356 nscd_rc_t
1357 _nscd_cfg_frontend_notify(
1358 void *data,
1359 struct nscd_cfg_param_desc *pdesc,
1360 nscd_cfg_id_t *nswdb,
1361 nscd_cfg_flag_t dflag,
1362 nscd_cfg_error_t **errorp,
1363 void *cookie)
1365 void *dp;
1368 * At init time, the whole group of config params are received.
1369 * At update time, group or individual parameter value could
1370 * be received.
1373 if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_INIT) ||
1374 _nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) {
1376 * group data is received, copy in the
1377 * entire strcture
1379 if (_nscd_cfg_flag_is_set(pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL))
1380 frontend_cfg_g = *(nscd_cfg_global_frontend_t *)data;
1381 else
1382 frontend_cfg[nswdb->index] =
1383 *(nscd_cfg_frontend_t *)data;
1385 } else {
1387 * individual paramater is received: copy in the
1388 * parameter value.
1390 if (_nscd_cfg_flag_is_set(pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL))
1391 dp = (char *)&frontend_cfg_g + pdesc->p_offset;
1392 else
1393 dp = (char *)&frontend_cfg[nswdb->index] +
1394 pdesc->p_offset;
1395 (void) memcpy(dp, data, pdesc->p_size);
1398 return (NSCD_SUCCESS);
1401 /* ARGSUSED */
1402 nscd_rc_t
1403 _nscd_cfg_frontend_verify(
1404 void *data,
1405 struct nscd_cfg_param_desc *pdesc,
1406 nscd_cfg_id_t *nswdb,
1407 nscd_cfg_flag_t dflag,
1408 nscd_cfg_error_t **errorp,
1409 void **cookie)
1412 char *me = "_nscd_cfg_frontend_verify";
1415 * if max. number of server threads is set and in effect,
1416 * don't allow changing of the frontend configuration
1418 if (max_servers_set) {
1419 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_INFO)
1420 (me, "changing of the frontend configuration not allowed now");
1422 return (NSCD_CFG_CHANGE_NOT_ALLOWED);
1425 return (NSCD_SUCCESS);
1428 /* ARGSUSED */
1429 nscd_rc_t
1430 _nscd_cfg_frontend_get_stat(
1431 void **stat,
1432 struct nscd_cfg_stat_desc *sdesc,
1433 nscd_cfg_id_t *nswdb,
1434 nscd_cfg_flag_t *dflag,
1435 void (**free_stat)(void *stat),
1436 nscd_cfg_error_t **errorp)
1438 return (NSCD_SUCCESS);
1441 void
1442 _nscd_init_cache_sema(sema_t *sema, char *cache_name)
1444 int i, j;
1445 char *dbn;
1447 if (max_servers == 0)
1448 max_servers = frontend_cfg_g.common_worker_threads +
1449 frontend_cfg_g.cache_hit_threads;
1451 for (i = 0; i < NSCD_NUM_DB; i++) {
1453 dbn = NSCD_NSW_DB_NAME(i);
1454 if (strcasecmp(dbn, cache_name) == 0) {
1455 j = frontend_cfg[i].worker_thread_per_nsw_db;
1456 (void) sema_init(sema, j, USYNC_THREAD, 0);
1457 max_servers += j;
1458 break;
1464 * Monitor the routing socket. Address lists stored in the ipnodes
1465 * cache are sorted based on destination address selection rules,
1466 * so when things change that could affect that sorting (interfaces
1467 * go up or down, flags change, etc.), we clear that cache so the
1468 * list will be re-ordered the next time the hostname is resolved.
1470 static void
1471 rts_mon(void)
1473 int rt_sock, rdlen, idx;
1474 union {
1475 struct {
1476 struct rt_msghdr rtm;
1477 struct sockaddr_storage addrs[RTA_NUMBITS];
1478 } r;
1479 struct if_msghdr ifm;
1480 struct ifa_msghdr ifam;
1481 } mbuf;
1482 struct ifa_msghdr *ifam = &mbuf.ifam;
1483 char *me = "rts_mon";
1485 (void) thr_setname(thr_self(), me);
1487 rt_sock = socket(PF_ROUTE, SOCK_RAW, 0);
1488 if (rt_sock < 0) {
1489 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1490 (me, "Failed to open routing socket: %s\n", strerror(errno));
1491 thr_exit(0);
1494 for (;;) {
1495 rdlen = read(rt_sock, &mbuf, sizeof (mbuf));
1496 if (rdlen <= 0) {
1497 if (rdlen == 0 || (errno != EINTR && errno != EAGAIN)) {
1498 _NSCD_LOG(NSCD_LOG_FRONT_END,
1499 NSCD_LOG_LEVEL_ERROR)
1500 (me, "routing socket read: %s\n",
1501 strerror(errno));
1502 thr_exit(0);
1504 continue;
1506 if (ifam->ifam_version != RTM_VERSION) {
1507 _NSCD_LOG(NSCD_LOG_FRONT_END,
1508 NSCD_LOG_LEVEL_ERROR)
1509 (me, "rx unknown version (%d) on "
1510 "routing socket.\n",
1511 ifam->ifam_version);
1512 continue;
1514 switch (ifam->ifam_type) {
1515 case RTM_NEWADDR:
1516 case RTM_DELADDR:
1517 /* if no ipnodes cache, then nothing to do */
1518 idx = get_cache_idx("ipnodes");
1519 if (cache_ctx_p[idx] == NULL ||
1520 cache_ctx_p[idx]->reaper_on != nscd_true)
1521 break;
1522 nsc_invalidate(cache_ctx_p[idx], NULL, NULL);
1523 break;
1524 case RTM_ADD:
1525 case RTM_DELETE:
1526 case RTM_CHANGE:
1527 case RTM_GET:
1528 case RTM_LOSING:
1529 case RTM_REDIRECT:
1530 case RTM_MISS:
1531 case RTM_LOCK:
1532 case RTM_OLDADD:
1533 case RTM_OLDDEL:
1534 case RTM_RESOLVE:
1535 case RTM_IFINFO:
1536 case RTM_CHGADDR:
1537 case RTM_FREEADDR:
1538 break;
1539 default:
1540 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1541 (me, "rx unknown msg type (%d) on routing socket.\n",
1542 ifam->ifam_type);
1543 break;
1548 static void
1549 keep_open_dns_socket(void)
1551 _res.options |= RES_STAYOPEN; /* just keep this udp socket open */