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