10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 53378Srica * Common Development and Distribution License (the "License"). 63378Srica * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 215655Sth199096 220Sstevel@tonic-gate /* 23*12782SMarcel.Telka@Sun.COM * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 270Sstevel@tonic-gate /* All Rights Reserved */ 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988 310Sstevel@tonic-gate * The Regents of the University of California 320Sstevel@tonic-gate * All Rights Reserved 330Sstevel@tonic-gate * 340Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from 350Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 360Sstevel@tonic-gate * contributors. 370Sstevel@tonic-gate */ 380Sstevel@tonic-gate 390Sstevel@tonic-gate /* 400Sstevel@tonic-gate * nfs mount 410Sstevel@tonic-gate */ 420Sstevel@tonic-gate 430Sstevel@tonic-gate #define NFSCLIENT 440Sstevel@tonic-gate #include <locale.h> 450Sstevel@tonic-gate #include <stdio.h> 460Sstevel@tonic-gate #include <string.h> 470Sstevel@tonic-gate #include <memory.h> 480Sstevel@tonic-gate #include <stdarg.h> 490Sstevel@tonic-gate #include <unistd.h> 500Sstevel@tonic-gate #include <ctype.h> 510Sstevel@tonic-gate #include <stdlib.h> 520Sstevel@tonic-gate #include <signal.h> 530Sstevel@tonic-gate #include <sys/param.h> 540Sstevel@tonic-gate #include <rpc/rpc.h> 550Sstevel@tonic-gate #include <errno.h> 560Sstevel@tonic-gate #include <sys/stat.h> 570Sstevel@tonic-gate #include <netdb.h> 580Sstevel@tonic-gate #include <sys/mount.h> 590Sstevel@tonic-gate #include <sys/mntent.h> 600Sstevel@tonic-gate #include <sys/mnttab.h> 610Sstevel@tonic-gate #include <nfs/nfs.h> 620Sstevel@tonic-gate #include <nfs/mount.h> 630Sstevel@tonic-gate #include <rpcsvc/mount.h> 640Sstevel@tonic-gate #include <sys/pathconf.h> 650Sstevel@tonic-gate #include <netdir.h> 660Sstevel@tonic-gate #include <netconfig.h> 670Sstevel@tonic-gate #include <sys/sockio.h> 680Sstevel@tonic-gate #include <net/if.h> 690Sstevel@tonic-gate #include <syslog.h> 700Sstevel@tonic-gate #include <fslib.h> 710Sstevel@tonic-gate #include <deflt.h> 720Sstevel@tonic-gate #include <sys/wait.h> 730Sstevel@tonic-gate #include "replica.h" 740Sstevel@tonic-gate #include <netinet/in.h> 750Sstevel@tonic-gate #include <nfs/nfs_sec.h> 760Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h> 770Sstevel@tonic-gate #include <priv.h> 783378Srica #include <tsol/label.h> 790Sstevel@tonic-gate #include "nfs_subr.h" 800Sstevel@tonic-gate #include "webnfs.h" 810Sstevel@tonic-gate #include <rpcsvc/nfs4_prot.h> 82*12782SMarcel.Telka@Sun.COM #include <limits.h> 830Sstevel@tonic-gate 845302Sth199096 #include <nfs/nfssys.h> 855302Sth199096 extern int _nfssys(enum nfssys_op, void *); 865302Sth199096 870Sstevel@tonic-gate #ifndef NFS_VERSMAX 880Sstevel@tonic-gate #define NFS_VERSMAX 4 890Sstevel@tonic-gate #endif 900Sstevel@tonic-gate #ifndef NFS_VERSMIN 910Sstevel@tonic-gate #define NFS_VERSMIN 2 920Sstevel@tonic-gate #endif 930Sstevel@tonic-gate 940Sstevel@tonic-gate #define RET_OK 0 950Sstevel@tonic-gate #define RET_RETRY 32 960Sstevel@tonic-gate #define RET_ERR 33 970Sstevel@tonic-gate #define RET_MNTERR 1000 980Sstevel@tonic-gate #define ERR_PROTO_NONE 0 990Sstevel@tonic-gate #define ERR_PROTO_INVALID 901 1000Sstevel@tonic-gate #define ERR_PROTO_UNSUPP 902 1010Sstevel@tonic-gate #define ERR_NETPATH 903 1020Sstevel@tonic-gate #define ERR_NOHOST 904 1030Sstevel@tonic-gate #define ERR_RPCERROR 905 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate typedef struct err_ret { 1060Sstevel@tonic-gate int error_type; 1070Sstevel@tonic-gate int error_value; 1080Sstevel@tonic-gate } err_ret_t; 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate #define SET_ERR_RET(errst, etype, eval) \ 1110Sstevel@tonic-gate if (errst) { \ 1120Sstevel@tonic-gate (errst)->error_type = etype; \ 1130Sstevel@tonic-gate (errst)->error_value = eval; \ 1140Sstevel@tonic-gate } 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate /* number of transports to try */ 1170Sstevel@tonic-gate #define MNT_PREF_LISTLEN 2 1180Sstevel@tonic-gate #define FIRST_TRY 1 1190Sstevel@tonic-gate #define SECOND_TRY 2 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate #define BIGRETRY 10000 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate /* maximum length of RPC header for NFS messages */ 1240Sstevel@tonic-gate #define NFS_RPC_HDR 432 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate #define NFS_ARGS_EXTB_secdata(args, secdata) \ 1270Sstevel@tonic-gate { (args)->nfs_args_ext = NFS_ARGS_EXTB, \ 1280Sstevel@tonic-gate (args)->nfs_ext_u.nfs_extB.secdata = secdata; } 1290Sstevel@tonic-gate 1305655Sth199096 extern int __clnt_bindresvport(CLIENT *); 1310Sstevel@tonic-gate extern char *nfs_get_qop_name(); 1320Sstevel@tonic-gate extern AUTH * nfs_create_ah(); 1330Sstevel@tonic-gate extern enum snego_stat nfs_sec_nego(); 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate static void usage(void); 1360Sstevel@tonic-gate static int retry(struct mnttab *, int); 1370Sstevel@tonic-gate static int set_args(int *, struct nfs_args *, char *, struct mnttab *); 1380Sstevel@tonic-gate static int get_fh_via_pub(struct nfs_args *, char *, char *, bool_t, bool_t, 1390Sstevel@tonic-gate int *, struct netconfig **, ushort_t); 1400Sstevel@tonic-gate static int get_fh(struct nfs_args *, char *, char *, int *, bool_t, 1410Sstevel@tonic-gate struct netconfig **, ushort_t); 1420Sstevel@tonic-gate static int make_secure(struct nfs_args *, char *, struct netconfig *, 1430Sstevel@tonic-gate bool_t, rpcvers_t); 144489Soa138391 static int mount_nfs(struct mnttab *, int, err_ret_t *); 1450Sstevel@tonic-gate static int getaddr_nfs(struct nfs_args *, char *, struct netconfig **, 1460Sstevel@tonic-gate bool_t, char *, ushort_t, err_ret_t *, bool_t); 1470Sstevel@tonic-gate static void pr_err(const char *fmt, ...); 1480Sstevel@tonic-gate static void usage(void); 1490Sstevel@tonic-gate static struct netbuf *get_addr(char *, rpcprog_t, rpcvers_t, 1500Sstevel@tonic-gate struct netconfig **, char *, ushort_t, struct t_info *, 1510Sstevel@tonic-gate caddr_t *, bool_t, char *, err_ret_t *); 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate static struct netbuf *get_the_addr(char *, rpcprog_t, rpcvers_t, 1540Sstevel@tonic-gate struct netconfig *, ushort_t, struct t_info *, caddr_t *, 1550Sstevel@tonic-gate bool_t, char *, err_ret_t *); 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate extern int self_check(char *); 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate static void read_default(void); 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate static char typename[64]; 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate static int bg = 0; 1640Sstevel@tonic-gate static int backgrounded = 0; 1650Sstevel@tonic-gate static int posix = 0; 1660Sstevel@tonic-gate static int retries = BIGRETRY; 1670Sstevel@tonic-gate static ushort_t nfs_port = 0; 1680Sstevel@tonic-gate static char *nfs_proto = NULL; 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate static int mflg = 0; 1710Sstevel@tonic-gate static int Oflg = 0; /* Overlay mounts */ 1720Sstevel@tonic-gate static int qflg = 0; /* quiet - don't print warnings on bad options */ 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate static char *fstype = MNTTYPE_NFS; 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate static seconfig_t nfs_sec; 1770Sstevel@tonic-gate static int sec_opt = 0; /* any security option ? */ 1780Sstevel@tonic-gate static bool_t snego_done; 1790Sstevel@tonic-gate static void sigusr1(int); 1800Sstevel@tonic-gate 1815302Sth199096 extern void set_nfsv4_ephemeral_mount_to(void); 1825302Sth199096 1830Sstevel@tonic-gate /* 1840Sstevel@tonic-gate * list of support services needed 1850Sstevel@tonic-gate */ 1860Sstevel@tonic-gate static char *service_list[] = { STATD, LOCKD, NULL }; 1870Sstevel@tonic-gate static char *service_list_v4[] = { STATD, LOCKD, NFS4CBD, NFSMAPID, NULL }; 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate /* 1900Sstevel@tonic-gate * These two variables control the NFS version number to be used. 1910Sstevel@tonic-gate * 1920Sstevel@tonic-gate * nfsvers defaults to 0 which means to use the highest number that 1930Sstevel@tonic-gate * both the client and the server support. It can also be set to 1940Sstevel@tonic-gate * a particular value, either 2, 3, or 4 to indicate the version 1950Sstevel@tonic-gate * number of choice. If the server (or the client) do not support 1960Sstevel@tonic-gate * the version indicated, then the mount attempt will be failed. 1970Sstevel@tonic-gate * 1980Sstevel@tonic-gate * nfsvers_to_use is the actual version number found to use. It 1990Sstevel@tonic-gate * is determined in get_fh by pinging the various versions of the 2000Sstevel@tonic-gate * NFS service on the server to see which responds positively. 201489Soa138391 * 202489Soa138391 * nfsretry_vers is the version number set when we retry the mount 203489Soa138391 * command with the version decremented from nfsvers_to_use. 204489Soa138391 * nfsretry_vers is set from nfsvers_to_use when we retry the mount 205489Soa138391 * for errors other than RPC errors; it helps un know why we are 206489Soa138391 * retrying. It is an indication that the retry is due to 207489Soa138391 * non-RPC errors. 2080Sstevel@tonic-gate */ 2090Sstevel@tonic-gate static rpcvers_t nfsvers = 0; 2100Sstevel@tonic-gate static rpcvers_t nfsvers_to_use = 0; 211489Soa138391 static rpcvers_t nfsretry_vers = 0; 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate /* 2140Sstevel@tonic-gate * There are the defaults (range) for the client when determining 2150Sstevel@tonic-gate * which NFS version to use when probing the server (see above). 2160Sstevel@tonic-gate * These will only be used when the vers mount option is not used and 2170Sstevel@tonic-gate * these may be reset if /etc/default/nfs is configured to do so. 2180Sstevel@tonic-gate */ 2190Sstevel@tonic-gate static rpcvers_t vers_max_default = NFS_VERSMAX_DEFAULT; 2200Sstevel@tonic-gate static rpcvers_t vers_min_default = NFS_VERSMIN_DEFAULT; 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate /* 2230Sstevel@tonic-gate * This variable controls whether to try the public file handle. 2240Sstevel@tonic-gate */ 2250Sstevel@tonic-gate static bool_t public_opt; 2260Sstevel@tonic-gate 227249Sjwahlig int 228249Sjwahlig main(int argc, char *argv[]) 2290Sstevel@tonic-gate { 2300Sstevel@tonic-gate struct mnttab mnt; 2310Sstevel@tonic-gate extern char *optarg; 2320Sstevel@tonic-gate extern int optind; 2330Sstevel@tonic-gate char optbuf[MAX_MNTOPT_STR]; 2340Sstevel@tonic-gate int ro = 0; 2350Sstevel@tonic-gate int r; 2360Sstevel@tonic-gate int c; 2370Sstevel@tonic-gate char *myname; 238489Soa138391 err_ret_t retry_error; 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 2410Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 2420Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 2430Sstevel@tonic-gate #endif 2440Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate myname = strrchr(argv[0], '/'); 2470Sstevel@tonic-gate myname = myname ? myname + 1 : argv[0]; 2480Sstevel@tonic-gate (void) snprintf(typename, sizeof (typename), "%s %s", 2490Sstevel@tonic-gate MNTTYPE_NFS, myname); 2500Sstevel@tonic-gate argv[0] = typename; 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate mnt.mnt_mntopts = optbuf; 2530Sstevel@tonic-gate (void) strcpy(optbuf, "rw"); 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate /* 2560Sstevel@tonic-gate * Set options 2570Sstevel@tonic-gate */ 2580Sstevel@tonic-gate while ((c = getopt(argc, argv, "ro:mOq")) != EOF) { 2590Sstevel@tonic-gate switch (c) { 2600Sstevel@tonic-gate case 'r': 2610Sstevel@tonic-gate ro++; 2620Sstevel@tonic-gate break; 2630Sstevel@tonic-gate case 'o': 2640Sstevel@tonic-gate if (strlen(optarg) >= MAX_MNTOPT_STR) { 2650Sstevel@tonic-gate pr_err(gettext("option string too long")); 2660Sstevel@tonic-gate return (RET_ERR); 2670Sstevel@tonic-gate } 2680Sstevel@tonic-gate (void) strcpy(mnt.mnt_mntopts, optarg); 2690Sstevel@tonic-gate #ifdef LATER /* XXX */ 2700Sstevel@tonic-gate if (strstr(optarg, MNTOPT_REMOUNT)) { 2710Sstevel@tonic-gate /* 2720Sstevel@tonic-gate * If remount is specified, only rw is allowed. 2730Sstevel@tonic-gate */ 2740Sstevel@tonic-gate if ((strcmp(optarg, MNTOPT_REMOUNT) != 0) && 2750Sstevel@tonic-gate (strcmp(optarg, "remount,rw") != 0) && 2760Sstevel@tonic-gate (strcmp(optarg, "rw,remount") != 0)) { 2770Sstevel@tonic-gate pr_err(gettext("Invalid options\n")); 2780Sstevel@tonic-gate exit(RET_ERR); 2790Sstevel@tonic-gate } 2800Sstevel@tonic-gate } 2810Sstevel@tonic-gate #endif /* LATER */ /* XXX */ 2820Sstevel@tonic-gate break; 2830Sstevel@tonic-gate case 'm': 2840Sstevel@tonic-gate mflg++; 2850Sstevel@tonic-gate break; 2860Sstevel@tonic-gate case 'O': 2870Sstevel@tonic-gate Oflg++; 2880Sstevel@tonic-gate break; 2890Sstevel@tonic-gate case 'q': 2900Sstevel@tonic-gate qflg++; 2910Sstevel@tonic-gate break; 2920Sstevel@tonic-gate default: 2930Sstevel@tonic-gate usage(); 2940Sstevel@tonic-gate exit(RET_ERR); 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate } 2970Sstevel@tonic-gate if (argc - optind != 2) { 2980Sstevel@tonic-gate usage(); 2990Sstevel@tonic-gate exit(RET_ERR); 3000Sstevel@tonic-gate } 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate mnt.mnt_special = argv[optind]; 3030Sstevel@tonic-gate mnt.mnt_mountp = argv[optind+1]; 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate if (!priv_ineffect(PRIV_SYS_MOUNT) || 3060Sstevel@tonic-gate !priv_ineffect(PRIV_NET_PRIVADDR)) { 3070Sstevel@tonic-gate pr_err(gettext("insufficient privileges\n")); 3080Sstevel@tonic-gate exit(RET_ERR); 3090Sstevel@tonic-gate } 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate /* 3123378Srica * On a labeled system, allow read-down nfs mounts if privileged 3133378Srica * (PRIV_NET_MAC_AWARE) to do so. Otherwise, ignore the error 3143378Srica * and "mount equal label only" behavior will result. 3153378Srica */ 3163378Srica if (is_system_labeled()) 3173378Srica (void) setpflags(NET_MAC_AWARE, 1); 3183378Srica 3193378Srica /* 3200Sstevel@tonic-gate * Read the defaults file to see if the min/max versions have 3210Sstevel@tonic-gate * been set and therefore would override the encoded defaults. 3220Sstevel@tonic-gate * Then check to make sure that if they were set that the 3230Sstevel@tonic-gate * values are reasonable. 3240Sstevel@tonic-gate */ 3250Sstevel@tonic-gate read_default(); 3260Sstevel@tonic-gate if (vers_min_default > vers_max_default || 3275302Sth199096 vers_min_default < NFS_VERSMIN || 3285302Sth199096 vers_max_default > NFS_VERSMAX) { 3290Sstevel@tonic-gate pr_err("%s %s\n%s %s\n", 3305302Sth199096 gettext("Incorrect configuration of client\'s"), 3315302Sth199096 NFSADMIN, 3325302Sth199096 gettext("NFS_CLIENT_VERSMIN or NFS_CLIENT_VERSMAX"), 3335302Sth199096 gettext("is either out of range or overlaps.")); 3340Sstevel@tonic-gate } 3350Sstevel@tonic-gate 336489Soa138391 SET_ERR_RET(&retry_error, ERR_PROTO_NONE, 0); 337489Soa138391 r = mount_nfs(&mnt, ro, &retry_error); 338489Soa138391 if (r == RET_RETRY && retries) { 339489Soa138391 /* 340489Soa138391 * Check the error code from the last mount attempt if it was 341489Soa138391 * an RPC error, then retry as is. Otherwise we retry with the 342489Soa138391 * nfsretry_vers set. It is set by decrementing nfsvers_to_use. 343489Soa138391 * If we are retrying with nfsretry_vers then we don't print any 344489Soa138391 * retry messages, since we are not retrying due to an RPC 345489Soa138391 * error. 346489Soa138391 */ 347489Soa138391 if (retry_error.error_type) { 348489Soa138391 if (retry_error.error_type != ERR_RPCERROR) { 349489Soa138391 nfsretry_vers = nfsvers_to_use = 350489Soa138391 nfsvers_to_use - 1; 351489Soa138391 if (nfsretry_vers < NFS_VERSMIN) 352489Soa138391 return (r); 353489Soa138391 } 354489Soa138391 } 355489Soa138391 3560Sstevel@tonic-gate r = retry(&mnt, ro); 357489Soa138391 } 3580Sstevel@tonic-gate /* 3590Sstevel@tonic-gate * exit(r); 3600Sstevel@tonic-gate */ 3610Sstevel@tonic-gate return (r); 3620Sstevel@tonic-gate } 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate static void 3650Sstevel@tonic-gate pr_err(const char *fmt, ...) 3660Sstevel@tonic-gate { 3670Sstevel@tonic-gate va_list ap; 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate va_start(ap, fmt); 3700Sstevel@tonic-gate if (backgrounded != 0) { 3710Sstevel@tonic-gate (void) vsyslog(LOG_ERR, fmt, ap); 3720Sstevel@tonic-gate } else { 3730Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", typename); 3740Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap); 3750Sstevel@tonic-gate (void) fflush(stderr); 3760Sstevel@tonic-gate } 3770Sstevel@tonic-gate va_end(ap); 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate static void 3810Sstevel@tonic-gate usage() 3820Sstevel@tonic-gate { 3830Sstevel@tonic-gate (void) fprintf(stderr, 3840Sstevel@tonic-gate gettext("Usage: nfs mount [-r] [-o opts] [server:]path dir\n")); 3850Sstevel@tonic-gate exit(RET_ERR); 3860Sstevel@tonic-gate } 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate static int 389489Soa138391 mount_nfs(struct mnttab *mntp, int ro, err_ret_t *retry_error) 3900Sstevel@tonic-gate { 3910Sstevel@tonic-gate struct nfs_args *args = NULL, *argp = NULL, *prev_argp = NULL; 3920Sstevel@tonic-gate struct netconfig *nconf = NULL; 3930Sstevel@tonic-gate struct replica *list = NULL; 3940Sstevel@tonic-gate int mntflags = 0; 3950Sstevel@tonic-gate int i, r, n; 3960Sstevel@tonic-gate int oldvers = 0, vers = 0; 3970Sstevel@tonic-gate int last_error = RET_OK; 3980Sstevel@tonic-gate int replicated = 0; 3990Sstevel@tonic-gate char *p; 4000Sstevel@tonic-gate bool_t url; 4010Sstevel@tonic-gate bool_t use_pubfh; 4020Sstevel@tonic-gate char *special = NULL; 4030Sstevel@tonic-gate char *oldpath = NULL; 4040Sstevel@tonic-gate char *newpath = NULL; 4050Sstevel@tonic-gate char *service; 4060Sstevel@tonic-gate pid_t pi; 4070Sstevel@tonic-gate struct flock f; 4080Sstevel@tonic-gate char *saveopts = NULL; 4090Sstevel@tonic-gate char **sl = NULL; 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate mntp->mnt_fstype = MNTTYPE_NFS; 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate if (ro) { 4140Sstevel@tonic-gate mntflags |= MS_RDONLY; 4150Sstevel@tonic-gate /* convert "rw"->"ro" */ 4160Sstevel@tonic-gate if (p = strstr(mntp->mnt_mntopts, "rw")) { 4170Sstevel@tonic-gate if (*(p+2) == ',' || *(p+2) == '\0') 4180Sstevel@tonic-gate *(p+1) = 'o'; 4190Sstevel@tonic-gate } 4200Sstevel@tonic-gate } 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate if (Oflg) 4230Sstevel@tonic-gate mntflags |= MS_OVERLAY; 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate list = parse_replica(mntp->mnt_special, &n); 4260Sstevel@tonic-gate if (list == NULL) { 4270Sstevel@tonic-gate if (n < 0) 4280Sstevel@tonic-gate pr_err(gettext("nfs file system; use [host:]path\n")); 4290Sstevel@tonic-gate else 4300Sstevel@tonic-gate pr_err(gettext("no memory\n")); 4310Sstevel@tonic-gate return (RET_ERR); 4320Sstevel@tonic-gate } 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate replicated = (n > 1); 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate /* 4370Sstevel@tonic-gate * There are some free() calls at the bottom of this loop, so be 4380Sstevel@tonic-gate * careful about adding continue statements. 4390Sstevel@tonic-gate */ 4400Sstevel@tonic-gate for (i = 0; i < n; i++) { 4410Sstevel@tonic-gate char *path; 4420Sstevel@tonic-gate char *host; 4430Sstevel@tonic-gate ushort_t port; 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate argp = (struct nfs_args *)malloc(sizeof (*argp)); 4460Sstevel@tonic-gate if (argp == NULL) { 4470Sstevel@tonic-gate pr_err(gettext("no memory\n")); 4480Sstevel@tonic-gate last_error = RET_ERR; 4490Sstevel@tonic-gate goto out; 4500Sstevel@tonic-gate } 4510Sstevel@tonic-gate memset(argp, 0, sizeof (*argp)); 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate memset(&nfs_sec, 0, sizeof (nfs_sec)); 4540Sstevel@tonic-gate sec_opt = 0; 4550Sstevel@tonic-gate use_pubfh = FALSE; 4560Sstevel@tonic-gate url = FALSE; 4570Sstevel@tonic-gate port = 0; 4580Sstevel@tonic-gate snego_done = FALSE; 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate /* 4610Sstevel@tonic-gate * Looking for resources of the form 4620Sstevel@tonic-gate * nfs://server_host[:port_number]/path_name 4630Sstevel@tonic-gate */ 4640Sstevel@tonic-gate if (strcmp(list[i].host, "nfs") == 0 && strncmp(list[i].path, 4650Sstevel@tonic-gate "//", 2) == 0) { 4660Sstevel@tonic-gate char *sport, *cb; 4670Sstevel@tonic-gate url = TRUE; 4680Sstevel@tonic-gate oldpath = strdup(list[i].path); 4690Sstevel@tonic-gate if (oldpath == NULL) { 4700Sstevel@tonic-gate pr_err(gettext("memory allocation failure\n")); 4710Sstevel@tonic-gate last_error = RET_ERR; 4720Sstevel@tonic-gate goto out; 4730Sstevel@tonic-gate } 4740Sstevel@tonic-gate host = list[i].path+2; 4750Sstevel@tonic-gate path = strchr(host, '/'); 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate if (path == NULL) { 4780Sstevel@tonic-gate pr_err(gettext( 4790Sstevel@tonic-gate "illegal nfs url syntax\n")); 4800Sstevel@tonic-gate last_error = RET_ERR; 4810Sstevel@tonic-gate goto out; 4820Sstevel@tonic-gate } 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate *path = '\0'; 4850Sstevel@tonic-gate if (*host == '[') { 4860Sstevel@tonic-gate cb = strchr(host, ']'); 4870Sstevel@tonic-gate if (cb == NULL) { 4880Sstevel@tonic-gate pr_err(gettext( 4895302Sth199096 "illegal nfs url syntax\n")); 4900Sstevel@tonic-gate last_error = RET_ERR; 4910Sstevel@tonic-gate goto out; 4920Sstevel@tonic-gate } else { 4930Sstevel@tonic-gate *cb = '\0'; 4940Sstevel@tonic-gate host++; 4950Sstevel@tonic-gate cb++; 4960Sstevel@tonic-gate if (*cb == ':') 4970Sstevel@tonic-gate port = htons((ushort_t) 4985302Sth199096 atoi(cb+1)); 4990Sstevel@tonic-gate } 5000Sstevel@tonic-gate } else { 5010Sstevel@tonic-gate sport = strchr(host, ':'); 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate if (sport != NULL && sport < path) { 5040Sstevel@tonic-gate *sport = '\0'; 5050Sstevel@tonic-gate port = htons((ushort_t)atoi(sport+1)); 5060Sstevel@tonic-gate } 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate path++; 5100Sstevel@tonic-gate if (*path == '\0') 5110Sstevel@tonic-gate path = "."; 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate } else { 5140Sstevel@tonic-gate host = list[i].host; 5150Sstevel@tonic-gate path = list[i].path; 5160Sstevel@tonic-gate } 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate if (r = set_args(&mntflags, argp, host, mntp)) { 5190Sstevel@tonic-gate last_error = r; 5200Sstevel@tonic-gate goto out; 5210Sstevel@tonic-gate } 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate if (public_opt == TRUE) 5240Sstevel@tonic-gate use_pubfh = TRUE; 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate if (port == 0) { 5270Sstevel@tonic-gate port = nfs_port; 5280Sstevel@tonic-gate } else if (nfs_port != 0 && nfs_port != port) { 5290Sstevel@tonic-gate pr_err(gettext( 5300Sstevel@tonic-gate "port (%u) in nfs URL not the same" 5310Sstevel@tonic-gate " as port (%u) in port option\n"), 5320Sstevel@tonic-gate (unsigned int)ntohs(port), 5330Sstevel@tonic-gate (unsigned int)ntohs(nfs_port)); 5340Sstevel@tonic-gate last_error = RET_ERR; 5350Sstevel@tonic-gate goto out; 5360Sstevel@tonic-gate } 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate if (replicated && !(mntflags & MS_RDONLY)) { 5400Sstevel@tonic-gate pr_err(gettext( 5415302Sth199096 "replicated mounts must be read-only\n")); 5420Sstevel@tonic-gate last_error = RET_ERR; 5430Sstevel@tonic-gate goto out; 5440Sstevel@tonic-gate } 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate if (replicated && (argp->flags & NFSMNT_SOFT)) { 5470Sstevel@tonic-gate pr_err(gettext( 5485302Sth199096 "replicated mounts must not be soft\n")); 5490Sstevel@tonic-gate last_error = RET_ERR; 5500Sstevel@tonic-gate goto out; 5510Sstevel@tonic-gate } 5520Sstevel@tonic-gate 5530Sstevel@tonic-gate oldvers = vers; 5540Sstevel@tonic-gate nconf = NULL; 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate r = RET_ERR; 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate /* 5590Sstevel@tonic-gate * If -o public was specified, and/or a URL was specified, 5600Sstevel@tonic-gate * then try the public file handle method. 5610Sstevel@tonic-gate */ 5620Sstevel@tonic-gate if ((use_pubfh == TRUE) || (url == TRUE)) { 5630Sstevel@tonic-gate r = get_fh_via_pub(argp, host, path, url, use_pubfh, 5645302Sth199096 &vers, &nconf, port); 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate if (r != RET_OK) { 5670Sstevel@tonic-gate /* 5680Sstevel@tonic-gate * If -o public was specified, then return the 5690Sstevel@tonic-gate * error now. 5700Sstevel@tonic-gate */ 5710Sstevel@tonic-gate if (use_pubfh == TRUE) { 5720Sstevel@tonic-gate last_error = r; 5730Sstevel@tonic-gate goto out; 5740Sstevel@tonic-gate } 5750Sstevel@tonic-gate } else 5760Sstevel@tonic-gate use_pubfh = TRUE; 5770Sstevel@tonic-gate argp->flags |= NFSMNT_PUBLIC; 5780Sstevel@tonic-gate } 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate if ((r != RET_OK) || (vers == NFS_V4)) { 5810Sstevel@tonic-gate bool_t loud_on_mnt_err; 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate /* 5840Sstevel@tonic-gate * This can happen if -o public is not specified, 5850Sstevel@tonic-gate * special is a URL, and server doesn't support 5860Sstevel@tonic-gate * public file handle. 5870Sstevel@tonic-gate */ 5880Sstevel@tonic-gate if (url) { 5890Sstevel@tonic-gate URLparse(path); 5900Sstevel@tonic-gate } 5910Sstevel@tonic-gate 5920Sstevel@tonic-gate /* 5930Sstevel@tonic-gate * If the path portion of the URL didn't have 5940Sstevel@tonic-gate * a leading / then there is good possibility 5950Sstevel@tonic-gate * that a mount without a leading slash will 5960Sstevel@tonic-gate * fail. 5970Sstevel@tonic-gate */ 5980Sstevel@tonic-gate if (url == TRUE && *path != '/') 5990Sstevel@tonic-gate loud_on_mnt_err = FALSE; 6000Sstevel@tonic-gate else 6010Sstevel@tonic-gate loud_on_mnt_err = TRUE; 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate r = get_fh(argp, host, path, &vers, 6045302Sth199096 loud_on_mnt_err, &nconf, port); 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate if (r != RET_OK) { 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate /* 6090Sstevel@tonic-gate * If there was no leading / and the path was 6100Sstevel@tonic-gate * derived from a URL, then try again 6110Sstevel@tonic-gate * with a leading /. 6120Sstevel@tonic-gate */ 6130Sstevel@tonic-gate if ((r == RET_MNTERR) && 6140Sstevel@tonic-gate (loud_on_mnt_err == FALSE)) { 6150Sstevel@tonic-gate 6160Sstevel@tonic-gate newpath = malloc(strlen(path)+2); 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate if (newpath == NULL) { 6190Sstevel@tonic-gate pr_err(gettext("memory " 6200Sstevel@tonic-gate "allocation failure\n")); 6210Sstevel@tonic-gate last_error = RET_ERR; 6220Sstevel@tonic-gate goto out; 6230Sstevel@tonic-gate } 6240Sstevel@tonic-gate 6250Sstevel@tonic-gate strcpy(newpath, "/"); 6260Sstevel@tonic-gate strcat(newpath, path); 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate r = get_fh(argp, host, newpath, &vers, 6295302Sth199096 TRUE, &nconf, port); 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate if (r == RET_OK) 6320Sstevel@tonic-gate path = newpath; 6330Sstevel@tonic-gate } 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate /* 6360Sstevel@tonic-gate * map exit code back to RET_ERR. 6370Sstevel@tonic-gate */ 6380Sstevel@tonic-gate if (r == RET_MNTERR) 6390Sstevel@tonic-gate r = RET_ERR; 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate if (r != RET_OK) { 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate if (replicated) { 6440Sstevel@tonic-gate if (argp->fh) 6450Sstevel@tonic-gate free(argp->fh); 6460Sstevel@tonic-gate if (argp->pathconf) 6470Sstevel@tonic-gate free(argp->pathconf); 6480Sstevel@tonic-gate free(argp); 6490Sstevel@tonic-gate goto cont; 6500Sstevel@tonic-gate } 6510Sstevel@tonic-gate 6520Sstevel@tonic-gate last_error = r; 6530Sstevel@tonic-gate goto out; 6540Sstevel@tonic-gate } 6550Sstevel@tonic-gate } 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate if (oldvers && vers != oldvers) { 6590Sstevel@tonic-gate pr_err( 6600Sstevel@tonic-gate gettext("replicas must have the same version\n")); 6610Sstevel@tonic-gate last_error = RET_ERR; 6620Sstevel@tonic-gate goto out; 6630Sstevel@tonic-gate } 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate /* 6660Sstevel@tonic-gate * decide whether to use remote host's 6670Sstevel@tonic-gate * lockd or do local locking 6680Sstevel@tonic-gate */ 6690Sstevel@tonic-gate if (!(argp->flags & NFSMNT_LLOCK) && vers == NFS_VERSION && 6700Sstevel@tonic-gate remote_lock(host, argp->fh)) { 6710Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6720Sstevel@tonic-gate "WARNING: No network locking on %s:%s:"), 6730Sstevel@tonic-gate host, path); 6740Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6750Sstevel@tonic-gate " contact admin to install server change\n")); 6765302Sth199096 argp->flags |= NFSMNT_LLOCK; 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate if (self_check(host)) 6800Sstevel@tonic-gate argp->flags |= NFSMNT_LOOPBACK; 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate if (use_pubfh == FALSE) { 6830Sstevel@tonic-gate /* 6840Sstevel@tonic-gate * Call to get_fh() above may have obtained the 6850Sstevel@tonic-gate * netconfig info and NULL proc'd the server. 6860Sstevel@tonic-gate * This would be the case with v4 6870Sstevel@tonic-gate */ 6880Sstevel@tonic-gate if (!(argp->flags & NFSMNT_KNCONF)) { 6890Sstevel@tonic-gate nconf = NULL; 6900Sstevel@tonic-gate if (r = getaddr_nfs(argp, host, &nconf, 6915302Sth199096 FALSE, path, port, retry_error, 6925302Sth199096 TRUE)) { 693489Soa138391 last_error = r; 694489Soa138391 goto out; 6950Sstevel@tonic-gate } 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate if (make_secure(argp, host, nconf, use_pubfh, vers) < 0) { 7000Sstevel@tonic-gate last_error = RET_ERR; 7010Sstevel@tonic-gate goto out; 7020Sstevel@tonic-gate } 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate if ((url == TRUE) && (use_pubfh == FALSE)) { 7050Sstevel@tonic-gate /* 7060Sstevel@tonic-gate * Convert the special from 7070Sstevel@tonic-gate * nfs://host/path 7080Sstevel@tonic-gate * to 7090Sstevel@tonic-gate * host:path 7100Sstevel@tonic-gate */ 7110Sstevel@tonic-gate if (convert_special(&special, host, oldpath, path, 7120Sstevel@tonic-gate mntp->mnt_special) == -1) { 7130Sstevel@tonic-gate (void) fprintf(stderr, gettext( 7140Sstevel@tonic-gate "could not convert URL nfs:%s to %s:%s\n"), 7150Sstevel@tonic-gate oldpath, host, path); 7160Sstevel@tonic-gate last_error = RET_ERR; 7170Sstevel@tonic-gate goto out; 7180Sstevel@tonic-gate } else { 7190Sstevel@tonic-gate mntp->mnt_special = special; 7200Sstevel@tonic-gate } 7210Sstevel@tonic-gate } 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate if (prev_argp == NULL) 7240Sstevel@tonic-gate args = argp; 7250Sstevel@tonic-gate else 7260Sstevel@tonic-gate prev_argp->nfs_ext_u.nfs_extB.next = argp; 7270Sstevel@tonic-gate prev_argp = argp; 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate cont: 7300Sstevel@tonic-gate if (oldpath != NULL) { 7310Sstevel@tonic-gate free(oldpath); 7320Sstevel@tonic-gate oldpath = NULL; 7330Sstevel@tonic-gate } 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate if (newpath != NULL) { 7360Sstevel@tonic-gate free(newpath); 7370Sstevel@tonic-gate newpath = NULL; 7380Sstevel@tonic-gate } 7390Sstevel@tonic-gate } 7400Sstevel@tonic-gate 7410Sstevel@tonic-gate argp = NULL; 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate if (args == NULL) { 7440Sstevel@tonic-gate last_error = RET_RETRY; 7450Sstevel@tonic-gate goto out; 7460Sstevel@tonic-gate } 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate /* Determine which services are appropriate for the NFS version */ 7490Sstevel@tonic-gate if (strcmp(fstype, MNTTYPE_NFS4) == 0) 7500Sstevel@tonic-gate sl = service_list_v4; 7510Sstevel@tonic-gate else 7520Sstevel@tonic-gate sl = service_list; 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate /* 7550Sstevel@tonic-gate * enable services as needed. 7560Sstevel@tonic-gate */ 7570Sstevel@tonic-gate _check_services(sl); 7580Sstevel@tonic-gate 7590Sstevel@tonic-gate mntflags |= MS_DATA | MS_OPTIONSTR; 7600Sstevel@tonic-gate 7610Sstevel@tonic-gate if (mflg) 7620Sstevel@tonic-gate mntflags |= MS_NOMNTTAB; 7630Sstevel@tonic-gate 7640Sstevel@tonic-gate if (!qflg) 7650Sstevel@tonic-gate saveopts = strdup(mntp->mnt_mntopts); 7660Sstevel@tonic-gate 7675302Sth199096 /* 7685302Sth199096 * And make sure that we have the ephemeral mount_to 7695302Sth199096 * set for this zone. 7705302Sth199096 */ 7715302Sth199096 set_nfsv4_ephemeral_mount_to(); 7725302Sth199096 7730Sstevel@tonic-gate if (mount(mntp->mnt_special, mntp->mnt_mountp, mntflags, fstype, args, 7745302Sth199096 sizeof (*args), mntp->mnt_mntopts, MAX_MNTOPT_STR) < 0) { 7750Sstevel@tonic-gate if (errno != ENOENT) { 7760Sstevel@tonic-gate pr_err(gettext("mount: %s: %s\n"), 7775302Sth199096 mntp->mnt_mountp, strerror(errno)); 7780Sstevel@tonic-gate } else { 7790Sstevel@tonic-gate struct stat sb; 7800Sstevel@tonic-gate if (stat(mntp->mnt_mountp, &sb) < 0 && errno == ENOENT) 7810Sstevel@tonic-gate pr_err(gettext("mount: %s: %s\n"), 7825302Sth199096 mntp->mnt_mountp, strerror(ENOENT)); 7830Sstevel@tonic-gate else 7840Sstevel@tonic-gate pr_err("%s: %s\n", mntp->mnt_special, 7855302Sth199096 strerror(ENOENT)); 7860Sstevel@tonic-gate } 7870Sstevel@tonic-gate 7880Sstevel@tonic-gate last_error = RET_ERR; 7890Sstevel@tonic-gate goto out; 7900Sstevel@tonic-gate } 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate if (!qflg && saveopts != NULL) { 7930Sstevel@tonic-gate cmp_requested_to_actual_options(saveopts, mntp->mnt_mntopts, 7940Sstevel@tonic-gate mntp->mnt_special, mntp->mnt_mountp); 7950Sstevel@tonic-gate } 7960Sstevel@tonic-gate 7970Sstevel@tonic-gate out: 7980Sstevel@tonic-gate if (saveopts != NULL) 7990Sstevel@tonic-gate free(saveopts); 8000Sstevel@tonic-gate if (special != NULL) 8010Sstevel@tonic-gate free(special); 8020Sstevel@tonic-gate if (oldpath != NULL) 8030Sstevel@tonic-gate free(oldpath); 8040Sstevel@tonic-gate if (newpath != NULL) 8050Sstevel@tonic-gate free(newpath); 8060Sstevel@tonic-gate 8070Sstevel@tonic-gate free_replica(list, n); 8080Sstevel@tonic-gate 8090Sstevel@tonic-gate if (argp != NULL) { 8100Sstevel@tonic-gate /* 8110Sstevel@tonic-gate * If we had a new entry which was not added to the 8120Sstevel@tonic-gate * list yet, then add it now that it can be freed. 8130Sstevel@tonic-gate */ 8140Sstevel@tonic-gate if (prev_argp == NULL) 8150Sstevel@tonic-gate args = argp; 8160Sstevel@tonic-gate else 8170Sstevel@tonic-gate prev_argp->nfs_ext_u.nfs_extB.next = argp; 8180Sstevel@tonic-gate } 8190Sstevel@tonic-gate argp = args; 8200Sstevel@tonic-gate while (argp != NULL) { 8210Sstevel@tonic-gate if (argp->fh) 8220Sstevel@tonic-gate free(argp->fh); 8230Sstevel@tonic-gate if (argp->pathconf) 8240Sstevel@tonic-gate free(argp->pathconf); 8250Sstevel@tonic-gate if (argp->knconf) 8260Sstevel@tonic-gate free(argp->knconf); 8270Sstevel@tonic-gate if (argp->addr) { 8280Sstevel@tonic-gate free(argp->addr->buf); 8290Sstevel@tonic-gate free(argp->addr); 8300Sstevel@tonic-gate } 8310Sstevel@tonic-gate nfs_free_secdata(argp->nfs_ext_u.nfs_extB.secdata); 8320Sstevel@tonic-gate if (argp->syncaddr) { 8330Sstevel@tonic-gate free(argp->syncaddr->buf); 8340Sstevel@tonic-gate free(argp->syncaddr); 8350Sstevel@tonic-gate } 8360Sstevel@tonic-gate if (argp->netname) 8370Sstevel@tonic-gate free(argp->netname); 8380Sstevel@tonic-gate prev_argp = argp; 8390Sstevel@tonic-gate argp = argp->nfs_ext_u.nfs_extB.next; 8400Sstevel@tonic-gate free(prev_argp); 8410Sstevel@tonic-gate } 8420Sstevel@tonic-gate 8430Sstevel@tonic-gate return (last_error); 8440Sstevel@tonic-gate } 8450Sstevel@tonic-gate 8460Sstevel@tonic-gate /* 8470Sstevel@tonic-gate * These options are duplicated in uts/common/fs/nfs/nfs_dlinet.c 8480Sstevel@tonic-gate * Changes must be made to both lists. 8490Sstevel@tonic-gate */ 8500Sstevel@tonic-gate static char *optlist[] = { 8510Sstevel@tonic-gate #define OPT_RO 0 8520Sstevel@tonic-gate MNTOPT_RO, 8530Sstevel@tonic-gate #define OPT_RW 1 8540Sstevel@tonic-gate MNTOPT_RW, 8550Sstevel@tonic-gate #define OPT_QUOTA 2 8560Sstevel@tonic-gate MNTOPT_QUOTA, 8570Sstevel@tonic-gate #define OPT_NOQUOTA 3 8580Sstevel@tonic-gate MNTOPT_NOQUOTA, 8590Sstevel@tonic-gate #define OPT_SOFT 4 8600Sstevel@tonic-gate MNTOPT_SOFT, 8610Sstevel@tonic-gate #define OPT_HARD 5 8620Sstevel@tonic-gate MNTOPT_HARD, 8630Sstevel@tonic-gate #define OPT_SUID 6 8640Sstevel@tonic-gate MNTOPT_SUID, 8650Sstevel@tonic-gate #define OPT_NOSUID 7 8660Sstevel@tonic-gate MNTOPT_NOSUID, 8670Sstevel@tonic-gate #define OPT_GRPID 8 8680Sstevel@tonic-gate MNTOPT_GRPID, 8690Sstevel@tonic-gate #define OPT_REMOUNT 9 8700Sstevel@tonic-gate MNTOPT_REMOUNT, 8710Sstevel@tonic-gate #define OPT_NOSUB 10 8720Sstevel@tonic-gate MNTOPT_NOSUB, 8730Sstevel@tonic-gate #define OPT_INTR 11 8740Sstevel@tonic-gate MNTOPT_INTR, 8750Sstevel@tonic-gate #define OPT_NOINTR 12 8760Sstevel@tonic-gate MNTOPT_NOINTR, 8770Sstevel@tonic-gate #define OPT_PORT 13 8780Sstevel@tonic-gate MNTOPT_PORT, 8790Sstevel@tonic-gate #define OPT_SECURE 14 8800Sstevel@tonic-gate MNTOPT_SECURE, 8810Sstevel@tonic-gate #define OPT_RSIZE 15 8820Sstevel@tonic-gate MNTOPT_RSIZE, 8830Sstevel@tonic-gate #define OPT_WSIZE 16 8840Sstevel@tonic-gate MNTOPT_WSIZE, 8850Sstevel@tonic-gate #define OPT_TIMEO 17 8860Sstevel@tonic-gate MNTOPT_TIMEO, 8870Sstevel@tonic-gate #define OPT_RETRANS 18 8880Sstevel@tonic-gate MNTOPT_RETRANS, 8890Sstevel@tonic-gate #define OPT_ACTIMEO 19 8900Sstevel@tonic-gate MNTOPT_ACTIMEO, 8910Sstevel@tonic-gate #define OPT_ACREGMIN 20 8920Sstevel@tonic-gate MNTOPT_ACREGMIN, 8930Sstevel@tonic-gate #define OPT_ACREGMAX 21 8940Sstevel@tonic-gate MNTOPT_ACREGMAX, 8950Sstevel@tonic-gate #define OPT_ACDIRMIN 22 8960Sstevel@tonic-gate MNTOPT_ACDIRMIN, 8970Sstevel@tonic-gate #define OPT_ACDIRMAX 23 8980Sstevel@tonic-gate MNTOPT_ACDIRMAX, 8990Sstevel@tonic-gate #define OPT_BG 24 9000Sstevel@tonic-gate MNTOPT_BG, 9010Sstevel@tonic-gate #define OPT_FG 25 9020Sstevel@tonic-gate MNTOPT_FG, 9030Sstevel@tonic-gate #define OPT_RETRY 26 9040Sstevel@tonic-gate MNTOPT_RETRY, 9050Sstevel@tonic-gate #define OPT_NOAC 27 9060Sstevel@tonic-gate MNTOPT_NOAC, 9070Sstevel@tonic-gate #define OPT_NOCTO 28 9080Sstevel@tonic-gate MNTOPT_NOCTO, 9090Sstevel@tonic-gate #define OPT_LLOCK 29 9100Sstevel@tonic-gate MNTOPT_LLOCK, 9110Sstevel@tonic-gate #define OPT_POSIX 30 9120Sstevel@tonic-gate MNTOPT_POSIX, 9130Sstevel@tonic-gate #define OPT_VERS 31 9140Sstevel@tonic-gate MNTOPT_VERS, 9150Sstevel@tonic-gate #define OPT_PROTO 32 9160Sstevel@tonic-gate MNTOPT_PROTO, 9170Sstevel@tonic-gate #define OPT_SEMISOFT 33 9180Sstevel@tonic-gate MNTOPT_SEMISOFT, 9190Sstevel@tonic-gate #define OPT_NOPRINT 34 9200Sstevel@tonic-gate MNTOPT_NOPRINT, 9210Sstevel@tonic-gate #define OPT_SEC 35 9220Sstevel@tonic-gate MNTOPT_SEC, 9230Sstevel@tonic-gate #define OPT_LARGEFILES 36 9240Sstevel@tonic-gate MNTOPT_LARGEFILES, 9250Sstevel@tonic-gate #define OPT_NOLARGEFILES 37 9260Sstevel@tonic-gate MNTOPT_NOLARGEFILES, 9270Sstevel@tonic-gate #define OPT_PUBLIC 38 9280Sstevel@tonic-gate MNTOPT_PUBLIC, 9290Sstevel@tonic-gate #define OPT_DIRECTIO 39 9300Sstevel@tonic-gate MNTOPT_FORCEDIRECTIO, 9310Sstevel@tonic-gate #define OPT_NODIRECTIO 40 9320Sstevel@tonic-gate MNTOPT_NOFORCEDIRECTIO, 9330Sstevel@tonic-gate #define OPT_XATTR 41 9340Sstevel@tonic-gate MNTOPT_XATTR, 9350Sstevel@tonic-gate #define OPT_NOXATTR 42 9360Sstevel@tonic-gate MNTOPT_NOXATTR, 9370Sstevel@tonic-gate #define OPT_DEVICES 43 9380Sstevel@tonic-gate MNTOPT_DEVICES, 9390Sstevel@tonic-gate #define OPT_NODEVICES 44 9400Sstevel@tonic-gate MNTOPT_NODEVICES, 9410Sstevel@tonic-gate #define OPT_SETUID 45 9420Sstevel@tonic-gate MNTOPT_SETUID, 9430Sstevel@tonic-gate #define OPT_NOSETUID 46 9440Sstevel@tonic-gate MNTOPT_NOSETUID, 9450Sstevel@tonic-gate #define OPT_EXEC 47 9460Sstevel@tonic-gate MNTOPT_EXEC, 9470Sstevel@tonic-gate #define OPT_NOEXEC 48 9480Sstevel@tonic-gate MNTOPT_NOEXEC, 9490Sstevel@tonic-gate NULL 9500Sstevel@tonic-gate }; 9510Sstevel@tonic-gate 952*12782SMarcel.Telka@Sun.COM static int 953*12782SMarcel.Telka@Sun.COM convert_int(int *val, char *str) 954*12782SMarcel.Telka@Sun.COM { 955*12782SMarcel.Telka@Sun.COM long lval; 956*12782SMarcel.Telka@Sun.COM 957*12782SMarcel.Telka@Sun.COM if (str == NULL || !isdigit(*str)) 958*12782SMarcel.Telka@Sun.COM return (-1); 959*12782SMarcel.Telka@Sun.COM 960*12782SMarcel.Telka@Sun.COM lval = strtol(str, &str, 10); 961*12782SMarcel.Telka@Sun.COM if (*str != '\0' || lval > INT_MAX) 962*12782SMarcel.Telka@Sun.COM return (-2); 963*12782SMarcel.Telka@Sun.COM 964*12782SMarcel.Telka@Sun.COM *val = (int)lval; 965*12782SMarcel.Telka@Sun.COM return (0); 966*12782SMarcel.Telka@Sun.COM } 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate static int 9690Sstevel@tonic-gate set_args(int *mntflags, struct nfs_args *args, char *fshost, struct mnttab *mnt) 9700Sstevel@tonic-gate { 9710Sstevel@tonic-gate char *saveopt, *optstr, *opts, *newopts, *val; 972*12782SMarcel.Telka@Sun.COM int num; 9730Sstevel@tonic-gate int largefiles = 0; 9740Sstevel@tonic-gate int invalid = 0; 9750Sstevel@tonic-gate int attrpref = 0; 9760Sstevel@tonic-gate int optlen; 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate args->flags = NFSMNT_INT; /* default is "intr" */ 9790Sstevel@tonic-gate args->flags |= NFSMNT_HOSTNAME; 9800Sstevel@tonic-gate args->flags |= NFSMNT_NEWARGS; /* using extented nfs_args structure */ 9810Sstevel@tonic-gate args->hostname = fshost; 9820Sstevel@tonic-gate 9830Sstevel@tonic-gate optstr = opts = strdup(mnt->mnt_mntopts); 9840Sstevel@tonic-gate /* sizeof (MNTOPT_XXX) includes one extra byte we may need for "," */ 9850Sstevel@tonic-gate optlen = strlen(mnt->mnt_mntopts) + sizeof (MNTOPT_XATTR) + 1; 9860Sstevel@tonic-gate if (optlen > MAX_MNTOPT_STR) { 9870Sstevel@tonic-gate pr_err(gettext("option string too long")); 9880Sstevel@tonic-gate return (RET_ERR); 9890Sstevel@tonic-gate } 9900Sstevel@tonic-gate newopts = malloc(optlen); 9910Sstevel@tonic-gate if (opts == NULL || newopts == NULL) { 9920Sstevel@tonic-gate pr_err(gettext("no memory")); 9930Sstevel@tonic-gate if (opts) 9940Sstevel@tonic-gate free(opts); 9950Sstevel@tonic-gate if (newopts) 9960Sstevel@tonic-gate free(newopts); 9970Sstevel@tonic-gate return (RET_ERR); 9980Sstevel@tonic-gate } 9990Sstevel@tonic-gate newopts[0] = '\0'; 10000Sstevel@tonic-gate 10010Sstevel@tonic-gate while (*opts) { 10020Sstevel@tonic-gate invalid = 0; 10030Sstevel@tonic-gate saveopt = opts; 10040Sstevel@tonic-gate switch (getsubopt(&opts, optlist, &val)) { 10050Sstevel@tonic-gate case OPT_RO: 10060Sstevel@tonic-gate *mntflags |= MS_RDONLY; 10070Sstevel@tonic-gate break; 10080Sstevel@tonic-gate case OPT_RW: 10090Sstevel@tonic-gate *mntflags &= ~(MS_RDONLY); 10100Sstevel@tonic-gate break; 10110Sstevel@tonic-gate case OPT_QUOTA: 10120Sstevel@tonic-gate case OPT_NOQUOTA: 10130Sstevel@tonic-gate break; 10140Sstevel@tonic-gate case OPT_SOFT: 10150Sstevel@tonic-gate args->flags |= NFSMNT_SOFT; 10160Sstevel@tonic-gate args->flags &= ~(NFSMNT_SEMISOFT); 10170Sstevel@tonic-gate break; 10180Sstevel@tonic-gate case OPT_SEMISOFT: 10190Sstevel@tonic-gate args->flags |= NFSMNT_SOFT; 10200Sstevel@tonic-gate args->flags |= NFSMNT_SEMISOFT; 10210Sstevel@tonic-gate break; 10220Sstevel@tonic-gate case OPT_HARD: 10230Sstevel@tonic-gate args->flags &= ~(NFSMNT_SOFT); 10240Sstevel@tonic-gate args->flags &= ~(NFSMNT_SEMISOFT); 10250Sstevel@tonic-gate break; 10260Sstevel@tonic-gate case OPT_SUID: 10270Sstevel@tonic-gate *mntflags &= ~(MS_NOSUID); 10280Sstevel@tonic-gate break; 10290Sstevel@tonic-gate case OPT_NOSUID: 10300Sstevel@tonic-gate *mntflags |= MS_NOSUID; 10310Sstevel@tonic-gate break; 10320Sstevel@tonic-gate case OPT_GRPID: 10330Sstevel@tonic-gate args->flags |= NFSMNT_GRPID; 10340Sstevel@tonic-gate break; 10350Sstevel@tonic-gate case OPT_REMOUNT: 10360Sstevel@tonic-gate *mntflags |= MS_REMOUNT; 10370Sstevel@tonic-gate break; 10380Sstevel@tonic-gate case OPT_INTR: 10390Sstevel@tonic-gate args->flags |= NFSMNT_INT; 10400Sstevel@tonic-gate break; 10410Sstevel@tonic-gate case OPT_NOINTR: 10420Sstevel@tonic-gate args->flags &= ~(NFSMNT_INT); 10430Sstevel@tonic-gate break; 10440Sstevel@tonic-gate case OPT_NOAC: 10450Sstevel@tonic-gate args->flags |= NFSMNT_NOAC; 10460Sstevel@tonic-gate break; 10470Sstevel@tonic-gate case OPT_PORT: 1048*12782SMarcel.Telka@Sun.COM if (convert_int(&num, val) != 0) 10490Sstevel@tonic-gate goto badopt; 1050*12782SMarcel.Telka@Sun.COM nfs_port = htons((ushort_t)num); 10510Sstevel@tonic-gate break; 10520Sstevel@tonic-gate 10530Sstevel@tonic-gate case OPT_SECURE: 10540Sstevel@tonic-gate if (nfs_getseconfig_byname("dh", &nfs_sec)) { 10555302Sth199096 pr_err(gettext("can not get \"dh\" from %s\n"), 10565302Sth199096 NFSSEC_CONF); 10575302Sth199096 goto badopt; 10580Sstevel@tonic-gate } 10590Sstevel@tonic-gate sec_opt++; 10600Sstevel@tonic-gate break; 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate case OPT_NOCTO: 10630Sstevel@tonic-gate args->flags |= NFSMNT_NOCTO; 10640Sstevel@tonic-gate break; 10650Sstevel@tonic-gate 10660Sstevel@tonic-gate case OPT_RSIZE: 1067*12782SMarcel.Telka@Sun.COM if (convert_int(&args->rsize, val) != 0) 1068*12782SMarcel.Telka@Sun.COM goto badopt; 10690Sstevel@tonic-gate args->flags |= NFSMNT_RSIZE; 10700Sstevel@tonic-gate break; 10710Sstevel@tonic-gate case OPT_WSIZE: 1072*12782SMarcel.Telka@Sun.COM if (convert_int(&args->wsize, val) != 0) 1073*12782SMarcel.Telka@Sun.COM goto badopt; 10740Sstevel@tonic-gate args->flags |= NFSMNT_WSIZE; 10750Sstevel@tonic-gate break; 10760Sstevel@tonic-gate case OPT_TIMEO: 1077*12782SMarcel.Telka@Sun.COM if (convert_int(&args->timeo, val) != 0) 1078*12782SMarcel.Telka@Sun.COM goto badopt; 10790Sstevel@tonic-gate args->flags |= NFSMNT_TIMEO; 10800Sstevel@tonic-gate break; 10810Sstevel@tonic-gate case OPT_RETRANS: 1082*12782SMarcel.Telka@Sun.COM if (convert_int(&args->retrans, val) != 0) 1083*12782SMarcel.Telka@Sun.COM goto badopt; 10840Sstevel@tonic-gate args->flags |= NFSMNT_RETRANS; 10850Sstevel@tonic-gate break; 10860Sstevel@tonic-gate case OPT_ACTIMEO: 1087*12782SMarcel.Telka@Sun.COM if (convert_int(&args->acregmax, val) != 0) 1088*12782SMarcel.Telka@Sun.COM goto badopt; 1089*12782SMarcel.Telka@Sun.COM args->acdirmin = args->acregmin = args->acdirmax 1090*12782SMarcel.Telka@Sun.COM = args->acregmax; 10910Sstevel@tonic-gate args->flags |= NFSMNT_ACDIRMAX; 10920Sstevel@tonic-gate args->flags |= NFSMNT_ACREGMAX; 10930Sstevel@tonic-gate args->flags |= NFSMNT_ACDIRMIN; 10940Sstevel@tonic-gate args->flags |= NFSMNT_ACREGMIN; 10950Sstevel@tonic-gate break; 10960Sstevel@tonic-gate case OPT_ACREGMIN: 1097*12782SMarcel.Telka@Sun.COM if (convert_int(&args->acregmin, val) != 0) 1098*12782SMarcel.Telka@Sun.COM goto badopt; 10990Sstevel@tonic-gate args->flags |= NFSMNT_ACREGMIN; 11000Sstevel@tonic-gate break; 11010Sstevel@tonic-gate case OPT_ACREGMAX: 1102*12782SMarcel.Telka@Sun.COM if (convert_int(&args->acregmax, val) != 0) 1103*12782SMarcel.Telka@Sun.COM goto badopt; 11040Sstevel@tonic-gate args->flags |= NFSMNT_ACREGMAX; 11050Sstevel@tonic-gate break; 11060Sstevel@tonic-gate case OPT_ACDIRMIN: 1107*12782SMarcel.Telka@Sun.COM if (convert_int(&args->acdirmin, val) != 0) 1108*12782SMarcel.Telka@Sun.COM goto badopt; 11090Sstevel@tonic-gate args->flags |= NFSMNT_ACDIRMIN; 11100Sstevel@tonic-gate break; 11110Sstevel@tonic-gate case OPT_ACDIRMAX: 1112*12782SMarcel.Telka@Sun.COM if (convert_int(&args->acdirmax, val) != 0) 1113*12782SMarcel.Telka@Sun.COM goto badopt; 11140Sstevel@tonic-gate args->flags |= NFSMNT_ACDIRMAX; 11150Sstevel@tonic-gate break; 11160Sstevel@tonic-gate case OPT_BG: 11170Sstevel@tonic-gate bg++; 11180Sstevel@tonic-gate break; 11190Sstevel@tonic-gate case OPT_FG: 11200Sstevel@tonic-gate bg = 0; 11210Sstevel@tonic-gate break; 11220Sstevel@tonic-gate case OPT_RETRY: 1123*12782SMarcel.Telka@Sun.COM if (convert_int(&retries, val) != 0) 11240Sstevel@tonic-gate goto badopt; 11250Sstevel@tonic-gate break; 11260Sstevel@tonic-gate case OPT_LLOCK: 11270Sstevel@tonic-gate args->flags |= NFSMNT_LLOCK; 11280Sstevel@tonic-gate break; 11290Sstevel@tonic-gate case OPT_POSIX: 11300Sstevel@tonic-gate posix = 1; 11310Sstevel@tonic-gate break; 11320Sstevel@tonic-gate case OPT_VERS: 1133*12782SMarcel.Telka@Sun.COM if (convert_int(&num, val) != 0) 11340Sstevel@tonic-gate goto badopt; 1135*12782SMarcel.Telka@Sun.COM nfsvers = (rpcvers_t)num; 11360Sstevel@tonic-gate break; 11370Sstevel@tonic-gate case OPT_PROTO: 113877Soa138391 if (val == NULL) 113977Soa138391 goto badopt; 114077Soa138391 11410Sstevel@tonic-gate nfs_proto = (char *)malloc(strlen(val)+1); 114277Soa138391 if (!nfs_proto) { 114377Soa138391 pr_err(gettext("no memory")); 114477Soa138391 return (RET_ERR); 114577Soa138391 } 114677Soa138391 114777Soa138391 (void) strncpy(nfs_proto, val, strlen(val)+1); 11480Sstevel@tonic-gate break; 11495302Sth199096 11500Sstevel@tonic-gate case OPT_NOPRINT: 11510Sstevel@tonic-gate args->flags |= NFSMNT_NOPRINT; 11520Sstevel@tonic-gate break; 11535302Sth199096 11540Sstevel@tonic-gate case OPT_LARGEFILES: 11550Sstevel@tonic-gate largefiles = 1; 11560Sstevel@tonic-gate break; 11575302Sth199096 11580Sstevel@tonic-gate case OPT_NOLARGEFILES: 11590Sstevel@tonic-gate pr_err(gettext("NFS can't support \"nolargefiles\"\n")); 11600Sstevel@tonic-gate free(optstr); 11610Sstevel@tonic-gate return (RET_ERR); 11620Sstevel@tonic-gate 11630Sstevel@tonic-gate case OPT_SEC: 11645885Sdougm if (val == NULL) { 11655885Sdougm pr_err(gettext( 11665885Sdougm "\"sec\" option requires argument\n")); 11675885Sdougm return (RET_ERR); 11685885Sdougm } 11690Sstevel@tonic-gate if (nfs_getseconfig_byname(val, &nfs_sec)) { 11705302Sth199096 pr_err(gettext("can not get \"%s\" from %s\n"), 11715302Sth199096 val, NFSSEC_CONF); 11725302Sth199096 return (RET_ERR); 11730Sstevel@tonic-gate } 11740Sstevel@tonic-gate sec_opt++; 11750Sstevel@tonic-gate break; 11760Sstevel@tonic-gate 11770Sstevel@tonic-gate case OPT_PUBLIC: 11780Sstevel@tonic-gate public_opt = TRUE; 11790Sstevel@tonic-gate break; 11800Sstevel@tonic-gate 11810Sstevel@tonic-gate case OPT_DIRECTIO: 11820Sstevel@tonic-gate args->flags |= NFSMNT_DIRECTIO; 11830Sstevel@tonic-gate break; 11840Sstevel@tonic-gate 11850Sstevel@tonic-gate case OPT_NODIRECTIO: 11860Sstevel@tonic-gate args->flags &= ~(NFSMNT_DIRECTIO); 11870Sstevel@tonic-gate break; 11880Sstevel@tonic-gate 11890Sstevel@tonic-gate case OPT_XATTR: 11900Sstevel@tonic-gate case OPT_NOXATTR: 11910Sstevel@tonic-gate /* 11920Sstevel@tonic-gate * VFS options; just need to get them into the 11930Sstevel@tonic-gate * new mount option string and note we've seen them 11940Sstevel@tonic-gate */ 11950Sstevel@tonic-gate attrpref = 1; 11960Sstevel@tonic-gate break; 11970Sstevel@tonic-gate default: 11980Sstevel@tonic-gate /* 11990Sstevel@tonic-gate * Note that this could be a valid OPT_* option so 12000Sstevel@tonic-gate * we can't use "val" but need to use "saveopt". 12010Sstevel@tonic-gate */ 12020Sstevel@tonic-gate if (fsisstdopt(saveopt)) 12030Sstevel@tonic-gate break; 12040Sstevel@tonic-gate invalid = 1; 12050Sstevel@tonic-gate if (!qflg) 12060Sstevel@tonic-gate (void) fprintf(stderr, gettext( 12070Sstevel@tonic-gate "mount: %s on %s - WARNING unknown option" 12080Sstevel@tonic-gate " \"%s\"\n"), mnt->mnt_special, 12090Sstevel@tonic-gate mnt->mnt_mountp, saveopt); 12100Sstevel@tonic-gate break; 12110Sstevel@tonic-gate } 12120Sstevel@tonic-gate if (!invalid) { 12130Sstevel@tonic-gate if (newopts[0]) 12140Sstevel@tonic-gate strcat(newopts, ","); 12150Sstevel@tonic-gate strcat(newopts, saveopt); 12160Sstevel@tonic-gate } 12170Sstevel@tonic-gate } 12180Sstevel@tonic-gate /* Default is to turn extended attrs on */ 12190Sstevel@tonic-gate if (!attrpref) { 12200Sstevel@tonic-gate if (newopts[0]) 12210Sstevel@tonic-gate strcat(newopts, ","); 12220Sstevel@tonic-gate strcat(newopts, MNTOPT_XATTR); 12230Sstevel@tonic-gate } 12240Sstevel@tonic-gate strcpy(mnt->mnt_mntopts, newopts); 12250Sstevel@tonic-gate free(newopts); 12260Sstevel@tonic-gate free(optstr); 12270Sstevel@tonic-gate 12280Sstevel@tonic-gate /* ensure that only one secure mode is requested */ 12290Sstevel@tonic-gate if (sec_opt > 1) { 12300Sstevel@tonic-gate pr_err(gettext("Security options conflict\n")); 12310Sstevel@tonic-gate return (RET_ERR); 12320Sstevel@tonic-gate } 12330Sstevel@tonic-gate 12340Sstevel@tonic-gate /* ensure that the user isn't trying to get large files over V2 */ 12350Sstevel@tonic-gate if (nfsvers == NFS_VERSION && largefiles) { 12360Sstevel@tonic-gate pr_err(gettext("NFS V2 can't support \"largefiles\"\n")); 12370Sstevel@tonic-gate return (RET_ERR); 12380Sstevel@tonic-gate } 12390Sstevel@tonic-gate 12400Sstevel@tonic-gate if (nfsvers == NFS_V4 && 12410Sstevel@tonic-gate nfs_proto != NULL && 12420Sstevel@tonic-gate strncasecmp(nfs_proto, NC_UDP, strlen(NC_UDP)) == 0) { 12430Sstevel@tonic-gate pr_err(gettext("NFS V4 does not support %s\n"), nfs_proto); 12440Sstevel@tonic-gate return (RET_ERR); 12450Sstevel@tonic-gate } 12460Sstevel@tonic-gate 12470Sstevel@tonic-gate return (RET_OK); 12480Sstevel@tonic-gate 12490Sstevel@tonic-gate badopt: 12500Sstevel@tonic-gate pr_err(gettext("invalid option: \"%s\"\n"), saveopt); 12510Sstevel@tonic-gate free(optstr); 12520Sstevel@tonic-gate return (RET_ERR); 12530Sstevel@tonic-gate } 12540Sstevel@tonic-gate 12550Sstevel@tonic-gate static int 12560Sstevel@tonic-gate make_secure(struct nfs_args *args, char *hostname, struct netconfig *nconf, 12570Sstevel@tonic-gate bool_t use_pubfh, rpcvers_t vers) 12580Sstevel@tonic-gate { 12590Sstevel@tonic-gate sec_data_t *secdata; 12600Sstevel@tonic-gate int flags; 12610Sstevel@tonic-gate struct netbuf *syncaddr = NULL; 12620Sstevel@tonic-gate struct nd_addrlist *retaddrs = NULL; 12630Sstevel@tonic-gate char netname[MAXNETNAMELEN+1]; 12640Sstevel@tonic-gate 12650Sstevel@tonic-gate /* 12660Sstevel@tonic-gate * check to see if any secure mode is requested. 12670Sstevel@tonic-gate * if not, use default security mode. 12680Sstevel@tonic-gate */ 12690Sstevel@tonic-gate if (!snego_done && !sec_opt) { 12700Sstevel@tonic-gate /* 12715302Sth199096 * Get default security mode. 12725302Sth199096 * AUTH_UNIX has been the default choice for a long time. 12735302Sth199096 * The better NFS security service becomes, the better chance 12745302Sth199096 * we will set stronger security service as the default NFS 12755302Sth199096 * security mode. 12760Sstevel@tonic-gate */ 12775302Sth199096 if (nfs_getseconfig_default(&nfs_sec)) { 12785302Sth199096 pr_err(gettext("error getting default" 12795302Sth199096 " security entry\n")); 12805302Sth199096 return (-1); 12815302Sth199096 } 12825302Sth199096 args->flags |= NFSMNT_SECDEFAULT; 12830Sstevel@tonic-gate } 12840Sstevel@tonic-gate 12850Sstevel@tonic-gate /* 12860Sstevel@tonic-gate * Get the network address for the time service on the server. 12870Sstevel@tonic-gate * If an RPC based time service is not available then try the 12880Sstevel@tonic-gate * IP time service. 12890Sstevel@tonic-gate * 12900Sstevel@tonic-gate * This is for AUTH_DH processing. We will also pass down syncaddr 12910Sstevel@tonic-gate * and netname for NFS V4 even if AUTH_DH is not requested right now. 12920Sstevel@tonic-gate * NFS V4 does security negotiation in the kernel via SECINFO. 12930Sstevel@tonic-gate * These information might be needed later in the kernel. 12940Sstevel@tonic-gate * 12950Sstevel@tonic-gate * Eventurally, we want to move this code to nfs_clnt_secdata() 12960Sstevel@tonic-gate * when autod_nfs.c and mount.c can share the same get_the_addr() 12970Sstevel@tonic-gate * routine. 12980Sstevel@tonic-gate */ 12990Sstevel@tonic-gate flags = 0; 13000Sstevel@tonic-gate syncaddr = NULL; 13010Sstevel@tonic-gate 13020Sstevel@tonic-gate if (nfs_sec.sc_rpcnum == AUTH_DH || vers == NFS_V4) { 13030Sstevel@tonic-gate /* 13040Sstevel@tonic-gate * If using the public fh or nfsv4, we will not contact the 13050Sstevel@tonic-gate * remote RPCBINDer, since it is possibly behind a firewall. 13060Sstevel@tonic-gate */ 13075302Sth199096 if (use_pubfh == FALSE && vers != NFS_V4) 13080Sstevel@tonic-gate syncaddr = get_the_addr(hostname, RPCBPROG, RPCBVERS, 13095302Sth199096 nconf, 0, NULL, NULL, FALSE, NULL, NULL); 13100Sstevel@tonic-gate 13110Sstevel@tonic-gate if (syncaddr != NULL) { 13120Sstevel@tonic-gate /* for flags in sec_data */ 13130Sstevel@tonic-gate flags |= AUTH_F_RPCTIMESYNC; 13140Sstevel@tonic-gate } else { 13150Sstevel@tonic-gate struct nd_hostserv hs; 13160Sstevel@tonic-gate int error; 13170Sstevel@tonic-gate 13180Sstevel@tonic-gate hs.h_host = hostname; 13190Sstevel@tonic-gate hs.h_serv = "timserver"; 13200Sstevel@tonic-gate 13210Sstevel@tonic-gate error = netdir_getbyname(nconf, &hs, &retaddrs); 13220Sstevel@tonic-gate 13230Sstevel@tonic-gate if (error != ND_OK && (nfs_sec.sc_rpcnum == AUTH_DH)) { 13245302Sth199096 pr_err(gettext("%s: secure: no time service\n"), 13255302Sth199096 hostname); 13265302Sth199096 return (-1); 13270Sstevel@tonic-gate } 13280Sstevel@tonic-gate 13290Sstevel@tonic-gate if (error == ND_OK) 13300Sstevel@tonic-gate syncaddr = retaddrs->n_addrs; 13310Sstevel@tonic-gate 13320Sstevel@tonic-gate /* 13330Sstevel@tonic-gate * For NFS_V4 if AUTH_DH is negotiated later in the 13340Sstevel@tonic-gate * kernel thru SECINFO, it will need syncaddr 13350Sstevel@tonic-gate * and netname data. 13360Sstevel@tonic-gate */ 13370Sstevel@tonic-gate if (vers == NFS_V4 && syncaddr && 13385302Sth199096 host2netname(netname, hostname, NULL)) { 13395302Sth199096 args->syncaddr = malloc(sizeof (struct netbuf)); 13405302Sth199096 args->syncaddr->buf = malloc(syncaddr->len); 13415302Sth199096 (void) memcpy(args->syncaddr->buf, 13425302Sth199096 syncaddr->buf, syncaddr->len); 13435302Sth199096 args->syncaddr->len = syncaddr->len; 13445302Sth199096 args->syncaddr->maxlen = syncaddr->maxlen; 13455302Sth199096 args->netname = strdup(netname); 13465302Sth199096 args->flags |= NFSMNT_SECURE; 13470Sstevel@tonic-gate } 13480Sstevel@tonic-gate } 13490Sstevel@tonic-gate } 13500Sstevel@tonic-gate 13510Sstevel@tonic-gate /* 13520Sstevel@tonic-gate * For the initial chosen flavor (any flavor defined in nfssec.conf), 13530Sstevel@tonic-gate * the data will be stored in the sec_data structure via 13540Sstevel@tonic-gate * nfs_clnt_secdata() and be passed to the kernel via nfs_args_* 13550Sstevel@tonic-gate * extended data structure. 13560Sstevel@tonic-gate */ 13570Sstevel@tonic-gate if (!(secdata = nfs_clnt_secdata(&nfs_sec, hostname, args->knconf, 13585302Sth199096 syncaddr, flags))) { 13590Sstevel@tonic-gate pr_err(gettext("errors constructing security related data\n")); 13600Sstevel@tonic-gate if (flags & AUTH_F_RPCTIMESYNC) { 13610Sstevel@tonic-gate free(syncaddr->buf); 13620Sstevel@tonic-gate free(syncaddr); 13630Sstevel@tonic-gate } else if (retaddrs) 13640Sstevel@tonic-gate netdir_free((void *)retaddrs, ND_ADDRLIST); 13650Sstevel@tonic-gate return (-1); 13660Sstevel@tonic-gate } 13670Sstevel@tonic-gate 13680Sstevel@tonic-gate NFS_ARGS_EXTB_secdata(args, secdata); 13690Sstevel@tonic-gate if (flags & AUTH_F_RPCTIMESYNC) { 13700Sstevel@tonic-gate free(syncaddr->buf); 13710Sstevel@tonic-gate free(syncaddr); 13720Sstevel@tonic-gate } else if (retaddrs) 13730Sstevel@tonic-gate netdir_free((void *)retaddrs, ND_ADDRLIST); 13740Sstevel@tonic-gate return (0); 13750Sstevel@tonic-gate } 13760Sstevel@tonic-gate 13770Sstevel@tonic-gate /* 13780Sstevel@tonic-gate * Get the network address on "hostname" for program "prog" 13790Sstevel@tonic-gate * with version "vers" by using the nconf configuration data 13800Sstevel@tonic-gate * passed in. 13810Sstevel@tonic-gate * 13820Sstevel@tonic-gate * If the address of a netconfig pointer is null then 13830Sstevel@tonic-gate * information is not sufficient and no netbuf will be returned. 13840Sstevel@tonic-gate * 13850Sstevel@tonic-gate * Finally, ping the null procedure of that service. 13860Sstevel@tonic-gate * 13870Sstevel@tonic-gate * A similar routine is also defined in ../../autofs/autod_nfs.c. 13880Sstevel@tonic-gate * This is a potential routine to move to ../lib for common usage. 13890Sstevel@tonic-gate */ 13900Sstevel@tonic-gate static struct netbuf * 13910Sstevel@tonic-gate get_the_addr(char *hostname, ulong_t prog, ulong_t vers, 13920Sstevel@tonic-gate struct netconfig *nconf, ushort_t port, struct t_info *tinfo, 13930Sstevel@tonic-gate caddr_t *fhp, bool_t get_pubfh, char *fspath, err_ret_t *error) 13940Sstevel@tonic-gate { 13950Sstevel@tonic-gate struct netbuf *nb = NULL; 13960Sstevel@tonic-gate struct t_bind *tbind = NULL; 13970Sstevel@tonic-gate CLIENT *cl = NULL; 13980Sstevel@tonic-gate struct timeval tv; 13990Sstevel@tonic-gate int fd = -1; 14000Sstevel@tonic-gate AUTH *ah = NULL; 14010Sstevel@tonic-gate AUTH *new_ah = NULL; 14020Sstevel@tonic-gate struct snego_t snego; 14030Sstevel@tonic-gate 14040Sstevel@tonic-gate if (nconf == NULL) 14050Sstevel@tonic-gate return (NULL); 14060Sstevel@tonic-gate 14070Sstevel@tonic-gate if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) == -1) 14085302Sth199096 goto done; 14090Sstevel@tonic-gate 14100Sstevel@tonic-gate /* LINTED pointer alignment */ 14110Sstevel@tonic-gate if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR)) 14125302Sth199096 == NULL) 14130Sstevel@tonic-gate goto done; 14140Sstevel@tonic-gate 14150Sstevel@tonic-gate /* 14160Sstevel@tonic-gate * In the case of public filehandle usage or NFSv4 we want to 14170Sstevel@tonic-gate * avoid use of the rpcbind/portmap protocol 14180Sstevel@tonic-gate */ 14190Sstevel@tonic-gate if ((get_pubfh == TRUE) || (vers == NFS_V4)) { 14200Sstevel@tonic-gate struct nd_hostserv hs; 14210Sstevel@tonic-gate struct nd_addrlist *retaddrs; 14220Sstevel@tonic-gate int retval; 14230Sstevel@tonic-gate hs.h_host = hostname; 14240Sstevel@tonic-gate 14250Sstevel@tonic-gate /* NFS where vers==4 does not support UDP */ 14260Sstevel@tonic-gate if (vers == NFS_V4 && 14270Sstevel@tonic-gate strncasecmp(nconf->nc_proto, NC_UDP, 14285302Sth199096 strlen(NC_UDP)) == 0) { 142977Soa138391 SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0); 14300Sstevel@tonic-gate goto done; 14310Sstevel@tonic-gate } 14320Sstevel@tonic-gate 14330Sstevel@tonic-gate if (port == 0) 14340Sstevel@tonic-gate hs.h_serv = "nfs"; 14350Sstevel@tonic-gate else 14360Sstevel@tonic-gate hs.h_serv = NULL; 14370Sstevel@tonic-gate 14380Sstevel@tonic-gate if ((retval = netdir_getbyname(nconf, &hs, &retaddrs)) 14390Sstevel@tonic-gate != ND_OK) { 14400Sstevel@tonic-gate /* 14410Sstevel@tonic-gate * Carefully set the error value here. Want to signify 14420Sstevel@tonic-gate * that the error was an unknown host. 14430Sstevel@tonic-gate */ 14440Sstevel@tonic-gate if (retval == ND_NOHOST) { 14450Sstevel@tonic-gate SET_ERR_RET(error, ERR_NOHOST, retval); 14460Sstevel@tonic-gate } 14470Sstevel@tonic-gate 14480Sstevel@tonic-gate goto done; 14490Sstevel@tonic-gate } 14500Sstevel@tonic-gate memcpy(tbind->addr.buf, retaddrs->n_addrs->buf, 14515302Sth199096 retaddrs->n_addrs->len); 14520Sstevel@tonic-gate tbind->addr.len = retaddrs->n_addrs->len; 14530Sstevel@tonic-gate netdir_free((void *)retaddrs, ND_ADDRLIST); 14540Sstevel@tonic-gate (void) netdir_options(nconf, ND_SET_RESERVEDPORT, fd, NULL); 14550Sstevel@tonic-gate 14560Sstevel@tonic-gate } else { 14570Sstevel@tonic-gate if (rpcb_getaddr(prog, vers, nconf, &tbind->addr, 14580Sstevel@tonic-gate hostname) == FALSE) { 14590Sstevel@tonic-gate goto done; 14600Sstevel@tonic-gate } 14610Sstevel@tonic-gate } 14620Sstevel@tonic-gate 14630Sstevel@tonic-gate if (port) { 14640Sstevel@tonic-gate /* LINTED pointer alignment */ 14650Sstevel@tonic-gate if (strcmp(nconf->nc_protofmly, NC_INET) == 0) 14660Sstevel@tonic-gate ((struct sockaddr_in *)tbind->addr.buf)->sin_port 14675302Sth199096 = port; 14680Sstevel@tonic-gate else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) 14690Sstevel@tonic-gate ((struct sockaddr_in6 *)tbind->addr.buf)->sin6_port 14705302Sth199096 = port; 14710Sstevel@tonic-gate 14720Sstevel@tonic-gate } 14730Sstevel@tonic-gate 14740Sstevel@tonic-gate cl = clnt_tli_create(fd, nconf, &tbind->addr, prog, vers, 0, 0); 14750Sstevel@tonic-gate if (cl == NULL) { 147677Soa138391 /* 147777Soa138391 * clnt_tli_create() returns either RPC_SYSTEMERROR, 147877Soa138391 * RPC_UNKNOWNPROTO or RPC_TLIERROR. The RPC_TLIERROR translates 147977Soa138391 * to "Misc. TLI error". This is not too helpful. Most likely 148077Soa138391 * the connection to the remote server timed out, so this 148177Soa138391 * error is at least less perplexing. 148277Soa138391 * See: usr/src/cmd/rpcinfo/rpcinfo.c 148377Soa138391 */ 148477Soa138391 if (rpc_createerr.cf_stat == RPC_TLIERROR) { 148577Soa138391 SET_ERR_RET(error, ERR_RPCERROR, RPC_PMAPFAILURE); 148677Soa138391 } else { 148777Soa138391 SET_ERR_RET(error, ERR_RPCERROR, rpc_createerr.cf_stat); 148877Soa138391 } 14890Sstevel@tonic-gate goto done; 14900Sstevel@tonic-gate } 14910Sstevel@tonic-gate 14920Sstevel@tonic-gate ah = authsys_create_default(); 14930Sstevel@tonic-gate if (ah != NULL) 14940Sstevel@tonic-gate cl->cl_auth = ah; 14950Sstevel@tonic-gate 14960Sstevel@tonic-gate tv.tv_sec = 5; 14970Sstevel@tonic-gate tv.tv_usec = 0; 14980Sstevel@tonic-gate 14990Sstevel@tonic-gate (void) clnt_control(cl, CLSET_TIMEOUT, (char *)&tv); 15000Sstevel@tonic-gate 15010Sstevel@tonic-gate if ((get_pubfh == TRUE) && (vers != NFS_V4)) { 15025302Sth199096 enum snego_stat sec; 15030Sstevel@tonic-gate 15045302Sth199096 if (!snego_done) { 15055302Sth199096 /* 15065302Sth199096 * negotiate sec flavor. 15075302Sth199096 */ 15085302Sth199096 snego.cnt = 0; 15095302Sth199096 if ((sec = nfs_sec_nego(vers, cl, fspath, &snego)) == 15105302Sth199096 SNEGO_SUCCESS) { 15115302Sth199096 int jj; 15120Sstevel@tonic-gate 15135302Sth199096 /* 15145302Sth199096 * check if server supports the one 15155302Sth199096 * specified in the sec= option. 15165302Sth199096 */ 15170Sstevel@tonic-gate if (sec_opt) { 15185302Sth199096 for (jj = 0; jj < snego.cnt; jj++) { 15195302Sth199096 if (snego.array[jj] == 15205302Sth199096 nfs_sec.sc_nfsnum) { 15215302Sth199096 snego_done = TRUE; 15225302Sth199096 break; 15235302Sth199096 } 15245302Sth199096 } 15250Sstevel@tonic-gate } 15265302Sth199096 15275302Sth199096 /* 15285302Sth199096 * find a common sec flavor 15295302Sth199096 */ 15305302Sth199096 if (!snego_done) { 15315302Sth199096 if (sec_opt) { 15325302Sth199096 pr_err(gettext( 15335302Sth199096 "Server does not support" 15345302Sth199096 " the security flavor" 15355302Sth199096 " specified.\n")); 15365302Sth199096 } 15370Sstevel@tonic-gate 15385302Sth199096 for (jj = 0; jj < snego.cnt; jj++) { 15395302Sth199096 if (!nfs_getseconfig_bynumber( 15405302Sth199096 snego.array[jj], 15415302Sth199096 &nfs_sec)) { 15425302Sth199096 snego_done = TRUE; 15435302Sth199096 #define EMSG80SUX "Security flavor %d was negotiated and will be used.\n" 15445302Sth199096 if (sec_opt) 15455302Sth199096 pr_err(gettext( 15465302Sth199096 EMSG80SUX), 15475302Sth199096 nfs_sec. 15485302Sth199096 sc_nfsnum); 15495302Sth199096 break; 15505302Sth199096 } 15515302Sth199096 } 15525302Sth199096 } 15535302Sth199096 15545302Sth199096 if (!snego_done) 15555302Sth199096 return (NULL); 15560Sstevel@tonic-gate 15575302Sth199096 /* 15585302Sth199096 * Now that the flavor has been 15595302Sth199096 * negotiated, get the fh. 15605302Sth199096 * 15615302Sth199096 * First, create an auth handle using the 15625302Sth199096 * negotiated sec flavor in the next lookup to 15635302Sth199096 * fetch the filehandle. 15645302Sth199096 */ 15655302Sth199096 new_ah = nfs_create_ah(cl, hostname, &nfs_sec); 15665302Sth199096 if (new_ah == NULL) 15675302Sth199096 goto done; 15685302Sth199096 cl->cl_auth = new_ah; 15695302Sth199096 } else if (sec == SNEGO_ARRAY_TOO_SMALL || sec == 15705302Sth199096 SNEGO_FAILURE) { 15715302Sth199096 goto done; 15725302Sth199096 } 15730Sstevel@tonic-gate 15745302Sth199096 /* 15755302Sth199096 * Note that if sec == SNEGO_DEF_VALID 15765302Sth199096 * default sec flavor is acceptable. 15775302Sth199096 * Use it to get the filehandle. 15785302Sth199096 */ 15790Sstevel@tonic-gate } 15800Sstevel@tonic-gate 15815302Sth199096 if (vers == NFS_VERSION) { 15825302Sth199096 wnl_diropargs arg; 15837693SVallish.Vaidyeshwara@Sun.COM wnl_diropres res; 15845302Sth199096 15855302Sth199096 memset((char *)&arg.dir, 0, sizeof (wnl_fh)); 15865302Sth199096 arg.name = fspath; 15877693SVallish.Vaidyeshwara@Sun.COM memset((char *)&res, 0, sizeof (wnl_diropres)); 15887693SVallish.Vaidyeshwara@Sun.COM if (wnlproc_lookup_2(&arg, &res, cl) != 15897693SVallish.Vaidyeshwara@Sun.COM RPC_SUCCESS || res.status != NFS_OK) 15907693SVallish.Vaidyeshwara@Sun.COM goto done; 15915302Sth199096 15925302Sth199096 *fhp = malloc(sizeof (wnl_fh)); 15930Sstevel@tonic-gate 15945302Sth199096 if (*fhp == NULL) { 15955302Sth199096 pr_err(gettext("no memory\n")); 15965302Sth199096 goto done; 15975302Sth199096 } 15980Sstevel@tonic-gate 15995302Sth199096 memcpy((char *)*fhp, 16007693SVallish.Vaidyeshwara@Sun.COM (char *)&res.wnl_diropres_u.wnl_diropres.file, 16015302Sth199096 sizeof (wnl_fh)); 16025302Sth199096 } else { 16035302Sth199096 WNL_LOOKUP3args arg; 16047693SVallish.Vaidyeshwara@Sun.COM WNL_LOOKUP3res res; 16055302Sth199096 nfs_fh3 *fh3p; 16060Sstevel@tonic-gate 16075302Sth199096 memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3)); 16085302Sth199096 arg.what.name = fspath; 16097693SVallish.Vaidyeshwara@Sun.COM memset((char *)&res, 0, sizeof (WNL_LOOKUP3res)); 16107693SVallish.Vaidyeshwara@Sun.COM if (wnlproc3_lookup_3(&arg, &res, cl) != 16117693SVallish.Vaidyeshwara@Sun.COM RPC_SUCCESS || res.status != NFS3_OK) 16125302Sth199096 goto done; 16135302Sth199096 16145302Sth199096 fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p)); 16150Sstevel@tonic-gate 16165302Sth199096 if (fh3p == NULL) { 16175302Sth199096 pr_err(gettext("no memory\n")); 16185302Sth199096 goto done; 16195302Sth199096 } 16200Sstevel@tonic-gate 16215302Sth199096 fh3p->fh3_length = 16227693SVallish.Vaidyeshwara@Sun.COM res.WNL_LOOKUP3res_u.res_ok.object.data.data_len; 16235302Sth199096 memcpy(fh3p->fh3_u.data, 16248650SVallish.Vaidyeshwara@Sun.COM res.WNL_LOOKUP3res_u.res_ok.object.data.data_val, 16255302Sth199096 fh3p->fh3_length); 16260Sstevel@tonic-gate 16275302Sth199096 *fhp = (caddr_t)fh3p; 16285302Sth199096 } 16290Sstevel@tonic-gate } else { 16300Sstevel@tonic-gate struct rpc_err r_err; 16317693SVallish.Vaidyeshwara@Sun.COM enum clnt_stat rc; 16320Sstevel@tonic-gate 16337693SVallish.Vaidyeshwara@Sun.COM /* 16347693SVallish.Vaidyeshwara@Sun.COM * NULL procedures need not have an argument or 16357693SVallish.Vaidyeshwara@Sun.COM * result param. 16367693SVallish.Vaidyeshwara@Sun.COM */ 16370Sstevel@tonic-gate if (vers == NFS_VERSION) 16387693SVallish.Vaidyeshwara@Sun.COM rc = wnlproc_null_2(NULL, NULL, cl); 16390Sstevel@tonic-gate else if (vers == NFS_V3) 16407693SVallish.Vaidyeshwara@Sun.COM rc = wnlproc3_null_3(NULL, NULL, cl); 16410Sstevel@tonic-gate else 16427693SVallish.Vaidyeshwara@Sun.COM rc = wnlproc4_null_4(NULL, NULL, cl); 16430Sstevel@tonic-gate 16447693SVallish.Vaidyeshwara@Sun.COM if (rc != RPC_SUCCESS) { 16450Sstevel@tonic-gate clnt_geterr(cl, &r_err); 16460Sstevel@tonic-gate if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { 16470Sstevel@tonic-gate switch (r_err.re_status) { 16480Sstevel@tonic-gate case RPC_TLIERROR: 16490Sstevel@tonic-gate case RPC_CANTRECV: 16500Sstevel@tonic-gate case RPC_CANTSEND: 16510Sstevel@tonic-gate r_err.re_status = RPC_PROGVERSMISMATCH; 16520Sstevel@tonic-gate } 16530Sstevel@tonic-gate } 16540Sstevel@tonic-gate SET_ERR_RET(error, ERR_RPCERROR, r_err.re_status); 16550Sstevel@tonic-gate goto done; 16560Sstevel@tonic-gate } 16570Sstevel@tonic-gate } 16580Sstevel@tonic-gate 16590Sstevel@tonic-gate /* 16600Sstevel@tonic-gate * Make a copy of the netbuf to return 16610Sstevel@tonic-gate */ 16620Sstevel@tonic-gate nb = (struct netbuf *)malloc(sizeof (*nb)); 16630Sstevel@tonic-gate if (nb == NULL) { 16640Sstevel@tonic-gate pr_err(gettext("no memory\n")); 16650Sstevel@tonic-gate goto done; 16660Sstevel@tonic-gate } 16670Sstevel@tonic-gate *nb = tbind->addr; 16680Sstevel@tonic-gate nb->buf = (char *)malloc(nb->maxlen); 16690Sstevel@tonic-gate if (nb->buf == NULL) { 16700Sstevel@tonic-gate pr_err(gettext("no memory\n")); 16710Sstevel@tonic-gate free(nb); 16720Sstevel@tonic-gate nb = NULL; 16730Sstevel@tonic-gate goto done; 16740Sstevel@tonic-gate } 16750Sstevel@tonic-gate (void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len); 16760Sstevel@tonic-gate 16770Sstevel@tonic-gate done: 16780Sstevel@tonic-gate if (cl) { 16795302Sth199096 if (ah != NULL) { 16805302Sth199096 if (new_ah != NULL) 16815302Sth199096 AUTH_DESTROY(ah); 16825302Sth199096 AUTH_DESTROY(cl->cl_auth); 16835302Sth199096 cl->cl_auth = NULL; 16845302Sth199096 } 16855302Sth199096 clnt_destroy(cl); 16865302Sth199096 cl = NULL; 16870Sstevel@tonic-gate } 16880Sstevel@tonic-gate if (tbind) { 16890Sstevel@tonic-gate t_free((char *)tbind, T_BIND); 16900Sstevel@tonic-gate tbind = NULL; 16910Sstevel@tonic-gate } 16920Sstevel@tonic-gate if (fd >= 0) 16930Sstevel@tonic-gate (void) t_close(fd); 16940Sstevel@tonic-gate return (nb); 16950Sstevel@tonic-gate } 16960Sstevel@tonic-gate 16975302Sth199096 static int 16985302Sth199096 check_nconf(struct netconfig *nconf, int nthtry, int *valid_proto) 16995302Sth199096 { 17005302Sth199096 int try_test = 0; 17015302Sth199096 int valid_family; 17025302Sth199096 char *proto = NULL; 17035302Sth199096 17045302Sth199096 17055302Sth199096 if (nthtry == FIRST_TRY) { 17065302Sth199096 try_test = ((nconf->nc_semantics == NC_TPI_COTS_ORD) || 17075302Sth199096 (nconf->nc_semantics == NC_TPI_COTS)); 17085302Sth199096 proto = NC_TCP; 17095302Sth199096 } else if (nthtry == SECOND_TRY) { 17105302Sth199096 try_test = (nconf->nc_semantics == NC_TPI_CLTS); 17115302Sth199096 proto = NC_UDP; 17125302Sth199096 } 17135302Sth199096 17145302Sth199096 if (proto && 17155302Sth199096 (strcmp(nconf->nc_protofmly, NC_INET) == 0 || 17165302Sth199096 strcmp(nconf->nc_protofmly, NC_INET6) == 0) && 17175302Sth199096 (strcmp(nconf->nc_proto, proto) == 0)) 17185302Sth199096 *valid_proto = TRUE; 17195302Sth199096 else 17205302Sth199096 *valid_proto = FALSE; 17215302Sth199096 17225302Sth199096 return (try_test); 17235302Sth199096 } 17245302Sth199096 17250Sstevel@tonic-gate /* 17260Sstevel@tonic-gate * Get a network address on "hostname" for program "prog" 17270Sstevel@tonic-gate * with version "vers". If the port number is specified (non zero) 17280Sstevel@tonic-gate * then try for a TCP/UDP transport and set the port number of the 17290Sstevel@tonic-gate * resulting IP address. 17300Sstevel@tonic-gate * 17310Sstevel@tonic-gate * If the address of a netconfig pointer was passed and 17320Sstevel@tonic-gate * if it's not null, use it as the netconfig otherwise 17330Sstevel@tonic-gate * assign the address of the netconfig that was used to 17340Sstevel@tonic-gate * establish contact with the service. 17350Sstevel@tonic-gate * 17360Sstevel@tonic-gate * A similar routine is also defined in ../../autofs/autod_nfs.c. 17370Sstevel@tonic-gate * This is a potential routine to move to ../lib for common usage. 17380Sstevel@tonic-gate * 17390Sstevel@tonic-gate * "error" refers to a more descriptive term when get_addr fails 17400Sstevel@tonic-gate * and returns NULL: ERR_PROTO_NONE if no error introduced by 17410Sstevel@tonic-gate * -o proto option, ERR_NETPATH if error found in NETPATH 17420Sstevel@tonic-gate * environment variable, ERR_PROTO_INVALID if an unrecognized 17430Sstevel@tonic-gate * protocol is specified by user, and ERR_PROTO_UNSUPP for a 17440Sstevel@tonic-gate * recognized but invalid protocol (eg. ticlts, ticots, etc.). 17450Sstevel@tonic-gate * "error" is ignored if get_addr returns non-NULL result. 17460Sstevel@tonic-gate * 17470Sstevel@tonic-gate */ 17480Sstevel@tonic-gate static struct netbuf * 17490Sstevel@tonic-gate get_addr(char *hostname, ulong_t prog, ulong_t vers, struct netconfig **nconfp, 17500Sstevel@tonic-gate char *proto, ushort_t port, struct t_info *tinfo, caddr_t *fhp, 17510Sstevel@tonic-gate bool_t get_pubfh, char *fspath, err_ret_t *error) 17520Sstevel@tonic-gate { 17530Sstevel@tonic-gate struct netbuf *nb = NULL; 17540Sstevel@tonic-gate struct netconfig *nconf = NULL; 17550Sstevel@tonic-gate NCONF_HANDLE *nc = NULL; 17560Sstevel@tonic-gate int nthtry = FIRST_TRY; 17570Sstevel@tonic-gate err_ret_t errsave_nohost, errsave_rpcerr; 17580Sstevel@tonic-gate 17590Sstevel@tonic-gate SET_ERR_RET(&errsave_nohost, ERR_PROTO_NONE, 0); 17600Sstevel@tonic-gate SET_ERR_RET(&errsave_rpcerr, ERR_PROTO_NONE, 0); 17610Sstevel@tonic-gate 17620Sstevel@tonic-gate SET_ERR_RET(error, ERR_PROTO_NONE, 0); 17630Sstevel@tonic-gate 17640Sstevel@tonic-gate if (nconfp && *nconfp) 17650Sstevel@tonic-gate return (get_the_addr(hostname, prog, vers, *nconfp, port, 17665302Sth199096 tinfo, fhp, get_pubfh, fspath, error)); 17670Sstevel@tonic-gate /* 17680Sstevel@tonic-gate * No nconf passed in. 17690Sstevel@tonic-gate * 17700Sstevel@tonic-gate * Try to get a nconf from /etc/netconfig filtered by 17710Sstevel@tonic-gate * the NETPATH environment variable. 17720Sstevel@tonic-gate * First search for COTS, second for CLTS unless proto 17730Sstevel@tonic-gate * is specified. When we retry, we reset the 17740Sstevel@tonic-gate * netconfig list so that we would search the whole list 17750Sstevel@tonic-gate * all over again. 17760Sstevel@tonic-gate */ 17770Sstevel@tonic-gate 17780Sstevel@tonic-gate if ((nc = setnetpath()) == NULL) { 17790Sstevel@tonic-gate /* should only return an error if problems with NETPATH */ 17800Sstevel@tonic-gate /* In which case you are hosed */ 17810Sstevel@tonic-gate SET_ERR_RET(error, ERR_NETPATH, 0); 17820Sstevel@tonic-gate goto done; 17830Sstevel@tonic-gate } 17840Sstevel@tonic-gate 17850Sstevel@tonic-gate /* 17860Sstevel@tonic-gate * If proto is specified, then only search for the match, 17870Sstevel@tonic-gate * otherwise try COTS first, if failed, try CLTS. 17880Sstevel@tonic-gate */ 17890Sstevel@tonic-gate if (proto) { 17900Sstevel@tonic-gate /* no matching proto name */ 17910Sstevel@tonic-gate SET_ERR_RET(error, ERR_PROTO_INVALID, 0); 17920Sstevel@tonic-gate 17930Sstevel@tonic-gate while (nconf = getnetpath(nc)) { 17940Sstevel@tonic-gate if (strcmp(nconf->nc_netid, proto)) 17950Sstevel@tonic-gate continue; 17960Sstevel@tonic-gate 17970Sstevel@tonic-gate /* may be unsupported */ 17980Sstevel@tonic-gate SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0); 17990Sstevel@tonic-gate 18000Sstevel@tonic-gate if ((port != 0) && 18015302Sth199096 ((strcmp(nconf->nc_protofmly, NC_INET) == 0 || 18025302Sth199096 strcmp(nconf->nc_protofmly, NC_INET6) == 0) && 18035302Sth199096 (strcmp(nconf->nc_proto, NC_TCP) != 0 && 18045302Sth199096 strcmp(nconf->nc_proto, NC_UDP) != 0))) { 18050Sstevel@tonic-gate continue; 18065302Sth199096 } else { 18070Sstevel@tonic-gate nb = get_the_addr(hostname, prog, 18085302Sth199096 vers, nconf, port, tinfo, 18095302Sth199096 fhp, get_pubfh, fspath, error); 18100Sstevel@tonic-gate 18110Sstevel@tonic-gate if (nb != NULL) 18120Sstevel@tonic-gate break; 18130Sstevel@tonic-gate 18140Sstevel@tonic-gate /* nb is NULL - deal with errors */ 18150Sstevel@tonic-gate if (error) { 18160Sstevel@tonic-gate if (error->error_type == ERR_NOHOST) 18170Sstevel@tonic-gate SET_ERR_RET(&errsave_nohost, 18185302Sth199096 error->error_type, 18195302Sth199096 error->error_value); 18200Sstevel@tonic-gate if (error->error_type == ERR_RPCERROR) 18210Sstevel@tonic-gate SET_ERR_RET(&errsave_rpcerr, 18225302Sth199096 error->error_type, 18235302Sth199096 error->error_value); 18240Sstevel@tonic-gate } 18250Sstevel@tonic-gate /* 18260Sstevel@tonic-gate * continue with same protocol 18270Sstevel@tonic-gate * selection 18280Sstevel@tonic-gate */ 18290Sstevel@tonic-gate continue; 18300Sstevel@tonic-gate } 18310Sstevel@tonic-gate } /* end of while */ 18320Sstevel@tonic-gate 18330Sstevel@tonic-gate if (nconf == NULL) 18340Sstevel@tonic-gate goto done; 18350Sstevel@tonic-gate 18360Sstevel@tonic-gate if ((nb = get_the_addr(hostname, prog, vers, nconf, port, 18375302Sth199096 tinfo, fhp, get_pubfh, fspath, error)) == NULL) 18380Sstevel@tonic-gate goto done; 18390Sstevel@tonic-gate } else { 18400Sstevel@tonic-gate retry: 18410Sstevel@tonic-gate SET_ERR_RET(error, ERR_NETPATH, 0); 18420Sstevel@tonic-gate while (nconf = getnetpath(nc)) { 18430Sstevel@tonic-gate SET_ERR_RET(error, ERR_PROTO_NONE, 0); 18445302Sth199096 18450Sstevel@tonic-gate if (nconf->nc_flag & NC_VISIBLE) { 18465302Sth199096 int valid_proto; 18470Sstevel@tonic-gate 18485302Sth199096 if (check_nconf(nconf, 18495302Sth199096 nthtry, &valid_proto)) { 18505302Sth199096 if (port == 0) 18515302Sth199096 break; 18525302Sth199096 18535302Sth199096 if (valid_proto == TRUE) 18545302Sth199096 break; 18550Sstevel@tonic-gate } 18560Sstevel@tonic-gate } 18570Sstevel@tonic-gate } /* while */ 18580Sstevel@tonic-gate if (nconf == NULL) { 18590Sstevel@tonic-gate if (++nthtry <= MNT_PREF_LISTLEN) { 18600Sstevel@tonic-gate endnetpath(nc); 18610Sstevel@tonic-gate if ((nc = setnetpath()) == NULL) 18620Sstevel@tonic-gate goto done; 18630Sstevel@tonic-gate goto retry; 18640Sstevel@tonic-gate } else 18650Sstevel@tonic-gate goto done; 18660Sstevel@tonic-gate } else { 18670Sstevel@tonic-gate if ((nb = get_the_addr(hostname, prog, vers, nconf, 18685302Sth199096 port, tinfo, fhp, get_pubfh, fspath, error)) 18695302Sth199096 == NULL) { 18700Sstevel@tonic-gate /* nb is NULL - deal with errors */ 18710Sstevel@tonic-gate if (error) { 18720Sstevel@tonic-gate if (error->error_type == ERR_NOHOST) 18730Sstevel@tonic-gate SET_ERR_RET(&errsave_nohost, 18745302Sth199096 error->error_type, 18755302Sth199096 error->error_value); 18760Sstevel@tonic-gate if (error->error_type == ERR_RPCERROR) 18770Sstevel@tonic-gate SET_ERR_RET(&errsave_rpcerr, 18785302Sth199096 error->error_type, 18795302Sth199096 error->error_value); 18800Sstevel@tonic-gate } 18810Sstevel@tonic-gate /* 18820Sstevel@tonic-gate * Continue the same search path in the 18830Sstevel@tonic-gate * netconfig db until no more matched 18840Sstevel@tonic-gate * nconf (nconf == NULL). 18850Sstevel@tonic-gate */ 18860Sstevel@tonic-gate goto retry; 18870Sstevel@tonic-gate } 18880Sstevel@tonic-gate } 18890Sstevel@tonic-gate } 18900Sstevel@tonic-gate SET_ERR_RET(error, ERR_PROTO_NONE, 0); 18910Sstevel@tonic-gate 18920Sstevel@tonic-gate /* 18930Sstevel@tonic-gate * Got nconf and nb. Now dup the netconfig structure (nconf) 18940Sstevel@tonic-gate * and return it thru nconfp. 18950Sstevel@tonic-gate */ 18960Sstevel@tonic-gate *nconfp = getnetconfigent(nconf->nc_netid); 18970Sstevel@tonic-gate if (*nconfp == NULL) { 18980Sstevel@tonic-gate syslog(LOG_ERR, "no memory\n"); 18990Sstevel@tonic-gate free(nb); 19000Sstevel@tonic-gate nb = NULL; 19010Sstevel@tonic-gate } 19020Sstevel@tonic-gate done: 19030Sstevel@tonic-gate if (nc) 19040Sstevel@tonic-gate endnetpath(nc); 19050Sstevel@tonic-gate 19060Sstevel@tonic-gate if (nb == NULL) { 190777Soa138391 /* 190877Soa138391 * Check the saved errors. The RPC error has * 190977Soa138391 * precedence over the no host error. 191077Soa138391 */ 191177Soa138391 if (errsave_nohost.error_type != ERR_PROTO_NONE) 191277Soa138391 SET_ERR_RET(error, errsave_nohost.error_type, 19135302Sth199096 errsave_nohost.error_value); 191477Soa138391 191577Soa138391 if (errsave_rpcerr.error_type != ERR_PROTO_NONE) 191677Soa138391 SET_ERR_RET(error, errsave_rpcerr.error_type, 19175302Sth199096 errsave_rpcerr.error_value); 19180Sstevel@tonic-gate } 191977Soa138391 19200Sstevel@tonic-gate return (nb); 19210Sstevel@tonic-gate } 19220Sstevel@tonic-gate 19230Sstevel@tonic-gate /* 19240Sstevel@tonic-gate * Get a file handle usinging multi-component lookup with the public 19250Sstevel@tonic-gate * file handle. 19260Sstevel@tonic-gate */ 19270Sstevel@tonic-gate static int 19280Sstevel@tonic-gate get_fh_via_pub(struct nfs_args *args, char *fshost, char *fspath, bool_t url, 19290Sstevel@tonic-gate bool_t loud, int *versp, struct netconfig **nconfp, ushort_t port) 19300Sstevel@tonic-gate { 19310Sstevel@tonic-gate uint_t vers_min; 19320Sstevel@tonic-gate uint_t vers_max; 19330Sstevel@tonic-gate int r; 19340Sstevel@tonic-gate char *path; 19350Sstevel@tonic-gate 19360Sstevel@tonic-gate if (nfsvers != 0) { 19370Sstevel@tonic-gate vers_max = vers_min = nfsvers; 19380Sstevel@tonic-gate } else { 19390Sstevel@tonic-gate vers_max = vers_max_default; 19400Sstevel@tonic-gate vers_min = vers_min_default; 19410Sstevel@tonic-gate } 19420Sstevel@tonic-gate 19430Sstevel@tonic-gate if (url == FALSE) { 19440Sstevel@tonic-gate path = malloc(strlen(fspath) + 2); 19450Sstevel@tonic-gate if (path == NULL) { 19465302Sth199096 if (loud == TRUE) 19470Sstevel@tonic-gate pr_err(gettext("no memory\n")); 19480Sstevel@tonic-gate return (RET_ERR); 19490Sstevel@tonic-gate } 19500Sstevel@tonic-gate 19510Sstevel@tonic-gate path[0] = (char)WNL_NATIVEPATH; 19520Sstevel@tonic-gate (void) strcpy(&path[1], fspath); 19530Sstevel@tonic-gate 19540Sstevel@tonic-gate } else { 19550Sstevel@tonic-gate path = fspath; 19560Sstevel@tonic-gate } 19570Sstevel@tonic-gate 19580Sstevel@tonic-gate for (nfsvers_to_use = vers_max; nfsvers_to_use >= vers_min; 19590Sstevel@tonic-gate nfsvers_to_use--) { 19600Sstevel@tonic-gate /* 19610Sstevel@tonic-gate * getaddr_nfs will also fill in the fh for us. 19620Sstevel@tonic-gate */ 19630Sstevel@tonic-gate r = getaddr_nfs(args, fshost, nconfp, 19645302Sth199096 TRUE, path, port, NULL, FALSE); 19650Sstevel@tonic-gate 19660Sstevel@tonic-gate if (r == RET_OK) { 19670Sstevel@tonic-gate /* 19680Sstevel@tonic-gate * Since we are using the public fh, and NLM is 19690Sstevel@tonic-gate * not firewall friendly, use local locking. 19700Sstevel@tonic-gate * Not the case for v4. 19710Sstevel@tonic-gate */ 19720Sstevel@tonic-gate *versp = nfsvers_to_use; 19730Sstevel@tonic-gate switch (nfsvers_to_use) { 19740Sstevel@tonic-gate case NFS_V4: 19750Sstevel@tonic-gate fstype = MNTTYPE_NFS4; 19760Sstevel@tonic-gate break; 19770Sstevel@tonic-gate case NFS_V3: 19780Sstevel@tonic-gate fstype = MNTTYPE_NFS3; 19790Sstevel@tonic-gate /* fall through to pick up llock option */ 19800Sstevel@tonic-gate default: 19810Sstevel@tonic-gate args->flags |= NFSMNT_LLOCK; 19820Sstevel@tonic-gate break; 19830Sstevel@tonic-gate } 19840Sstevel@tonic-gate if (fspath != path) 19850Sstevel@tonic-gate free(path); 19860Sstevel@tonic-gate 19870Sstevel@tonic-gate return (r); 19880Sstevel@tonic-gate } 19890Sstevel@tonic-gate } 19900Sstevel@tonic-gate 19915302Sth199096 if (fspath != path) 19920Sstevel@tonic-gate free(path); 19930Sstevel@tonic-gate 19940Sstevel@tonic-gate if (loud == TRUE) { 19950Sstevel@tonic-gate pr_err(gettext("Could not use public filehandle in request to" 19965302Sth199096 " server %s\n"), fshost); 19970Sstevel@tonic-gate } 19980Sstevel@tonic-gate 19990Sstevel@tonic-gate return (r); 20000Sstevel@tonic-gate } 20010Sstevel@tonic-gate 20020Sstevel@tonic-gate /* 20030Sstevel@tonic-gate * get fhandle of remote path from server's mountd 20040Sstevel@tonic-gate */ 20050Sstevel@tonic-gate static int 20060Sstevel@tonic-gate get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp, 20070Sstevel@tonic-gate bool_t loud_on_mnt_err, struct netconfig **nconfp, ushort_t port) 20080Sstevel@tonic-gate { 20090Sstevel@tonic-gate static struct fhstatus fhs; 20100Sstevel@tonic-gate static struct mountres3 mountres3; 20110Sstevel@tonic-gate static struct pathcnf p; 20120Sstevel@tonic-gate nfs_fh3 *fh3p; 20130Sstevel@tonic-gate struct timeval timeout = { 25, 0}; 20140Sstevel@tonic-gate CLIENT *cl; 20150Sstevel@tonic-gate enum clnt_stat rpc_stat; 20160Sstevel@tonic-gate rpcvers_t outvers = 0; 20170Sstevel@tonic-gate rpcvers_t vers_to_try; 20180Sstevel@tonic-gate rpcvers_t vers_min; 20190Sstevel@tonic-gate static int printed = 0; 20200Sstevel@tonic-gate int count, i, *auths; 20210Sstevel@tonic-gate char *msg; 20220Sstevel@tonic-gate 20230Sstevel@tonic-gate switch (nfsvers) { 20240Sstevel@tonic-gate case 2: /* version 2 specified try that only */ 20250Sstevel@tonic-gate vers_to_try = MOUNTVERS_POSIX; 20260Sstevel@tonic-gate vers_min = MOUNTVERS; 20270Sstevel@tonic-gate break; 20280Sstevel@tonic-gate case 3: /* version 3 specified try that only */ 20290Sstevel@tonic-gate vers_to_try = MOUNTVERS3; 20300Sstevel@tonic-gate vers_min = MOUNTVERS3; 20310Sstevel@tonic-gate break; 20320Sstevel@tonic-gate case 4: /* version 4 specified try that only */ 20330Sstevel@tonic-gate /* 20340Sstevel@tonic-gate * This assignment is in the wrong version sequence. 20350Sstevel@tonic-gate * The above are MOUNT program and this is NFS 20360Sstevel@tonic-gate * program. However, it happens to work out since the 20370Sstevel@tonic-gate * two don't collide for NFSv4. 20380Sstevel@tonic-gate */ 20390Sstevel@tonic-gate vers_to_try = NFS_V4; 20400Sstevel@tonic-gate vers_min = NFS_V4; 20410Sstevel@tonic-gate break; 20420Sstevel@tonic-gate default: /* no version specified, start with default */ 2043489Soa138391 /* 2044489Soa138391 * If the retry version is set, use that. This will 2045489Soa138391 * be set if the last mount attempt returned any other 2046489Soa138391 * besides an RPC error. 2047489Soa138391 */ 2048489Soa138391 if (nfsretry_vers) 2049489Soa138391 vers_to_try = nfsretry_vers; 2050489Soa138391 else { 2051489Soa138391 vers_to_try = vers_max_default; 2052489Soa138391 vers_min = vers_min_default; 2053489Soa138391 } 2054489Soa138391 20550Sstevel@tonic-gate break; 20560Sstevel@tonic-gate } 20570Sstevel@tonic-gate 20580Sstevel@tonic-gate /* 20590Sstevel@tonic-gate * In the case of version 4, just NULL proc the server since 20600Sstevel@tonic-gate * there is no MOUNT program. If this fails, then decrease 20610Sstevel@tonic-gate * vers_to_try and continue on with regular MOUNT program 20620Sstevel@tonic-gate * processing. 20630Sstevel@tonic-gate */ 20640Sstevel@tonic-gate if (vers_to_try == NFS_V4) { 20650Sstevel@tonic-gate int savevers = nfsvers_to_use; 20660Sstevel@tonic-gate err_ret_t error; 20670Sstevel@tonic-gate int retval; 20680Sstevel@tonic-gate SET_ERR_RET(&error, ERR_PROTO_NONE, 0); 20690Sstevel@tonic-gate 20700Sstevel@tonic-gate /* Let's hope for the best */ 20710Sstevel@tonic-gate nfsvers_to_use = NFS_V4; 20725302Sth199096 retval = getaddr_nfs(args, fshost, nconfp, FALSE, 20735302Sth199096 fspath, port, &error, vers_min == NFS_V4); 20740Sstevel@tonic-gate 20750Sstevel@tonic-gate if (retval == RET_OK) { 20760Sstevel@tonic-gate *versp = nfsvers_to_use = NFS_V4; 20770Sstevel@tonic-gate fstype = MNTTYPE_NFS4; 20780Sstevel@tonic-gate args->fh = strdup(fspath); 20790Sstevel@tonic-gate if (args->fh == NULL) { 20800Sstevel@tonic-gate pr_err(gettext("no memory\n")); 20810Sstevel@tonic-gate *versp = nfsvers_to_use = savevers; 20820Sstevel@tonic-gate return (RET_ERR); 20830Sstevel@tonic-gate } 20840Sstevel@tonic-gate return (RET_OK); 20850Sstevel@tonic-gate } 20860Sstevel@tonic-gate nfsvers_to_use = savevers; 20870Sstevel@tonic-gate 20880Sstevel@tonic-gate vers_to_try--; 20890Sstevel@tonic-gate /* If no more versions to try, let the user know. */ 20905302Sth199096 if (vers_to_try < vers_min) 20910Sstevel@tonic-gate return (retval); 20920Sstevel@tonic-gate 20930Sstevel@tonic-gate /* 20940Sstevel@tonic-gate * If we are here, there are more versions to try but 20950Sstevel@tonic-gate * there has been an error of some sort. If it is not 20960Sstevel@tonic-gate * an RPC error (e.g. host unknown), we just stop and 20970Sstevel@tonic-gate * return the error since the other versions would see 20980Sstevel@tonic-gate * the same error as well. 20990Sstevel@tonic-gate */ 21000Sstevel@tonic-gate if (retval == RET_ERR && error.error_type != ERR_RPCERROR) 21010Sstevel@tonic-gate return (retval); 21020Sstevel@tonic-gate } 21030Sstevel@tonic-gate 21040Sstevel@tonic-gate while ((cl = clnt_create_vers(fshost, MOUNTPROG, &outvers, 21055302Sth199096 vers_min, vers_to_try, "datagram_v")) == NULL) { 21060Sstevel@tonic-gate if (rpc_createerr.cf_stat == RPC_UNKNOWNHOST) { 21070Sstevel@tonic-gate pr_err(gettext("%s: %s\n"), fshost, 21080Sstevel@tonic-gate clnt_spcreateerror("")); 21090Sstevel@tonic-gate return (RET_ERR); 21100Sstevel@tonic-gate } 21110Sstevel@tonic-gate 21120Sstevel@tonic-gate /* 21130Sstevel@tonic-gate * We don't want to downgrade version on lost packets 21140Sstevel@tonic-gate */ 21150Sstevel@tonic-gate if ((rpc_createerr.cf_stat == RPC_TIMEDOUT) || 21165302Sth199096 (rpc_createerr.cf_stat == RPC_PMAPFAILURE)) { 21170Sstevel@tonic-gate pr_err(gettext("%s: %s\n"), fshost, 21180Sstevel@tonic-gate clnt_spcreateerror("")); 21190Sstevel@tonic-gate return (RET_RETRY); 21200Sstevel@tonic-gate } 21210Sstevel@tonic-gate 21220Sstevel@tonic-gate /* 21230Sstevel@tonic-gate * back off and try the previous version - patch to the 21240Sstevel@tonic-gate * problem of version numbers not being contigous and 21250Sstevel@tonic-gate * clnt_create_vers failing (SunOS4.1 clients & SGI servers) 21260Sstevel@tonic-gate * The problem happens with most non-Sun servers who 21270Sstevel@tonic-gate * don't support mountd protocol #2. So, in case the 21280Sstevel@tonic-gate * call fails, we re-try the call anyway. 21290Sstevel@tonic-gate */ 21300Sstevel@tonic-gate vers_to_try--; 21310Sstevel@tonic-gate if (vers_to_try < vers_min) { 21320Sstevel@tonic-gate if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH) { 21330Sstevel@tonic-gate if (nfsvers == 0) { 21340Sstevel@tonic-gate pr_err(gettext( 21350Sstevel@tonic-gate "%s:%s: no applicable versions of NFS supported\n"), 21360Sstevel@tonic-gate fshost, fspath); 21370Sstevel@tonic-gate } else { 21380Sstevel@tonic-gate pr_err(gettext( 21390Sstevel@tonic-gate "%s:%s: NFS Version %d not supported\n"), 21400Sstevel@tonic-gate fshost, fspath, nfsvers); 21410Sstevel@tonic-gate } 21420Sstevel@tonic-gate return (RET_ERR); 21430Sstevel@tonic-gate } 21440Sstevel@tonic-gate if (!printed) { 21450Sstevel@tonic-gate pr_err(gettext("%s: %s\n"), fshost, 21460Sstevel@tonic-gate clnt_spcreateerror("")); 21470Sstevel@tonic-gate printed = 1; 21480Sstevel@tonic-gate } 21490Sstevel@tonic-gate return (RET_RETRY); 21500Sstevel@tonic-gate } 21510Sstevel@tonic-gate } 21520Sstevel@tonic-gate if (posix && outvers < MOUNTVERS_POSIX) { 21530Sstevel@tonic-gate pr_err(gettext("%s: %s: no pathconf info\n"), 21540Sstevel@tonic-gate fshost, clnt_sperror(cl, "")); 21550Sstevel@tonic-gate clnt_destroy(cl); 21560Sstevel@tonic-gate return (RET_ERR); 21570Sstevel@tonic-gate } 21580Sstevel@tonic-gate 21590Sstevel@tonic-gate if (__clnt_bindresvport(cl) < 0) { 21600Sstevel@tonic-gate pr_err(gettext("Couldn't bind to reserved port\n")); 21610Sstevel@tonic-gate clnt_destroy(cl); 21620Sstevel@tonic-gate return (RET_RETRY); 21630Sstevel@tonic-gate } 21640Sstevel@tonic-gate 21650Sstevel@tonic-gate if ((cl->cl_auth = authsys_create_default()) == NULL) { 21660Sstevel@tonic-gate pr_err( 21670Sstevel@tonic-gate gettext("Couldn't create default authentication handle\n")); 21680Sstevel@tonic-gate clnt_destroy(cl); 21690Sstevel@tonic-gate return (RET_RETRY); 21700Sstevel@tonic-gate } 21710Sstevel@tonic-gate 21720Sstevel@tonic-gate switch (outvers) { 21730Sstevel@tonic-gate case MOUNTVERS: 21740Sstevel@tonic-gate case MOUNTVERS_POSIX: 21750Sstevel@tonic-gate *versp = nfsvers_to_use = NFS_VERSION; 21760Sstevel@tonic-gate rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath, 21775302Sth199096 (caddr_t)&fspath, xdr_fhstatus, (caddr_t)&fhs, timeout); 21780Sstevel@tonic-gate if (rpc_stat != RPC_SUCCESS) { 21790Sstevel@tonic-gate pr_err(gettext("%s:%s: server not responding %s\n"), 21800Sstevel@tonic-gate fshost, fspath, clnt_sperror(cl, "")); 21810Sstevel@tonic-gate clnt_destroy(cl); 21820Sstevel@tonic-gate return (RET_RETRY); 21830Sstevel@tonic-gate } 21840Sstevel@tonic-gate 21850Sstevel@tonic-gate if ((errno = fhs.fhs_status) != MNT_OK) { 21860Sstevel@tonic-gate if (loud_on_mnt_err) { 21875302Sth199096 if (errno == EACCES) { 21885302Sth199096 pr_err(gettext( 21895302Sth199096 "%s:%s: access denied\n"), 21905302Sth199096 fshost, fspath); 21915302Sth199096 } else { 21925302Sth199096 pr_err(gettext("%s:%s: %s\n"), fshost, 21935706Sgt29601 fspath, errno >= 0 ? 21945706Sgt29601 strerror(errno) : "invalid error " 21955706Sgt29601 "returned by server"); 21965302Sth199096 } 21970Sstevel@tonic-gate } 21980Sstevel@tonic-gate clnt_destroy(cl); 21990Sstevel@tonic-gate return (RET_MNTERR); 22000Sstevel@tonic-gate } 22010Sstevel@tonic-gate args->fh = malloc(sizeof (fhs.fhstatus_u.fhs_fhandle)); 22020Sstevel@tonic-gate if (args->fh == NULL) { 22030Sstevel@tonic-gate pr_err(gettext("no memory\n")); 22040Sstevel@tonic-gate return (RET_ERR); 22050Sstevel@tonic-gate } 22060Sstevel@tonic-gate memcpy((caddr_t)args->fh, (caddr_t)&fhs.fhstatus_u.fhs_fhandle, 22075302Sth199096 sizeof (fhs.fhstatus_u.fhs_fhandle)); 22080Sstevel@tonic-gate if (!errno && posix) { 22090Sstevel@tonic-gate rpc_stat = clnt_call(cl, MOUNTPROC_PATHCONF, 22105302Sth199096 xdr_dirpath, (caddr_t)&fspath, xdr_ppathcnf, 22115302Sth199096 (caddr_t)&p, timeout); 22120Sstevel@tonic-gate if (rpc_stat != RPC_SUCCESS) { 22130Sstevel@tonic-gate pr_err(gettext( 22140Sstevel@tonic-gate "%s:%s: server not responding %s\n"), 22150Sstevel@tonic-gate fshost, fspath, clnt_sperror(cl, "")); 22160Sstevel@tonic-gate free(args->fh); 22170Sstevel@tonic-gate clnt_destroy(cl); 22180Sstevel@tonic-gate return (RET_RETRY); 22190Sstevel@tonic-gate } 22200Sstevel@tonic-gate if (_PC_ISSET(_PC_ERROR, p.pc_mask)) { 22210Sstevel@tonic-gate pr_err(gettext( 22220Sstevel@tonic-gate "%s:%s: no pathconf info\n"), 22230Sstevel@tonic-gate fshost, fspath); 22240Sstevel@tonic-gate free(args->fh); 22250Sstevel@tonic-gate clnt_destroy(cl); 22260Sstevel@tonic-gate return (RET_ERR); 22270Sstevel@tonic-gate } 22280Sstevel@tonic-gate args->flags |= NFSMNT_POSIX; 22290Sstevel@tonic-gate args->pathconf = malloc(sizeof (p)); 22300Sstevel@tonic-gate if (args->pathconf == NULL) { 22310Sstevel@tonic-gate pr_err(gettext("no memory\n")); 22320Sstevel@tonic-gate free(args->fh); 22330Sstevel@tonic-gate clnt_destroy(cl); 22340Sstevel@tonic-gate return (RET_ERR); 22350Sstevel@tonic-gate } 22360Sstevel@tonic-gate memcpy((caddr_t)args->pathconf, (caddr_t)&p, 22375302Sth199096 sizeof (p)); 22380Sstevel@tonic-gate } 22390Sstevel@tonic-gate break; 22400Sstevel@tonic-gate 22410Sstevel@tonic-gate case MOUNTVERS3: 22420Sstevel@tonic-gate *versp = nfsvers_to_use = NFS_V3; 22430Sstevel@tonic-gate rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath, 22445302Sth199096 (caddr_t)&fspath, xdr_mountres3, (caddr_t)&mountres3, 22455302Sth199096 timeout); 22460Sstevel@tonic-gate if (rpc_stat != RPC_SUCCESS) { 22470Sstevel@tonic-gate pr_err(gettext("%s:%s: server not responding %s\n"), 22480Sstevel@tonic-gate fshost, fspath, clnt_sperror(cl, "")); 22490Sstevel@tonic-gate clnt_destroy(cl); 22500Sstevel@tonic-gate return (RET_RETRY); 22510Sstevel@tonic-gate } 22520Sstevel@tonic-gate 22530Sstevel@tonic-gate /* 22540Sstevel@tonic-gate * Assume here that most of the MNT3ERR_* 22550Sstevel@tonic-gate * codes map into E* errors. 22560Sstevel@tonic-gate */ 22570Sstevel@tonic-gate if ((errno = mountres3.fhs_status) != MNT_OK) { 22585302Sth199096 if (loud_on_mnt_err) { 22595302Sth199096 switch (errno) { 22605302Sth199096 case MNT3ERR_NAMETOOLONG: 22615302Sth199096 msg = "path name is too long"; 22625302Sth199096 break; 22635302Sth199096 case MNT3ERR_NOTSUPP: 22645302Sth199096 msg = "operation not supported"; 22655302Sth199096 break; 22665302Sth199096 case MNT3ERR_SERVERFAULT: 22675302Sth199096 msg = "server fault"; 22685302Sth199096 break; 22695302Sth199096 default: 22705706Sgt29601 if (errno >= 0) 22715706Sgt29601 msg = strerror(errno); 22725706Sgt29601 else 22735706Sgt29601 msg = "invalid error returned " 22745706Sgt29601 "by server"; 22755302Sth199096 break; 22765302Sth199096 } 22775302Sth199096 pr_err(gettext("%s:%s: %s\n"), fshost, 22785302Sth199096 fspath, msg); 22790Sstevel@tonic-gate } 22805302Sth199096 clnt_destroy(cl); 22815302Sth199096 return (RET_MNTERR); 22820Sstevel@tonic-gate } 22830Sstevel@tonic-gate 22840Sstevel@tonic-gate fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p)); 22850Sstevel@tonic-gate if (fh3p == NULL) { 22860Sstevel@tonic-gate pr_err(gettext("no memory\n")); 22870Sstevel@tonic-gate return (RET_ERR); 22880Sstevel@tonic-gate } 22890Sstevel@tonic-gate fh3p->fh3_length = 22905302Sth199096 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len; 22910Sstevel@tonic-gate (void) memcpy(fh3p->fh3_u.data, 22925302Sth199096 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val, 22935302Sth199096 fh3p->fh3_length); 22940Sstevel@tonic-gate args->fh = (caddr_t)fh3p; 22950Sstevel@tonic-gate fstype = MNTTYPE_NFS3; 22960Sstevel@tonic-gate 22970Sstevel@tonic-gate /* 22980Sstevel@tonic-gate * Check the security flavor to be used. 22990Sstevel@tonic-gate * 23000Sstevel@tonic-gate * If "secure" or "sec=flavor" is a mount 23010Sstevel@tonic-gate * option, check if the server supports the "flavor". 23020Sstevel@tonic-gate * If the server does not support the flavor, return 23030Sstevel@tonic-gate * error. 23040Sstevel@tonic-gate * 230510186SVallish.Vaidyeshwara@Sun.COM * If no mount option is given then look for default auth 230610186SVallish.Vaidyeshwara@Sun.COM * (default auth entry in /etc/nfssec.conf) in the auth list 230710186SVallish.Vaidyeshwara@Sun.COM * returned from server. If default auth not found, then use 230810186SVallish.Vaidyeshwara@Sun.COM * the first supported security flavor (by the client) in the 230910186SVallish.Vaidyeshwara@Sun.COM * auth list returned from the server. 23100Sstevel@tonic-gate * 23110Sstevel@tonic-gate */ 23120Sstevel@tonic-gate auths = 23135302Sth199096 mountres3.mountres3_u.mountinfo.auth_flavors 23145302Sth199096 .auth_flavors_val; 23150Sstevel@tonic-gate count = 23165302Sth199096 mountres3.mountres3_u.mountinfo.auth_flavors 23175302Sth199096 .auth_flavors_len; 23180Sstevel@tonic-gate 231910186SVallish.Vaidyeshwara@Sun.COM if (count <= 0) { 232010186SVallish.Vaidyeshwara@Sun.COM pr_err(gettext( 232110186SVallish.Vaidyeshwara@Sun.COM "server %s did not return any security mode\n"), 232210186SVallish.Vaidyeshwara@Sun.COM fshost); 232310186SVallish.Vaidyeshwara@Sun.COM clnt_destroy(cl); 232410186SVallish.Vaidyeshwara@Sun.COM return (RET_ERR); 232510186SVallish.Vaidyeshwara@Sun.COM } 232610186SVallish.Vaidyeshwara@Sun.COM 23270Sstevel@tonic-gate if (sec_opt) { 23280Sstevel@tonic-gate for (i = 0; i < count; i++) { 23290Sstevel@tonic-gate if (auths[i] == nfs_sec.sc_nfsnum) 23305302Sth199096 break; 23310Sstevel@tonic-gate } 233210186SVallish.Vaidyeshwara@Sun.COM if (i == count) 23330Sstevel@tonic-gate goto autherr; 23340Sstevel@tonic-gate } else { 233510186SVallish.Vaidyeshwara@Sun.COM seconfig_t default_sec; 233610186SVallish.Vaidyeshwara@Sun.COM 233710186SVallish.Vaidyeshwara@Sun.COM /* 233810186SVallish.Vaidyeshwara@Sun.COM * Get client configured default auth. 233910186SVallish.Vaidyeshwara@Sun.COM */ 234010186SVallish.Vaidyeshwara@Sun.COM nfs_sec.sc_nfsnum = -1; 234110186SVallish.Vaidyeshwara@Sun.COM default_sec.sc_nfsnum = -1; 234210186SVallish.Vaidyeshwara@Sun.COM (void) nfs_getseconfig_default(&default_sec); 23435302Sth199096 234410186SVallish.Vaidyeshwara@Sun.COM /* 234510186SVallish.Vaidyeshwara@Sun.COM * Look for clients default auth in servers list. 234610186SVallish.Vaidyeshwara@Sun.COM */ 234710186SVallish.Vaidyeshwara@Sun.COM if (default_sec.sc_nfsnum != -1) { 234810186SVallish.Vaidyeshwara@Sun.COM for (i = 0; i < count; i++) { 234910186SVallish.Vaidyeshwara@Sun.COM if (auths[i] == default_sec.sc_nfsnum) { 235010186SVallish.Vaidyeshwara@Sun.COM sec_opt++; 235110186SVallish.Vaidyeshwara@Sun.COM nfs_sec = default_sec; 235210186SVallish.Vaidyeshwara@Sun.COM break; 235310186SVallish.Vaidyeshwara@Sun.COM } 23545302Sth199096 } 23550Sstevel@tonic-gate } 23565302Sth199096 235710186SVallish.Vaidyeshwara@Sun.COM /* 235810186SVallish.Vaidyeshwara@Sun.COM * Could not find clients default auth in servers list. 235910186SVallish.Vaidyeshwara@Sun.COM * Pick the first auth from servers list that is 236010186SVallish.Vaidyeshwara@Sun.COM * also supported on the client. 236110186SVallish.Vaidyeshwara@Sun.COM */ 236210186SVallish.Vaidyeshwara@Sun.COM if (nfs_sec.sc_nfsnum == -1) { 236310186SVallish.Vaidyeshwara@Sun.COM for (i = 0; i < count; i++) { 236410186SVallish.Vaidyeshwara@Sun.COM if (!nfs_getseconfig_bynumber(auths[i], 236510186SVallish.Vaidyeshwara@Sun.COM &nfs_sec)) { 236610186SVallish.Vaidyeshwara@Sun.COM sec_opt++; 236710186SVallish.Vaidyeshwara@Sun.COM break; 236810186SVallish.Vaidyeshwara@Sun.COM 236910186SVallish.Vaidyeshwara@Sun.COM } 237010186SVallish.Vaidyeshwara@Sun.COM } 237110186SVallish.Vaidyeshwara@Sun.COM } 237210186SVallish.Vaidyeshwara@Sun.COM 237310186SVallish.Vaidyeshwara@Sun.COM if (i == count) 23745302Sth199096 goto autherr; 23750Sstevel@tonic-gate } 23760Sstevel@tonic-gate break; 23770Sstevel@tonic-gate default: 23780Sstevel@tonic-gate pr_err(gettext("%s:%s: Unknown MOUNT version %d\n"), 23790Sstevel@tonic-gate fshost, fspath, outvers); 23800Sstevel@tonic-gate clnt_destroy(cl); 23810Sstevel@tonic-gate return (RET_ERR); 23820Sstevel@tonic-gate } 23830Sstevel@tonic-gate 23840Sstevel@tonic-gate clnt_destroy(cl); 23850Sstevel@tonic-gate return (RET_OK); 23860Sstevel@tonic-gate 23870Sstevel@tonic-gate autherr: 23880Sstevel@tonic-gate pr_err(gettext( 23895302Sth199096 "security mode does not match the server exporting %s:%s\n"), 23905302Sth199096 fshost, fspath); 23910Sstevel@tonic-gate clnt_destroy(cl); 23920Sstevel@tonic-gate return (RET_ERR); 23930Sstevel@tonic-gate } 23940Sstevel@tonic-gate 23950Sstevel@tonic-gate /* 23960Sstevel@tonic-gate * Fill in the address for the server's NFS service and 23970Sstevel@tonic-gate * fill in a knetconfig structure for the transport that 23980Sstevel@tonic-gate * the service is available on. 23990Sstevel@tonic-gate */ 24000Sstevel@tonic-gate static int 24010Sstevel@tonic-gate getaddr_nfs(struct nfs_args *args, char *fshost, struct netconfig **nconfp, 24020Sstevel@tonic-gate bool_t get_pubfh, char *fspath, ushort_t port, err_ret_t *error, 24030Sstevel@tonic-gate bool_t print_rpcerror) 24040Sstevel@tonic-gate { 24050Sstevel@tonic-gate struct stat sb; 24060Sstevel@tonic-gate struct netconfig *nconf; 24070Sstevel@tonic-gate struct knetconfig *knconfp; 24080Sstevel@tonic-gate static int printed = 0; 24090Sstevel@tonic-gate struct t_info tinfo; 24100Sstevel@tonic-gate err_ret_t addr_error; 24110Sstevel@tonic-gate 24120Sstevel@tonic-gate SET_ERR_RET(error, ERR_PROTO_NONE, 0); 24130Sstevel@tonic-gate SET_ERR_RET(&addr_error, ERR_PROTO_NONE, 0); 24140Sstevel@tonic-gate 24150Sstevel@tonic-gate if (nfs_proto) { 24160Sstevel@tonic-gate /* 24170Sstevel@tonic-gate * If a proto is specified and its rdma try this. The kernel 24180Sstevel@tonic-gate * will later do the reachablity test and fail form there 24190Sstevel@tonic-gate * if rdma transport is not available to kernel rpc 24200Sstevel@tonic-gate */ 24210Sstevel@tonic-gate if (strcmp(nfs_proto, "rdma") == 0) { 24220Sstevel@tonic-gate args->addr = get_addr(fshost, NFS_PROGRAM, 24230Sstevel@tonic-gate nfsvers_to_use, nconfp, NULL, port, &tinfo, 24240Sstevel@tonic-gate &args->fh, get_pubfh, fspath, &addr_error); 24250Sstevel@tonic-gate 24260Sstevel@tonic-gate args->flags |= NFSMNT_DORDMA; 24270Sstevel@tonic-gate } else { 24280Sstevel@tonic-gate args->addr = get_addr(fshost, NFS_PROGRAM, 24290Sstevel@tonic-gate nfsvers_to_use, nconfp, nfs_proto, port, &tinfo, 24300Sstevel@tonic-gate &args->fh, get_pubfh, fspath, &addr_error); 24310Sstevel@tonic-gate } 24320Sstevel@tonic-gate } else { 24330Sstevel@tonic-gate args->addr = get_addr(fshost, NFS_PROGRAM, nfsvers_to_use, 24340Sstevel@tonic-gate nconfp, nfs_proto, port, &tinfo, &args->fh, get_pubfh, 24350Sstevel@tonic-gate fspath, &addr_error); 24360Sstevel@tonic-gate /* 24370Sstevel@tonic-gate * If no proto is specified set this flag. 24380Sstevel@tonic-gate * Kernel mount code will try to use RDMA if its on the 24390Sstevel@tonic-gate * system, otherwise it will keep on using the protocol 24400Sstevel@tonic-gate * selected here, through the above get_addr call. 24410Sstevel@tonic-gate */ 24420Sstevel@tonic-gate if (nfs_proto == NULL) 24430Sstevel@tonic-gate args->flags |= NFSMNT_TRYRDMA; 24440Sstevel@tonic-gate } 24450Sstevel@tonic-gate 24460Sstevel@tonic-gate if (args->addr == NULL) { 24470Sstevel@tonic-gate /* 24480Sstevel@tonic-gate * We could have failed because the server had no public 24490Sstevel@tonic-gate * file handle support. So don't print a message and don't 24500Sstevel@tonic-gate * retry. 24510Sstevel@tonic-gate */ 24520Sstevel@tonic-gate if (get_pubfh == TRUE) 24530Sstevel@tonic-gate return (RET_ERR); 24540Sstevel@tonic-gate 24550Sstevel@tonic-gate if (!printed) { 24560Sstevel@tonic-gate switch (addr_error.error_type) { 24570Sstevel@tonic-gate case 0: 2458489Soa138391 printed = 1; 24590Sstevel@tonic-gate break; 24600Sstevel@tonic-gate case ERR_RPCERROR: 24610Sstevel@tonic-gate if (!print_rpcerror) 24620Sstevel@tonic-gate /* no error print at this time */ 24630Sstevel@tonic-gate break; 24640Sstevel@tonic-gate pr_err(gettext("%s NFS service not" 24655302Sth199096 " available %s\n"), fshost, 24660Sstevel@tonic-gate clnt_sperrno(addr_error.error_value)); 2467489Soa138391 printed = 1; 24680Sstevel@tonic-gate break; 24690Sstevel@tonic-gate case ERR_NETPATH: 24700Sstevel@tonic-gate pr_err(gettext("%s: Error in NETPATH.\n"), 24715302Sth199096 fshost); 2472489Soa138391 printed = 1; 24730Sstevel@tonic-gate break; 24740Sstevel@tonic-gate case ERR_PROTO_INVALID: 24750Sstevel@tonic-gate pr_err(gettext("%s: NFS service does not" 24765302Sth199096 " recognize protocol: %s.\n"), fshost, 24775302Sth199096 nfs_proto); 2478489Soa138391 printed = 1; 24790Sstevel@tonic-gate break; 24800Sstevel@tonic-gate case ERR_PROTO_UNSUPP: 2481489Soa138391 if (nfsvers || nfsvers_to_use == NFS_VERSMIN) { 2482112Soa138391 /* 2483489Soa138391 * Don't set "printed" here. Since we 2484489Soa138391 * have to keep checking here till we 2485489Soa138391 * exhaust transport errors on all vers. 2486489Soa138391 * 2487489Soa138391 * Print this message if: 2488489Soa138391 * 1. After we have tried all versions 2489489Soa138391 * of NFS and none support the asked 2490489Soa138391 * transport. 2491489Soa138391 * 2492489Soa138391 * 2. If a version is specified and it 2493489Soa138391 * does'nt support the asked 2494489Soa138391 * transport. 2495489Soa138391 * 2496489Soa138391 * Otherwise we decrement the version 2497112Soa138391 * and retry below. 2498112Soa138391 */ 2499112Soa138391 pr_err(gettext("%s: NFS service does" 25005302Sth199096 " not support protocol: %s.\n"), 25015302Sth199096 fshost, nfs_proto); 2502112Soa138391 } 25030Sstevel@tonic-gate break; 25040Sstevel@tonic-gate case ERR_NOHOST: 250577Soa138391 pr_err("%s: %s\n", fshost, "Unknown host"); 2506489Soa138391 printed = 1; 25070Sstevel@tonic-gate break; 25080Sstevel@tonic-gate default: 25090Sstevel@tonic-gate /* case ERR_PROTO_NONE falls through */ 25100Sstevel@tonic-gate pr_err(gettext("%s: NFS service not responding" 25115302Sth199096 "\n"), fshost); 2512489Soa138391 printed = 1; 25130Sstevel@tonic-gate break; 25140Sstevel@tonic-gate } 25150Sstevel@tonic-gate } 25160Sstevel@tonic-gate SET_ERR_RET(error, 25175302Sth199096 addr_error.error_type, addr_error.error_value); 25180Sstevel@tonic-gate if (addr_error.error_type == ERR_PROTO_NONE) 25190Sstevel@tonic-gate return (RET_RETRY); 25200Sstevel@tonic-gate else if (addr_error.error_type == ERR_RPCERROR && 25215302Sth199096 !IS_UNRECOVERABLE_RPC(addr_error.error_value)) { 25220Sstevel@tonic-gate return (RET_RETRY); 2523112Soa138391 } else if (nfsvers == 0 && addr_error.error_type == 25245302Sth199096 ERR_PROTO_UNSUPP && nfsvers_to_use != NFS_VERSMIN) { 2525112Soa138391 /* 2526112Soa138391 * If no version is specified, and the error is due 2527489Soa138391 * to an unsupported transport, then decrement the 2528112Soa138391 * version and retry. 2529112Soa138391 */ 2530112Soa138391 return (RET_RETRY); 2531112Soa138391 } else 25320Sstevel@tonic-gate return (RET_ERR); 25330Sstevel@tonic-gate } 25340Sstevel@tonic-gate nconf = *nconfp; 25350Sstevel@tonic-gate 25360Sstevel@tonic-gate if (stat(nconf->nc_device, &sb) < 0) { 25370Sstevel@tonic-gate pr_err(gettext("getaddr_nfs: couldn't stat: %s: %s\n"), 25380Sstevel@tonic-gate nconf->nc_device, strerror(errno)); 25390Sstevel@tonic-gate return (RET_ERR); 25400Sstevel@tonic-gate } 25410Sstevel@tonic-gate 25420Sstevel@tonic-gate knconfp = (struct knetconfig *)malloc(sizeof (*knconfp)); 25430Sstevel@tonic-gate if (!knconfp) { 25440Sstevel@tonic-gate pr_err(gettext("no memory\n")); 25450Sstevel@tonic-gate return (RET_ERR); 25460Sstevel@tonic-gate } 25470Sstevel@tonic-gate knconfp->knc_semantics = nconf->nc_semantics; 25480Sstevel@tonic-gate knconfp->knc_protofmly = nconf->nc_protofmly; 25490Sstevel@tonic-gate knconfp->knc_proto = nconf->nc_proto; 25500Sstevel@tonic-gate knconfp->knc_rdev = sb.st_rdev; 25510Sstevel@tonic-gate 25520Sstevel@tonic-gate /* make sure we don't overload the transport */ 25530Sstevel@tonic-gate if (tinfo.tsdu > 0 && tinfo.tsdu < NFS_MAXDATA + NFS_RPC_HDR) { 25540Sstevel@tonic-gate args->flags |= (NFSMNT_RSIZE | NFSMNT_WSIZE); 25550Sstevel@tonic-gate if (args->rsize == 0 || args->rsize > tinfo.tsdu - NFS_RPC_HDR) 25560Sstevel@tonic-gate args->rsize = tinfo.tsdu - NFS_RPC_HDR; 25570Sstevel@tonic-gate if (args->wsize == 0 || args->wsize > tinfo.tsdu - NFS_RPC_HDR) 25580Sstevel@tonic-gate args->wsize = tinfo.tsdu - NFS_RPC_HDR; 25590Sstevel@tonic-gate } 25600Sstevel@tonic-gate 25610Sstevel@tonic-gate args->flags |= NFSMNT_KNCONF; 25620Sstevel@tonic-gate args->knconf = knconfp; 25630Sstevel@tonic-gate return (RET_OK); 25640Sstevel@tonic-gate } 25650Sstevel@tonic-gate 25660Sstevel@tonic-gate static int 25670Sstevel@tonic-gate retry(struct mnttab *mntp, int ro) 25680Sstevel@tonic-gate { 25690Sstevel@tonic-gate int delay = 5; 25700Sstevel@tonic-gate int count = retries; 25710Sstevel@tonic-gate int r; 25720Sstevel@tonic-gate 2573489Soa138391 /* 2574489Soa138391 * Please see comments on nfsretry_vers in the beginning of this file 2575489Soa138391 * and in main() routine. 2576489Soa138391 */ 2577489Soa138391 25780Sstevel@tonic-gate if (bg) { 25790Sstevel@tonic-gate if (fork() > 0) 25800Sstevel@tonic-gate return (RET_OK); 25815706Sgt29601 backgrounded = 1; 25820Sstevel@tonic-gate pr_err(gettext("backgrounding: %s\n"), mntp->mnt_mountp); 2583489Soa138391 } else { 2584489Soa138391 if (!nfsretry_vers) 2585489Soa138391 pr_err(gettext("retrying: %s\n"), mntp->mnt_mountp); 2586489Soa138391 } 25870Sstevel@tonic-gate 25880Sstevel@tonic-gate while (count--) { 2589489Soa138391 if ((r = mount_nfs(mntp, ro, NULL)) == RET_OK) { 25900Sstevel@tonic-gate pr_err(gettext("%s: mounted OK\n"), mntp->mnt_mountp); 25910Sstevel@tonic-gate return (RET_OK); 25920Sstevel@tonic-gate } 25930Sstevel@tonic-gate if (r != RET_RETRY) 25940Sstevel@tonic-gate break; 25950Sstevel@tonic-gate 25960Sstevel@tonic-gate if (count > 0) { 25975302Sth199096 (void) sleep(delay); 25985302Sth199096 delay *= 2; 25995302Sth199096 if (delay > 120) 26005302Sth199096 delay = 120; 26010Sstevel@tonic-gate } 26020Sstevel@tonic-gate } 2603489Soa138391 2604489Soa138391 if (!nfsretry_vers) 2605489Soa138391 pr_err(gettext("giving up on: %s\n"), mntp->mnt_mountp); 2606489Soa138391 26070Sstevel@tonic-gate return (RET_ERR); 26080Sstevel@tonic-gate } 26090Sstevel@tonic-gate 26100Sstevel@tonic-gate /* 26110Sstevel@tonic-gate * Read the /etc/default/nfs configuration file to determine if the 26120Sstevel@tonic-gate * client has been configured for a new min/max for the NFS version to 26130Sstevel@tonic-gate * use. 26140Sstevel@tonic-gate */ 26150Sstevel@tonic-gate static void 26160Sstevel@tonic-gate read_default(void) 26170Sstevel@tonic-gate { 26180Sstevel@tonic-gate char *defval; 26190Sstevel@tonic-gate int errno; 26200Sstevel@tonic-gate int tmp; 26210Sstevel@tonic-gate 26220Sstevel@tonic-gate /* Fail silently if error in opening the default nfs config file */ 26230Sstevel@tonic-gate if ((defopen(NFSADMIN)) == 0) { 26240Sstevel@tonic-gate if ((defval = defread("NFS_CLIENT_VERSMIN=")) != NULL) { 26250Sstevel@tonic-gate errno = 0; 26260Sstevel@tonic-gate tmp = strtol(defval, (char **)NULL, 10); 26270Sstevel@tonic-gate if (errno == 0) { 26280Sstevel@tonic-gate vers_min_default = tmp; 26290Sstevel@tonic-gate } 26300Sstevel@tonic-gate } 26310Sstevel@tonic-gate if ((defval = defread("NFS_CLIENT_VERSMAX=")) != NULL) { 26320Sstevel@tonic-gate errno = 0; 26330Sstevel@tonic-gate tmp = strtol(defval, (char **)NULL, 10); 26340Sstevel@tonic-gate if (errno == 0) { 26350Sstevel@tonic-gate vers_max_default = tmp; 26360Sstevel@tonic-gate } 26370Sstevel@tonic-gate } 26380Sstevel@tonic-gate /* close defaults file */ 26390Sstevel@tonic-gate defopen(NULL); 26400Sstevel@tonic-gate } 26410Sstevel@tonic-gate } 26420Sstevel@tonic-gate 26430Sstevel@tonic-gate static void 26440Sstevel@tonic-gate sigusr1(int s) 26450Sstevel@tonic-gate { 26460Sstevel@tonic-gate } 2647