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