1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
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 2019 Nexenta Systems, Inc.
26 */
27
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"
53
54 static void rts_mon(void);
55 static void keep_open_dns_socket(void);
56
57 extern nsc_ctx_t *cache_ctx_p[];
58
59 /*
60 * Current active Configuration data for the frontend component
61 */
62 static nscd_cfg_global_frontend_t frontend_cfg_g;
63 static nscd_cfg_frontend_t *frontend_cfg;
64
65 static int max_servers = 0;
66 static int max_servers_set = 0;
67 static int per_user_is_on = 1;
68
69 static char *main_execname;
70 static char **main_argv;
71 extern int _whoami;
72 extern long activity;
73 extern mutex_t activity_lock;
74
75 static sema_t common_sema;
76
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;
81
82 /*
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.
86 */
87 /*ARGSUSED*/
88 static void *
89 server_tsd_bind(void *arg)
90 {
91 static void *value = "NON-NULL TSD";
92
93 /* disable cancellation to avoid hangs if server threads disappear */
94 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
95 (void) thr_setspecific(server_key, value);
96 (void) door_return(NULL, 0, NULL, 0);
97
98 /* make lint happy */
99 return (NULL);
100 }
101
102 /*
103 * Server threads are created here.
104 */
105 /*ARGSUSED*/
106 static void
107 server_create(door_info_t *dip)
108 {
109 (void) mutex_lock(&create_lock);
110 if (++num_servers > max_servers) {
111 num_servers--;
112 (void) mutex_unlock(&create_lock);
113 return;
114 }
115 (void) mutex_unlock(&create_lock);
116 (void) thr_create(NULL, 0, server_tsd_bind, NULL,
117 THR_BOUND|THR_DETACHED, NULL);
118 }
119
120 /*
121 * Server thread are destroyed here
122 */
123 /*ARGSUSED*/
124 static void
125 server_destroy(void *arg)
126 {
127 (void) mutex_lock(&create_lock);
128 num_servers--;
129 (void) mutex_unlock(&create_lock);
130 (void) thr_setspecific(server_key, NULL);
131 }
132
133 /*
134 * get clearance
135 */
136 int
137 _nscd_get_clearance(sema_t *sema) {
138 if (sema_trywait(&common_sema) == 0) {
139 (void) thr_setspecific(lookup_state_key, NULL);
140 return (0);
141 }
142
143 if (sema_trywait(sema) == 0) {
144 (void) thr_setspecific(lookup_state_key, (void*)1);
145 return (0);
146 }
147
148 return (1);
149 }
150
151
152 /*
153 * release clearance
154 */
155 int
156 _nscd_release_clearance(sema_t *sema) {
157 int which;
158
159 (void) thr_getspecific(lookup_state_key, (void**)&which);
160 if (which == 0) /* from common pool */ {
161 (void) sema_post(&common_sema);
162 return (0);
163 }
164
165 (void) sema_post(sema);
166 return (1);
167 }
168
169 static void
170 dozip(void)
171 {
172 /* not much here */
173 }
174
175 /*
176 * _nscd_restart_if_cfgfile_changed()
177 * Restart if modification times of nsswitch.conf or resolv.conf have changed.
178 *
179 * If nsswitch.conf has changed then it is possible that sources for
180 * various backends have changed and therefore the current cached
181 * data may not be consistent with the new data sources. By
182 * restarting the cache will be cleared and the new configuration will
183 * be used.
184 *
185 * The check for resolv.conf is made as only the first call to
186 * res_gethostbyname() or res_getaddrbyname() causes a call to
187 * res_ninit() to occur which in turn parses resolv.conf. Therefore
188 * to benefit from changes to resolv.conf nscd must be restarted when
189 * resolv.conf is updated, removed or created. If res_getXbyY calls
190 * are removed from NSS then this check could be removed.
191 *
192 */
193 void
194 _nscd_restart_if_cfgfile_changed()
195 {
196
197 static mutex_t nsswitch_lock = DEFAULTMUTEX;
198 static timestruc_t last_nsswitch_check = { 0 };
199 static timestruc_t last_nsswitch_modified = { 0 };
200 static timestruc_t last_resolv_modified = { -1, 0 };
201 static mutex_t restarting_lock = DEFAULTMUTEX;
202 static int restarting = 0;
203 int restart = 0;
204 time_t now = time(NULL);
205 char *me = "_nscd_restart_if_cfgfile_changed";
206
207 #define FLAG_RESTART_REQUIRED if (restarting == 0) {\
208 (void) mutex_lock(&restarting_lock);\
209 if (restarting == 0) {\
210 restarting = 1;\
211 restart = 1;\
212 }\
213 (void) mutex_unlock(&restarting_lock);\
214 }
215
216 if (restarting == 1)
217 return;
218
219 if (now - last_nsswitch_check.tv_sec < _NSC_FILE_CHECK_TIME)
220 return;
221
222 (void) mutex_lock(&nsswitch_lock);
223
224 if (now - last_nsswitch_check.tv_sec >= _NSC_FILE_CHECK_TIME) {
225 struct stat nss_buf;
226 struct stat res_buf;
227
228 last_nsswitch_check.tv_sec = now;
229 last_nsswitch_check.tv_nsec = 0;
230
231 (void) mutex_unlock(&nsswitch_lock); /* let others continue */
232
233 if (stat("/etc/nsswitch.conf", &nss_buf) < 0) {
234 return;
235 } else if (last_nsswitch_modified.tv_sec == 0) {
236 last_nsswitch_modified = nss_buf.st_mtim;
237 }
238
239 if (last_nsswitch_modified.tv_sec < nss_buf.st_mtim.tv_sec ||
240 (last_nsswitch_modified.tv_sec == nss_buf.st_mtim.tv_sec &&
241 last_nsswitch_modified.tv_nsec < nss_buf.st_mtim.tv_nsec)) {
242 FLAG_RESTART_REQUIRED;
243 }
244
245 if (restart == 0) {
246 if (stat("/etc/resolv.conf", &res_buf) < 0) {
247 /* Unable to stat file, were we previously? */
248 if (last_resolv_modified.tv_sec > 0) {
249 /* Yes, it must have been removed. */
250 FLAG_RESTART_REQUIRED;
251 } else if (last_resolv_modified.tv_sec == -1) {
252 /* No, then we've never seen it. */
253 last_resolv_modified.tv_sec = 0;
254 }
255 } else if (last_resolv_modified.tv_sec == -1) {
256 /* We've just started and file is present. */
257 last_resolv_modified = res_buf.st_mtim;
258 } else if (last_resolv_modified.tv_sec == 0) {
259 /* Wasn't there at start-up. */
260 FLAG_RESTART_REQUIRED;
261 } else if (last_resolv_modified.tv_sec <
262 res_buf.st_mtim.tv_sec ||
263 (last_resolv_modified.tv_sec ==
264 res_buf.st_mtim.tv_sec &&
265 last_resolv_modified.tv_nsec <
266 res_buf.st_mtim.tv_nsec)) {
267 FLAG_RESTART_REQUIRED;
268 }
269 }
270
271 if (restart == 1) {
272 char *fmri;
273
274 /*
275 * if in self cred mode, kill the forker and
276 * child nscds
277 */
278 if (_nscd_is_self_cred_on(0, NULL)) {
279 _nscd_kill_forker();
280 _nscd_kill_all_children();
281 }
282
283 /*
284 * time for restart
285 */
286 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_INFO)
287 (me, "nscd restart due to %s or %s change\n",
288 "/etc/nsswitch.conf", "resolv.conf");
289 /*
290 * try to restart under smf
291 */
292 if ((fmri = getenv("SMF_FMRI")) == NULL) {
293 /* not running under smf - reexec */
294 (void) execv(main_execname, main_argv);
295 exit(1); /* just in case */
296 }
297
298 if (smf_restart_instance(fmri) == 0)
299 (void) sleep(10); /* wait a bit */
300 exit(1); /* give up waiting for resurrection */
301 }
302
303 } else
304 (void) mutex_unlock(&nsswitch_lock);
305 }
306
307 uid_t
308 _nscd_get_client_euid()
309 {
310 ucred_t *uc = NULL;
311 uid_t id;
312 char *me = "get_client_euid";
313
314 if (door_ucred(&uc) != 0) {
315 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
316 (me, "door_ucred: %s\n", strerror(errno));
317 return ((uid_t)-1);
318 }
319
320 id = ucred_geteuid(uc);
321 ucred_free(uc);
322 return (id);
323 }
324
325 /*
326 * Check to see if the door client's euid is 0 or if it has required_priv
327 * privilege. Return 0 if yes, -1 otherwise.
328 * Supported values for required_priv are:
329 * - NSCD_ALL_PRIV: for all zones privileges
330 * - NSCD_READ_PRIV: for PRIV_FILE_DAC_READ privilege
331 */
332 int
333 _nscd_check_client_priv(int required_priv)
334 {
335 int rc = 0;
336 ucred_t *uc = NULL;
337 const priv_set_t *eset;
338 char *me = "_nscd_check_client_read_priv";
339 priv_set_t *zs; /* zone */
340
341 if (door_ucred(&uc) != 0) {
342 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
343 (me, "door_ucred: %s\n", strerror(errno));
344 return (-1);
345 }
346
347 if (ucred_geteuid(uc) == 0) {
348 ucred_free(uc);
349 return (0);
350 }
351
352 eset = ucred_getprivset(uc, PRIV_EFFECTIVE);
353 switch (required_priv) {
354 case NSCD_ALL_PRIV:
355 zs = priv_str_to_set("zone", ",", NULL);
356 if (!priv_isequalset(eset, zs)) {
357 _NSCD_LOG(NSCD_LOG_FRONT_END,
358 NSCD_LOG_LEVEL_ERROR)
359 (me, "missing all zones privileges\n");
360 rc = -1;
361 }
362 priv_freeset(zs);
363 break;
364 case NSCD_READ_PRIV:
365 if (!priv_ismember(eset, PRIV_FILE_DAC_READ))
366 rc = -1;
367 break;
368 default:
369 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
370 (me, "unknown required_priv: %d\n", required_priv);
371 rc = -1;
372 break;
373 }
374 ucred_free(uc);
375 return (rc);
376 }
377
378 static void
379 N2N_check_priv(
380 void *buf,
381 char *dc_str)
382 {
383 nss_pheader_t *phdr = (nss_pheader_t *)buf;
384 ucred_t *uc = NULL;
385 const priv_set_t *eset;
386 zoneid_t zoneid;
387 int errnum;
388 char *me = "N2N_check_priv";
389
390 if (door_ucred(&uc) != 0) {
391 errnum = errno;
392 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
393 (me, "door_ucred: %s\n", strerror(errno));
394
395 NSCD_SET_STATUS(phdr, NSS_ERROR, errnum);
396 return;
397 }
398
399 eset = ucred_getprivset(uc, PRIV_EFFECTIVE);
400 zoneid = ucred_getzoneid(uc);
401
402 if ((zoneid != GLOBAL_ZONEID && zoneid != getzoneid()) ||
403 eset != NULL ? !priv_ismember(eset, PRIV_SYS_ADMIN) :
404 ucred_geteuid(uc) != 0) {
405
406 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT)
407 (me, "%s call failed(cred): caller pid %d, uid %d, "
408 "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc),
409 ucred_getruid(uc), ucred_geteuid(uc), zoneid);
410 ucred_free(uc);
411
412 NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES);
413 return;
414 }
415
416 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
417 (me, "nscd received %s cmd from pid %d, uid %d, "
418 "euid %d, zoneid %d\n", dc_str, ucred_getpid(uc),
419 ucred_getruid(uc), ucred_geteuid(uc), zoneid);
420
421 ucred_free(uc);
422
423 NSCD_SET_STATUS_SUCCESS(phdr);
424 }
425
426 void
427 _nscd_APP_check_cred(
428 void *buf,
429 pid_t *pidp,
430 char *dc_str,
431 int log_comp,
432 int log_level)
433 {
434 nss_pheader_t *phdr = (nss_pheader_t *)buf;
435 ucred_t *uc = NULL;
436 uid_t ruid;
437 uid_t euid;
438 pid_t pid;
439 int errnum;
440 char *me = "_nscd_APP_check_cred";
441
442 if (door_ucred(&uc) != 0) {
443 errnum = errno;
444 _NSCD_LOG(log_comp, NSCD_LOG_LEVEL_ERROR)
445 (me, "door_ucred: %s\n", strerror(errno));
446
447 NSCD_SET_STATUS(phdr, NSS_ERROR, errnum);
448 return;
449 }
450
451 NSCD_SET_STATUS_SUCCESS(phdr);
452 pid = ucred_getpid(uc);
453 if (NSS_PACKED_CRED_CHECK(buf, ruid = ucred_getruid(uc),
454 euid = ucred_geteuid(uc))) {
455 if (pidp != NULL) {
456 if (*pidp == (pid_t)-1)
457 *pidp = pid;
458 else if (*pidp != pid) {
459 NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES);
460 }
461 }
462 } else {
463 NSCD_SET_STATUS(phdr, NSS_ERROR, EACCES);
464 }
465
466 ucred_free(uc);
467
468 if (NSCD_STATUS_IS_NOT_OK(phdr)) {
469 _NSCD_LOG(log_comp, log_level)
470 (me, "%s call failed: caller pid %d (input pid = %d), ruid %d, "
471 "euid %d, header ruid %d, header euid %d\n", dc_str,
472 pid, (pidp != NULL) ? *pidp : -1, ruid, euid,
473 ((nss_pheader_t *)(buf))->p_ruid,
474 ((nss_pheader_t *)(buf))->p_euid);
475 }
476 }
477
478 /* log error and return -1 when an invalid packed buffer header is found */
479 static int
480 pheader_error(nss_pheader_t *phdr, uint32_t call_number)
481 {
482 char *call_num_str;
483
484 switch (call_number) {
485 case NSCD_SEARCH:
486 call_num_str = "NSCD_SEARCH";
487 break;
488 case NSCD_SETENT:
489 call_num_str = "NSCD_SETENT";
490 break;
491 case NSCD_GETENT:
492 call_num_str = "NSCD_GETENT";
493 break;
494 case NSCD_ENDENT:
495 call_num_str = "NSCD_ENDENT";
496 break;
497 case NSCD_PUT:
498 call_num_str = "NSCD_PUT";
499 break;
500 case NSCD_GETHINTS:
501 call_num_str = "NSCD_GETHINTS";
502 break;
503 default:
504 call_num_str = "UNKNOWN";
505 break;
506 }
507
508 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT)
509 ("pheader_error", "call number %s: invalid packed buffer header\n",
510 call_num_str);
511
512 NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL);
513 return (-1);
514 }
515
516 /*
517 * Validate the header of a getXbyY or setent/getent/endent request.
518 * Return 0 if good, -1 otherwise.
519 *
520 * A valid header looks like the following (size is arg_size, does
521 * not include the output area):
522 * +----------------------------------+ --
523 * | nss_pheader_t (header fixed part)| ^
524 * | | |
525 * | pbufsiz, dbd,off, key_off, | len = sizeof(nss_pheader_t)
526 * | data_off .... | |
527 * | | v
528 * +----------------------------------+ <----- dbd_off
529 * | dbd (database description) | ^
530 * | nss_dbd_t + up to 3 strings | |
531 * | length = sizeof(nss_dbd_t) + | len = key_off - dbd_off
532 * | length of 3 strings + | |
533 * | length of padding | |
534 * | (total length in multiple of 4) | v
535 * +----------------------------------+ <----- key_off
536 * | lookup key | ^
537 * | nss_XbyY_key_t, content varies, | |
538 * | based on database and lookup op | len = data_off - key_off
539 * | length = data_off - key_off | |
540 * | including padding, multiple of 4 | v
541 * +----------------------------------+ <----- data_off (= arg_size)
542 * | | ^
543 * | area to hold results | |
544 * | | len = data_len (= pbufsiz -
545 * | | | data_off)
546 * | | v
547 * +----------------------------------+ <----- pbufsiz
548 */
549 static int
550 validate_pheader(
551 void *argp,
552 size_t arg_size,
553 uint32_t call_number)
554 {
555 nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp;
556 nssuint_t l1, l2;
557
558 /*
559 * current version is NSCD_HEADER_REV, length of the fixed part
560 * of the header must match the size of nss_pheader_t
561 */
562 if (phdr->p_version != NSCD_HEADER_REV ||
563 phdr->dbd_off != sizeof (nss_pheader_t))
564 return (pheader_error(phdr, call_number));
565
566 /*
567 * buffer size and offsets must be in multiple of 4
568 */
569 if ((arg_size & 3) || (phdr->dbd_off & 3) || (phdr->key_off & 3) ||
570 (phdr->data_off & 3))
571 return (pheader_error(phdr, call_number));
572
573 /*
574 * the input arg_size is the length of the request header
575 * and should be less than NSCD_PHDR_MAXLEN
576 */
577 if (phdr->data_off != arg_size || arg_size > NSCD_PHDR_MAXLEN)
578 return (pheader_error(phdr, call_number));
579
580 /* get length of the dbd area */
581 l1 = phdr->key_off - phdr-> dbd_off;
582
583 /*
584 * dbd area may contain padding, so length of dbd should
585 * not be less than the length of the actual data
586 */
587 if (l1 < phdr->dbd_len)
588 return (pheader_error(phdr, call_number));
589
590 /* get length of the key area */
591 l2 = phdr->data_off - phdr->key_off;
592
593 /*
594 * key area may contain padding, so length of key area should
595 * not be less than the length of the actual data
596 */
597 if (l2 < phdr->key_len)
598 return (pheader_error(phdr, call_number));
599
600 /*
601 * length of fixed part + lengths of dbd and key area = length of
602 * the request header
603 */
604 if (sizeof (nss_pheader_t) + l1 + l2 != phdr->data_off)
605 return (pheader_error(phdr, call_number));
606
607 /* header length + data length = buffer length */
608 if (phdr->data_off + phdr->data_len != phdr->pbufsiz)
609 return (pheader_error(phdr, call_number));
610
611 return (0);
612 }
613
614 /* log error and return -1 when an invalid nscd to nscd buffer is found */
615 static int
616 N2Nbuf_error(nss_pheader_t *phdr, uint32_t call_number)
617 {
618 char *call_num_str;
619
620 switch (call_number) {
621 case NSCD_PING:
622 call_num_str = "NSCD_PING";
623 break;
624
625 case NSCD_IMHERE:
626 call_num_str = "NSCD_IMHERE";
627 break;
628
629 case NSCD_PULSE:
630 call_num_str = "NSCD_PULSE";
631 break;
632
633 case NSCD_FORK:
634 call_num_str = "NSCD_FORK";
635 break;
636
637 case NSCD_KILL:
638 call_num_str = "NSCD_KILL";
639 break;
640
641 case NSCD_REFRESH:
642 call_num_str = "NSCD_REFRESH";
643 break;
644
645 case NSCD_GETPUADMIN:
646 call_num_str = "NSCD_GETPUADMIN";
647 break;
648
649 case NSCD_GETADMIN:
650 call_num_str = "NSCD_GETADMIN";
651 break;
652
653 case NSCD_SETADMIN:
654 call_num_str = "NSCD_SETADMIN";
655 break;
656
657 case NSCD_KILLSERVER:
658 call_num_str = "NSCD_KILLSERVER";
659 break;
660 default:
661 call_num_str = "UNKNOWN";
662 break;
663 }
664
665 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT)
666 ("N2Nbuf_error", "call number %s: invalid N2N buffer\n", call_num_str);
667
668 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
669 NSCD_DOOR_BUFFER_CHECK_FAILED);
670
671 return (-1);
672 }
673
674 /*
675 * Validate the buffer of an nscd to nscd request.
676 * Return 0 if good, -1 otherwise.
677 *
678 * A valid buffer looks like the following (size is arg_size):
679 * +----------------------------------+ --
680 * | nss_pheader_t (header fixed part)| ^
681 * | | |
682 * | pbufsiz, dbd,off, key_off, | len = sizeof(nss_pheader_t)
683 * | data_off .... | |
684 * | | v
685 * +----------------------------------+ <---dbd_off = key_off = data_off
686 * | | ^
687 * | input data/output data | |
688 * | OR no data | len = data_len (= pbufsiz -
689 * | | | data_off)
690 * | | | len could be zero
691 * | | v
692 * +----------------------------------+ <--- pbufsiz
693 */
694 static int
695 validate_N2Nbuf(
696 void *argp,
697 size_t arg_size,
698 uint32_t call_number)
699 {
700 nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp;
701
702 /*
703 * current version is NSCD_HEADER_REV, length of the fixed part
704 * of the header must match the size of nss_pheader_t
705 */
706 if (phdr->p_version != NSCD_HEADER_REV ||
707 phdr->dbd_off != sizeof (nss_pheader_t))
708 return (N2Nbuf_error(phdr, call_number));
709
710 /*
711 * There are no dbd and key data, so the dbd, key, data
712 * offsets should be equal
713 */
714 if (phdr->dbd_off != phdr->key_off ||
715 phdr->dbd_off != phdr->data_off)
716 return (N2Nbuf_error(phdr, call_number));
717
718 /*
719 * the input arg_size is the buffer length and should
720 * be less or equal than NSCD_N2NBUF_MAXLEN
721 */
722 if (phdr->pbufsiz != arg_size || arg_size > NSCD_N2NBUF_MAXLEN)
723 return (N2Nbuf_error(phdr, call_number));
724
725 /* header length + data length = buffer length */
726 if (phdr->data_off + phdr->data_len != phdr->pbufsiz)
727 return (N2Nbuf_error(phdr, call_number));
728
729 return (0);
730 }
731
732 static void
733 lookup(char *argp, size_t arg_size)
734 {
735 nsc_lookup_args_t largs;
736 char space[NSCD_LOOKUP_BUFSIZE];
737 nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp;
738
739 NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr, space,
740 sizeof (space));
741
742 /*
743 * make sure the first couple bytes of the data area is null,
744 * so that bad strings in the packed header stop here
745 */
746 (void) memset((char *)phdr + phdr->data_off, 0, 16);
747
748 (void) memset(&largs, 0, sizeof (largs));
749 largs.buffer = argp;
750 largs.bufsize = arg_size;
751 nsc_lookup(&largs, 0);
752
753 /*
754 * only the PUN needs to keep track of the
755 * activity count to determine when to
756 * terminate itself
757 */
758 if (_whoami == NSCD_CHILD) {
759 (void) mutex_lock(&activity_lock);
760 ++activity;
761 (void) mutex_unlock(&activity_lock);
762 }
763
764 NSCD_SET_RETURN_ARG(phdr, arg_size);
765 (void) door_return(argp, arg_size, NULL, 0);
766 }
767
768 static void
769 getent(char *argp, size_t arg_size)
770 {
771 char space[NSCD_LOOKUP_BUFSIZE];
772 nss_pheader_t *phdr = (nss_pheader_t *)(void *)argp;
773
774 NSCD_ALLOC_LOOKUP_BUFFER(argp, arg_size, phdr, space, sizeof (space));
775
776 nss_pgetent(argp, arg_size);
777
778 NSCD_SET_RETURN_ARG(phdr, arg_size);
779 (void) door_return(argp, arg_size, NULL, 0);
780 }
781
782 static int
783 is_db_per_user(void *buf, char *dblist)
784 {
785 nss_pheader_t *phdr = (nss_pheader_t *)buf;
786 nss_dbd_t *pdbd;
787 char *dbname, *dbn;
788 int len;
789
790 /* copy db name into a temp buffer */
791 pdbd = (nss_dbd_t *)((void *)((char *)buf + phdr->dbd_off));
792 dbname = (char *)pdbd + pdbd->o_name;
793 len = strlen(dbname);
794 dbn = alloca(len + 2);
795 (void) memcpy(dbn, dbname, len);
796
797 /* check if <dbname> + ',' can be found in the dblist string */
798 dbn[len] = ',';
799 dbn[len + 1] = '\0';
800 if (strstr(dblist, dbn) != NULL)
801 return (1);
802
803 /*
804 * check if <dbname> can be found in the last part
805 * of the dblist string
806 */
807 dbn[len] = '\0';
808 if (strstr(dblist, dbn) != NULL)
809 return (1);
810
811 return (0);
812 }
813
814 /*
815 * Check to see if all conditions are met for processing per-user
816 * requests. Returns 1 if yes, -1 if backend is not configured,
817 * 0 otherwise.
818 */
819 static int
820 need_per_user_door(void *buf, int whoami, uid_t uid, char **dblist)
821 {
822 nss_pheader_t *phdr = (nss_pheader_t *)buf;
823
824 NSCD_SET_STATUS_SUCCESS(phdr);
825
826 /* if already a per-user nscd, no need to get per-user door */
827 if (whoami == NSCD_CHILD)
828 return (0);
829
830 /* forker shouldn't be asked */
831 if (whoami == NSCD_FORKER) {
832 NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP);
833 return (0);
834 }
835
836 /* if door client is root, no need for a per-user door */
837 if (uid == 0)
838 return (0);
839
840 /*
841 * if per-user lookup is not configured, no per-user
842 * door available
843 */
844 if (_nscd_is_self_cred_on(0, dblist) == 0)
845 return (-1);
846
847 /*
848 * if per-user lookup is not configured for the db,
849 * don't bother
850 */
851 if (is_db_per_user(phdr, *dblist) == 0)
852 return (0);
853
854 return (1);
855 }
856
857 static void
858 if_selfcred_return_per_user_door(char *argp, size_t arg_size,
859 door_desc_t *dp, int whoami)
860 {
861 nss_pheader_t *phdr = (nss_pheader_t *)((void *)argp);
862 char *dblist;
863 int door = -1;
864 int rc = 0;
865 door_desc_t desc;
866 char *space;
867 int len;
868
869 /*
870 * check to see if self-cred is configured and
871 * need to return an alternate PUN door
872 */
873 if (per_user_is_on == 1) {
874 rc = need_per_user_door(argp, whoami,
875 _nscd_get_client_euid(), &dblist);
876 if (rc == -1)
877 per_user_is_on = 0;
878 }
879 if (rc <= 0) {
880 /*
881 * self-cred not configured, and no error detected,
882 * return to continue the door call processing
883 */
884 if (NSCD_STATUS_IS_OK(phdr))
885 return;
886 else
887 /*
888 * configured but error detected,
889 * stop the door call processing
890 */
891 (void) door_return(argp, phdr->data_off, NULL, 0);
892 }
893
894 /* get the alternate PUN door */
895 _nscd_proc_alt_get(argp, &door);
896 if (NSCD_GET_STATUS(phdr) != NSS_ALTRETRY) {
897 (void) door_return(argp, phdr->data_off, NULL, 0);
898 }
899
900 /* return the alternate door descriptor */
901 len = strlen(dblist) + 1;
902 space = alloca(arg_size + len);
903 phdr->data_len = len;
904 (void) memcpy(space, phdr, arg_size);
905 (void) strncpy((char *)space + arg_size, dblist, len);
906 dp = &desc;
907 dp->d_attributes = DOOR_DESCRIPTOR;
908 dp->d_data.d_desc.d_descriptor = door;
909 arg_size += len;
910 (void) door_return(space, arg_size, dp, 1);
911 }
912
913 /*ARGSUSED*/
914 static void
915 switcher(void *cookie, char *argp, size_t arg_size,
916 door_desc_t *dp, uint_t n_desc)
917 {
918 int iam;
919 pid_t ent_pid = -1;
920 nss_pheader_t *phdr = (nss_pheader_t *)((void *)argp);
921 void *uptr;
922 int len;
923 size_t buflen;
924 int callnum;
925 char *me = "switcher";
926
927 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
928 (me, "switcher ...\n");
929
930 if (argp == DOOR_UNREF_DATA) {
931 (void) printf("Door Slam... exiting\n");
932 exit(0);
933 }
934
935 if (argp == NULL) { /* empty door call */
936 (void) door_return(NULL, 0, 0, 0); /* return the favor */
937 }
938
939 /*
940 * need to restart if main nscd and config file(s) changed
941 */
942 if (_whoami == NSCD_MAIN)
943 _nscd_restart_if_cfgfile_changed();
944
945 if ((phdr->nsc_callnumber & NSCDV2CATMASK) == NSCD_CALLCAT_APP) {
946
947 /* make sure the packed buffer header is good */
948 if (validate_pheader(argp, arg_size,
949 phdr->nsc_callnumber) == -1)
950 (void) door_return(argp, arg_size, NULL, 0);
951
952 switch (phdr->nsc_callnumber) {
953
954 case NSCD_SEARCH:
955
956 /* if a fallback to main nscd, skip per-user setup */
957 if (phdr->p_status != NSS_ALTRETRY)
958 if_selfcred_return_per_user_door(argp, arg_size,
959 dp, _whoami);
960 lookup(argp, arg_size);
961
962 break;
963
964 case NSCD_SETENT:
965
966 _nscd_APP_check_cred(argp, &ent_pid, "NSCD_SETENT",
967 NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT);
968 if (NSCD_STATUS_IS_OK(phdr)) {
969 if_selfcred_return_per_user_door(argp, arg_size,
970 dp, _whoami);
971 nss_psetent(argp, arg_size, ent_pid);
972 }
973 break;
974
975 case NSCD_GETENT:
976
977 getent(argp, arg_size);
978 break;
979
980 case NSCD_ENDENT:
981
982 nss_pendent(argp, arg_size);
983 break;
984
985 case NSCD_PUT:
986
987 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
988 (me, "door call NSCD_PUT not supported yet\n");
989
990 NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP);
991 break;
992
993 case NSCD_GETHINTS:
994
995 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
996 (me, "door call NSCD_GETHINTS not supported yet\n");
997
998 NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP);
999 break;
1000
1001 default:
1002
1003 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1004 (me, "Unknown name service door call op %x\n",
1005 phdr->nsc_callnumber);
1006
1007 NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL);
1008 break;
1009 }
1010
1011 (void) door_return(argp, arg_size, NULL, 0);
1012 }
1013
1014 iam = NSCD_MAIN;
1015 callnum = phdr->nsc_callnumber & ~NSCD_WHOAMI;
1016 if (callnum == NSCD_IMHERE ||
1017 callnum == NSCD_PULSE || callnum == NSCD_FORK)
1018 iam = phdr->nsc_callnumber & NSCD_WHOAMI;
1019 else
1020 callnum = phdr->nsc_callnumber;
1021
1022 /* nscd -> nscd v2 calls */
1023
1024 /* make sure the buffer is good */
1025 if (validate_N2Nbuf(argp, arg_size, callnum) == -1)
1026 (void) door_return(argp, arg_size, NULL, 0);
1027
1028 switch (callnum) {
1029
1030 case NSCD_PING:
1031 NSCD_SET_STATUS_SUCCESS(phdr);
1032 break;
1033
1034 case NSCD_IMHERE:
1035 _nscd_proc_iamhere(argp, dp, n_desc, iam);
1036 break;
1037
1038 case NSCD_PULSE:
1039 N2N_check_priv(argp, "NSCD_PULSE");
1040 if (NSCD_STATUS_IS_OK(phdr))
1041 _nscd_proc_pulse(argp, iam);
1042 break;
1043
1044 case NSCD_FORK:
1045 N2N_check_priv(argp, "NSCD_FORK");
1046 if (NSCD_STATUS_IS_OK(phdr))
1047 _nscd_proc_fork(argp, iam);
1048 break;
1049
1050 case NSCD_KILL:
1051 N2N_check_priv(argp, "NSCD_KILL");
1052 if (NSCD_STATUS_IS_OK(phdr))
1053 exit(0);
1054 break;
1055
1056 case NSCD_REFRESH:
1057 N2N_check_priv(argp, "NSCD_REFRESH");
1058 if (NSCD_STATUS_IS_OK(phdr)) {
1059 if (_nscd_refresh() != NSCD_SUCCESS)
1060 exit(1);
1061 NSCD_SET_STATUS_SUCCESS(phdr);
1062 }
1063 break;
1064
1065 case NSCD_GETPUADMIN:
1066
1067 if (_nscd_is_self_cred_on(0, NULL)) {
1068 _nscd_peruser_getadmin(argp, sizeof (nscd_admin_t));
1069 } else {
1070 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
1071 NSCD_SELF_CRED_NOT_CONFIGURED);
1072 }
1073 break;
1074
1075 case NSCD_GETADMIN:
1076
1077 len = _nscd_door_getadmin((void *)argp);
1078 if (len == 0)
1079 break;
1080
1081 /* size of door buffer not big enough, allocate one */
1082 NSCD_ALLOC_DOORBUF(NSCD_GETADMIN, len, uptr, buflen);
1083
1084 /* copy packed header */
1085 *(nss_pheader_t *)uptr = *(nss_pheader_t *)((void *)argp);
1086
1087 /* set new buffer size */
1088 ((nss_pheader_t *)uptr)->pbufsiz = buflen;
1089
1090 /* try one more time */
1091 (void) _nscd_door_getadmin((void *)uptr);
1092 (void) door_return(uptr, buflen, NULL, 0);
1093 break;
1094
1095 case NSCD_SETADMIN:
1096 N2N_check_priv(argp, "NSCD_SETADMIN");
1097 if (NSCD_STATUS_IS_OK(phdr))
1098 _nscd_door_setadmin(argp);
1099 break;
1100
1101 case NSCD_KILLSERVER:
1102 N2N_check_priv(argp, "NSCD_KILLSERVER");
1103 if (NSCD_STATUS_IS_OK(phdr)) {
1104 /* also kill the forker nscd if one is running */
1105 _nscd_kill_forker();
1106 exit(0);
1107 }
1108 break;
1109
1110 default:
1111 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1112 (me, "Unknown name service door call op %d\n",
1113 phdr->nsc_callnumber);
1114
1115 NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL);
1116
1117 (void) door_return(argp, arg_size, NULL, 0);
1118 break;
1119
1120 }
1121 (void) door_return(argp, arg_size, NULL, 0);
1122 }
1123
1124 int
1125 _nscd_setup_server(char *execname, char **argv)
1126 {
1127
1128 int fd;
1129 int errnum;
1130 int bind_failed = 0;
1131 mode_t old_mask;
1132 struct stat buf;
1133 sigset_t myset;
1134 struct sigaction action;
1135 char *me = "_nscd_setup_server";
1136
1137 main_execname = execname;
1138 main_argv = argv;
1139
1140 /* Any nscd process is to ignore SIGPIPE */
1141 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
1142 errnum = errno;
1143 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1144 (me, "signal (SIGPIPE): %s\n", strerror(errnum));
1145 return (-1);
1146 }
1147
1148 keep_open_dns_socket();
1149
1150 /*
1151 * the max number of server threads should be fixed now, so
1152 * set flag to indicate that no in-flight change is allowed
1153 */
1154 max_servers_set = 1;
1155
1156 (void) thr_keycreate(&lookup_state_key, NULL);
1157 (void) sema_init(&common_sema, frontend_cfg_g.common_worker_threads,
1158 USYNC_THREAD, 0);
1159
1160 /* Establish server thread pool */
1161 (void) door_server_create(server_create);
1162 if (thr_keycreate(&server_key, server_destroy) != 0) {
1163 errnum = errno;
1164 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1165 (me, "thr_keycreate (server thread): %s\n",
1166 strerror(errnum));
1167 return (-1);
1168 }
1169
1170 /* Create a door */
1171 if ((fd = door_create(switcher, NAME_SERVICE_DOOR_COOKIE,
1172 DOOR_UNREF | DOOR_NO_CANCEL)) < 0) {
1173 errnum = errno;
1174 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1175 (me, "door_create: %s\n", strerror(errnum));
1176 return (-1);
1177 }
1178
1179 /* if not main nscd, no more setup to do */
1180 if (_whoami != NSCD_MAIN)
1181 return (fd);
1182
1183 /* bind to file system */
1184 if (is_system_labeled() && (getzoneid() == GLOBAL_ZONEID)) {
1185 if (stat(TSOL_NAME_SERVICE_DOOR, &buf) < 0) {
1186 int newfd;
1187
1188 /* make sure the door will be readable by all */
1189 old_mask = umask(0);
1190 if ((newfd = creat(TSOL_NAME_SERVICE_DOOR, 0444)) < 0) {
1191 errnum = errno;
1192 _NSCD_LOG(NSCD_LOG_FRONT_END,
1193 NSCD_LOG_LEVEL_ERROR)
1194 (me, "Cannot create %s: %s\n",
1195 TSOL_NAME_SERVICE_DOOR,
1196 strerror(errnum));
1197 bind_failed = 1;
1198 }
1199 /* rstore the old file mode creation mask */
1200 (void) umask(old_mask);
1201 (void) close(newfd);
1202 }
1203 if (symlink(TSOL_NAME_SERVICE_DOOR, NAME_SERVICE_DOOR) != 0) {
1204 if (errno != EEXIST) {
1205 errnum = errno;
1206 _NSCD_LOG(NSCD_LOG_FRONT_END,
1207 NSCD_LOG_LEVEL_ERROR)
1208 (me, "Cannot symlink %s: %s\n",
1209 NAME_SERVICE_DOOR, strerror(errnum));
1210 bind_failed = 1;
1211 }
1212 }
1213 } else if (stat(NAME_SERVICE_DOOR, &buf) < 0) {
1214 int newfd;
1215
1216 /* make sure the door will be readable by all */
1217 old_mask = umask(0);
1218 if ((newfd = creat(NAME_SERVICE_DOOR, 0444)) < 0) {
1219 errnum = errno;
1220 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1221 (me, "Cannot create %s: %s\n", NAME_SERVICE_DOOR,
1222 strerror(errnum));
1223 bind_failed = 1;
1224 }
1225 /* rstore the old file mode creation mask */
1226 (void) umask(old_mask);
1227 (void) close(newfd);
1228 }
1229
1230 if (bind_failed == 1) {
1231 (void) door_revoke(fd);
1232 return (-1);
1233 }
1234
1235 if (fattach(fd, NAME_SERVICE_DOOR) < 0) {
1236 if ((errno != EBUSY) ||
1237 (fdetach(NAME_SERVICE_DOOR) < 0) ||
1238 (fattach(fd, NAME_SERVICE_DOOR) < 0)) {
1239 errnum = errno;
1240 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1241 (me, "fattach: %s\n", strerror(errnum));
1242 (void) door_revoke(fd);
1243 return (-1);
1244 }
1245 }
1246
1247 /*
1248 * kick off routing socket monitor thread
1249 */
1250 if (thr_create(NULL, NULL,
1251 (void *(*)(void *))rts_mon, 0, 0, NULL) != 0) {
1252 errnum = errno;
1253 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1254 (me, "thr_create (routing socket monitor): %s\n",
1255 strerror(errnum));
1256
1257 (void) door_revoke(fd);
1258 return (-1);
1259 }
1260
1261 /*
1262 * set up signal handler for SIGHUP
1263 */
1264 action.sa_handler = dozip;
1265 action.sa_flags = 0;
1266 (void) sigemptyset(&action.sa_mask);
1267 (void) sigemptyset(&myset);
1268 (void) sigaddset(&myset, SIGHUP);
1269
1270 if (sigaction(SIGHUP, &action, NULL) < 0) {
1271 errnum = errno;
1272 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1273 (me, "sigaction (SIGHUP): %s\n", strerror(errnum));
1274
1275 (void) door_revoke(fd);
1276 return (-1);
1277 }
1278
1279 return (fd);
1280 }
1281
1282 int
1283 _nscd_setup_child_server(int did)
1284 {
1285
1286 int errnum;
1287 int fd;
1288 nscd_rc_t rc;
1289 char *me = "_nscd_setup_child_server";
1290
1291 /* Re-establish our own server thread pool */
1292 (void) door_server_create(server_create);
1293 if (thr_keycreate(&server_key, server_destroy) != 0) {
1294 errnum = errno;
1295 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
1296 (me, "thr_keycreate failed: %s", strerror(errnum));
1297 return (-1);
1298 }
1299
1300 /*
1301 * Create a new door.
1302 * Keep DOOR_REFUSE_DESC (self-cred nscds don't fork)
1303 */
1304 (void) close(did);
1305 if ((fd = door_create(switcher, NAME_SERVICE_DOOR_COOKIE,
1306 DOOR_REFUSE_DESC|DOOR_UNREF|DOOR_NO_CANCEL)) < 0) {
1307 errnum = errno;
1308 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG)
1309 (me, "door_create failed: %s", strerror(errnum));
1310 return (-1);
1311 }
1312
1313 /*
1314 * kick off routing socket monitor thread
1315 */
1316 if (thr_create(NULL, NULL,
1317 (void *(*)(void *))rts_mon, 0, 0, NULL) != 0) {
1318 errnum = errno;
1319 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1320 (me, "thr_create (routing socket monitor): %s\n",
1321 strerror(errnum));
1322 (void) door_revoke(fd);
1323 return (-1);
1324 }
1325
1326 /*
1327 * start monitoring the states of the name service clients
1328 */
1329 rc = _nscd_init_smf_monitor();
1330 if (rc != NSCD_SUCCESS) {
1331 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1332 (me, "unable to start the SMF monitor (rc = %d)\n", rc);
1333
1334 (void) door_revoke(fd);
1335 return (-1);
1336 }
1337
1338 return (fd);
1339 }
1340
1341 nscd_rc_t
1342 _nscd_alloc_frontend_cfg()
1343 {
1344 frontend_cfg = calloc(NSCD_NUM_DB, sizeof (nscd_cfg_frontend_t));
1345 if (frontend_cfg == NULL)
1346 return (NSCD_NO_MEMORY);
1347
1348 return (NSCD_SUCCESS);
1349 }
1350
1351
1352 /* ARGSUSED */
1353 nscd_rc_t
1354 _nscd_cfg_frontend_notify(
1355 void *data,
1356 struct nscd_cfg_param_desc *pdesc,
1357 nscd_cfg_id_t *nswdb,
1358 nscd_cfg_flag_t dflag,
1359 nscd_cfg_error_t **errorp,
1360 void *cookie)
1361 {
1362 void *dp;
1363
1364 /*
1365 * At init time, the whole group of config params are received.
1366 * At update time, group or individual parameter value could
1367 * be received.
1368 */
1369
1370 if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_INIT) ||
1371 _nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) {
1372 /*
1373 * group data is received, copy in the
1374 * entire strcture
1375 */
1376 if (_nscd_cfg_flag_is_set(pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL))
1377 frontend_cfg_g = *(nscd_cfg_global_frontend_t *)data;
1378 else
1379 frontend_cfg[nswdb->index] =
1380 *(nscd_cfg_frontend_t *)data;
1381
1382 } else {
1383 /*
1384 * individual paramater is received: copy in the
1385 * parameter value.
1386 */
1387 if (_nscd_cfg_flag_is_set(pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL))
1388 dp = (char *)&frontend_cfg_g + pdesc->p_offset;
1389 else
1390 dp = (char *)&frontend_cfg[nswdb->index] +
1391 pdesc->p_offset;
1392 (void) memcpy(dp, data, pdesc->p_size);
1393 }
1394
1395 return (NSCD_SUCCESS);
1396 }
1397
1398 /* ARGSUSED */
1399 nscd_rc_t
1400 _nscd_cfg_frontend_verify(
1401 void *data,
1402 struct nscd_cfg_param_desc *pdesc,
1403 nscd_cfg_id_t *nswdb,
1404 nscd_cfg_flag_t dflag,
1405 nscd_cfg_error_t **errorp,
1406 void **cookie)
1407 {
1408
1409 char *me = "_nscd_cfg_frontend_verify";
1410
1411 /*
1412 * if max. number of server threads is set and in effect,
1413 * don't allow changing of the frontend configuration
1414 */
1415 if (max_servers_set) {
1416 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_INFO)
1417 (me, "changing of the frontend configuration not allowed now");
1418
1419 return (NSCD_CFG_CHANGE_NOT_ALLOWED);
1420 }
1421
1422 return (NSCD_SUCCESS);
1423 }
1424
1425 /* ARGSUSED */
1426 nscd_rc_t
1427 _nscd_cfg_frontend_get_stat(
1428 void **stat,
1429 struct nscd_cfg_stat_desc *sdesc,
1430 nscd_cfg_id_t *nswdb,
1431 nscd_cfg_flag_t *dflag,
1432 void (**free_stat)(void *stat),
1433 nscd_cfg_error_t **errorp)
1434 {
1435 return (NSCD_SUCCESS);
1436 }
1437
1438 void
1439 _nscd_init_cache_sema(sema_t *sema, char *cache_name)
1440 {
1441 int i, j;
1442 char *dbn;
1443
1444 if (max_servers == 0)
1445 max_servers = frontend_cfg_g.common_worker_threads +
1446 frontend_cfg_g.cache_hit_threads;
1447
1448 for (i = 0; i < NSCD_NUM_DB; i++) {
1449
1450 dbn = NSCD_NSW_DB_NAME(i);
1451 if (strcasecmp(dbn, cache_name) == 0) {
1452 j = frontend_cfg[i].worker_thread_per_nsw_db;
1453 (void) sema_init(sema, j, USYNC_THREAD, 0);
1454 max_servers += j;
1455 break;
1456 }
1457 }
1458 }
1459
1460 /*
1461 * Monitor the routing socket. Address lists stored in the ipnodes
1462 * cache are sorted based on destination address selection rules,
1463 * so when things change that could affect that sorting (interfaces
1464 * go up or down, flags change, etc.), we clear that cache so the
1465 * list will be re-ordered the next time the hostname is resolved.
1466 */
1467 static void
1468 rts_mon(void)
1469 {
1470 int rt_sock, rdlen, idx;
1471 union {
1472 struct {
1473 struct rt_msghdr rtm;
1474 struct sockaddr_storage addrs[RTA_NUMBITS];
1475 } r;
1476 struct if_msghdr ifm;
1477 struct ifa_msghdr ifam;
1478 } mbuf;
1479 struct ifa_msghdr *ifam = &mbuf.ifam;
1480 char *me = "rts_mon";
1481
1482 rt_sock = socket(PF_ROUTE, SOCK_RAW, 0);
1483 if (rt_sock < 0) {
1484 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1485 (me, "Failed to open routing socket: %s\n", strerror(errno));
1486 thr_exit(0);
1487 }
1488
1489 for (;;) {
1490 rdlen = read(rt_sock, &mbuf, sizeof (mbuf));
1491 if (rdlen <= 0) {
1492 if (rdlen == 0 || (errno != EINTR && errno != EAGAIN)) {
1493 _NSCD_LOG(NSCD_LOG_FRONT_END,
1494 NSCD_LOG_LEVEL_ERROR)
1495 (me, "routing socket read: %s\n",
1496 strerror(errno));
1497 thr_exit(0);
1498 }
1499 continue;
1500 }
1501 if (ifam->ifam_version != RTM_VERSION) {
1502 _NSCD_LOG(NSCD_LOG_FRONT_END,
1503 NSCD_LOG_LEVEL_ERROR)
1504 (me, "rx unknown version (%d) on "
1505 "routing socket.\n",
1506 ifam->ifam_version);
1507 continue;
1508 }
1509 switch (ifam->ifam_type) {
1510 case RTM_NEWADDR:
1511 case RTM_DELADDR:
1512 /* if no ipnodes cache, then nothing to do */
1513 idx = get_cache_idx("ipnodes");
1514 if (cache_ctx_p[idx] == NULL ||
1515 cache_ctx_p[idx]->reaper_on != nscd_true)
1516 break;
1517 nsc_invalidate(cache_ctx_p[idx], NULL, NULL);
1518 break;
1519 case RTM_ADD:
1520 case RTM_DELETE:
1521 case RTM_CHANGE:
1522 case RTM_GET:
1523 case RTM_LOSING:
1524 case RTM_REDIRECT:
1525 case RTM_MISS:
1526 case RTM_LOCK:
1527 case RTM_OLDADD:
1528 case RTM_OLDDEL:
1529 case RTM_RESOLVE:
1530 case RTM_IFINFO:
1531 case RTM_CHGADDR:
1532 case RTM_FREEADDR:
1533 break;
1534 default:
1535 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
1536 (me, "rx unknown msg type (%d) on routing socket.\n",
1537 ifam->ifam_type);
1538 break;
1539 }
1540 }
1541 }
1542
1543 static void
1544 keep_open_dns_socket(void)
1545 {
1546 _res.options |= RES_STAYOPEN; /* just keep this udp socket open */
1547 }