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