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 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 /* 43 * nfs mount 44 */ 45 46 #define NFSCLIENT 47 #include <locale.h> 48 #include <stdio.h> 49 #include <string.h> 50 #include <memory.h> 51 #include <stdarg.h> 52 #include <unistd.h> 53 #include <ctype.h> 54 #include <stdlib.h> 55 #include <signal.h> 56 #include <sys/param.h> 57 #include <rpc/rpc.h> 58 #include <errno.h> 59 #include <sys/stat.h> 60 #include <netdb.h> 61 #include <sys/mount.h> 62 #include <sys/mntent.h> 63 #include <sys/mnttab.h> 64 #include <nfs/nfs.h> 65 #include <nfs/mount.h> 66 #include <rpcsvc/mount.h> 67 #include <sys/pathconf.h> 68 #include <netdir.h> 69 #include <netconfig.h> 70 #include <sys/sockio.h> 71 #include <net/if.h> 72 #include <syslog.h> 73 #include <fslib.h> 74 #include <deflt.h> 75 #include <sys/wait.h> 76 #include "replica.h" 77 #include <netinet/in.h> 78 #include <nfs/nfs_sec.h> 79 #include <rpcsvc/daemon_utils.h> 80 #include <priv.h> 81 #include "nfs_subr.h" 82 #include "webnfs.h" 83 #include <rpcsvc/nfs4_prot.h> 84 85 #ifndef NFS_VERSMAX 86 #define NFS_VERSMAX 4 87 #endif 88 #ifndef NFS_VERSMIN 89 #define NFS_VERSMIN 2 90 #endif 91 92 #define RET_OK 0 93 #define RET_RETRY 32 94 #define RET_ERR 33 95 #define RET_MNTERR 1000 96 #define ERR_PROTO_NONE 0 97 #define ERR_PROTO_INVALID 901 98 #define ERR_PROTO_UNSUPP 902 99 #define ERR_NETPATH 903 100 #define ERR_NOHOST 904 101 #define ERR_RPCERROR 905 102 103 typedef struct err_ret { 104 int error_type; 105 int error_value; 106 } err_ret_t; 107 108 #define SET_ERR_RET(errst, etype, eval) \ 109 if (errst) { \ 110 (errst)->error_type = etype; \ 111 (errst)->error_value = eval; \ 112 } 113 114 /* number of transports to try */ 115 #define MNT_PREF_LISTLEN 2 116 #define FIRST_TRY 1 117 #define SECOND_TRY 2 118 119 #define BIGRETRY 10000 120 121 /* maximum length of RPC header for NFS messages */ 122 #define NFS_RPC_HDR 432 123 124 #define NFS_ARGS_EXTB_secdata(args, secdata) \ 125 { (args)->nfs_args_ext = NFS_ARGS_EXTB, \ 126 (args)->nfs_ext_u.nfs_extB.secdata = secdata; } 127 128 extern int __clnt_bindresvport(); 129 extern char *nfs_get_qop_name(); 130 extern AUTH * nfs_create_ah(); 131 extern enum snego_stat nfs_sec_nego(); 132 133 static void usage(void); 134 static int retry(struct mnttab *, int); 135 static int set_args(int *, struct nfs_args *, char *, struct mnttab *); 136 static int get_fh_via_pub(struct nfs_args *, char *, char *, bool_t, bool_t, 137 int *, struct netconfig **, ushort_t); 138 static int get_fh(struct nfs_args *, char *, char *, int *, bool_t, 139 struct netconfig **, ushort_t); 140 static int make_secure(struct nfs_args *, char *, struct netconfig *, 141 bool_t, rpcvers_t); 142 static int mount_nfs(struct mnttab *, int); 143 static int getaddr_nfs(struct nfs_args *, char *, struct netconfig **, 144 bool_t, char *, ushort_t, err_ret_t *, bool_t); 145 static void pr_err(const char *fmt, ...); 146 static void usage(void); 147 static struct netbuf *get_addr(char *, rpcprog_t, rpcvers_t, 148 struct netconfig **, char *, ushort_t, struct t_info *, 149 caddr_t *, bool_t, char *, err_ret_t *); 150 151 static struct netbuf *get_the_addr(char *, rpcprog_t, rpcvers_t, 152 struct netconfig *, ushort_t, struct t_info *, caddr_t *, 153 bool_t, char *, err_ret_t *); 154 155 extern int self_check(char *); 156 157 static void read_default(void); 158 159 static char typename[64]; 160 161 static int bg = 0; 162 static int backgrounded = 0; 163 static int posix = 0; 164 static int retries = BIGRETRY; 165 static ushort_t nfs_port = 0; 166 static char *nfs_proto = NULL; 167 168 static int mflg = 0; 169 static int Oflg = 0; /* Overlay mounts */ 170 static int qflg = 0; /* quiet - don't print warnings on bad options */ 171 172 static char *fstype = MNTTYPE_NFS; 173 174 static seconfig_t nfs_sec; 175 static int sec_opt = 0; /* any security option ? */ 176 static bool_t snego_done; 177 static void sigusr1(int); 178 179 /* 180 * list of support services needed 181 */ 182 static char *service_list[] = { STATD, LOCKD, NULL }; 183 static char *service_list_v4[] = { STATD, LOCKD, NFS4CBD, NFSMAPID, NULL }; 184 185 /* 186 * These two variables control the NFS version number to be used. 187 * 188 * nfsvers defaults to 0 which means to use the highest number that 189 * both the client and the server support. It can also be set to 190 * a particular value, either 2, 3, or 4 to indicate the version 191 * number of choice. If the server (or the client) do not support 192 * the version indicated, then the mount attempt will be failed. 193 * 194 * nfsvers_to_use is the actual version number found to use. It 195 * is determined in get_fh by pinging the various versions of the 196 * NFS service on the server to see which responds positively. 197 */ 198 static rpcvers_t nfsvers = 0; 199 static rpcvers_t nfsvers_to_use = 0; 200 201 /* 202 * There are the defaults (range) for the client when determining 203 * which NFS version to use when probing the server (see above). 204 * These will only be used when the vers mount option is not used and 205 * these may be reset if /etc/default/nfs is configured to do so. 206 */ 207 static rpcvers_t vers_max_default = NFS_VERSMAX_DEFAULT; 208 static rpcvers_t vers_min_default = NFS_VERSMIN_DEFAULT; 209 210 /* 211 * This variable controls whether to try the public file handle. 212 */ 213 static bool_t public_opt; 214 215 main(int argc, char **argv) 216 { 217 struct mnttab mnt; 218 extern char *optarg; 219 extern int optind; 220 char optbuf[MAX_MNTOPT_STR]; 221 int ro = 0; 222 int r; 223 int c; 224 char *myname; 225 226 (void) setlocale(LC_ALL, ""); 227 #if !defined(TEXT_DOMAIN) 228 #define TEXT_DOMAIN "SYS_TEST" 229 #endif 230 (void) textdomain(TEXT_DOMAIN); 231 232 myname = strrchr(argv[0], '/'); 233 myname = myname ? myname + 1 : argv[0]; 234 (void) snprintf(typename, sizeof (typename), "%s %s", 235 MNTTYPE_NFS, myname); 236 argv[0] = typename; 237 238 mnt.mnt_mntopts = optbuf; 239 (void) strcpy(optbuf, "rw"); 240 241 /* 242 * Set options 243 */ 244 while ((c = getopt(argc, argv, "ro:mOq")) != EOF) { 245 switch (c) { 246 case 'r': 247 ro++; 248 break; 249 case 'o': 250 if (strlen(optarg) >= MAX_MNTOPT_STR) { 251 pr_err(gettext("option string too long")); 252 return (RET_ERR); 253 } 254 (void) strcpy(mnt.mnt_mntopts, optarg); 255 #ifdef LATER /* XXX */ 256 if (strstr(optarg, MNTOPT_REMOUNT)) { 257 /* 258 * If remount is specified, only rw is allowed. 259 */ 260 if ((strcmp(optarg, MNTOPT_REMOUNT) != 0) && 261 (strcmp(optarg, "remount,rw") != 0) && 262 (strcmp(optarg, "rw,remount") != 0)) { 263 pr_err(gettext("Invalid options\n")); 264 exit(RET_ERR); 265 } 266 } 267 #endif /* LATER */ /* XXX */ 268 break; 269 case 'm': 270 mflg++; 271 break; 272 case 'O': 273 Oflg++; 274 break; 275 case 'q': 276 qflg++; 277 break; 278 default: 279 usage(); 280 exit(RET_ERR); 281 } 282 } 283 if (argc - optind != 2) { 284 usage(); 285 exit(RET_ERR); 286 } 287 288 mnt.mnt_special = argv[optind]; 289 mnt.mnt_mountp = argv[optind+1]; 290 291 if (!priv_ineffect(PRIV_SYS_MOUNT) || 292 !priv_ineffect(PRIV_NET_PRIVADDR)) { 293 pr_err(gettext("insufficient privileges\n")); 294 exit(RET_ERR); 295 } 296 297 /* 298 * Read the defaults file to see if the min/max versions have 299 * been set and therefore would override the encoded defaults. 300 * Then check to make sure that if they were set that the 301 * values are reasonable. 302 */ 303 read_default(); 304 if (vers_min_default > vers_max_default || 305 vers_min_default < NFS_VERSMIN || 306 vers_max_default > NFS_VERSMAX) { 307 pr_err("%s %s\n%s %s\n", 308 gettext("Incorrect configuration of client\'s"), 309 NFSADMIN, 310 gettext("NFS_CLIENT_VERSMIN or NFS_CLIENT_VERSMAX"), 311 gettext("is either out of range or overlaps.")); 312 } 313 314 r = mount_nfs(&mnt, ro); 315 if (r == RET_RETRY && retries) 316 r = retry(&mnt, ro); 317 318 /* 319 * exit(r); 320 */ 321 return (r); 322 } 323 324 static void 325 pr_err(const char *fmt, ...) 326 { 327 va_list ap; 328 329 va_start(ap, fmt); 330 if (backgrounded != 0) { 331 (void) vsyslog(LOG_ERR, fmt, ap); 332 } else { 333 (void) fprintf(stderr, "%s: ", typename); 334 (void) vfprintf(stderr, fmt, ap); 335 (void) fflush(stderr); 336 } 337 va_end(ap); 338 } 339 340 static void 341 usage() 342 { 343 (void) fprintf(stderr, 344 gettext("Usage: nfs mount [-r] [-o opts] [server:]path dir\n")); 345 exit(RET_ERR); 346 } 347 348 static int 349 mount_nfs(struct mnttab *mntp, int ro) 350 { 351 struct nfs_args *args = NULL, *argp = NULL, *prev_argp = NULL; 352 struct netconfig *nconf = NULL; 353 struct replica *list = NULL; 354 int mntflags = 0; 355 int i, r, n; 356 int oldvers = 0, vers = 0; 357 int last_error = RET_OK; 358 int replicated = 0; 359 char *p; 360 bool_t url; 361 bool_t use_pubfh; 362 char *special = NULL; 363 char *oldpath = NULL; 364 char *newpath = NULL; 365 char *service; 366 pid_t pi; 367 struct flock f; 368 char *saveopts = NULL; 369 char **sl = NULL; 370 371 mntp->mnt_fstype = MNTTYPE_NFS; 372 373 if (ro) { 374 mntflags |= MS_RDONLY; 375 /* convert "rw"->"ro" */ 376 if (p = strstr(mntp->mnt_mntopts, "rw")) { 377 if (*(p+2) == ',' || *(p+2) == '\0') 378 *(p+1) = 'o'; 379 } 380 } 381 382 if (Oflg) 383 mntflags |= MS_OVERLAY; 384 385 list = parse_replica(mntp->mnt_special, &n); 386 if (list == NULL) { 387 if (n < 0) 388 pr_err(gettext("nfs file system; use [host:]path\n")); 389 else 390 pr_err(gettext("no memory\n")); 391 return (RET_ERR); 392 } 393 394 replicated = (n > 1); 395 396 /* 397 * There are some free() calls at the bottom of this loop, so be 398 * careful about adding continue statements. 399 */ 400 for (i = 0; i < n; i++) { 401 char *path; 402 char *host; 403 ushort_t port; 404 405 argp = (struct nfs_args *)malloc(sizeof (*argp)); 406 if (argp == NULL) { 407 pr_err(gettext("no memory\n")); 408 last_error = RET_ERR; 409 goto out; 410 } 411 memset(argp, 0, sizeof (*argp)); 412 413 memset(&nfs_sec, 0, sizeof (nfs_sec)); 414 sec_opt = 0; 415 use_pubfh = FALSE; 416 url = FALSE; 417 port = 0; 418 snego_done = FALSE; 419 420 /* 421 * Looking for resources of the form 422 * nfs://server_host[:port_number]/path_name 423 */ 424 if (strcmp(list[i].host, "nfs") == 0 && strncmp(list[i].path, 425 "//", 2) == 0) { 426 char *sport, *cb; 427 url = TRUE; 428 oldpath = strdup(list[i].path); 429 if (oldpath == NULL) { 430 pr_err(gettext("memory allocation failure\n")); 431 last_error = RET_ERR; 432 goto out; 433 } 434 host = list[i].path+2; 435 path = strchr(host, '/'); 436 437 if (path == NULL) { 438 pr_err(gettext( 439 "illegal nfs url syntax\n")); 440 last_error = RET_ERR; 441 goto out; 442 } 443 444 *path = '\0'; 445 if (*host == '[') { 446 cb = strchr(host, ']'); 447 if (cb == NULL) { 448 pr_err(gettext( 449 "illegal nfs url syntax\n")); 450 last_error = RET_ERR; 451 goto out; 452 } else { 453 *cb = '\0'; 454 host++; 455 cb++; 456 if (*cb == ':') 457 port = htons((ushort_t) 458 atoi(cb+1)); 459 } 460 } else { 461 sport = strchr(host, ':'); 462 463 if (sport != NULL && sport < path) { 464 *sport = '\0'; 465 port = htons((ushort_t)atoi(sport+1)); 466 } 467 } 468 469 path++; 470 if (*path == '\0') 471 path = "."; 472 473 } else { 474 host = list[i].host; 475 path = list[i].path; 476 } 477 478 if (r = set_args(&mntflags, argp, host, mntp)) { 479 last_error = r; 480 goto out; 481 } 482 483 if (public_opt == TRUE) 484 use_pubfh = TRUE; 485 486 if (port == 0) { 487 port = nfs_port; 488 } else if (nfs_port != 0 && nfs_port != port) { 489 pr_err(gettext( 490 "port (%u) in nfs URL not the same" 491 " as port (%u) in port option\n"), 492 (unsigned int)ntohs(port), 493 (unsigned int)ntohs(nfs_port)); 494 last_error = RET_ERR; 495 goto out; 496 } 497 498 499 if (replicated && !(mntflags & MS_RDONLY)) { 500 pr_err(gettext( 501 "replicated mounts must be read-only\n")); 502 last_error = RET_ERR; 503 goto out; 504 } 505 506 if (replicated && (argp->flags & NFSMNT_SOFT)) { 507 pr_err(gettext( 508 "replicated mounts must not be soft\n")); 509 last_error = RET_ERR; 510 goto out; 511 } 512 513 oldvers = vers; 514 nconf = NULL; 515 516 r = RET_ERR; 517 518 /* 519 * If -o public was specified, and/or a URL was specified, 520 * then try the public file handle method. 521 */ 522 if ((use_pubfh == TRUE) || (url == TRUE)) { 523 r = get_fh_via_pub(argp, host, path, url, use_pubfh, 524 &vers, &nconf, port); 525 526 if (r != RET_OK) { 527 /* 528 * If -o public was specified, then return the 529 * error now. 530 */ 531 if (use_pubfh == TRUE) { 532 last_error = r; 533 goto out; 534 } 535 } else 536 use_pubfh = TRUE; 537 argp->flags |= NFSMNT_PUBLIC; 538 } 539 540 if ((r != RET_OK) || (vers == NFS_V4)) { 541 bool_t loud_on_mnt_err; 542 543 /* 544 * This can happen if -o public is not specified, 545 * special is a URL, and server doesn't support 546 * public file handle. 547 */ 548 if (url) { 549 URLparse(path); 550 } 551 552 /* 553 * If the path portion of the URL didn't have 554 * a leading / then there is good possibility 555 * that a mount without a leading slash will 556 * fail. 557 */ 558 if (url == TRUE && *path != '/') 559 loud_on_mnt_err = FALSE; 560 else 561 loud_on_mnt_err = TRUE; 562 563 r = get_fh(argp, host, path, &vers, 564 loud_on_mnt_err, &nconf, port); 565 566 if (r != RET_OK) { 567 568 /* 569 * If there was no leading / and the path was 570 * derived from a URL, then try again 571 * with a leading /. 572 */ 573 if ((r == RET_MNTERR) && 574 (loud_on_mnt_err == FALSE)) { 575 576 newpath = malloc(strlen(path)+2); 577 578 if (newpath == NULL) { 579 pr_err(gettext("memory " 580 "allocation failure\n")); 581 last_error = RET_ERR; 582 goto out; 583 } 584 585 strcpy(newpath, "/"); 586 strcat(newpath, path); 587 588 r = get_fh(argp, host, newpath, &vers, 589 TRUE, &nconf, port); 590 591 if (r == RET_OK) 592 path = newpath; 593 } 594 595 /* 596 * map exit code back to RET_ERR. 597 */ 598 if (r == RET_MNTERR) 599 r = RET_ERR; 600 601 if (r != RET_OK) { 602 603 if (replicated) { 604 if (argp->fh) 605 free(argp->fh); 606 if (argp->pathconf) 607 free(argp->pathconf); 608 free(argp); 609 goto cont; 610 } 611 612 last_error = r; 613 goto out; 614 } 615 } 616 } 617 618 if (oldvers && vers != oldvers) { 619 pr_err( 620 gettext("replicas must have the same version\n")); 621 last_error = RET_ERR; 622 goto out; 623 } 624 625 /* 626 * decide whether to use remote host's 627 * lockd or do local locking 628 */ 629 if (!(argp->flags & NFSMNT_LLOCK) && vers == NFS_VERSION && 630 remote_lock(host, argp->fh)) { 631 (void) fprintf(stderr, gettext( 632 "WARNING: No network locking on %s:%s:"), 633 host, path); 634 (void) fprintf(stderr, gettext( 635 " contact admin to install server change\n")); 636 argp->flags |= NFSMNT_LLOCK; 637 } 638 639 if (self_check(host)) 640 argp->flags |= NFSMNT_LOOPBACK; 641 642 if (use_pubfh == FALSE) { 643 /* 644 * Call to get_fh() above may have obtained the 645 * netconfig info and NULL proc'd the server. 646 * This would be the case with v4 647 */ 648 if (!(argp->flags & NFSMNT_KNCONF)) { 649 nconf = NULL; 650 if (r = getaddr_nfs(argp, host, &nconf, 651 FALSE, path, port, NULL, TRUE)) { 652 last_error = r; 653 goto out; 654 } 655 } 656 } 657 658 if (make_secure(argp, host, nconf, use_pubfh, vers) < 0) { 659 last_error = RET_ERR; 660 goto out; 661 } 662 663 if ((url == TRUE) && (use_pubfh == FALSE)) { 664 /* 665 * Convert the special from 666 * nfs://host/path 667 * to 668 * host:path 669 */ 670 if (convert_special(&special, host, oldpath, path, 671 mntp->mnt_special) == -1) { 672 (void) fprintf(stderr, gettext( 673 "could not convert URL nfs:%s to %s:%s\n"), 674 oldpath, host, path); 675 last_error = RET_ERR; 676 goto out; 677 } else { 678 mntp->mnt_special = special; 679 } 680 } 681 682 if (prev_argp == NULL) 683 args = argp; 684 else 685 prev_argp->nfs_ext_u.nfs_extB.next = argp; 686 prev_argp = argp; 687 688 cont: 689 if (oldpath != NULL) { 690 free(oldpath); 691 oldpath = NULL; 692 } 693 694 if (newpath != NULL) { 695 free(newpath); 696 newpath = NULL; 697 } 698 } 699 700 argp = NULL; 701 702 if (args == NULL) { 703 last_error = RET_RETRY; 704 goto out; 705 } 706 707 /* Determine which services are appropriate for the NFS version */ 708 if (strcmp(fstype, MNTTYPE_NFS4) == 0) 709 sl = service_list_v4; 710 else 711 sl = service_list; 712 713 /* 714 * enable services as needed. 715 */ 716 _check_services(sl); 717 718 mntflags |= MS_DATA | MS_OPTIONSTR; 719 720 if (mflg) 721 mntflags |= MS_NOMNTTAB; 722 723 if (!qflg) 724 saveopts = strdup(mntp->mnt_mntopts); 725 726 if (mount(mntp->mnt_special, mntp->mnt_mountp, mntflags, fstype, args, 727 sizeof (*args), mntp->mnt_mntopts, MAX_MNTOPT_STR) < 0) { 728 if (errno != ENOENT) { 729 pr_err(gettext("mount: %s: %s\n"), 730 mntp->mnt_mountp, strerror(errno)); 731 } else { 732 struct stat sb; 733 if (stat(mntp->mnt_mountp, &sb) < 0 && errno == ENOENT) 734 pr_err(gettext("mount: %s: %s\n"), 735 mntp->mnt_mountp, strerror(ENOENT)); 736 else 737 pr_err("%s: %s\n", mntp->mnt_special, 738 strerror(ENOENT)); 739 } 740 741 last_error = RET_ERR; 742 goto out; 743 } 744 745 if (!qflg && saveopts != NULL) { 746 cmp_requested_to_actual_options(saveopts, mntp->mnt_mntopts, 747 mntp->mnt_special, mntp->mnt_mountp); 748 } 749 750 out: 751 if (saveopts != NULL) 752 free(saveopts); 753 if (special != NULL) 754 free(special); 755 if (oldpath != NULL) 756 free(oldpath); 757 if (newpath != NULL) 758 free(newpath); 759 760 free_replica(list, n); 761 762 if (argp != NULL) { 763 /* 764 * If we had a new entry which was not added to the 765 * list yet, then add it now that it can be freed. 766 */ 767 if (prev_argp == NULL) 768 args = argp; 769 else 770 prev_argp->nfs_ext_u.nfs_extB.next = argp; 771 } 772 argp = args; 773 while (argp != NULL) { 774 if (argp->fh) 775 free(argp->fh); 776 if (argp->pathconf) 777 free(argp->pathconf); 778 if (argp->knconf) 779 free(argp->knconf); 780 if (argp->addr) { 781 free(argp->addr->buf); 782 free(argp->addr); 783 } 784 nfs_free_secdata(argp->nfs_ext_u.nfs_extB.secdata); 785 if (argp->syncaddr) { 786 free(argp->syncaddr->buf); 787 free(argp->syncaddr); 788 } 789 if (argp->netname) 790 free(argp->netname); 791 prev_argp = argp; 792 argp = argp->nfs_ext_u.nfs_extB.next; 793 free(prev_argp); 794 } 795 796 return (last_error); 797 } 798 799 /* 800 * These options are duplicated in uts/common/fs/nfs/nfs_dlinet.c 801 * Changes must be made to both lists. 802 */ 803 static char *optlist[] = { 804 #define OPT_RO 0 805 MNTOPT_RO, 806 #define OPT_RW 1 807 MNTOPT_RW, 808 #define OPT_QUOTA 2 809 MNTOPT_QUOTA, 810 #define OPT_NOQUOTA 3 811 MNTOPT_NOQUOTA, 812 #define OPT_SOFT 4 813 MNTOPT_SOFT, 814 #define OPT_HARD 5 815 MNTOPT_HARD, 816 #define OPT_SUID 6 817 MNTOPT_SUID, 818 #define OPT_NOSUID 7 819 MNTOPT_NOSUID, 820 #define OPT_GRPID 8 821 MNTOPT_GRPID, 822 #define OPT_REMOUNT 9 823 MNTOPT_REMOUNT, 824 #define OPT_NOSUB 10 825 MNTOPT_NOSUB, 826 #define OPT_INTR 11 827 MNTOPT_INTR, 828 #define OPT_NOINTR 12 829 MNTOPT_NOINTR, 830 #define OPT_PORT 13 831 MNTOPT_PORT, 832 #define OPT_SECURE 14 833 MNTOPT_SECURE, 834 #define OPT_RSIZE 15 835 MNTOPT_RSIZE, 836 #define OPT_WSIZE 16 837 MNTOPT_WSIZE, 838 #define OPT_TIMEO 17 839 MNTOPT_TIMEO, 840 #define OPT_RETRANS 18 841 MNTOPT_RETRANS, 842 #define OPT_ACTIMEO 19 843 MNTOPT_ACTIMEO, 844 #define OPT_ACREGMIN 20 845 MNTOPT_ACREGMIN, 846 #define OPT_ACREGMAX 21 847 MNTOPT_ACREGMAX, 848 #define OPT_ACDIRMIN 22 849 MNTOPT_ACDIRMIN, 850 #define OPT_ACDIRMAX 23 851 MNTOPT_ACDIRMAX, 852 #define OPT_BG 24 853 MNTOPT_BG, 854 #define OPT_FG 25 855 MNTOPT_FG, 856 #define OPT_RETRY 26 857 MNTOPT_RETRY, 858 #define OPT_NOAC 27 859 MNTOPT_NOAC, 860 #define OPT_NOCTO 28 861 MNTOPT_NOCTO, 862 #define OPT_LLOCK 29 863 MNTOPT_LLOCK, 864 #define OPT_POSIX 30 865 MNTOPT_POSIX, 866 #define OPT_VERS 31 867 MNTOPT_VERS, 868 #define OPT_PROTO 32 869 MNTOPT_PROTO, 870 #define OPT_SEMISOFT 33 871 MNTOPT_SEMISOFT, 872 #define OPT_NOPRINT 34 873 MNTOPT_NOPRINT, 874 #define OPT_SEC 35 875 MNTOPT_SEC, 876 #define OPT_LARGEFILES 36 877 MNTOPT_LARGEFILES, 878 #define OPT_NOLARGEFILES 37 879 MNTOPT_NOLARGEFILES, 880 #define OPT_PUBLIC 38 881 MNTOPT_PUBLIC, 882 #define OPT_DIRECTIO 39 883 MNTOPT_FORCEDIRECTIO, 884 #define OPT_NODIRECTIO 40 885 MNTOPT_NOFORCEDIRECTIO, 886 #define OPT_XATTR 41 887 MNTOPT_XATTR, 888 #define OPT_NOXATTR 42 889 MNTOPT_NOXATTR, 890 #define OPT_DEVICES 43 891 MNTOPT_DEVICES, 892 #define OPT_NODEVICES 44 893 MNTOPT_NODEVICES, 894 #define OPT_SETUID 45 895 MNTOPT_SETUID, 896 #define OPT_NOSETUID 46 897 MNTOPT_NOSETUID, 898 #define OPT_EXEC 47 899 MNTOPT_EXEC, 900 #define OPT_NOEXEC 48 901 MNTOPT_NOEXEC, 902 NULL 903 }; 904 905 #define bad(val) (val == NULL || !isdigit(*val)) 906 907 static int 908 set_args(int *mntflags, struct nfs_args *args, char *fshost, struct mnttab *mnt) 909 { 910 char *saveopt, *optstr, *opts, *newopts, *val; 911 int largefiles = 0; 912 int invalid = 0; 913 int attrpref = 0; 914 int optlen; 915 916 args->flags = NFSMNT_INT; /* default is "intr" */ 917 args->flags |= NFSMNT_HOSTNAME; 918 args->flags |= NFSMNT_NEWARGS; /* using extented nfs_args structure */ 919 args->hostname = fshost; 920 921 optstr = opts = strdup(mnt->mnt_mntopts); 922 /* sizeof (MNTOPT_XXX) includes one extra byte we may need for "," */ 923 optlen = strlen(mnt->mnt_mntopts) + sizeof (MNTOPT_XATTR) + 1; 924 if (optlen > MAX_MNTOPT_STR) { 925 pr_err(gettext("option string too long")); 926 return (RET_ERR); 927 } 928 newopts = malloc(optlen); 929 if (opts == NULL || newopts == NULL) { 930 pr_err(gettext("no memory")); 931 if (opts) 932 free(opts); 933 if (newopts) 934 free(newopts); 935 return (RET_ERR); 936 } 937 newopts[0] = '\0'; 938 939 while (*opts) { 940 invalid = 0; 941 saveopt = opts; 942 switch (getsubopt(&opts, optlist, &val)) { 943 case OPT_RO: 944 *mntflags |= MS_RDONLY; 945 break; 946 case OPT_RW: 947 *mntflags &= ~(MS_RDONLY); 948 break; 949 case OPT_QUOTA: 950 case OPT_NOQUOTA: 951 break; 952 case OPT_SOFT: 953 args->flags |= NFSMNT_SOFT; 954 args->flags &= ~(NFSMNT_SEMISOFT); 955 break; 956 case OPT_SEMISOFT: 957 args->flags |= NFSMNT_SOFT; 958 args->flags |= NFSMNT_SEMISOFT; 959 break; 960 case OPT_HARD: 961 args->flags &= ~(NFSMNT_SOFT); 962 args->flags &= ~(NFSMNT_SEMISOFT); 963 break; 964 case OPT_SUID: 965 *mntflags &= ~(MS_NOSUID); 966 break; 967 case OPT_NOSUID: 968 *mntflags |= MS_NOSUID; 969 break; 970 case OPT_GRPID: 971 args->flags |= NFSMNT_GRPID; 972 break; 973 case OPT_REMOUNT: 974 *mntflags |= MS_REMOUNT; 975 break; 976 case OPT_INTR: 977 args->flags |= NFSMNT_INT; 978 break; 979 case OPT_NOINTR: 980 args->flags &= ~(NFSMNT_INT); 981 break; 982 case OPT_NOAC: 983 args->flags |= NFSMNT_NOAC; 984 break; 985 case OPT_PORT: 986 if (bad(val)) 987 goto badopt; 988 nfs_port = htons((ushort_t)atoi(val)); 989 break; 990 991 case OPT_SECURE: 992 if (nfs_getseconfig_byname("dh", &nfs_sec)) { 993 pr_err(gettext("can not get \"dh\" from %s\n"), 994 NFSSEC_CONF); 995 goto badopt; 996 } 997 sec_opt++; 998 break; 999 1000 case OPT_NOCTO: 1001 args->flags |= NFSMNT_NOCTO; 1002 break; 1003 1004 case OPT_RSIZE: 1005 args->flags |= NFSMNT_RSIZE; 1006 if (bad(val)) 1007 goto badopt; 1008 args->rsize = atoi(val); 1009 break; 1010 case OPT_WSIZE: 1011 args->flags |= NFSMNT_WSIZE; 1012 if (bad(val)) 1013 goto badopt; 1014 args->wsize = atoi(val); 1015 break; 1016 case OPT_TIMEO: 1017 args->flags |= NFSMNT_TIMEO; 1018 if (bad(val)) 1019 goto badopt; 1020 args->timeo = atoi(val); 1021 break; 1022 case OPT_RETRANS: 1023 args->flags |= NFSMNT_RETRANS; 1024 if (bad(val)) 1025 goto badopt; 1026 args->retrans = atoi(val); 1027 break; 1028 case OPT_ACTIMEO: 1029 args->flags |= NFSMNT_ACDIRMAX; 1030 args->flags |= NFSMNT_ACREGMAX; 1031 args->flags |= NFSMNT_ACDIRMIN; 1032 args->flags |= NFSMNT_ACREGMIN; 1033 if (bad(val)) 1034 goto badopt; 1035 args->acdirmin = args->acregmin = args->acdirmax 1036 = args->acregmax = atoi(val); 1037 break; 1038 case OPT_ACREGMIN: 1039 args->flags |= NFSMNT_ACREGMIN; 1040 if (bad(val)) 1041 goto badopt; 1042 args->acregmin = atoi(val); 1043 break; 1044 case OPT_ACREGMAX: 1045 args->flags |= NFSMNT_ACREGMAX; 1046 if (bad(val)) 1047 goto badopt; 1048 args->acregmax = atoi(val); 1049 break; 1050 case OPT_ACDIRMIN: 1051 args->flags |= NFSMNT_ACDIRMIN; 1052 if (bad(val)) 1053 goto badopt; 1054 args->acdirmin = atoi(val); 1055 break; 1056 case OPT_ACDIRMAX: 1057 args->flags |= NFSMNT_ACDIRMAX; 1058 if (bad(val)) 1059 goto badopt; 1060 args->acdirmax = atoi(val); 1061 break; 1062 case OPT_BG: 1063 bg++; 1064 break; 1065 case OPT_FG: 1066 bg = 0; 1067 break; 1068 case OPT_RETRY: 1069 if (bad(val)) 1070 goto badopt; 1071 retries = atoi(val); 1072 break; 1073 case OPT_LLOCK: 1074 args->flags |= NFSMNT_LLOCK; 1075 break; 1076 case OPT_POSIX: 1077 posix = 1; 1078 break; 1079 case OPT_VERS: 1080 if (bad(val)) 1081 goto badopt; 1082 nfsvers = (rpcvers_t)atoi(val); 1083 break; 1084 case OPT_PROTO: 1085 if (val == NULL) 1086 goto badopt; 1087 1088 nfs_proto = (char *)malloc(strlen(val)+1); 1089 if (!nfs_proto) { 1090 pr_err(gettext("no memory")); 1091 return (RET_ERR); 1092 } 1093 1094 (void) strncpy(nfs_proto, val, strlen(val)+1); 1095 break; 1096 case OPT_NOPRINT: 1097 args->flags |= NFSMNT_NOPRINT; 1098 break; 1099 case OPT_LARGEFILES: 1100 largefiles = 1; 1101 break; 1102 case OPT_NOLARGEFILES: 1103 pr_err(gettext("NFS can't support \"nolargefiles\"\n")); 1104 free(optstr); 1105 return (RET_ERR); 1106 1107 case OPT_SEC: 1108 if (nfs_getseconfig_byname(val, &nfs_sec)) { 1109 pr_err(gettext("can not get \"%s\" from %s\n"), 1110 val, NFSSEC_CONF); 1111 return (RET_ERR); 1112 } 1113 sec_opt++; 1114 break; 1115 1116 case OPT_PUBLIC: 1117 public_opt = TRUE; 1118 break; 1119 1120 case OPT_DIRECTIO: 1121 args->flags |= NFSMNT_DIRECTIO; 1122 break; 1123 1124 case OPT_NODIRECTIO: 1125 args->flags &= ~(NFSMNT_DIRECTIO); 1126 break; 1127 1128 case OPT_XATTR: 1129 case OPT_NOXATTR: 1130 /* 1131 * VFS options; just need to get them into the 1132 * new mount option string and note we've seen them 1133 */ 1134 attrpref = 1; 1135 break; 1136 default: 1137 /* 1138 * Note that this could be a valid OPT_* option so 1139 * we can't use "val" but need to use "saveopt". 1140 */ 1141 if (fsisstdopt(saveopt)) 1142 break; 1143 invalid = 1; 1144 if (!qflg) 1145 (void) fprintf(stderr, gettext( 1146 "mount: %s on %s - WARNING unknown option" 1147 " \"%s\"\n"), mnt->mnt_special, 1148 mnt->mnt_mountp, saveopt); 1149 break; 1150 } 1151 if (!invalid) { 1152 if (newopts[0]) 1153 strcat(newopts, ","); 1154 strcat(newopts, saveopt); 1155 } 1156 } 1157 /* Default is to turn extended attrs on */ 1158 if (!attrpref) { 1159 if (newopts[0]) 1160 strcat(newopts, ","); 1161 strcat(newopts, MNTOPT_XATTR); 1162 } 1163 strcpy(mnt->mnt_mntopts, newopts); 1164 free(newopts); 1165 free(optstr); 1166 1167 /* ensure that only one secure mode is requested */ 1168 if (sec_opt > 1) { 1169 pr_err(gettext("Security options conflict\n")); 1170 return (RET_ERR); 1171 } 1172 1173 /* ensure that the user isn't trying to get large files over V2 */ 1174 if (nfsvers == NFS_VERSION && largefiles) { 1175 pr_err(gettext("NFS V2 can't support \"largefiles\"\n")); 1176 return (RET_ERR); 1177 } 1178 1179 if (nfsvers == NFS_V4 && 1180 nfs_proto != NULL && 1181 strncasecmp(nfs_proto, NC_UDP, strlen(NC_UDP)) == 0) { 1182 pr_err(gettext("NFS V4 does not support %s\n"), nfs_proto); 1183 return (RET_ERR); 1184 } 1185 1186 return (RET_OK); 1187 1188 badopt: 1189 pr_err(gettext("invalid option: \"%s\"\n"), saveopt); 1190 free(optstr); 1191 return (RET_ERR); 1192 } 1193 1194 static int 1195 make_secure(struct nfs_args *args, char *hostname, struct netconfig *nconf, 1196 bool_t use_pubfh, rpcvers_t vers) 1197 { 1198 sec_data_t *secdata; 1199 int flags; 1200 struct netbuf *syncaddr = NULL; 1201 struct nd_addrlist *retaddrs = NULL; 1202 char netname[MAXNETNAMELEN+1]; 1203 1204 /* 1205 * check to see if any secure mode is requested. 1206 * if not, use default security mode. 1207 */ 1208 if (!snego_done && !sec_opt) { 1209 /* 1210 * Get default security mode. 1211 * AUTH_UNIX has been the default choice for a long time. 1212 * The better NFS security service becomes, the better chance 1213 * we will set stronger security service as the default NFS 1214 * security mode. 1215 * 1216 */ 1217 if (nfs_getseconfig_default(&nfs_sec)) { 1218 pr_err(gettext("error getting default security entry\n")); 1219 return (-1); 1220 } 1221 args->flags |= NFSMNT_SECDEFAULT; 1222 } 1223 1224 /* 1225 * Get the network address for the time service on the server. 1226 * If an RPC based time service is not available then try the 1227 * IP time service. 1228 * 1229 * This is for AUTH_DH processing. We will also pass down syncaddr 1230 * and netname for NFS V4 even if AUTH_DH is not requested right now. 1231 * NFS V4 does security negotiation in the kernel via SECINFO. 1232 * These information might be needed later in the kernel. 1233 * 1234 * Eventurally, we want to move this code to nfs_clnt_secdata() 1235 * when autod_nfs.c and mount.c can share the same get_the_addr() 1236 * routine. 1237 */ 1238 flags = 0; 1239 syncaddr = NULL; 1240 1241 if (nfs_sec.sc_rpcnum == AUTH_DH || vers == NFS_V4) { 1242 /* 1243 * If using the public fh or nfsv4, we will not contact the 1244 * remote RPCBINDer, since it is possibly behind a firewall. 1245 */ 1246 if (use_pubfh == FALSE && vers != NFS_V4) { 1247 syncaddr = get_the_addr(hostname, RPCBPROG, RPCBVERS, 1248 nconf, 0, NULL, NULL, FALSE, NULL, NULL); 1249 } 1250 1251 if (syncaddr != NULL) { 1252 /* for flags in sec_data */ 1253 flags |= AUTH_F_RPCTIMESYNC; 1254 } else { 1255 struct nd_hostserv hs; 1256 int error; 1257 1258 hs.h_host = hostname; 1259 hs.h_serv = "timserver"; 1260 1261 error = netdir_getbyname(nconf, &hs, &retaddrs); 1262 1263 if (error != ND_OK && (nfs_sec.sc_rpcnum == AUTH_DH)) { 1264 pr_err(gettext("%s: secure: no time service\n"), 1265 hostname); 1266 return (-1); 1267 } 1268 1269 if (error == ND_OK) 1270 syncaddr = retaddrs->n_addrs; 1271 1272 /* 1273 * For NFS_V4 if AUTH_DH is negotiated later in the 1274 * kernel thru SECINFO, it will need syncaddr 1275 * and netname data. 1276 */ 1277 if (vers == NFS_V4 && syncaddr && 1278 host2netname(netname, hostname, NULL)) { 1279 args->syncaddr = malloc(sizeof (struct netbuf)); 1280 args->syncaddr->buf = malloc(syncaddr->len); 1281 (void) memcpy(args->syncaddr->buf, syncaddr->buf, 1282 syncaddr->len); 1283 args->syncaddr->len = syncaddr->len; 1284 args->syncaddr->maxlen = syncaddr->maxlen; 1285 args->netname = strdup(netname); 1286 args->flags |= NFSMNT_SECURE; 1287 } 1288 } 1289 } 1290 1291 /* 1292 * For the initial chosen flavor (any flavor defined in nfssec.conf), 1293 * the data will be stored in the sec_data structure via 1294 * nfs_clnt_secdata() and be passed to the kernel via nfs_args_* 1295 * extended data structure. 1296 */ 1297 if (!(secdata = nfs_clnt_secdata(&nfs_sec, hostname, args->knconf, 1298 syncaddr, flags))) { 1299 pr_err(gettext("errors constructing security related data\n")); 1300 if (flags & AUTH_F_RPCTIMESYNC) { 1301 free(syncaddr->buf); 1302 free(syncaddr); 1303 } else if (retaddrs) 1304 netdir_free((void *)retaddrs, ND_ADDRLIST); 1305 return (-1); 1306 } 1307 1308 NFS_ARGS_EXTB_secdata(args, secdata); 1309 if (flags & AUTH_F_RPCTIMESYNC) { 1310 free(syncaddr->buf); 1311 free(syncaddr); 1312 } else if (retaddrs) 1313 netdir_free((void *)retaddrs, ND_ADDRLIST); 1314 return (0); 1315 } 1316 1317 /* 1318 * Get the network address on "hostname" for program "prog" 1319 * with version "vers" by using the nconf configuration data 1320 * passed in. 1321 * 1322 * If the address of a netconfig pointer is null then 1323 * information is not sufficient and no netbuf will be returned. 1324 * 1325 * Finally, ping the null procedure of that service. 1326 * 1327 * A similar routine is also defined in ../../autofs/autod_nfs.c. 1328 * This is a potential routine to move to ../lib for common usage. 1329 */ 1330 static struct netbuf * 1331 get_the_addr(char *hostname, ulong_t prog, ulong_t vers, 1332 struct netconfig *nconf, ushort_t port, struct t_info *tinfo, 1333 caddr_t *fhp, bool_t get_pubfh, char *fspath, err_ret_t *error) 1334 { 1335 struct netbuf *nb = NULL; 1336 struct t_bind *tbind = NULL; 1337 CLIENT *cl = NULL; 1338 struct timeval tv; 1339 int fd = -1; 1340 AUTH *ah = NULL; 1341 AUTH *new_ah = NULL; 1342 struct snego_t snego; 1343 1344 if (nconf == NULL) 1345 return (NULL); 1346 1347 if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) == -1) 1348 goto done; 1349 1350 /* LINTED pointer alignment */ 1351 if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR)) 1352 == NULL) 1353 goto done; 1354 1355 /* 1356 * In the case of public filehandle usage or NFSv4 we want to 1357 * avoid use of the rpcbind/portmap protocol 1358 */ 1359 if ((get_pubfh == TRUE) || (vers == NFS_V4)) { 1360 struct nd_hostserv hs; 1361 struct nd_addrlist *retaddrs; 1362 int retval; 1363 hs.h_host = hostname; 1364 1365 /* NFS where vers==4 does not support UDP */ 1366 if (vers == NFS_V4 && 1367 strncasecmp(nconf->nc_proto, NC_UDP, 1368 strlen(NC_UDP)) == 0) { 1369 SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0); 1370 goto done; 1371 } 1372 1373 if (port == 0) 1374 hs.h_serv = "nfs"; 1375 else 1376 hs.h_serv = NULL; 1377 1378 if ((retval = netdir_getbyname(nconf, &hs, &retaddrs)) 1379 != ND_OK) { 1380 /* 1381 * Carefully set the error value here. Want to signify 1382 * that the error was an unknown host. 1383 */ 1384 if (retval == ND_NOHOST) { 1385 SET_ERR_RET(error, ERR_NOHOST, retval); 1386 } 1387 1388 goto done; 1389 } 1390 memcpy(tbind->addr.buf, retaddrs->n_addrs->buf, 1391 retaddrs->n_addrs->len); 1392 tbind->addr.len = retaddrs->n_addrs->len; 1393 netdir_free((void *)retaddrs, ND_ADDRLIST); 1394 (void) netdir_options(nconf, ND_SET_RESERVEDPORT, fd, NULL); 1395 1396 } else { 1397 if (rpcb_getaddr(prog, vers, nconf, &tbind->addr, 1398 hostname) == FALSE) { 1399 goto done; 1400 } 1401 } 1402 1403 if (port) { 1404 /* LINTED pointer alignment */ 1405 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) 1406 ((struct sockaddr_in *)tbind->addr.buf)->sin_port 1407 = port; 1408 else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) 1409 ((struct sockaddr_in6 *)tbind->addr.buf)->sin6_port 1410 = port; 1411 1412 } 1413 1414 cl = clnt_tli_create(fd, nconf, &tbind->addr, prog, vers, 0, 0); 1415 if (cl == NULL) { 1416 /* 1417 * clnt_tli_create() returns either RPC_SYSTEMERROR, 1418 * RPC_UNKNOWNPROTO or RPC_TLIERROR. The RPC_TLIERROR translates 1419 * to "Misc. TLI error". This is not too helpful. Most likely 1420 * the connection to the remote server timed out, so this 1421 * error is at least less perplexing. 1422 * See: usr/src/cmd/rpcinfo/rpcinfo.c 1423 */ 1424 if (rpc_createerr.cf_stat == RPC_TLIERROR) { 1425 SET_ERR_RET(error, ERR_RPCERROR, RPC_PMAPFAILURE); 1426 } else { 1427 SET_ERR_RET(error, ERR_RPCERROR, rpc_createerr.cf_stat); 1428 } 1429 goto done; 1430 } 1431 1432 ah = authsys_create_default(); 1433 if (ah != NULL) 1434 cl->cl_auth = ah; 1435 1436 tv.tv_sec = 5; 1437 tv.tv_usec = 0; 1438 1439 (void) clnt_control(cl, CLSET_TIMEOUT, (char *)&tv); 1440 1441 if ((get_pubfh == TRUE) && (vers != NFS_V4)) { 1442 enum snego_stat sec; 1443 1444 if (!snego_done) { 1445 /* 1446 * negotiate sec flavor. 1447 */ 1448 snego.cnt = 0; 1449 if ((sec = nfs_sec_nego(vers, cl, fspath, &snego)) == 1450 SNEGO_SUCCESS) { 1451 int jj; 1452 1453 /* 1454 * check if server supports the one 1455 * specified in the sec= option. 1456 */ 1457 if (sec_opt) { 1458 for (jj = 0; jj < snego.cnt; jj++) { 1459 if (snego.array[jj] == nfs_sec.sc_nfsnum) { 1460 snego_done = TRUE; 1461 break; 1462 } 1463 } 1464 } 1465 1466 /* 1467 * find a common sec flavor 1468 */ 1469 if (!snego_done) { 1470 if (sec_opt) { 1471 pr_err(gettext( 1472 "Server does not support the security" 1473 " flavor specified.\n")); 1474 } 1475 for (jj = 0; jj < snego.cnt; jj++) { 1476 if (!nfs_getseconfig_bynumber(snego.array[jj], 1477 &nfs_sec)) { 1478 snego_done = TRUE; 1479 if (sec_opt) { 1480 pr_err(gettext( 1481 "Security flavor %d was negotiated and" 1482 " will be used.\n"), 1483 nfs_sec.sc_nfsnum); 1484 } 1485 break; 1486 } 1487 } 1488 } 1489 if (!snego_done) 1490 return (NULL); 1491 1492 /* 1493 * Now that the flavor has been 1494 * negotiated, get the fh. 1495 * 1496 * First, create an auth handle using the negotiated 1497 * sec flavor in the next lookup to 1498 * fetch the filehandle. 1499 */ 1500 new_ah = nfs_create_ah(cl, hostname, &nfs_sec); 1501 if (new_ah == NULL) 1502 goto done; 1503 cl->cl_auth = new_ah; 1504 } else if (sec == SNEGO_ARRAY_TOO_SMALL || sec == 1505 SNEGO_FAILURE) { 1506 goto done; 1507 } 1508 /* 1509 * Note that if sec == SNEGO_DEF_VALID 1510 * default sec flavor is acceptable. 1511 * Use it to get the filehandle. 1512 */ 1513 } 1514 1515 if (vers == NFS_VERSION) { 1516 wnl_diropargs arg; 1517 wnl_diropres *res; 1518 1519 memset((char *)&arg.dir, 0, sizeof (wnl_fh)); 1520 arg.name = fspath; 1521 res = wnlproc_lookup_2(&arg, cl); 1522 1523 if (res == NULL || res->status != NFS_OK) 1524 goto done; 1525 *fhp = malloc(sizeof (wnl_fh)); 1526 1527 if (*fhp == NULL) { 1528 pr_err(gettext("no memory\n")); 1529 goto done; 1530 } 1531 1532 memcpy((char *)*fhp, 1533 (char *)&res->wnl_diropres_u.wnl_diropres.file, 1534 sizeof (wnl_fh)); 1535 } else { 1536 WNL_LOOKUP3args arg; 1537 WNL_LOOKUP3res *res; 1538 nfs_fh3 *fh3p; 1539 1540 memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3)); 1541 arg.what.name = fspath; 1542 res = wnlproc3_lookup_3(&arg, cl); 1543 1544 if (res == NULL || res->status != NFS3_OK) 1545 goto done; 1546 1547 fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p)); 1548 1549 if (fh3p == NULL) { 1550 pr_err(gettext("no memory\n")); 1551 CLNT_FREERES(cl, xdr_WNL_LOOKUP3res, (char *)res); 1552 goto done; 1553 } 1554 1555 fh3p->fh3_length = 1556 res->WNL_LOOKUP3res_u.res_ok.object.data.data_len; 1557 memcpy(fh3p->fh3_u.data, 1558 res->WNL_LOOKUP3res_u.res_ok.object.data.data_val, 1559 fh3p->fh3_length); 1560 1561 *fhp = (caddr_t)fh3p; 1562 1563 CLNT_FREERES(cl, xdr_WNL_LOOKUP3res, (char *)res); 1564 } 1565 } else { 1566 void *res; 1567 struct rpc_err r_err; 1568 1569 if (vers == NFS_VERSION) 1570 res = wnlproc_null_2(NULL, cl); 1571 else if (vers == NFS_V3) 1572 res = wnlproc3_null_3(NULL, cl); 1573 else 1574 res = wnlproc4_null_4(NULL, cl); 1575 1576 if (res == NULL) { 1577 clnt_geterr(cl, &r_err); 1578 if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { 1579 switch (r_err.re_status) { 1580 case RPC_TLIERROR: 1581 case RPC_CANTRECV: 1582 case RPC_CANTSEND: 1583 r_err.re_status = RPC_PROGVERSMISMATCH; 1584 } 1585 } 1586 SET_ERR_RET(error, ERR_RPCERROR, r_err.re_status); 1587 goto done; 1588 } 1589 } 1590 1591 /* 1592 * Make a copy of the netbuf to return 1593 */ 1594 nb = (struct netbuf *)malloc(sizeof (*nb)); 1595 if (nb == NULL) { 1596 pr_err(gettext("no memory\n")); 1597 goto done; 1598 } 1599 *nb = tbind->addr; 1600 nb->buf = (char *)malloc(nb->maxlen); 1601 if (nb->buf == NULL) { 1602 pr_err(gettext("no memory\n")); 1603 free(nb); 1604 nb = NULL; 1605 goto done; 1606 } 1607 (void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len); 1608 1609 done: 1610 if (cl) { 1611 if (ah != NULL) { 1612 if (new_ah != NULL) 1613 AUTH_DESTROY(ah); 1614 AUTH_DESTROY(cl->cl_auth); 1615 cl->cl_auth = NULL; 1616 } 1617 clnt_destroy(cl); 1618 cl = NULL; 1619 } 1620 if (tbind) { 1621 t_free((char *)tbind, T_BIND); 1622 tbind = NULL; 1623 } 1624 if (fd >= 0) 1625 (void) t_close(fd); 1626 return (nb); 1627 } 1628 1629 /* 1630 * Get a network address on "hostname" for program "prog" 1631 * with version "vers". If the port number is specified (non zero) 1632 * then try for a TCP/UDP transport and set the port number of the 1633 * resulting IP address. 1634 * 1635 * If the address of a netconfig pointer was passed and 1636 * if it's not null, use it as the netconfig otherwise 1637 * assign the address of the netconfig that was used to 1638 * establish contact with the service. 1639 * 1640 * A similar routine is also defined in ../../autofs/autod_nfs.c. 1641 * This is a potential routine to move to ../lib for common usage. 1642 * 1643 * "error" refers to a more descriptive term when get_addr fails 1644 * and returns NULL: ERR_PROTO_NONE if no error introduced by 1645 * -o proto option, ERR_NETPATH if error found in NETPATH 1646 * environment variable, ERR_PROTO_INVALID if an unrecognized 1647 * protocol is specified by user, and ERR_PROTO_UNSUPP for a 1648 * recognized but invalid protocol (eg. ticlts, ticots, etc.). 1649 * "error" is ignored if get_addr returns non-NULL result. 1650 * 1651 */ 1652 static struct netbuf * 1653 get_addr(char *hostname, ulong_t prog, ulong_t vers, struct netconfig **nconfp, 1654 char *proto, ushort_t port, struct t_info *tinfo, caddr_t *fhp, 1655 bool_t get_pubfh, char *fspath, err_ret_t *error) 1656 { 1657 struct netbuf *nb = NULL; 1658 struct netconfig *nconf = NULL; 1659 NCONF_HANDLE *nc = NULL; 1660 int nthtry = FIRST_TRY; 1661 err_ret_t errsave_nohost, errsave_rpcerr; 1662 1663 SET_ERR_RET(&errsave_nohost, ERR_PROTO_NONE, 0); 1664 SET_ERR_RET(&errsave_rpcerr, ERR_PROTO_NONE, 0); 1665 1666 SET_ERR_RET(error, ERR_PROTO_NONE, 0); 1667 1668 if (nconfp && *nconfp) 1669 return (get_the_addr(hostname, prog, vers, *nconfp, port, 1670 tinfo, fhp, get_pubfh, fspath, error)); 1671 /* 1672 * No nconf passed in. 1673 * 1674 * Try to get a nconf from /etc/netconfig filtered by 1675 * the NETPATH environment variable. 1676 * First search for COTS, second for CLTS unless proto 1677 * is specified. When we retry, we reset the 1678 * netconfig list so that we would search the whole list 1679 * all over again. 1680 */ 1681 1682 if ((nc = setnetpath()) == NULL) { 1683 /* should only return an error if problems with NETPATH */ 1684 /* In which case you are hosed */ 1685 SET_ERR_RET(error, ERR_NETPATH, 0); 1686 goto done; 1687 } 1688 1689 /* 1690 * If proto is specified, then only search for the match, 1691 * otherwise try COTS first, if failed, try CLTS. 1692 */ 1693 if (proto) { 1694 /* no matching proto name */ 1695 SET_ERR_RET(error, ERR_PROTO_INVALID, 0); 1696 1697 while (nconf = getnetpath(nc)) { 1698 if (strcmp(nconf->nc_netid, proto)) 1699 continue; 1700 1701 /* may be unsupported */ 1702 SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0); 1703 1704 if ((port != 0) && 1705 ((strcmp(nconf->nc_protofmly, NC_INET) == 0 || 1706 strcmp(nconf->nc_protofmly, NC_INET6) == 0) && 1707 (strcmp(nconf->nc_proto, NC_TCP) != 0 && 1708 strcmp(nconf->nc_proto, NC_UDP) != 0))) 1709 1710 continue; 1711 1712 else { 1713 nb = get_the_addr(hostname, prog, 1714 vers, nconf, port, tinfo, 1715 fhp, get_pubfh, fspath, error); 1716 1717 if (nb != NULL) 1718 break; 1719 1720 /* nb is NULL - deal with errors */ 1721 if (error) { 1722 if (error->error_type == ERR_NOHOST) 1723 SET_ERR_RET(&errsave_nohost, 1724 error->error_type, 1725 error->error_value); 1726 if (error->error_type == ERR_RPCERROR) 1727 SET_ERR_RET(&errsave_rpcerr, 1728 error->error_type, 1729 error->error_value); 1730 } 1731 /* 1732 * continue with same protocol 1733 * selection 1734 */ 1735 continue; 1736 } 1737 } /* end of while */ 1738 1739 if (nconf == NULL) 1740 goto done; 1741 1742 if ((nb = get_the_addr(hostname, prog, vers, nconf, port, 1743 tinfo, fhp, get_pubfh, fspath, error)) == NULL) 1744 goto done; 1745 1746 1747 } else { 1748 retry: 1749 SET_ERR_RET(error, ERR_NETPATH, 0); 1750 while (nconf = getnetpath(nc)) { 1751 SET_ERR_RET(error, ERR_PROTO_NONE, 0); 1752 if (nconf->nc_flag & NC_VISIBLE) { 1753 if (nthtry == FIRST_TRY) { 1754 if ((nconf->nc_semantics == 1755 NC_TPI_COTS_ORD) || 1756 (nconf->nc_semantics == 1757 NC_TPI_COTS)) { 1758 1759 if (port == 0) 1760 break; 1761 1762 if ((strcmp(nconf->nc_protofmly, 1763 NC_INET) == 0 || 1764 strcmp(nconf-> 1765 nc_protofmly, 1766 NC_INET6) == 0) && 1767 (strcmp(nconf->nc_proto, 1768 NC_TCP) == 0)) 1769 1770 break; 1771 } 1772 } 1773 if (nthtry == SECOND_TRY) { 1774 if (nconf->nc_semantics == 1775 NC_TPI_CLTS) { 1776 if (port == 0) 1777 break; 1778 if ((strcmp(nconf->nc_protofmly, 1779 NC_INET) == 0 || 1780 strcmp(nconf-> 1781 nc_protofmly, NC_INET6) 1782 == 0) && 1783 (strcmp( 1784 nconf->nc_proto, 1785 NC_UDP) == 0)) 1786 break; 1787 } 1788 } 1789 } 1790 } /* while */ 1791 if (nconf == NULL) { 1792 if (++nthtry <= MNT_PREF_LISTLEN) { 1793 endnetpath(nc); 1794 if ((nc = setnetpath()) == NULL) 1795 goto done; 1796 goto retry; 1797 } else 1798 goto done; 1799 } else { 1800 if ((nb = get_the_addr(hostname, prog, vers, nconf, 1801 port, tinfo, fhp, get_pubfh, fspath, error)) 1802 == NULL) { 1803 /* nb is NULL - deal with errors */ 1804 if (error) { 1805 if (error->error_type == ERR_NOHOST) 1806 SET_ERR_RET(&errsave_nohost, 1807 error->error_type, 1808 error->error_value); 1809 if (error->error_type == ERR_RPCERROR) 1810 SET_ERR_RET(&errsave_rpcerr, 1811 error->error_type, 1812 error->error_value); 1813 } 1814 /* 1815 * Continue the same search path in the 1816 * netconfig db until no more matched 1817 * nconf (nconf == NULL). 1818 */ 1819 goto retry; 1820 } 1821 } 1822 } 1823 SET_ERR_RET(error, ERR_PROTO_NONE, 0); 1824 1825 /* 1826 * Got nconf and nb. Now dup the netconfig structure (nconf) 1827 * and return it thru nconfp. 1828 */ 1829 *nconfp = getnetconfigent(nconf->nc_netid); 1830 if (*nconfp == NULL) { 1831 syslog(LOG_ERR, "no memory\n"); 1832 free(nb); 1833 nb = NULL; 1834 } 1835 done: 1836 if (nc) 1837 endnetpath(nc); 1838 1839 if (nb == NULL) { 1840 /* 1841 * Check the saved errors. The RPC error has * 1842 * precedence over the no host error. 1843 */ 1844 if (errsave_nohost.error_type != ERR_PROTO_NONE) 1845 SET_ERR_RET(error, errsave_nohost.error_type, 1846 errsave_nohost.error_value); 1847 1848 if (errsave_rpcerr.error_type != ERR_PROTO_NONE) 1849 SET_ERR_RET(error, errsave_rpcerr.error_type, 1850 errsave_rpcerr.error_value); 1851 } 1852 1853 return (nb); 1854 } 1855 1856 /* 1857 * Get a file handle usinging multi-component lookup with the public 1858 * file handle. 1859 */ 1860 static int 1861 get_fh_via_pub(struct nfs_args *args, char *fshost, char *fspath, bool_t url, 1862 bool_t loud, int *versp, struct netconfig **nconfp, ushort_t port) 1863 { 1864 uint_t vers_min; 1865 uint_t vers_max; 1866 int r; 1867 char *path; 1868 1869 if (nfsvers != 0) { 1870 vers_max = vers_min = nfsvers; 1871 } else { 1872 vers_max = vers_max_default; 1873 vers_min = vers_min_default; 1874 } 1875 1876 if (url == FALSE) { 1877 path = malloc(strlen(fspath) + 2); 1878 if (path == NULL) { 1879 if (loud == TRUE) { 1880 pr_err(gettext("no memory\n")); 1881 } 1882 return (RET_ERR); 1883 } 1884 1885 path[0] = (char)WNL_NATIVEPATH; 1886 (void) strcpy(&path[1], fspath); 1887 1888 } else { 1889 path = fspath; 1890 } 1891 1892 for (nfsvers_to_use = vers_max; nfsvers_to_use >= vers_min; 1893 nfsvers_to_use--) { 1894 /* 1895 * getaddr_nfs will also fill in the fh for us. 1896 */ 1897 r = getaddr_nfs(args, fshost, nconfp, 1898 TRUE, path, port, NULL, FALSE); 1899 1900 if (r == RET_OK) { 1901 /* 1902 * Since we are using the public fh, and NLM is 1903 * not firewall friendly, use local locking. 1904 * Not the case for v4. 1905 */ 1906 *versp = nfsvers_to_use; 1907 switch (nfsvers_to_use) { 1908 case NFS_V4: 1909 fstype = MNTTYPE_NFS4; 1910 break; 1911 case NFS_V3: 1912 fstype = MNTTYPE_NFS3; 1913 /* fall through to pick up llock option */ 1914 default: 1915 args->flags |= NFSMNT_LLOCK; 1916 break; 1917 } 1918 if (fspath != path) 1919 free(path); 1920 1921 return (r); 1922 } 1923 } 1924 1925 if (fspath != path) { 1926 free(path); 1927 } 1928 1929 if (loud == TRUE) { 1930 pr_err(gettext("Could not use public filehandle in request to" 1931 " server %s\n"), fshost); 1932 } 1933 1934 return (r); 1935 } 1936 1937 /* 1938 * get fhandle of remote path from server's mountd 1939 */ 1940 static int 1941 get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp, 1942 bool_t loud_on_mnt_err, struct netconfig **nconfp, ushort_t port) 1943 { 1944 static struct fhstatus fhs; 1945 static struct mountres3 mountres3; 1946 static struct pathcnf p; 1947 nfs_fh3 *fh3p; 1948 struct timeval timeout = { 25, 0}; 1949 CLIENT *cl; 1950 enum clnt_stat rpc_stat; 1951 rpcvers_t outvers = 0; 1952 rpcvers_t vers_to_try; 1953 rpcvers_t vers_min; 1954 static int printed = 0; 1955 int count, i, *auths; 1956 char *msg; 1957 1958 switch (nfsvers) { 1959 case 2: /* version 2 specified try that only */ 1960 vers_to_try = MOUNTVERS_POSIX; 1961 vers_min = MOUNTVERS; 1962 break; 1963 case 3: /* version 3 specified try that only */ 1964 vers_to_try = MOUNTVERS3; 1965 vers_min = MOUNTVERS3; 1966 break; 1967 case 4: /* version 4 specified try that only */ 1968 /* 1969 * This assignment is in the wrong version sequence. 1970 * The above are MOUNT program and this is NFS 1971 * program. However, it happens to work out since the 1972 * two don't collide for NFSv4. 1973 */ 1974 vers_to_try = NFS_V4; 1975 vers_min = NFS_V4; 1976 break; 1977 default: /* no version specified, start with default */ 1978 vers_to_try = vers_max_default; 1979 vers_min = vers_min_default; 1980 break; 1981 } 1982 1983 /* 1984 * In the case of version 4, just NULL proc the server since 1985 * there is no MOUNT program. If this fails, then decrease 1986 * vers_to_try and continue on with regular MOUNT program 1987 * processing. 1988 */ 1989 if (vers_to_try == NFS_V4) { 1990 int savevers = nfsvers_to_use; 1991 err_ret_t error; 1992 int retval; 1993 SET_ERR_RET(&error, ERR_PROTO_NONE, 0); 1994 1995 /* Let's hope for the best */ 1996 nfsvers_to_use = NFS_V4; 1997 retval = 1998 getaddr_nfs(args, fshost, nconfp, FALSE, 1999 fspath, port, &error, vers_min == NFS_V4); 2000 2001 if (retval == RET_OK) { 2002 *versp = nfsvers_to_use = NFS_V4; 2003 fstype = MNTTYPE_NFS4; 2004 args->fh = strdup(fspath); 2005 if (args->fh == NULL) { 2006 pr_err(gettext("no memory\n")); 2007 *versp = nfsvers_to_use = savevers; 2008 return (RET_ERR); 2009 } 2010 return (RET_OK); 2011 } 2012 nfsvers_to_use = savevers; 2013 2014 vers_to_try--; 2015 /* If no more versions to try, let the user know. */ 2016 if (vers_to_try < vers_min) { 2017 return (retval); 2018 } 2019 2020 /* 2021 * If we are here, there are more versions to try but 2022 * there has been an error of some sort. If it is not 2023 * an RPC error (e.g. host unknown), we just stop and 2024 * return the error since the other versions would see 2025 * the same error as well. 2026 */ 2027 if (retval == RET_ERR && error.error_type != ERR_RPCERROR) 2028 return (retval); 2029 } 2030 2031 while ((cl = clnt_create_vers(fshost, MOUNTPROG, &outvers, 2032 vers_min, vers_to_try, "datagram_v")) == NULL) { 2033 if (rpc_createerr.cf_stat == RPC_UNKNOWNHOST) { 2034 pr_err(gettext("%s: %s\n"), fshost, 2035 clnt_spcreateerror("")); 2036 return (RET_ERR); 2037 } 2038 2039 /* 2040 * We don't want to downgrade version on lost packets 2041 */ 2042 if ((rpc_createerr.cf_stat == RPC_TIMEDOUT) || 2043 (rpc_createerr.cf_stat == RPC_PMAPFAILURE)) { 2044 pr_err(gettext("%s: %s\n"), fshost, 2045 clnt_spcreateerror("")); 2046 return (RET_RETRY); 2047 } 2048 2049 /* 2050 * back off and try the previous version - patch to the 2051 * problem of version numbers not being contigous and 2052 * clnt_create_vers failing (SunOS4.1 clients & SGI servers) 2053 * The problem happens with most non-Sun servers who 2054 * don't support mountd protocol #2. So, in case the 2055 * call fails, we re-try the call anyway. 2056 */ 2057 vers_to_try--; 2058 if (vers_to_try < vers_min) { 2059 if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH) { 2060 if (nfsvers == 0) { 2061 pr_err(gettext( 2062 "%s:%s: no applicable versions of NFS supported\n"), 2063 fshost, fspath); 2064 } else { 2065 pr_err(gettext( 2066 "%s:%s: NFS Version %d not supported\n"), 2067 fshost, fspath, nfsvers); 2068 } 2069 return (RET_ERR); 2070 } 2071 if (!printed) { 2072 pr_err(gettext("%s: %s\n"), fshost, 2073 clnt_spcreateerror("")); 2074 printed = 1; 2075 } 2076 return (RET_RETRY); 2077 } 2078 } 2079 if (posix && outvers < MOUNTVERS_POSIX) { 2080 pr_err(gettext("%s: %s: no pathconf info\n"), 2081 fshost, clnt_sperror(cl, "")); 2082 clnt_destroy(cl); 2083 return (RET_ERR); 2084 } 2085 2086 if (__clnt_bindresvport(cl) < 0) { 2087 pr_err(gettext("Couldn't bind to reserved port\n")); 2088 clnt_destroy(cl); 2089 return (RET_RETRY); 2090 } 2091 2092 if ((cl->cl_auth = authsys_create_default()) == NULL) { 2093 pr_err( 2094 gettext("Couldn't create default authentication handle\n")); 2095 clnt_destroy(cl); 2096 return (RET_RETRY); 2097 } 2098 2099 switch (outvers) { 2100 case MOUNTVERS: 2101 case MOUNTVERS_POSIX: 2102 *versp = nfsvers_to_use = NFS_VERSION; 2103 rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath, 2104 (caddr_t)&fspath, xdr_fhstatus, (caddr_t)&fhs, timeout); 2105 if (rpc_stat != RPC_SUCCESS) { 2106 pr_err(gettext("%s:%s: server not responding %s\n"), 2107 fshost, fspath, clnt_sperror(cl, "")); 2108 clnt_destroy(cl); 2109 return (RET_RETRY); 2110 } 2111 2112 if ((errno = fhs.fhs_status) != MNT_OK) { 2113 if (loud_on_mnt_err) { 2114 if (errno == EACCES) { 2115 pr_err(gettext("%s:%s: access denied\n"), 2116 fshost, fspath); 2117 } else { 2118 pr_err(gettext("%s:%s: %s\n"), fshost, fspath, 2119 strerror(errno)); 2120 } 2121 } 2122 clnt_destroy(cl); 2123 return (RET_MNTERR); 2124 } 2125 args->fh = malloc(sizeof (fhs.fhstatus_u.fhs_fhandle)); 2126 if (args->fh == NULL) { 2127 pr_err(gettext("no memory\n")); 2128 return (RET_ERR); 2129 } 2130 memcpy((caddr_t)args->fh, (caddr_t)&fhs.fhstatus_u.fhs_fhandle, 2131 sizeof (fhs.fhstatus_u.fhs_fhandle)); 2132 if (!errno && posix) { 2133 rpc_stat = clnt_call(cl, MOUNTPROC_PATHCONF, 2134 xdr_dirpath, (caddr_t)&fspath, xdr_ppathcnf, 2135 (caddr_t)&p, timeout); 2136 if (rpc_stat != RPC_SUCCESS) { 2137 pr_err(gettext( 2138 "%s:%s: server not responding %s\n"), 2139 fshost, fspath, clnt_sperror(cl, "")); 2140 free(args->fh); 2141 clnt_destroy(cl); 2142 return (RET_RETRY); 2143 } 2144 if (_PC_ISSET(_PC_ERROR, p.pc_mask)) { 2145 pr_err(gettext( 2146 "%s:%s: no pathconf info\n"), 2147 fshost, fspath); 2148 free(args->fh); 2149 clnt_destroy(cl); 2150 return (RET_ERR); 2151 } 2152 args->flags |= NFSMNT_POSIX; 2153 args->pathconf = malloc(sizeof (p)); 2154 if (args->pathconf == NULL) { 2155 pr_err(gettext("no memory\n")); 2156 free(args->fh); 2157 clnt_destroy(cl); 2158 return (RET_ERR); 2159 } 2160 memcpy((caddr_t)args->pathconf, (caddr_t)&p, 2161 sizeof (p)); 2162 } 2163 break; 2164 2165 case MOUNTVERS3: 2166 *versp = nfsvers_to_use = NFS_V3; 2167 rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath, 2168 (caddr_t)&fspath, 2169 xdr_mountres3, (caddr_t)&mountres3, timeout); 2170 if (rpc_stat != RPC_SUCCESS) { 2171 pr_err(gettext("%s:%s: server not responding %s\n"), 2172 fshost, fspath, clnt_sperror(cl, "")); 2173 clnt_destroy(cl); 2174 return (RET_RETRY); 2175 } 2176 2177 /* 2178 * Assume here that most of the MNT3ERR_* 2179 * codes map into E* errors. 2180 */ 2181 if ((errno = mountres3.fhs_status) != MNT_OK) { 2182 if (loud_on_mnt_err) { 2183 switch (errno) { 2184 case MNT3ERR_NAMETOOLONG: 2185 msg = "path name is too long"; 2186 break; 2187 case MNT3ERR_NOTSUPP: 2188 msg = "operation not supported"; 2189 break; 2190 case MNT3ERR_SERVERFAULT: 2191 msg = "server fault"; 2192 break; 2193 default: 2194 msg = strerror(errno); 2195 break; 2196 } 2197 pr_err(gettext("%s:%s: %s\n"), fshost, fspath, msg); 2198 } 2199 clnt_destroy(cl); 2200 return (RET_MNTERR); 2201 } 2202 2203 fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p)); 2204 if (fh3p == NULL) { 2205 pr_err(gettext("no memory\n")); 2206 return (RET_ERR); 2207 } 2208 fh3p->fh3_length = 2209 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len; 2210 (void) memcpy(fh3p->fh3_u.data, 2211 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val, 2212 fh3p->fh3_length); 2213 args->fh = (caddr_t)fh3p; 2214 fstype = MNTTYPE_NFS3; 2215 2216 /* 2217 * Check the security flavor to be used. 2218 * 2219 * If "secure" or "sec=flavor" is a mount 2220 * option, check if the server supports the "flavor". 2221 * If the server does not support the flavor, return 2222 * error. 2223 * 2224 * If no mount option is given then use the first supported 2225 * security flavor (by the client) in the auth list returned 2226 * from the server. 2227 * 2228 */ 2229 auths = 2230 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val; 2231 count = 2232 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len; 2233 2234 if (sec_opt) { 2235 for (i = 0; i < count; i++) { 2236 if (auths[i] == nfs_sec.sc_nfsnum) 2237 break; 2238 } 2239 if (i >= count) { 2240 goto autherr; 2241 } 2242 } else { 2243 if (count > 0) { 2244 for (i = 0; i < count; i++) { 2245 if (!nfs_getseconfig_bynumber(auths[i], &nfs_sec)) { 2246 sec_opt++; 2247 break; 2248 } 2249 } 2250 if (i >= count) { 2251 goto autherr; 2252 } 2253 } 2254 } 2255 break; 2256 default: 2257 pr_err(gettext("%s:%s: Unknown MOUNT version %d\n"), 2258 fshost, fspath, outvers); 2259 clnt_destroy(cl); 2260 return (RET_ERR); 2261 } 2262 2263 clnt_destroy(cl); 2264 return (RET_OK); 2265 2266 autherr: 2267 pr_err(gettext( 2268 "security mode does not match the server exporting %s:%s\n"), 2269 fshost, fspath); 2270 clnt_destroy(cl); 2271 return (RET_ERR); 2272 } 2273 2274 /* 2275 * Fill in the address for the server's NFS service and 2276 * fill in a knetconfig structure for the transport that 2277 * the service is available on. 2278 */ 2279 static int 2280 getaddr_nfs(struct nfs_args *args, char *fshost, struct netconfig **nconfp, 2281 bool_t get_pubfh, char *fspath, ushort_t port, err_ret_t *error, 2282 bool_t print_rpcerror) 2283 { 2284 struct stat sb; 2285 struct netconfig *nconf; 2286 struct knetconfig *knconfp; 2287 static int printed = 0; 2288 struct t_info tinfo; 2289 err_ret_t addr_error; 2290 2291 SET_ERR_RET(error, ERR_PROTO_NONE, 0); 2292 SET_ERR_RET(&addr_error, ERR_PROTO_NONE, 0); 2293 2294 if (nfs_proto) { 2295 /* 2296 * If a proto is specified and its rdma try this. The kernel 2297 * will later do the reachablity test and fail form there 2298 * if rdma transport is not available to kernel rpc 2299 */ 2300 if (strcmp(nfs_proto, "rdma") == 0) { 2301 args->addr = get_addr(fshost, NFS_PROGRAM, 2302 nfsvers_to_use, nconfp, NULL, port, &tinfo, 2303 &args->fh, get_pubfh, fspath, &addr_error); 2304 2305 args->flags |= NFSMNT_DORDMA; 2306 } else { 2307 args->addr = get_addr(fshost, NFS_PROGRAM, 2308 nfsvers_to_use, nconfp, nfs_proto, port, &tinfo, 2309 &args->fh, get_pubfh, fspath, &addr_error); 2310 } 2311 } else { 2312 args->addr = get_addr(fshost, NFS_PROGRAM, nfsvers_to_use, 2313 nconfp, nfs_proto, port, &tinfo, &args->fh, get_pubfh, 2314 fspath, &addr_error); 2315 /* 2316 * If no proto is specified set this flag. 2317 * Kernel mount code will try to use RDMA if its on the 2318 * system, otherwise it will keep on using the protocol 2319 * selected here, through the above get_addr call. 2320 */ 2321 if (nfs_proto == NULL) 2322 args->flags |= NFSMNT_TRYRDMA; 2323 } 2324 2325 if (args->addr == NULL) { 2326 /* 2327 * We could have failed because the server had no public 2328 * file handle support. So don't print a message and don't 2329 * retry. 2330 */ 2331 if (get_pubfh == TRUE) 2332 return (RET_ERR); 2333 2334 if (!printed) { 2335 switch (addr_error.error_type) { 2336 case 0: 2337 break; 2338 case ERR_RPCERROR: 2339 if (!print_rpcerror) 2340 /* no error print at this time */ 2341 break; 2342 pr_err(gettext("%s NFS service not" 2343 " available %s\n"), fshost, 2344 clnt_sperrno(addr_error.error_value)); 2345 break; 2346 case ERR_NETPATH: 2347 pr_err(gettext("%s: Error in NETPATH.\n"), 2348 fshost); 2349 break; 2350 case ERR_PROTO_INVALID: 2351 pr_err(gettext("%s: NFS service does not" 2352 " recognize protocol: %s.\n"), fshost, 2353 nfs_proto); 2354 break; 2355 case ERR_PROTO_UNSUPP: 2356 if (nfsvers_to_use == NFS_VERSMIN) { 2357 /* 2358 * Print this message after we have 2359 * tried all versions of NFS and none 2360 * support the asked transport. 2361 * Otherwise we depricate the version 2362 * and retry below. 2363 */ 2364 pr_err(gettext("%s: NFS service does" 2365 " not support protocol: %s.\n"), 2366 fshost, nfs_proto); 2367 } 2368 break; 2369 case ERR_NOHOST: 2370 pr_err("%s: %s\n", fshost, "Unknown host"); 2371 break; 2372 default: 2373 /* case ERR_PROTO_NONE falls through */ 2374 pr_err(gettext("%s: NFS service not responding" 2375 "\n"), fshost); 2376 break; 2377 } 2378 printed = 1; 2379 } 2380 SET_ERR_RET(error, 2381 addr_error.error_type, addr_error.error_value); 2382 if (addr_error.error_type == ERR_PROTO_NONE) 2383 return (RET_RETRY); 2384 else if (addr_error.error_type == ERR_RPCERROR && 2385 ! IS_UNRECOVERABLE_RPC(addr_error.error_value)) { 2386 return (RET_RETRY); 2387 } else if (nfsvers == 0 && addr_error.error_type == 2388 ERR_PROTO_UNSUPP && nfsvers_to_use != NFS_VERSMIN) { 2389 /* 2390 * If no version is specified, and the error is due 2391 * to an unsupported transport, then depricate the 2392 * version and retry. 2393 */ 2394 return (RET_RETRY); 2395 } else 2396 return (RET_ERR); 2397 } 2398 nconf = *nconfp; 2399 2400 if (stat(nconf->nc_device, &sb) < 0) { 2401 pr_err(gettext("getaddr_nfs: couldn't stat: %s: %s\n"), 2402 nconf->nc_device, strerror(errno)); 2403 return (RET_ERR); 2404 } 2405 2406 knconfp = (struct knetconfig *)malloc(sizeof (*knconfp)); 2407 if (!knconfp) { 2408 pr_err(gettext("no memory\n")); 2409 return (RET_ERR); 2410 } 2411 knconfp->knc_semantics = nconf->nc_semantics; 2412 knconfp->knc_protofmly = nconf->nc_protofmly; 2413 knconfp->knc_proto = nconf->nc_proto; 2414 knconfp->knc_rdev = sb.st_rdev; 2415 2416 /* make sure we don't overload the transport */ 2417 if (tinfo.tsdu > 0 && tinfo.tsdu < NFS_MAXDATA + NFS_RPC_HDR) { 2418 args->flags |= (NFSMNT_RSIZE | NFSMNT_WSIZE); 2419 if (args->rsize == 0 || args->rsize > tinfo.tsdu - NFS_RPC_HDR) 2420 args->rsize = tinfo.tsdu - NFS_RPC_HDR; 2421 if (args->wsize == 0 || args->wsize > tinfo.tsdu - NFS_RPC_HDR) 2422 args->wsize = tinfo.tsdu - NFS_RPC_HDR; 2423 } 2424 2425 args->flags |= NFSMNT_KNCONF; 2426 args->knconf = knconfp; 2427 return (RET_OK); 2428 } 2429 2430 static int 2431 retry(struct mnttab *mntp, int ro) 2432 { 2433 int delay = 5; 2434 int count = retries; 2435 int r; 2436 2437 if (bg) { 2438 if (fork() > 0) 2439 return (RET_OK); 2440 pr_err(gettext("backgrounding: %s\n"), mntp->mnt_mountp); 2441 backgrounded = 1; 2442 } else 2443 pr_err(gettext("retrying: %s\n"), mntp->mnt_mountp); 2444 2445 while (count--) { 2446 if ((r = mount_nfs(mntp, ro)) == RET_OK) { 2447 pr_err(gettext("%s: mounted OK\n"), mntp->mnt_mountp); 2448 return (RET_OK); 2449 } 2450 if (r != RET_RETRY) 2451 break; 2452 2453 if (count > 0) { 2454 (void) sleep(delay); 2455 delay *= 2; 2456 if (delay > 120) 2457 delay = 120; 2458 } 2459 } 2460 pr_err(gettext("giving up on: %s\n"), mntp->mnt_mountp); 2461 return (RET_ERR); 2462 } 2463 2464 /* 2465 * Read the /etc/default/nfs configuration file to determine if the 2466 * client has been configured for a new min/max for the NFS version to 2467 * use. 2468 */ 2469 static void 2470 read_default(void) 2471 { 2472 char *defval; 2473 int errno; 2474 int tmp; 2475 2476 /* Fail silently if error in opening the default nfs config file */ 2477 if ((defopen(NFSADMIN)) == 0) { 2478 if ((defval = defread("NFS_CLIENT_VERSMIN=")) != NULL) { 2479 errno = 0; 2480 tmp = strtol(defval, (char **)NULL, 10); 2481 if (errno == 0) { 2482 vers_min_default = tmp; 2483 } 2484 } 2485 if ((defval = defread("NFS_CLIENT_VERSMAX=")) != NULL) { 2486 errno = 0; 2487 tmp = strtol(defval, (char **)NULL, 10); 2488 if (errno == 0) { 2489 vers_max_default = tmp; 2490 } 2491 } 2492 /* close defaults file */ 2493 defopen(NULL); 2494 } 2495 } 2496 2497 static void 2498 sigusr1(int s) 2499 { 2500 } 2501