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