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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Door server routines for nfsmapid daemon 31 * Translate NFSv4 users and groups between numeric and string values 32 */ 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <alloca.h> 36 #include <signal.h> 37 #include <libintl.h> 38 #include <limits.h> 39 #include <errno.h> 40 #include <sys/types.h> 41 #include <string.h> 42 #include <memory.h> 43 #include <pwd.h> 44 #include <grp.h> 45 #include <door.h> 46 #include <syslog.h> 47 #include <fcntl.h> 48 #include <unistd.h> 49 #include <assert.h> 50 #include <deflt.h> 51 #include <nfs/nfs4.h> 52 #include <nfs/nfssys.h> 53 #include <nfs/nfsid_map.h> 54 #include "nfsmapid_resolv.h" 55 56 /* 57 * We cannot use the backend nscd as it may make syscalls that may 58 * cause further nfsmapid upcalls introducing deadlock. 59 * Use the internal uncached versions of get*_r. 60 */ 61 extern struct group *_uncached_getgrgid_r(gid_t, struct group *, char *, int); 62 extern struct group *_uncached_getgrnam_r(const char *, struct group *, 63 char *, int); 64 extern struct passwd *_uncached_getpwuid_r(uid_t, struct passwd *, char *, int); 65 extern struct passwd *_uncached_getpwnam_r(const char *, struct passwd *, 66 char *, int); 67 68 /* 69 * is timestamp a == b? 70 */ 71 #define TIMESTRUC_EQ(a, b) \ 72 (((a).tv_sec == (b).tv_sec) && ((a).tv_nsec == (b).tv_nsec)) 73 74 #define UID_MAX_STR_LEN 11 /* Digits in UID_MAX + 1 */ 75 76 /* 77 * domain*: describe nfsmapid domain currently in use 78 * nfs_* : describe nfsmapid domain specified by /etc/default/nfs 79 * dns_* : describe nfsmapid domain speficied by /etc/resolv.conf 80 * 81 * domain_cfg_lock: rwlock used to serialize access/changes to the 82 * vars listed above (between nfsmapid service threads). 83 * 84 * Each nfsmapid thread holds the rdlock and stats the config files. 85 * If the mtime is different, then they get the writelock and update 86 * the cached info. 87 * 88 * If the domain is set via /etc/default/nfs, then we don't have 89 * to look at resolv.conf. 90 */ 91 timestruc_t nfs_mtime = {0}; 92 uint32_t nfs_domain_len = 0; 93 char nfs_domain[NS_MAXCDNAME + 1] = {0}; 94 95 timestruc_t dns_mtime = {0}; 96 uint32_t dns_domain_len = 0; 97 char dns_domain[NS_MAXCDNAME + 1] = {0}; 98 99 uint32_t cur_domain_len = 0; 100 char cur_domain[NS_MAXCDNAME + 1] = {0}; 101 #define CUR_DOMAIN_NULL() cur_domain[0] == '\0' 102 103 timestruc_t zapped_mtime = {0}; 104 105 #define ZAP_DOMAIN(which) { \ 106 which##_domain[0] = '\0'; \ 107 which##_domain_len = 0; \ 108 which##_mtime = zapped_mtime; \ 109 } 110 111 rwlock_t domain_cfg_lock = DEFAULTRWLOCK; 112 113 /* 114 * Diags 115 */ 116 #define DIAG_FILE "/var/run/nfs4_domain" 117 FILE *n4_fp; 118 119 extern size_t pwd_buflen; 120 extern size_t grp_buflen; 121 extern thread_t sig_thread; 122 123 /* 124 * Prototypes 125 */ 126 extern void check_domain(int); 127 extern void idmap_kcall(int); 128 extern int standard_domain_str(const char *); 129 extern int _nfssys(int, void *); 130 static int valid_domain(const char *); 131 static int validate_id_str(const char *); 132 static int get_mtime(char *, timestruc_t *); 133 static void get_nfs_domain(void); 134 static void get_dns_domain(void); 135 static int extract_domain(char *, char **, char **); 136 extern void update_diag_file(char *); 137 138 static void 139 nfsmapid_str_uid(struct mapid_arg *argp, size_t arg_size) 140 { 141 struct mapid_res result; 142 struct passwd pwd; 143 char *pwd_buf; 144 char *user; 145 char *domain; 146 147 if (argp->u_arg.len <= 0 || arg_size < MAPID_ARG_LEN(argp->u_arg.len)) { 148 result.status = NFSMAPID_INVALID; 149 result.u_res.uid = UID_NOBODY; 150 goto done; 151 } 152 153 if (!extract_domain(argp->str, &user, &domain)) { 154 long id; 155 156 /* 157 * Invalid "user@dns_domain" string. Still, the user 158 * part might be an encoded uid, so do a final check. 159 * Remember, domain part of string was not set since 160 * not a valid string. 161 */ 162 if (!validate_id_str(user)) { 163 result.status = NFSMAPID_UNMAPPABLE; 164 result.u_res.uid = UID_NOBODY; 165 goto done; 166 } 167 168 /* 169 * Since atoi() does not return proper errors for 170 * invalid translation, use strtol() instead. 171 */ 172 errno = 0; 173 id = strtol(user, (char **)NULL, 10); 174 175 if (errno || id < 0 || id > UID_MAX) { 176 result.status = NFSMAPID_UNMAPPABLE; 177 result.u_res.uid = UID_NOBODY; 178 goto done; 179 } 180 181 result.u_res.uid = (uid_t)id; 182 result.status = NFSMAPID_NUMSTR; 183 goto done; 184 } 185 186 /* 187 * String properly constructed. Now we check for domain and 188 * group validity. Note that we only look at the domain iff 189 * the local domain is configured. 190 */ 191 if (!CUR_DOMAIN_NULL() && !valid_domain(domain)) { 192 result.status = NFSMAPID_BADDOMAIN; 193 result.u_res.uid = UID_NOBODY; 194 goto done; 195 } 196 197 if ((pwd_buf = malloc(pwd_buflen)) == NULL || 198 _uncached_getpwnam_r(user, &pwd, pwd_buf, pwd_buflen) == NULL) { 199 200 if (pwd_buf == NULL) 201 result.status = NFSMAPID_INTERNAL; 202 else { 203 /* 204 * Not a valid user 205 */ 206 result.status = NFSMAPID_NOTFOUND; 207 free(pwd_buf); 208 } 209 result.u_res.uid = UID_NOBODY; 210 goto done; 211 } 212 213 /* 214 * Valid user entry 215 */ 216 result.u_res.uid = pwd.pw_uid; 217 result.status = NFSMAPID_OK; 218 free(pwd_buf); 219 done: 220 (void) door_return((char *)&result, sizeof (struct mapid_res), NULL, 0); 221 } 222 223 /* ARGSUSED1 */ 224 static void 225 nfsmapid_uid_str(struct mapid_arg *argp, size_t arg_size) 226 { 227 struct mapid_res result; 228 struct mapid_res *resp; 229 struct passwd pwd; 230 int pwd_len; 231 char *pwd_buf; 232 uid_t uid = argp->u_arg.uid; 233 size_t uid_str_len; 234 char *pw_str; 235 size_t pw_str_len; 236 char *at_str; 237 size_t at_str_len; 238 char dom_str[NS_MAXCDNAME + 1]; 239 size_t dom_str_len; 240 241 if (uid < 0 || uid > UID_MAX) { 242 /* 243 * Negative uid or greater than UID_MAX 244 */ 245 resp = &result; 246 resp->status = NFSMAPID_BADID; 247 resp->u_res.len = 0; 248 goto done; 249 } 250 251 /* 252 * Make local copy of domain for further manipuation 253 */ 254 (void) rw_rdlock(&domain_cfg_lock); 255 if (CUR_DOMAIN_NULL()) { 256 dom_str_len = 0; 257 dom_str[0] = '\0'; 258 } else { 259 dom_str_len = cur_domain_len; 260 bcopy(cur_domain, dom_str, cur_domain_len); 261 dom_str[dom_str_len] = '\0'; 262 } 263 (void) rw_unlock(&domain_cfg_lock); 264 265 /* 266 * We want to encode the uid into a literal string... : 267 * 268 * - upon failure to allocate space from the heap 269 * - if there is no current domain configured 270 * - if there is no such uid in the passwd DB's 271 */ 272 if ((pwd_buf = malloc(pwd_buflen)) == NULL || dom_str_len == 0 || 273 _uncached_getpwuid_r(uid, &pwd, pwd_buf, pwd_buflen) == NULL) { 274 275 /* 276 * If we could not allocate from the heap, try 277 * allocating from the stack as a last resort. 278 */ 279 if (pwd_buf == NULL && (pwd_buf = 280 alloca(MAPID_RES_LEN(UID_MAX_STR_LEN))) == NULL) { 281 resp = &result; 282 resp->status = NFSMAPID_INTERNAL; 283 resp->u_res.len = 0; 284 goto done; 285 } 286 287 /* 288 * Constructing literal string without '@' so that 289 * we'll know that it's not a user, but rather a 290 * uid encoded string. Can't overflow because we 291 * already checked UID_MAX. 292 */ 293 pw_str = pwd_buf; 294 (void) sprintf(pw_str, "%d", (int)uid); 295 pw_str_len = strlen(pw_str); 296 at_str_len = dom_str_len = 0; 297 at_str = ""; 298 dom_str[0] = '\0'; 299 } else { 300 /* 301 * Otherwise, we construct the "user@domain" string 302 */ 303 pw_str = pwd.pw_name; 304 pw_str_len = strlen(pw_str); 305 at_str = "@"; 306 at_str_len = 1; 307 } 308 309 uid_str_len = pw_str_len + at_str_len + dom_str_len; 310 if ((resp = alloca(MAPID_RES_LEN(UID_MAX_STR_LEN))) == NULL) { 311 resp = &result; 312 resp->status = NFSMAPID_INTERNAL; 313 resp->u_res.len = 0; 314 goto done; 315 } 316 /* LINTED format argument to sprintf */ 317 (void) sprintf(resp->str, "%s%s%s", pw_str, at_str, dom_str); 318 resp->u_res.len = uid_str_len; 319 free(pwd_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 static void 337 nfsmapid_str_gid(struct mapid_arg *argp, size_t arg_size) 338 { 339 struct mapid_res result; 340 struct group grp; 341 char *grp_buf; 342 char *group; 343 char *domain; 344 345 if (argp->u_arg.len <= 0 || 346 arg_size < MAPID_ARG_LEN(argp->u_arg.len)) { 347 result.status = NFSMAPID_INVALID; 348 result.u_res.gid = GID_NOBODY; 349 goto done; 350 } 351 352 if (!extract_domain(argp->str, &group, &domain)) { 353 long id; 354 355 /* 356 * Invalid "group@dns_domain" string. Still, the 357 * group part might be an encoded gid, so do a 358 * final check. Remember, domain part of string 359 * was not set since not a valid string. 360 */ 361 if (!validate_id_str(group)) { 362 result.status = NFSMAPID_UNMAPPABLE; 363 result.u_res.gid = GID_NOBODY; 364 goto done; 365 } 366 367 /* 368 * Since atoi() does not return proper errors for 369 * invalid translation, use strtol() instead. 370 */ 371 errno = 0; 372 id = strtol(group, (char **)NULL, 10); 373 374 if (errno || id < 0 || id > UID_MAX) { 375 result.status = NFSMAPID_UNMAPPABLE; 376 result.u_res.gid = GID_NOBODY; 377 goto done; 378 } 379 380 result.u_res.gid = (gid_t)id; 381 result.status = NFSMAPID_NUMSTR; 382 goto done; 383 } 384 385 /* 386 * String properly constructed. Now we check for domain and 387 * group validity. Note that we only look at the domain iff 388 * the local domain is configured. 389 */ 390 if (!CUR_DOMAIN_NULL() && !valid_domain(domain)) { 391 result.status = NFSMAPID_BADDOMAIN; 392 result.u_res.gid = GID_NOBODY; 393 goto done; 394 } 395 396 if ((grp_buf = malloc(grp_buflen)) == NULL || 397 _uncached_getgrnam_r(group, &grp, grp_buf, grp_buflen) == NULL) { 398 399 if (grp_buf == NULL) 400 result.status = NFSMAPID_INTERNAL; 401 else { 402 /* 403 * Not a valid group 404 */ 405 result.status = NFSMAPID_NOTFOUND; 406 free(grp_buf); 407 } 408 result.u_res.gid = GID_NOBODY; 409 goto done; 410 } 411 412 /* 413 * Valid group entry 414 */ 415 result.status = NFSMAPID_OK; 416 result.u_res.gid = grp.gr_gid; 417 free(grp_buf); 418 done: 419 (void) door_return((char *)&result, sizeof (struct mapid_res), NULL, 0); 420 } 421 422 /* ARGSUSED1 */ 423 static void 424 nfsmapid_gid_str(struct mapid_arg *argp, size_t arg_size) 425 { 426 struct mapid_res result; 427 struct mapid_res *resp; 428 struct group grp; 429 char *grp_buf; 430 gid_t gid = argp->u_arg.gid; 431 size_t gid_str_len; 432 char *gr_str; 433 size_t gr_str_len; 434 char *at_str; 435 size_t at_str_len; 436 char dom_str[NS_MAXCDNAME + 1]; 437 size_t dom_str_len; 438 439 if (gid < 0 || gid > UID_MAX) { 440 /* 441 * Negative gid or greater than UID_MAX 442 */ 443 resp = &result; 444 resp->status = NFSMAPID_BADID; 445 resp->u_res.len = 0; 446 goto done; 447 } 448 449 /* 450 * Make local copy of domain for further manipuation 451 */ 452 (void) rw_rdlock(&domain_cfg_lock); 453 if (CUR_DOMAIN_NULL()) { 454 dom_str_len = 0; 455 dom_str[0] = '\0'; 456 } else { 457 dom_str_len = cur_domain_len; 458 bcopy(cur_domain, dom_str, cur_domain_len); 459 dom_str[dom_str_len] = '\0'; 460 } 461 (void) rw_unlock(&domain_cfg_lock); 462 463 /* 464 * We want to encode the gid into a literal string... : 465 * 466 * - upon failure to allocate space from the heap 467 * - if there is no current domain configured 468 * - if there is no such gid in the group DB's 469 */ 470 if ((grp_buf = malloc(grp_buflen)) == NULL || dom_str_len == 0 || 471 _uncached_getgrgid_r(gid, &grp, grp_buf, grp_buflen) == NULL) { 472 473 /* 474 * If we could not allocate from the heap, try 475 * allocating from the stack as a last resort. 476 */ 477 if (grp_buf == NULL && (grp_buf = 478 alloca(MAPID_RES_LEN(UID_MAX_STR_LEN))) == NULL) { 479 resp = &result; 480 resp->status = NFSMAPID_INTERNAL; 481 resp->u_res.len = 0; 482 goto done; 483 } 484 485 /* 486 * Constructing literal string without '@' so that 487 * we'll know that it's not a group, but rather a 488 * gid encoded string. Can't overflow because we 489 * already checked UID_MAX. 490 */ 491 gr_str = grp_buf; 492 (void) sprintf(gr_str, "%d", (int)gid); 493 gr_str_len = strlen(gr_str); 494 at_str_len = dom_str_len = 0; 495 at_str = ""; 496 dom_str[0] = '\0'; 497 } else { 498 /* 499 * Otherwise, we construct the "group@domain" string 500 */ 501 gr_str = grp.gr_name; 502 gr_str_len = strlen(gr_str); 503 at_str = "@"; 504 at_str_len = 1; 505 } 506 507 gid_str_len = gr_str_len + at_str_len + dom_str_len; 508 if ((resp = alloca(MAPID_RES_LEN(UID_MAX_STR_LEN))) == NULL) { 509 resp = &result; 510 resp->status = NFSMAPID_INTERNAL; 511 resp->u_res.len = 0; 512 goto done; 513 } 514 /* LINTED format argument to sprintf */ 515 (void) sprintf(resp->str, "%s%s%s", gr_str, at_str, dom_str); 516 resp->u_res.len = gid_str_len; 517 free(grp_buf); 518 resp->status = NFSMAPID_OK; 519 520 done: 521 /* 522 * There is a chance that the door_return will fail because the 523 * resulting string is too large, try to indicate that if possible 524 */ 525 if (door_return((char *)resp, 526 MAPID_RES_LEN(resp->u_res.len), NULL, 0) == -1) { 527 resp->status = NFSMAPID_INTERNAL; 528 resp->u_res.len = 0; 529 (void) door_return((char *)&result, sizeof (struct mapid_res), 530 NULL, 0); 531 } 532 } 533 534 /* ARGSUSED */ 535 void 536 nfsmapid_func(void *cookie, char *argp, size_t arg_size, 537 door_desc_t *dp, uint_t n_desc) 538 { 539 struct mapid_arg *mapargp; 540 struct mapid_res mapres; 541 542 /* 543 * Make sure we have a valid argument 544 */ 545 if (arg_size < sizeof (struct mapid_arg)) { 546 mapres.status = NFSMAPID_INVALID; 547 mapres.u_res.len = 0; 548 (void) door_return((char *)&mapres, sizeof (struct mapid_res), 549 NULL, 0); 550 return; 551 } 552 553 /* LINTED pointer cast */ 554 mapargp = (struct mapid_arg *)argp; 555 switch (mapargp->cmd) { 556 case NFSMAPID_STR_UID: 557 nfsmapid_str_uid(mapargp, arg_size); 558 return; 559 case NFSMAPID_UID_STR: 560 nfsmapid_uid_str(mapargp, arg_size); 561 return; 562 case NFSMAPID_STR_GID: 563 nfsmapid_str_gid(mapargp, arg_size); 564 return; 565 case NFSMAPID_GID_STR: 566 nfsmapid_gid_str(mapargp, arg_size); 567 return; 568 default: 569 break; 570 } 571 mapres.status = NFSMAPID_INVALID; 572 mapres.u_res.len = 0; 573 (void) door_return((char *)&mapres, sizeof (struct mapid_res), NULL, 0); 574 } 575 576 static int 577 extract_domain(char *cp, char **upp, char **dpp) 578 { 579 /* 580 * Caller must insure that the string is valid 581 */ 582 *upp = cp; 583 584 if ((*dpp = strchr(cp, '@')) == NULL) 585 return (0); 586 *(*dpp)++ = '\0'; 587 return (1); 588 } 589 590 static int 591 valid_domain(const char *dom) 592 { 593 const char *whoami = "valid_domain"; 594 595 if (!standard_domain_str(dom)) { 596 syslog(LOG_ERR, gettext("%s: Invalid domain name %s. Check " 597 "configuration file and restart daemon."), whoami, dom); 598 return (0); 599 } 600 601 (void) rw_rdlock(&domain_cfg_lock); 602 if (strcasecmp(dom, cur_domain) == 0) { 603 (void) rw_unlock(&domain_cfg_lock); 604 return (1); 605 } 606 (void) rw_unlock(&domain_cfg_lock); 607 return (0); 608 } 609 610 static int 611 validate_id_str(const char *id) 612 { 613 while (*id) { 614 if (!isdigit(*id++)) 615 return (0); 616 } 617 return (1); 618 } 619 620 static int 621 get_mtime(char *fname, timestruc_t *mtim) 622 { 623 struct stat st; 624 int err; 625 626 if ((err = stat(fname, &st)) != 0) 627 return (err); 628 629 *mtim = st.st_mtim; 630 return (0); 631 } 632 633 static void 634 get_nfs_domain(void) 635 { 636 const char *whoami = "get_nfs_domain"; 637 char *ndomain; 638 timestruc_t ntime; 639 640 /* 641 * If we can't get stats for the config file, then 642 * zap the NFS domain info. If mtime hasn't changed, 643 * then there's no work to do, so just return. 644 */ 645 if (get_mtime(NFSADMIN, &ntime) != 0) { 646 ZAP_DOMAIN(nfs); 647 return; 648 } 649 650 if (TIMESTRUC_EQ(ntime, nfs_mtime)) 651 return; 652 653 /* 654 * Get NFSMAPID_DOMAIN value from /etc/default/nfs for now. 655 * Note: defread() returns a ptr to TSD. 656 */ 657 if (defopen(NFSADMIN) == 0) { 658 ndomain = (char *)defread("NFSMAPID_DOMAIN="); 659 660 /* close default file */ 661 (void) defopen(NULL); 662 663 /* 664 * NFSMAPID_DOMAIN was set so its time for validation. 665 * If its okay, then update NFS domain and return. If not, 666 * complain about invalid domain. 667 */ 668 if (ndomain) { 669 if (standard_domain_str(ndomain)) { 670 nfs_domain_len = strlen(ndomain); 671 (void) strncpy(nfs_domain, ndomain, 672 NS_MAXCDNAME); 673 nfs_mtime = ntime; 674 return; 675 } 676 677 syslog(LOG_ERR, gettext("%s: Invalid domain name %s. " 678 "Check configuration file and restart daemon."), 679 whoami, ndomain); 680 } 681 } 682 683 /* 684 * So the NFS config file changed but it couldn't be opened or 685 * it didn't specify NFSMAPID_DOMAIN or it specified an invalid 686 * NFSMAPID_DOMAIN. Time to zap current NFS domain info. 687 */ 688 ZAP_DOMAIN(nfs); 689 } 690 691 static void 692 get_dns_domain(void) 693 { 694 #ifdef DEBUG 695 const char *whoami = "get_dns_domain"; 696 #endif 697 timestruc_t ntime = {0}; 698 699 /* 700 * If we can't get stats for the config file, then 701 * zap the DNS domain info. If mtime hasn't changed, 702 * then there's no work to do, so just return. 703 */ 704 errno = 0; 705 if (get_mtime(_PATH_RESCONF, &ntime) != 0) { 706 switch (errno) { 707 case ENOENT: 708 /* 709 * The resolver defaults to obtaining the 710 * domain off of the NIS domainname(1M) if 711 * /etc/resolv.conf does not exist, so we 712 * move forward. 713 */ 714 IDMAP_DBG("%s: no %s file", whoami, 715 _PATH_RESCONF); 716 break; 717 718 default: 719 ZAP_DOMAIN(dns); 720 return; 721 } 722 } else if (TIMESTRUC_EQ(ntime, dns_mtime)) { 723 IDMAP_DBG("%s: no mtime changes in %s", whoami, _PATH_RESCONF); 724 return; 725 } 726 727 /* 728 * Re-initialize resolver to zap DNS domain from previous 729 * resolv_init() calls. 730 */ 731 (void) resolv_init(); 732 733 /* 734 * Update cached DNS domain. No need for validation since 735 * domain comes from resolver. If resolver doesn't return the 736 * domain, then zap the DNS domain. This shouldn't ever happen, 737 * and if it does, the machine has bigger problems (so no need 738 * to generating a message that says DNS appears to be broken). 739 */ 740 (void) rw_rdlock(&dns_data_lock); 741 if (sysdns_domain[0] != '\0') { 742 (void) strncpy(dns_domain, sysdns_domain, NS_MAXCDNAME); 743 dns_mtime = ntime; 744 dns_domain_len = strlen(sysdns_domain); 745 (void) rw_unlock(&dns_data_lock); 746 return; 747 } 748 (void) rw_unlock(&dns_data_lock); 749 750 ZAP_DOMAIN(dns); 751 } 752 753 void 754 idmap_kcall(int did) 755 { 756 struct nfsidmap_args args; 757 758 if (did >= 0) { 759 args.state = 1; 760 args.did = did; 761 } else { 762 args.state = 0; 763 args.did = 0; 764 } 765 766 (void) _nfssys(NFS_IDMAP, &args); 767 } 768 769 /* 770 * Get the current NFS domain. 771 * 772 * If NFSMAPID_DOMAIN is set in /etc/default/nfs, then it is the NFS domain; 773 * otherwise, the DNS domain is used. 774 */ 775 void 776 check_domain(int flush) 777 { 778 const char *whoami = "check_domain"; 779 char *new_domain; 780 int new_dlen = 0; 781 static int setup_done = 0; 782 783 get_nfs_domain(); 784 if (nfs_domain_len != 0) { 785 new_domain = nfs_domain; 786 new_dlen = nfs_domain_len; 787 IDMAP_DBG("%s: NFS File Domain: %s", whoami, nfs_domain); 788 goto dname_chkd; 789 } 790 791 /* 792 * If called in response to a SIGHUP, 793 * reset any cached DNS TXT RR state. 794 */ 795 get_dns_txt_domain(flush); 796 if (dns_txt_domain_len != 0) { 797 new_domain = dns_txt_domain; 798 new_dlen = dns_txt_domain_len; 799 IDMAP_DBG("%s: DNS TXT Record: %s", whoami, dns_txt_domain); 800 } else { 801 /* 802 * We're either here because: 803 * 804 * . NFSMAPID_DOMAIN was not set in /etc/default/nfs 805 * . No suitable DNS TXT resource record exists 806 * . DNS server is not responding to requests 807 * 808 * in either case, we want to default to using the 809 * system configured DNS domain. If this fails, then 810 * dns_domain will be empty and dns_domain_len will 811 * be 0. 812 */ 813 get_dns_domain(); 814 new_domain = dns_domain; 815 new_dlen = dns_domain_len; 816 IDMAP_DBG("%s: Default DNS Domain: %s", whoami, dns_domain); 817 } 818 819 dname_chkd: 820 /* 821 * Update cur_domain if new_domain is different. Set flush 822 * to guarantee that kernel idmapping caches are flushed. 823 */ 824 if (strncasecmp(new_domain, cur_domain, NS_MAXCDNAME)) { 825 (void) rw_wrlock(&domain_cfg_lock); 826 (void) strncpy(cur_domain, new_domain, NS_MAXCDNAME); 827 cur_domain_len = new_dlen; 828 update_diag_file(new_domain); 829 DTRACE_PROBE1(nfsmapid, daemon__domain, cur_domain); 830 (void) rw_unlock(&domain_cfg_lock); 831 flush = 1; 832 } 833 834 /* 835 * Restart the signal handler thread if we're still setting up 836 */ 837 if (!setup_done) { 838 setup_done = 1; 839 IDMAP_DBG("%s: Initial setup done !", whoami, NULL); 840 if (thr_continue(sig_thread)) { 841 syslog(LOG_ERR, gettext("%s: Fatal error: signal " 842 "handler thread could not be restarted."), whoami); 843 exit(6); 844 } 845 846 /* 847 * We force bail here so we don't end up flushing kernel 848 * caches until we _know_ we're up. 849 */ 850 return; 851 } 852 853 /* 854 * If caller requested flush or if domain has changed, then 855 * flush kernel idmapping caches. 856 */ 857 if (flush) 858 idmap_kcall(-1); 859 } 860 861 862 /* 863 * Based on the recommendations from 864 * RFC1033 DOMAIN ADMINISTRATORS OPERATIONS GUIDE 865 * RFC1035 DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION 866 * check if a given domain name string is valid. 867 */ 868 int 869 standard_domain_str(const char *ds) 870 { 871 int i; 872 873 for (i = 0; *ds && i < NS_MAXCDNAME; i++, ds++) { 874 if (!isalpha(*ds) && !isdigit(*ds) && (*ds != '.') && 875 (*ds != '-') && (*ds != '_')) 876 return (0); 877 } 878 if (i == NS_MAXCDNAME) 879 return (0); 880 return (1); 881 } 882 883 /* 884 * Need to be able to open the DIAG_FILE before nfsmapid(1m) 885 * releases it's root priviledges. The DIAG_FILE then remains 886 * open for the duration of this nfsmapid instance via n4_fp. 887 */ 888 void 889 open_diag_file() 890 { 891 static int msg_done = 0; 892 893 if ((n4_fp = fopen(DIAG_FILE, "w+")) != NULL) 894 return; 895 896 if (msg_done) 897 return; 898 899 syslog(LOG_ERR, "Failed to create %s. Enable syslog " 900 "daemon.debug for more info", DIAG_FILE); 901 msg_done = 1; 902 } 903 904 /* 905 * When a new domain name is configured, save to DIAG_FILE 906 * and log to syslog, with LOG_DEBUG level (if configured). 907 */ 908 void 909 update_diag_file(char *new) 910 { 911 rewind(n4_fp); 912 ftruncate(fileno(n4_fp), 0); 913 fprintf(n4_fp, "%.*s\n", NS_MAXCDNAME, new); 914 fflush(n4_fp); 915 916 syslog(LOG_DEBUG, "nfsmapid domain = %s", new); 917 } 918