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