1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Door server routines for nfsmapid daemon 30 * Translate NFSv4 users and groups between numeric and string values 31 */ 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <alloca.h> 35 #include <signal.h> 36 #include <libintl.h> 37 #include <limits.h> 38 #include <errno.h> 39 #include <sys/types.h> 40 #include <string.h> 41 #include <memory.h> 42 #include <pwd.h> 43 #include <grp.h> 44 #include <door.h> 45 #include <syslog.h> 46 #include <fcntl.h> 47 #include <unistd.h> 48 #include <assert.h> 49 #include <deflt.h> 50 #include <nfs/nfs4.h> 51 #include <nfs/nfssys.h> 52 #include <nfs/nfsid_map.h> 53 #include <nfs/mapid.h> 54 #include <sys/sdt.h> 55 #include <sys/idmap.h> 56 #include <idmap.h> 57 58 #define UID_MAX_STR_LEN 11 /* Digits in UID_MAX + 1 */ 59 #define DIAG_FILE "/var/run/nfs4_domain" 60 61 /* 62 * idmap_kcall() takes a door descriptor as it's argument when we 63 * need to (re)establish the in-kernel door handles. When we only 64 * want to flush the id kernel caches, we don't redo the door setup. 65 */ 66 #define FLUSH_KCACHES_ONLY (int)-1 67 68 FILE *n4_fp; 69 int n4_fd; 70 71 extern size_t pwd_buflen; 72 extern size_t grp_buflen; 73 extern thread_t sig_thread; 74 75 /* 76 * Prototypes 77 */ 78 extern void check_domain(int); 79 extern void idmap_kcall(int); 80 extern int _nfssys(int, void *); 81 extern int valid_domain(const char *); 82 extern int validate_id_str(const char *); 83 extern int extract_domain(char *, char **, char **); 84 extern void update_diag_file(char *); 85 extern void *cb_update_domain(void *); 86 extern int cur_domain_null(void); 87 88 void 89 nfsmapid_str_uid(struct mapid_arg *argp, size_t arg_size) 90 { 91 struct mapid_res result; 92 struct passwd pwd; 93 struct passwd *pwd_ptr; 94 int pwd_rc; 95 char *pwd_buf; 96 char *user; 97 char *domain; 98 idmap_stat rc; 99 100 if (argp->u_arg.len <= 0 || arg_size < MAPID_ARG_LEN(argp->u_arg.len)) { 101 result.status = NFSMAPID_INVALID; 102 result.u_res.uid = UID_NOBODY; 103 goto done; 104 } 105 106 if (!extract_domain(argp->str, &user, &domain)) { 107 unsigned long id; 108 109 /* 110 * Invalid "user@domain" string. Still, the user 111 * part might be an encoded uid, so do a final check. 112 * Remember, domain part of string was not set since 113 * not a valid string. 114 */ 115 if (!validate_id_str(user)) { 116 result.status = NFSMAPID_UNMAPPABLE; 117 result.u_res.uid = UID_NOBODY; 118 goto done; 119 } 120 121 errno = 0; 122 id = strtoul(user, (char **)NULL, 10); 123 124 /* 125 * We don't accept ephemeral ids from the wire. 126 */ 127 if (errno || id > UID_MAX) { 128 result.status = NFSMAPID_UNMAPPABLE; 129 result.u_res.uid = UID_NOBODY; 130 goto done; 131 } 132 133 result.u_res.uid = (uid_t)id; 134 result.status = NFSMAPID_NUMSTR; 135 goto done; 136 } 137 138 /* 139 * String properly constructed. Now we check for domain and 140 * group validity. 141 */ 142 if (!cur_domain_null() && !valid_domain(domain)) { 143 /* 144 * If the domain part of the string does not 145 * match the NFS domain, try to map it using 146 * idmap service. 147 */ 148 rc = idmap_getuidbywinname(user, domain, &result.u_res.uid); 149 if (rc != IDMAP_SUCCESS) { 150 result.status = NFSMAPID_BADDOMAIN; 151 result.u_res.uid = UID_NOBODY; 152 goto done; 153 } 154 result.status = NFSMAPID_OK; 155 goto done; 156 } 157 158 if ((pwd_buf = malloc(pwd_buflen)) == NULL || 159 (pwd_rc = getpwnam_r(user, &pwd, pwd_buf, pwd_buflen, &pwd_ptr)) 160 != 0 || pwd_ptr == NULL) { 161 162 if (pwd_buf == NULL || pwd_rc != 0) 163 result.status = NFSMAPID_INTERNAL; 164 else { 165 /* 166 * Not a valid user 167 */ 168 result.status = NFSMAPID_NOTFOUND; 169 free(pwd_buf); 170 } 171 result.u_res.uid = UID_NOBODY; 172 goto done; 173 } 174 175 /* 176 * Valid user entry 177 */ 178 result.u_res.uid = pwd.pw_uid; 179 result.status = NFSMAPID_OK; 180 free(pwd_buf); 181 done: 182 (void) door_return((char *)&result, sizeof (struct mapid_res), NULL, 0); 183 } 184 185 /* ARGSUSED1 */ 186 void 187 nfsmapid_uid_str(struct mapid_arg *argp, size_t arg_size) 188 { 189 struct mapid_res result; 190 struct mapid_res *resp; 191 struct passwd pwd; 192 struct passwd *pwd_ptr; 193 char *pwd_buf = NULL; 194 char *idmap_buf = NULL; 195 uid_t uid = argp->u_arg.uid; 196 size_t uid_str_len; 197 char *pw_str; 198 size_t pw_str_len; 199 char *at_str; 200 size_t at_str_len; 201 char dom_str[DNAMEMAX]; 202 size_t dom_str_len; 203 idmap_stat rc; 204 205 if (uid == (uid_t)-1) { 206 /* 207 * Sentinel uid is not a valid id 208 */ 209 resp = &result; 210 resp->status = NFSMAPID_BADID; 211 resp->u_res.len = 0; 212 goto done; 213 } 214 215 /* 216 * Make local copy of domain for further manipuation 217 * NOTE: mapid_get_domain() returns a ptr to TSD. 218 */ 219 if (cur_domain_null()) { 220 dom_str_len = 0; 221 dom_str[0] = '\0'; 222 } else { 223 dom_str_len = strlcpy(dom_str, mapid_get_domain(), DNAMEMAX); 224 } 225 226 /* 227 * If uid is ephemeral then resolve it using idmap service 228 */ 229 if (uid > UID_MAX) { 230 rc = idmap_getwinnamebyuid(uid, &idmap_buf, NULL); 231 if (rc != IDMAP_SUCCESS) { 232 /* 233 * We don't put stringified ephemeral uids on 234 * the wire. 235 */ 236 resp = &result; 237 resp->status = NFSMAPID_UNMAPPABLE; 238 resp->u_res.len = 0; 239 goto done; 240 } 241 242 /* 243 * idmap_buf is already in the desired form i.e. name@domain 244 */ 245 pw_str = idmap_buf; 246 pw_str_len = strlen(pw_str); 247 at_str_len = dom_str_len = 0; 248 at_str = ""; 249 dom_str[0] = '\0'; 250 goto gen_result; 251 } 252 253 /* 254 * Handling non-ephemeral uids 255 * 256 * We want to encode the uid into a literal string... : 257 * 258 * - upon failure to allocate space from the heap 259 * - if there is no current domain configured 260 * - if there is no such uid in the passwd DB's 261 */ 262 if ((pwd_buf = malloc(pwd_buflen)) == NULL || dom_str_len == 0 || 263 getpwuid_r(uid, &pwd, pwd_buf, pwd_buflen, &pwd_ptr) != 0 || 264 pwd_ptr == NULL) { 265 266 /* 267 * If we could not allocate from the heap, try 268 * allocating from the stack as a last resort. 269 */ 270 if (pwd_buf == NULL && (pwd_buf = 271 alloca(MAPID_RES_LEN(UID_MAX_STR_LEN))) == NULL) { 272 resp = &result; 273 resp->status = NFSMAPID_INTERNAL; 274 resp->u_res.len = 0; 275 goto done; 276 } 277 278 /* 279 * Constructing literal string without '@' so that 280 * we'll know that it's not a user, but rather a 281 * uid encoded string. 282 */ 283 pw_str = pwd_buf; 284 (void) sprintf(pw_str, "%u", uid); 285 pw_str_len = strlen(pw_str); 286 at_str_len = dom_str_len = 0; 287 at_str = ""; 288 dom_str[0] = '\0'; 289 } else { 290 /* 291 * Otherwise, we construct the "user@domain" string if 292 * it's not already in that form. 293 */ 294 pw_str = pwd.pw_name; 295 pw_str_len = strlen(pw_str); 296 if (strchr(pw_str, '@') == NULL) { 297 at_str = "@"; 298 at_str_len = 1; 299 } else { 300 at_str_len = dom_str_len = 0; 301 at_str = ""; 302 dom_str[0] = '\0'; 303 } 304 } 305 306 gen_result: 307 uid_str_len = pw_str_len + at_str_len + dom_str_len; 308 if ((resp = alloca(MAPID_RES_LEN(uid_str_len))) == NULL) { 309 resp = &result; 310 resp->status = NFSMAPID_INTERNAL; 311 resp->u_res.len = 0; 312 goto done; 313 } 314 /* LINTED format argument to sprintf */ 315 (void) sprintf(resp->str, "%s%s%s", pw_str, at_str, dom_str); 316 resp->u_res.len = uid_str_len; 317 if (pwd_buf) 318 free(pwd_buf); 319 if (idmap_buf) 320 idmap_free(idmap_buf); 321 resp->status = NFSMAPID_OK; 322 323 done: 324 /* 325 * There is a chance that the door_return will fail because the 326 * resulting string is too large, try to indicate that if possible 327 */ 328 if (door_return((char *)resp, 329 MAPID_RES_LEN(resp->u_res.len), NULL, 0) == -1) { 330 resp->status = NFSMAPID_INTERNAL; 331 resp->u_res.len = 0; 332 (void) door_return((char *)&result, sizeof (struct mapid_res), 333 NULL, 0); 334 } 335 } 336 337 void 338 nfsmapid_str_gid(struct mapid_arg *argp, size_t arg_size) 339 { 340 struct mapid_res result; 341 struct group grp; 342 struct group *grp_ptr; 343 int grp_rc; 344 char *grp_buf; 345 char *group; 346 char *domain; 347 idmap_stat rc; 348 349 if (argp->u_arg.len <= 0 || 350 arg_size < MAPID_ARG_LEN(argp->u_arg.len)) { 351 result.status = NFSMAPID_INVALID; 352 result.u_res.gid = GID_NOBODY; 353 goto done; 354 } 355 356 if (!extract_domain(argp->str, &group, &domain)) { 357 unsigned long id; 358 359 /* 360 * Invalid "group@domain" string. Still, the 361 * group part might be an encoded gid, so do a 362 * final check. Remember, domain part of string 363 * was not set since not a valid string. 364 */ 365 if (!validate_id_str(group)) { 366 result.status = NFSMAPID_UNMAPPABLE; 367 result.u_res.gid = GID_NOBODY; 368 goto done; 369 } 370 371 errno = 0; 372 id = strtoul(group, (char **)NULL, 10); 373 374 /* 375 * We don't accept ephemeral ids from the wire. 376 */ 377 if (errno || id > UID_MAX) { 378 result.status = NFSMAPID_UNMAPPABLE; 379 result.u_res.gid = GID_NOBODY; 380 goto done; 381 } 382 383 result.u_res.gid = (gid_t)id; 384 result.status = NFSMAPID_NUMSTR; 385 goto done; 386 } 387 388 /* 389 * String properly constructed. Now we check for domain and 390 * group validity. 391 */ 392 if (!cur_domain_null() && !valid_domain(domain)) { 393 /* 394 * If the domain part of the string does not 395 * match the NFS domain, try to map it using 396 * idmap service. 397 */ 398 rc = idmap_getgidbywinname(group, domain, &result.u_res.gid); 399 if (rc != IDMAP_SUCCESS) { 400 result.status = NFSMAPID_BADDOMAIN; 401 result.u_res.gid = GID_NOBODY; 402 goto done; 403 } 404 result.status = NFSMAPID_OK; 405 goto done; 406 } 407 408 if ((grp_buf = malloc(grp_buflen)) == NULL || 409 (grp_rc = getgrnam_r(group, &grp, grp_buf, grp_buflen, &grp_ptr)) 410 != 0 || grp_ptr == NULL) { 411 412 if (grp_buf == NULL || grp_rc != 0) 413 result.status = NFSMAPID_INTERNAL; 414 else { 415 /* 416 * Not a valid group 417 */ 418 result.status = NFSMAPID_NOTFOUND; 419 free(grp_buf); 420 } 421 result.u_res.gid = GID_NOBODY; 422 goto done; 423 } 424 425 /* 426 * Valid group entry 427 */ 428 result.status = NFSMAPID_OK; 429 result.u_res.gid = grp.gr_gid; 430 free(grp_buf); 431 done: 432 (void) door_return((char *)&result, sizeof (struct mapid_res), NULL, 0); 433 } 434 435 /* ARGSUSED1 */ 436 void 437 nfsmapid_gid_str(struct mapid_arg *argp, size_t arg_size) 438 { 439 struct mapid_res result; 440 struct mapid_res *resp; 441 struct group grp; 442 struct group *grp_ptr; 443 char *grp_buf = NULL; 444 char *idmap_buf = NULL; 445 idmap_stat rc; 446 gid_t gid = argp->u_arg.gid; 447 size_t gid_str_len; 448 char *gr_str; 449 size_t gr_str_len; 450 char *at_str; 451 size_t at_str_len; 452 char dom_str[DNAMEMAX]; 453 size_t dom_str_len; 454 455 if (gid == (gid_t)-1) { 456 /* 457 * Sentinel gid is not a valid id 458 */ 459 resp = &result; 460 resp->status = NFSMAPID_BADID; 461 resp->u_res.len = 0; 462 goto done; 463 } 464 465 /* 466 * Make local copy of domain for further manipuation 467 * NOTE: mapid_get_domain() returns a ptr to TSD. 468 */ 469 if (cur_domain_null()) { 470 dom_str_len = 0; 471 dom_str[0] = '\0'; 472 } else { 473 dom_str_len = strlen(mapid_get_domain()); 474 bcopy(mapid_get_domain(), dom_str, dom_str_len); 475 dom_str[dom_str_len] = '\0'; 476 } 477 478 /* 479 * If gid is ephemeral then resolve it using idmap service 480 */ 481 if (gid > UID_MAX) { 482 rc = idmap_getwinnamebygid(gid, &idmap_buf, NULL); 483 if (rc != IDMAP_SUCCESS) { 484 /* 485 * We don't put stringified ephemeral gids on 486 * the wire. 487 */ 488 resp = &result; 489 resp->status = NFSMAPID_UNMAPPABLE; 490 resp->u_res.len = 0; 491 goto done; 492 } 493 494 /* 495 * idmap_buf is already in the desired form i.e. name@domain 496 */ 497 gr_str = idmap_buf; 498 gr_str_len = strlen(gr_str); 499 at_str_len = dom_str_len = 0; 500 at_str = ""; 501 dom_str[0] = '\0'; 502 goto gen_result; 503 } 504 505 /* 506 * Handling non-ephemeral gids 507 * 508 * We want to encode the gid into a literal string... : 509 * 510 * - upon failure to allocate space from the heap 511 * - if there is no current domain configured 512 * - if there is no such gid in the group DB's 513 */ 514 if ((grp_buf = malloc(grp_buflen)) == NULL || dom_str_len == 0 || 515 getgrgid_r(gid, &grp, grp_buf, grp_buflen, &grp_ptr) != 0 || 516 grp_ptr == NULL) { 517 518 /* 519 * If we could not allocate from the heap, try 520 * allocating from the stack as a last resort. 521 */ 522 if (grp_buf == NULL && (grp_buf = 523 alloca(MAPID_RES_LEN(UID_MAX_STR_LEN))) == NULL) { 524 resp = &result; 525 resp->status = NFSMAPID_INTERNAL; 526 resp->u_res.len = 0; 527 goto done; 528 } 529 530 /* 531 * Constructing literal string without '@' so that 532 * we'll know that it's not a group, but rather a 533 * gid encoded string. 534 */ 535 gr_str = grp_buf; 536 (void) sprintf(gr_str, "%u", gid); 537 gr_str_len = strlen(gr_str); 538 at_str_len = dom_str_len = 0; 539 at_str = ""; 540 dom_str[0] = '\0'; 541 } else { 542 /* 543 * Otherwise, we construct the "group@domain" string if 544 * it's not already in that form. 545 */ 546 gr_str = grp.gr_name; 547 gr_str_len = strlen(gr_str); 548 if (strchr(gr_str, '@') == NULL) { 549 at_str = "@"; 550 at_str_len = 1; 551 } else { 552 at_str_len = dom_str_len = 0; 553 at_str = ""; 554 dom_str[0] = '\0'; 555 } 556 } 557 558 gen_result: 559 gid_str_len = gr_str_len + at_str_len + dom_str_len; 560 if ((resp = alloca(MAPID_RES_LEN(gid_str_len))) == NULL) { 561 resp = &result; 562 resp->status = NFSMAPID_INTERNAL; 563 resp->u_res.len = 0; 564 goto done; 565 } 566 /* LINTED format argument to sprintf */ 567 (void) sprintf(resp->str, "%s%s%s", gr_str, at_str, dom_str); 568 resp->u_res.len = gid_str_len; 569 if (grp_buf) 570 free(grp_buf); 571 if (idmap_buf) 572 idmap_free(idmap_buf); 573 resp->status = NFSMAPID_OK; 574 575 done: 576 /* 577 * There is a chance that the door_return will fail because the 578 * resulting string is too large, try to indicate that if possible 579 */ 580 if (door_return((char *)resp, 581 MAPID_RES_LEN(resp->u_res.len), NULL, 0) == -1) { 582 resp->status = NFSMAPID_INTERNAL; 583 resp->u_res.len = 0; 584 (void) door_return((char *)&result, sizeof (struct mapid_res), 585 NULL, 0); 586 } 587 } 588 589 /* ARGSUSED */ 590 void 591 nfsmapid_func(void *cookie, char *argp, size_t arg_size, 592 door_desc_t *dp, uint_t n_desc) 593 { 594 struct mapid_arg *mapargp; 595 struct mapid_res mapres; 596 597 /* 598 * Make sure we have a valid argument 599 */ 600 if (arg_size < sizeof (struct mapid_arg)) { 601 mapres.status = NFSMAPID_INVALID; 602 mapres.u_res.len = 0; 603 (void) door_return((char *)&mapres, sizeof (struct mapid_res), 604 NULL, 0); 605 return; 606 } 607 608 /* LINTED pointer cast */ 609 mapargp = (struct mapid_arg *)argp; 610 switch (mapargp->cmd) { 611 case NFSMAPID_STR_UID: 612 nfsmapid_str_uid(mapargp, arg_size); 613 return; 614 case NFSMAPID_UID_STR: 615 nfsmapid_uid_str(mapargp, arg_size); 616 return; 617 case NFSMAPID_STR_GID: 618 nfsmapid_str_gid(mapargp, arg_size); 619 return; 620 case NFSMAPID_GID_STR: 621 nfsmapid_gid_str(mapargp, arg_size); 622 return; 623 default: 624 break; 625 } 626 mapres.status = NFSMAPID_INVALID; 627 mapres.u_res.len = 0; 628 (void) door_return((char *)&mapres, sizeof (struct mapid_res), NULL, 0); 629 } 630 631 /* 632 * mapid_get_domain() always returns a ptr to TSD, so the 633 * check for a NULL domain is not a simple comparison with 634 * NULL but we need to check the contents of the TSD data. 635 */ 636 int 637 cur_domain_null(void) 638 { 639 char *p; 640 641 if ((p = mapid_get_domain()) == NULL) 642 return (1); 643 644 return (p[0] == '\0'); 645 } 646 647 int 648 extract_domain(char *cp, char **upp, char **dpp) 649 { 650 /* 651 * Caller must insure that the string is valid 652 */ 653 *upp = cp; 654 655 if ((*dpp = strchr(cp, '@')) == NULL) 656 return (0); 657 *(*dpp)++ = '\0'; 658 return (1); 659 } 660 661 int 662 valid_domain(const char *dom) 663 { 664 const char *whoami = "valid_domain"; 665 666 if (!mapid_stdchk_domain(dom)) { 667 syslog(LOG_ERR, gettext("%s: Invalid inbound domain name %s."), 668 whoami, dom); 669 return (0); 670 } 671 672 /* 673 * NOTE: mapid_get_domain() returns a ptr to TSD. 674 */ 675 return (strcasecmp(dom, mapid_get_domain()) == 0); 676 } 677 678 int 679 validate_id_str(const char *id) 680 { 681 while (*id) { 682 if (!isdigit(*id++)) 683 return (0); 684 } 685 return (1); 686 } 687 688 void 689 idmap_kcall(int door_id) 690 { 691 struct nfsidmap_args args; 692 693 if (door_id >= 0) { 694 args.state = 1; 695 args.did = door_id; 696 } else { 697 args.state = 0; 698 args.did = 0; 699 } 700 (void) _nfssys(NFS_IDMAP, &args); 701 } 702 703 /* 704 * Get the current NFS domain. 705 * 706 * If NFSMAPID_DOMAIN is set in /etc/default/nfs, then it is the NFS domain; 707 * otherwise, the DNS domain is used. 708 */ 709 void 710 check_domain(int sighup) 711 { 712 const char *whoami = "check_domain"; 713 static int setup_done = 0; 714 static cb_t cb; 715 716 /* 717 * Construct the arguments to be passed to libmapid interface 718 * If called in response to a SIGHUP, reset any cached DNS TXT 719 * RR state. 720 */ 721 cb.fcn = cb_update_domain; 722 cb.signal = sighup; 723 mapid_reeval_domain(&cb); 724 725 /* 726 * Restart the signal handler thread if we're still setting up 727 */ 728 if (!setup_done) { 729 setup_done = 1; 730 if (thr_continue(sig_thread)) { 731 syslog(LOG_ERR, gettext("%s: Fatal error: signal " 732 "handler thread could not be restarted."), whoami); 733 exit(6); 734 } 735 } 736 } 737 738 /* 739 * Need to be able to open the DIAG_FILE before nfsmapid(1m) 740 * releases it's root priviledges. The DIAG_FILE then remains 741 * open for the duration of this nfsmapid instance via n4_fd. 742 */ 743 void 744 open_diag_file() 745 { 746 static int msg_done = 0; 747 748 if ((n4_fp = fopen(DIAG_FILE, "w+")) != NULL) { 749 n4_fd = fileno(n4_fp); 750 return; 751 } 752 753 if (msg_done) 754 return; 755 756 syslog(LOG_ERR, "Failed to create %s. Enable syslog " 757 "daemon.debug for more info", DIAG_FILE); 758 msg_done = 1; 759 } 760 761 /* 762 * When a new domain name is configured, save to DIAG_FILE 763 * and log to syslog, with LOG_DEBUG level (if configured). 764 */ 765 void 766 update_diag_file(char *new) 767 { 768 char buf[DNAMEMAX]; 769 ssize_t n; 770 size_t len; 771 772 (void) lseek(n4_fd, (off_t)0, SEEK_SET); 773 (void) ftruncate(n4_fd, 0); 774 (void) snprintf(buf, DNAMEMAX, "%s\n", new); 775 776 len = strlen(buf); 777 n = write(n4_fd, buf, len); 778 if (n < 0 || n < len) 779 syslog(LOG_DEBUG, "Could not write %s to diag file", new); 780 (void) fsync(n4_fd); 781 782 syslog(LOG_DEBUG, "nfsmapid domain = %s", new); 783 } 784 785 /* 786 * Callback function for libmapid. This will be called 787 * by the lib, everytime the nfsmapid(1m) domain changes. 788 */ 789 void * 790 cb_update_domain(void *arg) 791 { 792 char *new_dname = (char *)arg; 793 794 DTRACE_PROBE1(nfsmapid, daemon__domain, new_dname); 795 update_diag_file(new_dname); 796 idmap_kcall(FLUSH_KCACHES_ONLY); 797 798 return (NULL); 799 } 800