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