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