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