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