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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 26 /* 27 * Door server routines for nfsmapid daemon 28 * Translate NFSv4 users and groups between numeric and string values 29 */ 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <alloca.h> 33 #include <signal.h> 34 #include <libintl.h> 35 #include <limits.h> 36 #include <errno.h> 37 #include <sys/types.h> 38 #include <string.h> 39 #include <memory.h> 40 #include <pwd.h> 41 #include <grp.h> 42 #include <door.h> 43 #include <syslog.h> 44 #include <fcntl.h> 45 #include <unistd.h> 46 #include <assert.h> 47 #include <deflt.h> 48 #include <nfs/nfs4.h> 49 #include <nfs/nfssys.h> 50 #include <nfs/nfsid_map.h> 51 #include <nfs/mapid.h> 52 #include <sys/sdt.h> 53 #include <sys/idmap.h> 54 #include <idmap.h> 55 #include <sys/fs/autofs.h> 56 #include <sys/mkdev.h> 57 #include "nfs_resolve.h" 58 59 #define UID_MAX_STR_LEN 11 /* Digits in UID_MAX + 1 */ 60 #define DIAG_FILE "/var/run/nfs4_domain" 61 62 /* 63 * idmap_kcall() takes a door descriptor as it's argument when we 64 * need to (re)establish the in-kernel door handles. When we only 65 * want to flush the id kernel caches, we don't redo the door setup. 66 */ 67 #define FLUSH_KCACHES_ONLY (int)-1 68 69 FILE *n4_fp; 70 int n4_fd; 71 72 extern size_t pwd_buflen; 73 extern size_t grp_buflen; 74 extern thread_t sig_thread; 75 76 /* 77 * Prototypes 78 */ 79 extern void check_domain(int); 80 extern void idmap_kcall(int); 81 extern int _nfssys(int, void *); 82 extern int valid_domain(const char *); 83 extern int validate_id_str(const char *); 84 extern int extract_domain(char *, char **, char **); 85 extern void update_diag_file(char *); 86 extern void *cb_update_domain(void *); 87 extern int cur_domain_null(void); 88 89 void 90 nfsmapid_str_uid(struct mapid_arg *argp, size_t arg_size) 91 { 92 struct mapid_res result; 93 struct passwd pwd; 94 struct passwd *pwd_ptr; 95 int pwd_rc; 96 char *pwd_buf; 97 char *user; 98 char *domain; 99 idmap_stat rc; 100 101 if (argp->u_arg.len <= 0 || arg_size < MAPID_ARG_LEN(argp->u_arg.len)) { 102 result.status = NFSMAPID_INVALID; 103 result.u_res.uid = UID_NOBODY; 104 goto done; 105 } 106 107 if (!extract_domain(argp->str, &user, &domain)) { 108 unsigned long id; 109 110 /* 111 * Invalid "user@domain" string. Still, the user 112 * part might be an encoded uid, so do a final check. 113 * Remember, domain part of string was not set since 114 * not a valid string. 115 */ 116 if (!validate_id_str(user)) { 117 result.status = NFSMAPID_UNMAPPABLE; 118 result.u_res.uid = UID_NOBODY; 119 goto done; 120 } 121 122 errno = 0; 123 id = strtoul(user, (char **)NULL, 10); 124 125 /* 126 * We don't accept ephemeral ids from the wire. 127 */ 128 if (errno || id > UID_MAX) { 129 result.status = NFSMAPID_UNMAPPABLE; 130 result.u_res.uid = UID_NOBODY; 131 goto done; 132 } 133 134 result.u_res.uid = (uid_t)id; 135 result.status = NFSMAPID_NUMSTR; 136 goto done; 137 } 138 139 /* 140 * String properly constructed. Now we check for domain and 141 * group validity. 142 */ 143 if (!cur_domain_null() && !valid_domain(domain)) { 144 /* 145 * If the domain part of the string does not 146 * match the NFS domain, try to map it using 147 * idmap service. 148 */ 149 rc = idmap_getuidbywinname(user, domain, 0, &result.u_res.uid); 150 if (rc != IDMAP_SUCCESS) { 151 result.status = NFSMAPID_BADDOMAIN; 152 result.u_res.uid = UID_NOBODY; 153 goto done; 154 } 155 result.status = NFSMAPID_OK; 156 goto done; 157 } 158 159 if ((pwd_buf = malloc(pwd_buflen)) == NULL || 160 (pwd_rc = getpwnam_r(user, &pwd, pwd_buf, pwd_buflen, &pwd_ptr)) 161 != 0 || pwd_ptr == NULL) { 162 163 if (pwd_buf == NULL || pwd_rc != 0) 164 result.status = NFSMAPID_INTERNAL; 165 else { 166 /* 167 * Not a valid user 168 */ 169 result.status = NFSMAPID_NOTFOUND; 170 free(pwd_buf); 171 } 172 result.u_res.uid = UID_NOBODY; 173 goto done; 174 } 175 176 /* 177 * Valid user entry 178 */ 179 result.u_res.uid = pwd.pw_uid; 180 result.status = NFSMAPID_OK; 181 free(pwd_buf); 182 done: 183 (void) door_return((char *)&result, sizeof (struct mapid_res), NULL, 0); 184 } 185 186 /* ARGSUSED1 */ 187 void 188 nfsmapid_uid_str(struct mapid_arg *argp, size_t arg_size) 189 { 190 struct mapid_res result; 191 struct mapid_res *resp; 192 struct passwd pwd; 193 struct passwd *pwd_ptr; 194 char *pwd_buf = NULL; 195 char *idmap_buf = NULL; 196 uid_t uid = argp->u_arg.uid; 197 size_t uid_str_len; 198 char *pw_str; 199 size_t pw_str_len; 200 char *at_str; 201 size_t at_str_len; 202 char dom_str[DNAMEMAX]; 203 size_t dom_str_len; 204 idmap_stat rc; 205 206 if (uid == (uid_t)-1) { 207 /* 208 * Sentinel uid is not a valid id 209 */ 210 resp = &result; 211 resp->status = NFSMAPID_BADID; 212 resp->u_res.len = 0; 213 goto done; 214 } 215 216 /* 217 * Make local copy of domain for further manipuation 218 * NOTE: mapid_get_domain() returns a ptr to TSD. 219 */ 220 if (cur_domain_null()) { 221 dom_str_len = 0; 222 dom_str[0] = '\0'; 223 } else { 224 dom_str_len = strlcpy(dom_str, mapid_get_domain(), DNAMEMAX); 225 } 226 227 /* 228 * If uid is ephemeral then resolve it using idmap service 229 */ 230 if (uid > UID_MAX) { 231 rc = idmap_getwinnamebyuid(uid, 0, &idmap_buf, NULL); 232 if (rc != IDMAP_SUCCESS) { 233 /* 234 * We don't put stringified ephemeral uids on 235 * the wire. 236 */ 237 resp = &result; 238 resp->status = NFSMAPID_UNMAPPABLE; 239 resp->u_res.len = 0; 240 goto done; 241 } 242 243 /* 244 * idmap_buf is already in the desired form i.e. name@domain 245 */ 246 pw_str = idmap_buf; 247 pw_str_len = strlen(pw_str); 248 at_str_len = dom_str_len = 0; 249 at_str = ""; 250 dom_str[0] = '\0'; 251 goto gen_result; 252 } 253 254 /* 255 * Handling non-ephemeral uids 256 * 257 * We want to encode the uid into a literal string... : 258 * 259 * - upon failure to allocate space from the heap 260 * - if there is no current domain configured 261 * - if there is no such uid in the passwd DB's 262 */ 263 if ((pwd_buf = malloc(pwd_buflen)) == NULL || dom_str_len == 0 || 264 getpwuid_r(uid, &pwd, pwd_buf, pwd_buflen, &pwd_ptr) != 0 || 265 pwd_ptr == NULL) { 266 267 /* 268 * If we could not allocate from the heap, try 269 * allocating from the stack as a last resort. 270 */ 271 if (pwd_buf == NULL && (pwd_buf = 272 alloca(MAPID_RES_LEN(UID_MAX_STR_LEN))) == NULL) { 273 resp = &result; 274 resp->status = NFSMAPID_INTERNAL; 275 resp->u_res.len = 0; 276 goto done; 277 } 278 279 /* 280 * Constructing literal string without '@' so that 281 * we'll know that it's not a user, but rather a 282 * uid encoded string. 283 */ 284 pw_str = pwd_buf; 285 (void) sprintf(pw_str, "%u", uid); 286 pw_str_len = strlen(pw_str); 287 at_str_len = dom_str_len = 0; 288 at_str = ""; 289 dom_str[0] = '\0'; 290 } else { 291 /* 292 * Otherwise, we construct the "user@domain" string if 293 * it's not already in that form. 294 */ 295 pw_str = pwd.pw_name; 296 pw_str_len = strlen(pw_str); 297 if (strchr(pw_str, '@') == NULL) { 298 at_str = "@"; 299 at_str_len = 1; 300 } else { 301 at_str_len = dom_str_len = 0; 302 at_str = ""; 303 dom_str[0] = '\0'; 304 } 305 } 306 307 gen_result: 308 uid_str_len = pw_str_len + at_str_len + dom_str_len; 309 if ((resp = alloca(MAPID_RES_LEN(uid_str_len))) == NULL) { 310 resp = &result; 311 resp->status = NFSMAPID_INTERNAL; 312 resp->u_res.len = 0; 313 goto done; 314 } 315 /* LINTED format argument to sprintf */ 316 (void) sprintf(resp->str, "%s%s%s", pw_str, at_str, dom_str); 317 resp->u_res.len = uid_str_len; 318 if (pwd_buf) 319 free(pwd_buf); 320 if (idmap_buf) 321 idmap_free(idmap_buf); 322 resp->status = NFSMAPID_OK; 323 324 done: 325 /* 326 * There is a chance that the door_return will fail because the 327 * resulting string is too large, try to indicate that if possible 328 */ 329 if (door_return((char *)resp, 330 MAPID_RES_LEN(resp->u_res.len), NULL, 0) == -1) { 331 resp->status = NFSMAPID_INTERNAL; 332 resp->u_res.len = 0; 333 (void) door_return((char *)&result, sizeof (struct mapid_res), 334 NULL, 0); 335 } 336 } 337 338 void 339 nfsmapid_str_gid(struct mapid_arg *argp, size_t arg_size) 340 { 341 struct mapid_res result; 342 struct group grp; 343 struct group *grp_ptr; 344 int grp_rc; 345 char *grp_buf; 346 char *group; 347 char *domain; 348 idmap_stat rc; 349 350 if (argp->u_arg.len <= 0 || 351 arg_size < MAPID_ARG_LEN(argp->u_arg.len)) { 352 result.status = NFSMAPID_INVALID; 353 result.u_res.gid = GID_NOBODY; 354 goto done; 355 } 356 357 if (!extract_domain(argp->str, &group, &domain)) { 358 unsigned long id; 359 360 /* 361 * Invalid "group@domain" string. Still, the 362 * group part might be an encoded gid, so do a 363 * final check. Remember, domain part of string 364 * was not set since not a valid string. 365 */ 366 if (!validate_id_str(group)) { 367 result.status = NFSMAPID_UNMAPPABLE; 368 result.u_res.gid = GID_NOBODY; 369 goto done; 370 } 371 372 errno = 0; 373 id = strtoul(group, (char **)NULL, 10); 374 375 /* 376 * We don't accept ephemeral ids from the wire. 377 */ 378 if (errno || id > UID_MAX) { 379 result.status = NFSMAPID_UNMAPPABLE; 380 result.u_res.gid = GID_NOBODY; 381 goto done; 382 } 383 384 result.u_res.gid = (gid_t)id; 385 result.status = NFSMAPID_NUMSTR; 386 goto done; 387 } 388 389 /* 390 * String properly constructed. Now we check for domain and 391 * group validity. 392 */ 393 if (!cur_domain_null() && !valid_domain(domain)) { 394 /* 395 * If the domain part of the string does not 396 * match the NFS domain, try to map it using 397 * idmap service. 398 */ 399 rc = idmap_getgidbywinname(group, domain, 0, &result.u_res.gid); 400 if (rc != IDMAP_SUCCESS) { 401 result.status = NFSMAPID_BADDOMAIN; 402 result.u_res.gid = GID_NOBODY; 403 goto done; 404 } 405 result.status = NFSMAPID_OK; 406 goto done; 407 } 408 409 if ((grp_buf = malloc(grp_buflen)) == NULL || 410 (grp_rc = getgrnam_r(group, &grp, grp_buf, grp_buflen, &grp_ptr)) 411 != 0 || grp_ptr == NULL) { 412 413 if (grp_buf == NULL || grp_rc != 0) 414 result.status = NFSMAPID_INTERNAL; 415 else { 416 /* 417 * Not a valid group 418 */ 419 result.status = NFSMAPID_NOTFOUND; 420 free(grp_buf); 421 } 422 result.u_res.gid = GID_NOBODY; 423 goto done; 424 } 425 426 /* 427 * Valid group entry 428 */ 429 result.status = NFSMAPID_OK; 430 result.u_res.gid = grp.gr_gid; 431 free(grp_buf); 432 done: 433 (void) door_return((char *)&result, sizeof (struct mapid_res), NULL, 0); 434 } 435 436 /* ARGSUSED1 */ 437 void 438 nfsmapid_gid_str(struct mapid_arg *argp, size_t arg_size) 439 { 440 struct mapid_res result; 441 struct mapid_res *resp; 442 struct group grp; 443 struct group *grp_ptr; 444 char *grp_buf = NULL; 445 char *idmap_buf = NULL; 446 idmap_stat rc; 447 gid_t gid = argp->u_arg.gid; 448 size_t gid_str_len; 449 char *gr_str; 450 size_t gr_str_len; 451 char *at_str; 452 size_t at_str_len; 453 char dom_str[DNAMEMAX]; 454 size_t dom_str_len; 455 456 if (gid == (gid_t)-1) { 457 /* 458 * Sentinel gid is not a valid id 459 */ 460 resp = &result; 461 resp->status = NFSMAPID_BADID; 462 resp->u_res.len = 0; 463 goto done; 464 } 465 466 /* 467 * Make local copy of domain for further manipuation 468 * NOTE: mapid_get_domain() returns a ptr to TSD. 469 */ 470 if (cur_domain_null()) { 471 dom_str_len = 0; 472 dom_str[0] = '\0'; 473 } else { 474 dom_str_len = strlen(mapid_get_domain()); 475 bcopy(mapid_get_domain(), dom_str, dom_str_len); 476 dom_str[dom_str_len] = '\0'; 477 } 478 479 /* 480 * If gid is ephemeral then resolve it using idmap service 481 */ 482 if (gid > UID_MAX) { 483 rc = idmap_getwinnamebygid(gid, 0, &idmap_buf, NULL); 484 if (rc != IDMAP_SUCCESS) { 485 /* 486 * We don't put stringified ephemeral gids on 487 * the wire. 488 */ 489 resp = &result; 490 resp->status = NFSMAPID_UNMAPPABLE; 491 resp->u_res.len = 0; 492 goto done; 493 } 494 495 /* 496 * idmap_buf is already in the desired form i.e. name@domain 497 */ 498 gr_str = idmap_buf; 499 gr_str_len = strlen(gr_str); 500 at_str_len = dom_str_len = 0; 501 at_str = ""; 502 dom_str[0] = '\0'; 503 goto gen_result; 504 } 505 506 /* 507 * Handling non-ephemeral gids 508 * 509 * We want to encode the gid into a literal string... : 510 * 511 * - upon failure to allocate space from the heap 512 * - if there is no current domain configured 513 * - if there is no such gid in the group DB's 514 */ 515 if ((grp_buf = malloc(grp_buflen)) == NULL || dom_str_len == 0 || 516 getgrgid_r(gid, &grp, grp_buf, grp_buflen, &grp_ptr) != 0 || 517 grp_ptr == NULL) { 518 519 /* 520 * If we could not allocate from the heap, try 521 * allocating from the stack as a last resort. 522 */ 523 if (grp_buf == NULL && (grp_buf = 524 alloca(MAPID_RES_LEN(UID_MAX_STR_LEN))) == NULL) { 525 resp = &result; 526 resp->status = NFSMAPID_INTERNAL; 527 resp->u_res.len = 0; 528 goto done; 529 } 530 531 /* 532 * Constructing literal string without '@' so that 533 * we'll know that it's not a group, but rather a 534 * gid encoded string. 535 */ 536 gr_str = grp_buf; 537 (void) sprintf(gr_str, "%u", gid); 538 gr_str_len = strlen(gr_str); 539 at_str_len = dom_str_len = 0; 540 at_str = ""; 541 dom_str[0] = '\0'; 542 } else { 543 /* 544 * Otherwise, we construct the "group@domain" string if 545 * it's not already in that form. 546 */ 547 gr_str = grp.gr_name; 548 gr_str_len = strlen(gr_str); 549 if (strchr(gr_str, '@') == NULL) { 550 at_str = "@"; 551 at_str_len = 1; 552 } else { 553 at_str_len = dom_str_len = 0; 554 at_str = ""; 555 dom_str[0] = '\0'; 556 } 557 } 558 559 gen_result: 560 gid_str_len = gr_str_len + at_str_len + dom_str_len; 561 if ((resp = alloca(MAPID_RES_LEN(gid_str_len))) == NULL) { 562 resp = &result; 563 resp->status = NFSMAPID_INTERNAL; 564 resp->u_res.len = 0; 565 goto done; 566 } 567 /* LINTED format argument to sprintf */ 568 (void) sprintf(resp->str, "%s%s%s", gr_str, at_str, dom_str); 569 resp->u_res.len = gid_str_len; 570 if (grp_buf) 571 free(grp_buf); 572 if (idmap_buf) 573 idmap_free(idmap_buf); 574 resp->status = NFSMAPID_OK; 575 576 done: 577 /* 578 * There is a chance that the door_return will fail because the 579 * resulting string is too large, try to indicate that if possible 580 */ 581 if (door_return((char *)resp, 582 MAPID_RES_LEN(resp->u_res.len), NULL, 0) == -1) { 583 resp->status = NFSMAPID_INTERNAL; 584 resp->u_res.len = 0; 585 (void) door_return((char *)&result, sizeof (struct mapid_res), 586 NULL, 0); 587 } 588 } 589 590 void 591 nfsmapid_server_netinfo(refd_door_args_t *referral_args, size_t arg_size) 592 { 593 char *res; 594 int res_size; 595 int error; 596 int srsz = 0; 597 char host[MAXHOSTNAMELEN]; 598 utf8string *nfsfsloc_args; 599 refd_door_res_t *door_res; 600 refd_door_res_t failed_res; 601 struct nfs_fsl_info *nfs_fsloc_res; 602 603 if (arg_size < sizeof (refd_door_args_t)) { 604 failed_res.res_status = EINVAL; 605 res = (char *)&failed_res; 606 res_size = sizeof (refd_door_res_t); 607 syslog(LOG_ERR, 608 "nfsmapid_server_netinfo failed: Invalid data\n"); 609 goto send_response; 610 } 611 612 if (decode_args(xdr_utf8string, (refd_door_args_t *)referral_args, 613 (caddr_t *)&nfsfsloc_args, sizeof (utf8string))) { 614 syslog(LOG_ERR, "cannot allocate memory"); 615 failed_res.res_status = ENOMEM; 616 failed_res.xdr_len = 0; 617 res = (caddr_t)&failed_res; 618 res_size = sizeof (refd_door_res_t); 619 goto send_response; 620 } 621 622 if (nfsfsloc_args->utf8string_len >= MAXHOSTNAMELEN) { 623 syslog(LOG_ERR, "argument too large"); 624 failed_res.res_status = EOVERFLOW; 625 failed_res.xdr_len = 0; 626 res = (caddr_t)&failed_res; 627 res_size = sizeof (refd_door_res_t); 628 goto send_response; 629 } 630 631 snprintf(host, nfsfsloc_args->utf8string_len + 1, 632 "%s", nfsfsloc_args->utf8string_val); 633 634 nfs_fsloc_res = 635 get_nfs4ref_info(host, NFS_PORT, NFS_V4); 636 637 xdr_free(xdr_utf8string, (char *)&nfsfsloc_args); 638 639 if (nfs_fsloc_res) { 640 error = 0; 641 error = encode_res(xdr_nfs_fsl_info, &door_res, 642 (caddr_t)nfs_fsloc_res, &res_size); 643 free_nfs4ref_info(nfs_fsloc_res); 644 if (error != 0) { 645 syslog(LOG_ERR, 646 "error allocating fs_locations " 647 "results buffer"); 648 failed_res.res_status = error; 649 failed_res.xdr_len = srsz; 650 res = (caddr_t)&failed_res; 651 res_size = sizeof (refd_door_res_t); 652 } else { 653 door_res->res_status = 0; 654 res = (caddr_t)door_res; 655 } 656 } else { 657 failed_res.res_status = EINVAL; 658 failed_res.xdr_len = 0; 659 res = (caddr_t)&failed_res; 660 res_size = sizeof (refd_door_res_t); 661 } 662 663 send_response: 664 srsz = res_size; 665 errno = 0; 666 667 error = door_return(res, res_size, NULL, 0); 668 if (errno == E2BIG) { 669 failed_res.res_status = EOVERFLOW; 670 failed_res.xdr_len = srsz; 671 res = (caddr_t)&failed_res; 672 res_size = sizeof (refd_door_res_t); 673 } else { 674 res = NULL; 675 res_size = 0; 676 } 677 678 door_return(res, res_size, NULL, 0); 679 } 680 681 /* ARGSUSED */ 682 void 683 nfsmapid_func(void *cookie, char *argp, size_t arg_size, 684 door_desc_t *dp, uint_t n_desc) 685 { 686 struct mapid_arg *mapargp; 687 struct mapid_res mapres; 688 refd_door_args_t *referral_args; 689 690 /* 691 * Make sure we have a valid argument 692 */ 693 if (arg_size < sizeof (struct mapid_arg)) { 694 mapres.status = NFSMAPID_INVALID; 695 mapres.u_res.len = 0; 696 (void) door_return((char *)&mapres, sizeof (struct mapid_res), 697 NULL, 0); 698 return; 699 } 700 701 /* LINTED pointer cast */ 702 mapargp = (struct mapid_arg *)argp; 703 referral_args = (refd_door_args_t *)argp; 704 switch (mapargp->cmd) { 705 case NFSMAPID_STR_UID: 706 nfsmapid_str_uid(mapargp, arg_size); 707 return; 708 case NFSMAPID_UID_STR: 709 nfsmapid_uid_str(mapargp, arg_size); 710 return; 711 case NFSMAPID_STR_GID: 712 nfsmapid_str_gid(mapargp, arg_size); 713 return; 714 case NFSMAPID_GID_STR: 715 nfsmapid_gid_str(mapargp, arg_size); 716 return; 717 case NFSMAPID_SRV_NETINFO: 718 nfsmapid_server_netinfo(referral_args, arg_size); 719 default: 720 break; 721 } 722 mapres.status = NFSMAPID_INVALID; 723 mapres.u_res.len = 0; 724 (void) door_return((char *)&mapres, sizeof (struct mapid_res), NULL, 0); 725 } 726 727 /* 728 * mapid_get_domain() always returns a ptr to TSD, so the 729 * check for a NULL domain is not a simple comparison with 730 * NULL but we need to check the contents of the TSD data. 731 */ 732 int 733 cur_domain_null(void) 734 { 735 char *p; 736 737 if ((p = mapid_get_domain()) == NULL) 738 return (1); 739 740 return (p[0] == '\0'); 741 } 742 743 int 744 extract_domain(char *cp, char **upp, char **dpp) 745 { 746 /* 747 * Caller must insure that the string is valid 748 */ 749 *upp = cp; 750 751 if ((*dpp = strchr(cp, '@')) == NULL) 752 return (0); 753 *(*dpp)++ = '\0'; 754 return (1); 755 } 756 757 int 758 valid_domain(const char *dom) 759 { 760 const char *whoami = "valid_domain"; 761 762 if (!mapid_stdchk_domain(dom)) { 763 syslog(LOG_ERR, gettext("%s: Invalid inbound domain name %s."), 764 whoami, dom); 765 return (0); 766 } 767 768 /* 769 * NOTE: mapid_get_domain() returns a ptr to TSD. 770 */ 771 return (strcasecmp(dom, mapid_get_domain()) == 0); 772 } 773 774 int 775 validate_id_str(const char *id) 776 { 777 while (*id) { 778 if (!isdigit(*id++)) 779 return (0); 780 } 781 return (1); 782 } 783 784 void 785 idmap_kcall(int door_id) 786 { 787 struct nfsidmap_args args; 788 789 if (door_id >= 0) { 790 args.state = 1; 791 args.did = door_id; 792 } else { 793 args.state = 0; 794 args.did = 0; 795 } 796 (void) _nfssys(NFS_IDMAP, &args); 797 } 798 799 /* 800 * Get the current NFS domain. 801 * 802 * If nfsmapid_domain is set in NFS SMF, then it is the NFS domain; 803 * otherwise, the DNS domain is used. 804 */ 805 void 806 check_domain(int sighup) 807 { 808 const char *whoami = "check_domain"; 809 static int setup_done = 0; 810 static cb_t cb; 811 812 /* 813 * Construct the arguments to be passed to libmapid interface 814 * If called in response to a SIGHUP, reset any cached DNS TXT 815 * RR state. 816 */ 817 cb.fcn = cb_update_domain; 818 cb.signal = sighup; 819 mapid_reeval_domain(&cb); 820 821 /* 822 * Restart the signal handler thread if we're still setting up 823 */ 824 if (!setup_done) { 825 setup_done = 1; 826 if (thr_continue(sig_thread)) { 827 syslog(LOG_ERR, gettext("%s: Fatal error: signal " 828 "handler thread could not be restarted."), whoami); 829 exit(6); 830 } 831 } 832 } 833 834 /* 835 * Need to be able to open the DIAG_FILE before nfsmapid(1m) 836 * releases it's root priviledges. The DIAG_FILE then remains 837 * open for the duration of this nfsmapid instance via n4_fd. 838 */ 839 void 840 open_diag_file() 841 { 842 static int msg_done = 0; 843 844 if ((n4_fp = fopen(DIAG_FILE, "w+")) != NULL) { 845 n4_fd = fileno(n4_fp); 846 return; 847 } 848 849 if (msg_done) 850 return; 851 852 syslog(LOG_ERR, "Failed to create %s. Enable syslog " 853 "daemon.debug for more info", DIAG_FILE); 854 msg_done = 1; 855 } 856 857 /* 858 * When a new domain name is configured, save to DIAG_FILE 859 * and log to syslog, with LOG_DEBUG level (if configured). 860 */ 861 void 862 update_diag_file(char *new) 863 { 864 char buf[DNAMEMAX]; 865 ssize_t n; 866 size_t len; 867 868 (void) lseek(n4_fd, (off_t)0, SEEK_SET); 869 (void) ftruncate(n4_fd, 0); 870 (void) snprintf(buf, DNAMEMAX, "%s\n", new); 871 872 len = strlen(buf); 873 n = write(n4_fd, buf, len); 874 if (n < 0 || n < len) 875 syslog(LOG_DEBUG, "Could not write %s to diag file", new); 876 (void) fsync(n4_fd); 877 878 syslog(LOG_DEBUG, "nfsmapid domain = %s", new); 879 } 880 881 /* 882 * Callback function for libmapid. This will be called 883 * by the lib, everytime the nfsmapid(1m) domain changes. 884 */ 885 void * 886 cb_update_domain(void *arg) 887 { 888 char *new_dname = (char *)arg; 889 890 DTRACE_PROBE1(nfsmapid, daemon__domain, new_dname); 891 update_diag_file(new_dname); 892 idmap_kcall(FLUSH_KCACHES_ONLY); 893 894 return (NULL); 895 } 896 897 bool_t 898 xdr_utf8string(XDR *xdrs, utf8string *objp) 899 { 900 if (xdrs->x_op != XDR_FREE) 901 return (xdr_bytes(xdrs, (char **)&objp->utf8string_val, 902 (uint_t *)&objp->utf8string_len, NFS4_MAX_UTF8STRING)); 903 return (TRUE); 904 } 905 906 907 int 908 decode_args(xdrproc_t xdrfunc, refd_door_args_t *argp, caddr_t *xdrargs, 909 int size) 910 { 911 XDR xdrs; 912 913 caddr_t tmpargs = (caddr_t)&((refd_door_args_t *)argp)->xdr_arg; 914 size_t arg_size = ((refd_door_args_t *)argp)->xdr_len; 915 916 xdrmem_create(&xdrs, tmpargs, arg_size, XDR_DECODE); 917 918 *xdrargs = calloc(1, size); 919 if (*xdrargs == NULL) { 920 syslog(LOG_ERR, "error allocating arguments buffer"); 921 return (ENOMEM); 922 } 923 924 if (!(*xdrfunc)(&xdrs, *xdrargs)) { 925 free(*xdrargs); 926 *xdrargs = NULL; 927 syslog(LOG_ERR, "error decoding arguments"); 928 return (EINVAL); 929 } 930 931 return (0); 932 } 933 934 int 935 encode_res( 936 xdrproc_t xdrfunc, 937 refd_door_res_t **results, 938 caddr_t resp, 939 int *size) 940 { 941 XDR xdrs; 942 943 *size = xdr_sizeof((*xdrfunc), resp); 944 *results = malloc(sizeof (refd_door_res_t) + *size); 945 if (*results == NULL) { 946 return (ENOMEM); 947 } 948 (*results)->xdr_len = *size; 949 *size = sizeof (refd_door_res_t) + (*results)->xdr_len; 950 xdrmem_create(&xdrs, (caddr_t)((*results)->xdr_res), 951 (*results)->xdr_len, XDR_ENCODE); 952 if (!(*xdrfunc)(&xdrs, resp)) { 953 (*results)->res_status = EINVAL; 954 syslog(LOG_ERR, "error encoding results"); 955 return ((*results)->res_status); 956 } 957 (*results)->res_status = 0; 958 return ((*results)->res_status); 959 } 960 961 962 bool_t 963 xdr_knetconfig(XDR *xdrs, struct knetconfig *objp) 964 { 965 rpc_inline_t *buf; 966 int i; 967 u_longlong_t dev64; 968 #if !defined(_LP64) 969 uint32_t major, minor; 970 #endif 971 972 if (!xdr_u_int(xdrs, &objp->knc_semantics)) 973 return (FALSE); 974 if (!xdr_opaque(xdrs, objp->knc_protofmly, KNC_STRSIZE)) 975 return (FALSE); 976 if (!xdr_opaque(xdrs, objp->knc_proto, KNC_STRSIZE)) 977 return (FALSE); 978 979 /* 980 * For interoperability between 32-bit daemon and 64-bit kernel, 981 * we always treat dev_t as 64-bit number and do the expanding 982 * or compression of dev_t as needed. 983 * We have to hand craft the conversion since there is no available 984 * function in ddi.c. Besides ddi.c is available only in the kernel 985 * and we want to keep both user and kernel of xdr_knetconfig() the 986 * same for consistency. 987 */ 988 989 if (xdrs->x_op == XDR_ENCODE) { 990 #if defined(_LP64) 991 dev64 = objp->knc_rdev; 992 #else 993 major = (objp->knc_rdev >> NBITSMINOR32) & MAXMAJ32; 994 minor = objp->knc_rdev & MAXMIN32; 995 dev64 = (((unsigned long long)major) << NBITSMINOR64) | minor; 996 #endif 997 if (!xdr_u_longlong_t(xdrs, &dev64)) 998 return (FALSE); 999 } 1000 if (xdrs->x_op == XDR_DECODE) { 1001 #if defined(_LP64) 1002 if (!xdr_u_longlong_t(xdrs, (u_longlong_t *)&objp->knc_rdev)) 1003 return (FALSE); 1004 #else 1005 if (!xdr_u_longlong_t(xdrs, &dev64)) 1006 return (FALSE); 1007 1008 major = (dev64 >> NBITSMINOR64) & L_MAXMAJ32; 1009 minor = dev64 & L_MAXMIN32; 1010 objp->knc_rdev = (major << L_BITSMINOR32) | minor; 1011 #endif 1012 } 1013 1014 if (xdrs->x_op == XDR_ENCODE) { 1015 buf = XDR_INLINE(xdrs, (8) * BYTES_PER_XDR_UNIT); 1016 if (buf == NULL) { 1017 if (!xdr_vector(xdrs, (char *)objp->knc_unused, 8, 1018 sizeof (uint_t), (xdrproc_t)xdr_u_int)) 1019 return (FALSE); 1020 } else { 1021 uint_t *genp; 1022 1023 for (i = 0, genp = objp->knc_unused; 1024 i < 8; i++) { 1025 #if defined(_LP64) || defined(_KERNEL) 1026 IXDR_PUT_U_INT32(buf, *genp++); 1027 #else 1028 IXDR_PUT_U_LONG(buf, *genp++); 1029 #endif 1030 } 1031 } 1032 return (TRUE); 1033 } else if (xdrs->x_op == XDR_DECODE) { 1034 buf = XDR_INLINE(xdrs, (8) * BYTES_PER_XDR_UNIT); 1035 if (buf == NULL) { 1036 if (!xdr_vector(xdrs, (char *)objp->knc_unused, 8, 1037 sizeof (uint_t), (xdrproc_t)xdr_u_int)) 1038 return (FALSE); 1039 } else { 1040 uint_t *genp; 1041 1042 for (i = 0, genp = objp->knc_unused; 1043 i < 8; i++) { 1044 #if defined(_LP64) || defined(_KERNEL) 1045 *genp++ = IXDR_GET_U_INT32(buf); 1046 #else 1047 *genp++ = IXDR_GET_U_LONG(buf); 1048 #endif 1049 } 1050 } 1051 return (TRUE); 1052 } 1053 1054 if (!xdr_vector(xdrs, (char *)objp->knc_unused, 8, 1055 sizeof (uint_t), (xdrproc_t)xdr_u_int)) 1056 return (FALSE); 1057 return (TRUE); 1058 } 1059 1060 /* 1061 * used by NFSv4 referrals to get info needed for NFSv4 referral mount. 1062 */ 1063 bool_t 1064 xdr_nfs_fsl_info(XDR *xdrs, struct nfs_fsl_info *objp) 1065 { 1066 1067 if (!xdr_u_int(xdrs, &objp->netbuf_len)) 1068 return (FALSE); 1069 if (!xdr_u_int(xdrs, &objp->netnm_len)) 1070 return (FALSE); 1071 if (!xdr_u_int(xdrs, &objp->knconf_len)) 1072 return (FALSE); 1073 if (!xdr_string(xdrs, &objp->netname, ~0)) 1074 return (FALSE); 1075 if (!xdr_pointer(xdrs, (char **)&objp->addr, objp->netbuf_len, 1076 (xdrproc_t)xdr_netbuf)) 1077 return (FALSE); 1078 if (!xdr_pointer(xdrs, (char **)&objp->knconf, 1079 objp->knconf_len, (xdrproc_t)xdr_knetconfig)) 1080 return (FALSE); 1081 return (TRUE); 1082 } 1083