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