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