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