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 */ 21*5655Sth199096 220Sstevel@tonic-gate /* 233378Srica * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 280Sstevel@tonic-gate /* All Rights Reserved */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate /* 310Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988 320Sstevel@tonic-gate * The Regents of the University of California 330Sstevel@tonic-gate * All Rights Reserved 340Sstevel@tonic-gate * 350Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from 360Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 370Sstevel@tonic-gate * contributors. 380Sstevel@tonic-gate */ 390Sstevel@tonic-gate 400Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 410Sstevel@tonic-gate 420Sstevel@tonic-gate /* 430Sstevel@tonic-gate * nfs mount 440Sstevel@tonic-gate */ 450Sstevel@tonic-gate 460Sstevel@tonic-gate #define NFSCLIENT 470Sstevel@tonic-gate #include <locale.h> 480Sstevel@tonic-gate #include <stdio.h> 490Sstevel@tonic-gate #include <string.h> 500Sstevel@tonic-gate #include <memory.h> 510Sstevel@tonic-gate #include <stdarg.h> 520Sstevel@tonic-gate #include <unistd.h> 530Sstevel@tonic-gate #include <ctype.h> 540Sstevel@tonic-gate #include <stdlib.h> 550Sstevel@tonic-gate #include <signal.h> 560Sstevel@tonic-gate #include <sys/param.h> 570Sstevel@tonic-gate #include <rpc/rpc.h> 580Sstevel@tonic-gate #include <errno.h> 590Sstevel@tonic-gate #include <sys/stat.h> 600Sstevel@tonic-gate #include <netdb.h> 610Sstevel@tonic-gate #include <sys/mount.h> 620Sstevel@tonic-gate #include <sys/mntent.h> 630Sstevel@tonic-gate #include <sys/mnttab.h> 640Sstevel@tonic-gate #include <nfs/nfs.h> 650Sstevel@tonic-gate #include <nfs/mount.h> 660Sstevel@tonic-gate #include <rpcsvc/mount.h> 670Sstevel@tonic-gate #include <sys/pathconf.h> 680Sstevel@tonic-gate #include <netdir.h> 690Sstevel@tonic-gate #include <netconfig.h> 700Sstevel@tonic-gate #include <sys/sockio.h> 710Sstevel@tonic-gate #include <net/if.h> 720Sstevel@tonic-gate #include <syslog.h> 730Sstevel@tonic-gate #include <fslib.h> 740Sstevel@tonic-gate #include <deflt.h> 750Sstevel@tonic-gate #include <sys/wait.h> 760Sstevel@tonic-gate #include "replica.h" 770Sstevel@tonic-gate #include <netinet/in.h> 780Sstevel@tonic-gate #include <nfs/nfs_sec.h> 790Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h> 800Sstevel@tonic-gate #include <priv.h> 813378Srica #include <tsol/label.h> 820Sstevel@tonic-gate #include "nfs_subr.h" 830Sstevel@tonic-gate #include "webnfs.h" 840Sstevel@tonic-gate #include <rpcsvc/nfs4_prot.h> 850Sstevel@tonic-gate 865302Sth199096 #include <nfs/nfssys.h> 875302Sth199096 extern int _nfssys(enum nfssys_op, void *); 885302Sth199096 890Sstevel@tonic-gate #ifndef NFS_VERSMAX 900Sstevel@tonic-gate #define NFS_VERSMAX 4 910Sstevel@tonic-gate #endif 920Sstevel@tonic-gate #ifndef NFS_VERSMIN 930Sstevel@tonic-gate #define NFS_VERSMIN 2 940Sstevel@tonic-gate #endif 950Sstevel@tonic-gate 960Sstevel@tonic-gate #define RET_OK 0 970Sstevel@tonic-gate #define RET_RETRY 32 980Sstevel@tonic-gate #define RET_ERR 33 990Sstevel@tonic-gate #define RET_MNTERR 1000 1000Sstevel@tonic-gate #define ERR_PROTO_NONE 0 1010Sstevel@tonic-gate #define ERR_PROTO_INVALID 901 1020Sstevel@tonic-gate #define ERR_PROTO_UNSUPP 902 1030Sstevel@tonic-gate #define ERR_NETPATH 903 1040Sstevel@tonic-gate #define ERR_NOHOST 904 1050Sstevel@tonic-gate #define ERR_RPCERROR 905 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate typedef struct err_ret { 1080Sstevel@tonic-gate int error_type; 1090Sstevel@tonic-gate int error_value; 1100Sstevel@tonic-gate } err_ret_t; 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate #define SET_ERR_RET(errst, etype, eval) \ 1130Sstevel@tonic-gate if (errst) { \ 1140Sstevel@tonic-gate (errst)->error_type = etype; \ 1150Sstevel@tonic-gate (errst)->error_value = eval; \ 1160Sstevel@tonic-gate } 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate /* number of transports to try */ 1190Sstevel@tonic-gate #define MNT_PREF_LISTLEN 2 1200Sstevel@tonic-gate #define FIRST_TRY 1 1210Sstevel@tonic-gate #define SECOND_TRY 2 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate #define BIGRETRY 10000 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate /* maximum length of RPC header for NFS messages */ 1260Sstevel@tonic-gate #define NFS_RPC_HDR 432 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate #define NFS_ARGS_EXTB_secdata(args, secdata) \ 1290Sstevel@tonic-gate { (args)->nfs_args_ext = NFS_ARGS_EXTB, \ 1300Sstevel@tonic-gate (args)->nfs_ext_u.nfs_extB.secdata = secdata; } 1310Sstevel@tonic-gate 132*5655Sth199096 extern int __clnt_bindresvport(CLIENT *); 1330Sstevel@tonic-gate extern char *nfs_get_qop_name(); 1340Sstevel@tonic-gate extern AUTH * nfs_create_ah(); 1350Sstevel@tonic-gate extern enum snego_stat nfs_sec_nego(); 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate static void usage(void); 1380Sstevel@tonic-gate static int retry(struct mnttab *, int); 1390Sstevel@tonic-gate static int set_args(int *, struct nfs_args *, char *, struct mnttab *); 1400Sstevel@tonic-gate static int get_fh_via_pub(struct nfs_args *, char *, char *, bool_t, bool_t, 1410Sstevel@tonic-gate int *, struct netconfig **, ushort_t); 1420Sstevel@tonic-gate static int get_fh(struct nfs_args *, char *, char *, int *, bool_t, 1430Sstevel@tonic-gate struct netconfig **, ushort_t); 1440Sstevel@tonic-gate static int make_secure(struct nfs_args *, char *, struct netconfig *, 1450Sstevel@tonic-gate bool_t, rpcvers_t); 146489Soa138391 static int mount_nfs(struct mnttab *, int, err_ret_t *); 1470Sstevel@tonic-gate static int getaddr_nfs(struct nfs_args *, char *, struct netconfig **, 1480Sstevel@tonic-gate bool_t, char *, ushort_t, err_ret_t *, bool_t); 1490Sstevel@tonic-gate static void pr_err(const char *fmt, ...); 1500Sstevel@tonic-gate static void usage(void); 1510Sstevel@tonic-gate static struct netbuf *get_addr(char *, rpcprog_t, rpcvers_t, 1520Sstevel@tonic-gate struct netconfig **, char *, ushort_t, struct t_info *, 1530Sstevel@tonic-gate caddr_t *, bool_t, char *, err_ret_t *); 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate static struct netbuf *get_the_addr(char *, rpcprog_t, rpcvers_t, 1560Sstevel@tonic-gate struct netconfig *, ushort_t, struct t_info *, caddr_t *, 1570Sstevel@tonic-gate bool_t, char *, err_ret_t *); 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate extern int self_check(char *); 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate static void read_default(void); 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate static char typename[64]; 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate static int bg = 0; 1660Sstevel@tonic-gate static int backgrounded = 0; 1670Sstevel@tonic-gate static int posix = 0; 1680Sstevel@tonic-gate static int retries = BIGRETRY; 1690Sstevel@tonic-gate static ushort_t nfs_port = 0; 1700Sstevel@tonic-gate static char *nfs_proto = NULL; 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate static int mflg = 0; 1730Sstevel@tonic-gate static int Oflg = 0; /* Overlay mounts */ 1740Sstevel@tonic-gate static int qflg = 0; /* quiet - don't print warnings on bad options */ 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate static char *fstype = MNTTYPE_NFS; 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate static seconfig_t nfs_sec; 1790Sstevel@tonic-gate static int sec_opt = 0; /* any security option ? */ 1800Sstevel@tonic-gate static bool_t snego_done; 1810Sstevel@tonic-gate static void sigusr1(int); 1820Sstevel@tonic-gate 1835302Sth199096 extern void set_nfsv4_ephemeral_mount_to(void); 1845302Sth199096 1850Sstevel@tonic-gate /* 1860Sstevel@tonic-gate * list of support services needed 1870Sstevel@tonic-gate */ 1880Sstevel@tonic-gate static char *service_list[] = { STATD, LOCKD, NULL }; 1890Sstevel@tonic-gate static char *service_list_v4[] = { STATD, LOCKD, NFS4CBD, NFSMAPID, NULL }; 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate /* 1920Sstevel@tonic-gate * These two variables control the NFS version number to be used. 1930Sstevel@tonic-gate * 1940Sstevel@tonic-gate * nfsvers defaults to 0 which means to use the highest number that 1950Sstevel@tonic-gate * both the client and the server support. It can also be set to 1960Sstevel@tonic-gate * a particular value, either 2, 3, or 4 to indicate the version 1970Sstevel@tonic-gate * number of choice. If the server (or the client) do not support 1980Sstevel@tonic-gate * the version indicated, then the mount attempt will be failed. 1990Sstevel@tonic-gate * 2000Sstevel@tonic-gate * nfsvers_to_use is the actual version number found to use. It 2010Sstevel@tonic-gate * is determined in get_fh by pinging the various versions of the 2020Sstevel@tonic-gate * NFS service on the server to see which responds positively. 203489Soa138391 * 204489Soa138391 * nfsretry_vers is the version number set when we retry the mount 205489Soa138391 * command with the version decremented from nfsvers_to_use. 206489Soa138391 * nfsretry_vers is set from nfsvers_to_use when we retry the mount 207489Soa138391 * for errors other than RPC errors; it helps un know why we are 208489Soa138391 * retrying. It is an indication that the retry is due to 209489Soa138391 * non-RPC errors. 2100Sstevel@tonic-gate */ 2110Sstevel@tonic-gate static rpcvers_t nfsvers = 0; 2120Sstevel@tonic-gate static rpcvers_t nfsvers_to_use = 0; 213489Soa138391 static rpcvers_t nfsretry_vers = 0; 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate /* 2160Sstevel@tonic-gate * There are the defaults (range) for the client when determining 2170Sstevel@tonic-gate * which NFS version to use when probing the server (see above). 2180Sstevel@tonic-gate * These will only be used when the vers mount option is not used and 2190Sstevel@tonic-gate * these may be reset if /etc/default/nfs is configured to do so. 2200Sstevel@tonic-gate */ 2210Sstevel@tonic-gate static rpcvers_t vers_max_default = NFS_VERSMAX_DEFAULT; 2220Sstevel@tonic-gate static rpcvers_t vers_min_default = NFS_VERSMIN_DEFAULT; 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate /* 2250Sstevel@tonic-gate * This variable controls whether to try the public file handle. 2260Sstevel@tonic-gate */ 2270Sstevel@tonic-gate static bool_t public_opt; 2280Sstevel@tonic-gate 229249Sjwahlig int 230249Sjwahlig main(int argc, char *argv[]) 2310Sstevel@tonic-gate { 2320Sstevel@tonic-gate struct mnttab mnt; 2330Sstevel@tonic-gate extern char *optarg; 2340Sstevel@tonic-gate extern int optind; 2350Sstevel@tonic-gate char optbuf[MAX_MNTOPT_STR]; 2360Sstevel@tonic-gate int ro = 0; 2370Sstevel@tonic-gate int r; 2380Sstevel@tonic-gate int c; 2390Sstevel@tonic-gate char *myname; 240489Soa138391 err_ret_t retry_error; 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 2430Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 2440Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 2450Sstevel@tonic-gate #endif 2460Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate myname = strrchr(argv[0], '/'); 2490Sstevel@tonic-gate myname = myname ? myname + 1 : argv[0]; 2500Sstevel@tonic-gate (void) snprintf(typename, sizeof (typename), "%s %s", 2510Sstevel@tonic-gate MNTTYPE_NFS, myname); 2520Sstevel@tonic-gate argv[0] = typename; 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate mnt.mnt_mntopts = optbuf; 2550Sstevel@tonic-gate (void) strcpy(optbuf, "rw"); 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate /* 2580Sstevel@tonic-gate * Set options 2590Sstevel@tonic-gate */ 2600Sstevel@tonic-gate while ((c = getopt(argc, argv, "ro:mOq")) != EOF) { 2610Sstevel@tonic-gate switch (c) { 2620Sstevel@tonic-gate case 'r': 2630Sstevel@tonic-gate ro++; 2640Sstevel@tonic-gate break; 2650Sstevel@tonic-gate case 'o': 2660Sstevel@tonic-gate if (strlen(optarg) >= MAX_MNTOPT_STR) { 2670Sstevel@tonic-gate pr_err(gettext("option string too long")); 2680Sstevel@tonic-gate return (RET_ERR); 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate (void) strcpy(mnt.mnt_mntopts, optarg); 2710Sstevel@tonic-gate #ifdef LATER /* XXX */ 2720Sstevel@tonic-gate if (strstr(optarg, MNTOPT_REMOUNT)) { 2730Sstevel@tonic-gate /* 2740Sstevel@tonic-gate * If remount is specified, only rw is allowed. 2750Sstevel@tonic-gate */ 2760Sstevel@tonic-gate if ((strcmp(optarg, MNTOPT_REMOUNT) != 0) && 2770Sstevel@tonic-gate (strcmp(optarg, "remount,rw") != 0) && 2780Sstevel@tonic-gate (strcmp(optarg, "rw,remount") != 0)) { 2790Sstevel@tonic-gate pr_err(gettext("Invalid options\n")); 2800Sstevel@tonic-gate exit(RET_ERR); 2810Sstevel@tonic-gate } 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate #endif /* LATER */ /* XXX */ 2840Sstevel@tonic-gate break; 2850Sstevel@tonic-gate case 'm': 2860Sstevel@tonic-gate mflg++; 2870Sstevel@tonic-gate break; 2880Sstevel@tonic-gate case 'O': 2890Sstevel@tonic-gate Oflg++; 2900Sstevel@tonic-gate break; 2910Sstevel@tonic-gate case 'q': 2920Sstevel@tonic-gate qflg++; 2930Sstevel@tonic-gate break; 2940Sstevel@tonic-gate default: 2950Sstevel@tonic-gate usage(); 2960Sstevel@tonic-gate exit(RET_ERR); 2970Sstevel@tonic-gate } 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate if (argc - optind != 2) { 3000Sstevel@tonic-gate usage(); 3010Sstevel@tonic-gate exit(RET_ERR); 3020Sstevel@tonic-gate } 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate mnt.mnt_special = argv[optind]; 3050Sstevel@tonic-gate mnt.mnt_mountp = argv[optind+1]; 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate if (!priv_ineffect(PRIV_SYS_MOUNT) || 3080Sstevel@tonic-gate !priv_ineffect(PRIV_NET_PRIVADDR)) { 3090Sstevel@tonic-gate pr_err(gettext("insufficient privileges\n")); 3100Sstevel@tonic-gate exit(RET_ERR); 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate /* 3143378Srica * On a labeled system, allow read-down nfs mounts if privileged 3153378Srica * (PRIV_NET_MAC_AWARE) to do so. Otherwise, ignore the error 3163378Srica * and "mount equal label only" behavior will result. 3173378Srica */ 3183378Srica if (is_system_labeled()) 3193378Srica (void) setpflags(NET_MAC_AWARE, 1); 3203378Srica 3213378Srica /* 3220Sstevel@tonic-gate * Read the defaults file to see if the min/max versions have 3230Sstevel@tonic-gate * been set and therefore would override the encoded defaults. 3240Sstevel@tonic-gate * Then check to make sure that if they were set that the 3250Sstevel@tonic-gate * values are reasonable. 3260Sstevel@tonic-gate */ 3270Sstevel@tonic-gate read_default(); 3280Sstevel@tonic-gate if (vers_min_default > vers_max_default || 3295302Sth199096 vers_min_default < NFS_VERSMIN || 3305302Sth199096 vers_max_default > NFS_VERSMAX) { 3310Sstevel@tonic-gate pr_err("%s %s\n%s %s\n", 3325302Sth199096 gettext("Incorrect configuration of client\'s"), 3335302Sth199096 NFSADMIN, 3345302Sth199096 gettext("NFS_CLIENT_VERSMIN or NFS_CLIENT_VERSMAX"), 3355302Sth199096 gettext("is either out of range or overlaps.")); 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate 338489Soa138391 SET_ERR_RET(&retry_error, ERR_PROTO_NONE, 0); 339489Soa138391 r = mount_nfs(&mnt, ro, &retry_error); 340489Soa138391 if (r == RET_RETRY && retries) { 341489Soa138391 /* 342489Soa138391 * Check the error code from the last mount attempt if it was 343489Soa138391 * an RPC error, then retry as is. Otherwise we retry with the 344489Soa138391 * nfsretry_vers set. It is set by decrementing nfsvers_to_use. 345489Soa138391 * If we are retrying with nfsretry_vers then we don't print any 346489Soa138391 * retry messages, since we are not retrying due to an RPC 347489Soa138391 * error. 348489Soa138391 */ 349489Soa138391 if (retry_error.error_type) { 350489Soa138391 if (retry_error.error_type != ERR_RPCERROR) { 351489Soa138391 nfsretry_vers = nfsvers_to_use = 352489Soa138391 nfsvers_to_use - 1; 353489Soa138391 if (nfsretry_vers < NFS_VERSMIN) 354489Soa138391 return (r); 355489Soa138391 } 356489Soa138391 } 357489Soa138391 3580Sstevel@tonic-gate r = retry(&mnt, ro); 359489Soa138391 } 3600Sstevel@tonic-gate /* 3610Sstevel@tonic-gate * exit(r); 3620Sstevel@tonic-gate */ 3630Sstevel@tonic-gate return (r); 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate static void 3670Sstevel@tonic-gate pr_err(const char *fmt, ...) 3680Sstevel@tonic-gate { 3690Sstevel@tonic-gate va_list ap; 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate va_start(ap, fmt); 3720Sstevel@tonic-gate if (backgrounded != 0) { 3730Sstevel@tonic-gate (void) vsyslog(LOG_ERR, fmt, ap); 3740Sstevel@tonic-gate } else { 3750Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", typename); 3760Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap); 3770Sstevel@tonic-gate (void) fflush(stderr); 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate va_end(ap); 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate static void 3830Sstevel@tonic-gate usage() 3840Sstevel@tonic-gate { 3850Sstevel@tonic-gate (void) fprintf(stderr, 3860Sstevel@tonic-gate gettext("Usage: nfs mount [-r] [-o opts] [server:]path dir\n")); 3870Sstevel@tonic-gate exit(RET_ERR); 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate static int 391489Soa138391 mount_nfs(struct mnttab *mntp, int ro, err_ret_t *retry_error) 3920Sstevel@tonic-gate { 3930Sstevel@tonic-gate struct nfs_args *args = NULL, *argp = NULL, *prev_argp = NULL; 3940Sstevel@tonic-gate struct netconfig *nconf = NULL; 3950Sstevel@tonic-gate struct replica *list = NULL; 3960Sstevel@tonic-gate int mntflags = 0; 3970Sstevel@tonic-gate int i, r, n; 3980Sstevel@tonic-gate int oldvers = 0, vers = 0; 3990Sstevel@tonic-gate int last_error = RET_OK; 4000Sstevel@tonic-gate int replicated = 0; 4010Sstevel@tonic-gate char *p; 4020Sstevel@tonic-gate bool_t url; 4030Sstevel@tonic-gate bool_t use_pubfh; 4040Sstevel@tonic-gate char *special = NULL; 4050Sstevel@tonic-gate char *oldpath = NULL; 4060Sstevel@tonic-gate char *newpath = NULL; 4070Sstevel@tonic-gate char *service; 4080Sstevel@tonic-gate pid_t pi; 4090Sstevel@tonic-gate struct flock f; 4100Sstevel@tonic-gate char *saveopts = NULL; 4110Sstevel@tonic-gate char **sl = NULL; 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate mntp->mnt_fstype = MNTTYPE_NFS; 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate if (ro) { 4160Sstevel@tonic-gate mntflags |= MS_RDONLY; 4170Sstevel@tonic-gate /* convert "rw"->"ro" */ 4180Sstevel@tonic-gate if (p = strstr(mntp->mnt_mntopts, "rw")) { 4190Sstevel@tonic-gate if (*(p+2) == ',' || *(p+2) == '\0') 4200Sstevel@tonic-gate *(p+1) = 'o'; 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate } 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate if (Oflg) 4250Sstevel@tonic-gate mntflags |= MS_OVERLAY; 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate list = parse_replica(mntp->mnt_special, &n); 4280Sstevel@tonic-gate if (list == NULL) { 4290Sstevel@tonic-gate if (n < 0) 4300Sstevel@tonic-gate pr_err(gettext("nfs file system; use [host:]path\n")); 4310Sstevel@tonic-gate else 4320Sstevel@tonic-gate pr_err(gettext("no memory\n")); 4330Sstevel@tonic-gate return (RET_ERR); 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate replicated = (n > 1); 4370Sstevel@tonic-gate 4380Sstevel@tonic-gate /* 4390Sstevel@tonic-gate * There are some free() calls at the bottom of this loop, so be 4400Sstevel@tonic-gate * careful about adding continue statements. 4410Sstevel@tonic-gate */ 4420Sstevel@tonic-gate for (i = 0; i < n; i++) { 4430Sstevel@tonic-gate char *path; 4440Sstevel@tonic-gate char *host; 4450Sstevel@tonic-gate ushort_t port; 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate argp = (struct nfs_args *)malloc(sizeof (*argp)); 4480Sstevel@tonic-gate if (argp == NULL) { 4490Sstevel@tonic-gate pr_err(gettext("no memory\n")); 4500Sstevel@tonic-gate last_error = RET_ERR; 4510Sstevel@tonic-gate goto out; 4520Sstevel@tonic-gate } 4530Sstevel@tonic-gate memset(argp, 0, sizeof (*argp)); 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate memset(&nfs_sec, 0, sizeof (nfs_sec)); 4560Sstevel@tonic-gate sec_opt = 0; 4570Sstevel@tonic-gate use_pubfh = FALSE; 4580Sstevel@tonic-gate url = FALSE; 4590Sstevel@tonic-gate port = 0; 4600Sstevel@tonic-gate snego_done = FALSE; 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate /* 4630Sstevel@tonic-gate * Looking for resources of the form 4640Sstevel@tonic-gate * nfs://server_host[:port_number]/path_name 4650Sstevel@tonic-gate */ 4660Sstevel@tonic-gate if (strcmp(list[i].host, "nfs") == 0 && strncmp(list[i].path, 4670Sstevel@tonic-gate "//", 2) == 0) { 4680Sstevel@tonic-gate char *sport, *cb; 4690Sstevel@tonic-gate url = TRUE; 4700Sstevel@tonic-gate oldpath = strdup(list[i].path); 4710Sstevel@tonic-gate if (oldpath == NULL) { 4720Sstevel@tonic-gate pr_err(gettext("memory allocation failure\n")); 4730Sstevel@tonic-gate last_error = RET_ERR; 4740Sstevel@tonic-gate goto out; 4750Sstevel@tonic-gate } 4760Sstevel@tonic-gate host = list[i].path+2; 4770Sstevel@tonic-gate path = strchr(host, '/'); 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate if (path == NULL) { 4800Sstevel@tonic-gate pr_err(gettext( 4810Sstevel@tonic-gate "illegal nfs url syntax\n")); 4820Sstevel@tonic-gate last_error = RET_ERR; 4830Sstevel@tonic-gate goto out; 4840Sstevel@tonic-gate } 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate *path = '\0'; 4870Sstevel@tonic-gate if (*host == '[') { 4880Sstevel@tonic-gate cb = strchr(host, ']'); 4890Sstevel@tonic-gate if (cb == NULL) { 4900Sstevel@tonic-gate pr_err(gettext( 4915302Sth199096 "illegal nfs url syntax\n")); 4920Sstevel@tonic-gate last_error = RET_ERR; 4930Sstevel@tonic-gate goto out; 4940Sstevel@tonic-gate } else { 4950Sstevel@tonic-gate *cb = '\0'; 4960Sstevel@tonic-gate host++; 4970Sstevel@tonic-gate cb++; 4980Sstevel@tonic-gate if (*cb == ':') 4990Sstevel@tonic-gate port = htons((ushort_t) 5005302Sth199096 atoi(cb+1)); 5010Sstevel@tonic-gate } 5020Sstevel@tonic-gate } else { 5030Sstevel@tonic-gate sport = strchr(host, ':'); 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate if (sport != NULL && sport < path) { 5060Sstevel@tonic-gate *sport = '\0'; 5070Sstevel@tonic-gate port = htons((ushort_t)atoi(sport+1)); 5080Sstevel@tonic-gate } 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate path++; 5120Sstevel@tonic-gate if (*path == '\0') 5130Sstevel@tonic-gate path = "."; 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate } else { 5160Sstevel@tonic-gate host = list[i].host; 5170Sstevel@tonic-gate path = list[i].path; 5180Sstevel@tonic-gate } 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate if (r = set_args(&mntflags, argp, host, mntp)) { 5210Sstevel@tonic-gate last_error = r; 5220Sstevel@tonic-gate goto out; 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate if (public_opt == TRUE) 5260Sstevel@tonic-gate use_pubfh = TRUE; 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate if (port == 0) { 5290Sstevel@tonic-gate port = nfs_port; 5300Sstevel@tonic-gate } else if (nfs_port != 0 && nfs_port != port) { 5310Sstevel@tonic-gate pr_err(gettext( 5320Sstevel@tonic-gate "port (%u) in nfs URL not the same" 5330Sstevel@tonic-gate " as port (%u) in port option\n"), 5340Sstevel@tonic-gate (unsigned int)ntohs(port), 5350Sstevel@tonic-gate (unsigned int)ntohs(nfs_port)); 5360Sstevel@tonic-gate last_error = RET_ERR; 5370Sstevel@tonic-gate goto out; 5380Sstevel@tonic-gate } 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate 5410Sstevel@tonic-gate if (replicated && !(mntflags & MS_RDONLY)) { 5420Sstevel@tonic-gate pr_err(gettext( 5435302Sth199096 "replicated mounts must be read-only\n")); 5440Sstevel@tonic-gate last_error = RET_ERR; 5450Sstevel@tonic-gate goto out; 5460Sstevel@tonic-gate } 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate if (replicated && (argp->flags & NFSMNT_SOFT)) { 5490Sstevel@tonic-gate pr_err(gettext( 5505302Sth199096 "replicated mounts must not be soft\n")); 5510Sstevel@tonic-gate last_error = RET_ERR; 5520Sstevel@tonic-gate goto out; 5530Sstevel@tonic-gate } 5540Sstevel@tonic-gate 5550Sstevel@tonic-gate oldvers = vers; 5560Sstevel@tonic-gate nconf = NULL; 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate r = RET_ERR; 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate /* 5610Sstevel@tonic-gate * If -o public was specified, and/or a URL was specified, 5620Sstevel@tonic-gate * then try the public file handle method. 5630Sstevel@tonic-gate */ 5640Sstevel@tonic-gate if ((use_pubfh == TRUE) || (url == TRUE)) { 5650Sstevel@tonic-gate r = get_fh_via_pub(argp, host, path, url, use_pubfh, 5665302Sth199096 &vers, &nconf, port); 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate if (r != RET_OK) { 5690Sstevel@tonic-gate /* 5700Sstevel@tonic-gate * If -o public was specified, then return the 5710Sstevel@tonic-gate * error now. 5720Sstevel@tonic-gate */ 5730Sstevel@tonic-gate if (use_pubfh == TRUE) { 5740Sstevel@tonic-gate last_error = r; 5750Sstevel@tonic-gate goto out; 5760Sstevel@tonic-gate } 5770Sstevel@tonic-gate } else 5780Sstevel@tonic-gate use_pubfh = TRUE; 5790Sstevel@tonic-gate argp->flags |= NFSMNT_PUBLIC; 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate if ((r != RET_OK) || (vers == NFS_V4)) { 5830Sstevel@tonic-gate bool_t loud_on_mnt_err; 5840Sstevel@tonic-gate 5850Sstevel@tonic-gate /* 5860Sstevel@tonic-gate * This can happen if -o public is not specified, 5870Sstevel@tonic-gate * special is a URL, and server doesn't support 5880Sstevel@tonic-gate * public file handle. 5890Sstevel@tonic-gate */ 5900Sstevel@tonic-gate if (url) { 5910Sstevel@tonic-gate URLparse(path); 5920Sstevel@tonic-gate } 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate /* 5950Sstevel@tonic-gate * If the path portion of the URL didn't have 5960Sstevel@tonic-gate * a leading / then there is good possibility 5970Sstevel@tonic-gate * that a mount without a leading slash will 5980Sstevel@tonic-gate * fail. 5990Sstevel@tonic-gate */ 6000Sstevel@tonic-gate if (url == TRUE && *path != '/') 6010Sstevel@tonic-gate loud_on_mnt_err = FALSE; 6020Sstevel@tonic-gate else 6030Sstevel@tonic-gate loud_on_mnt_err = TRUE; 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate r = get_fh(argp, host, path, &vers, 6065302Sth199096 loud_on_mnt_err, &nconf, port); 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate if (r != RET_OK) { 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate /* 6110Sstevel@tonic-gate * If there was no leading / and the path was 6120Sstevel@tonic-gate * derived from a URL, then try again 6130Sstevel@tonic-gate * with a leading /. 6140Sstevel@tonic-gate */ 6150Sstevel@tonic-gate if ((r == RET_MNTERR) && 6160Sstevel@tonic-gate (loud_on_mnt_err == FALSE)) { 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate newpath = malloc(strlen(path)+2); 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate if (newpath == NULL) { 6210Sstevel@tonic-gate pr_err(gettext("memory " 6220Sstevel@tonic-gate "allocation failure\n")); 6230Sstevel@tonic-gate last_error = RET_ERR; 6240Sstevel@tonic-gate goto out; 6250Sstevel@tonic-gate } 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate strcpy(newpath, "/"); 6280Sstevel@tonic-gate strcat(newpath, path); 6290Sstevel@tonic-gate 6300Sstevel@tonic-gate r = get_fh(argp, host, newpath, &vers, 6315302Sth199096 TRUE, &nconf, port); 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate if (r == RET_OK) 6340Sstevel@tonic-gate path = newpath; 6350Sstevel@tonic-gate } 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate /* 6380Sstevel@tonic-gate * map exit code back to RET_ERR. 6390Sstevel@tonic-gate */ 6400Sstevel@tonic-gate if (r == RET_MNTERR) 6410Sstevel@tonic-gate r = RET_ERR; 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate if (r != RET_OK) { 6440Sstevel@tonic-gate 6450Sstevel@tonic-gate if (replicated) { 6460Sstevel@tonic-gate if (argp->fh) 6470Sstevel@tonic-gate free(argp->fh); 6480Sstevel@tonic-gate if (argp->pathconf) 6490Sstevel@tonic-gate free(argp->pathconf); 6500Sstevel@tonic-gate free(argp); 6510Sstevel@tonic-gate goto cont; 6520Sstevel@tonic-gate } 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate last_error = r; 6550Sstevel@tonic-gate goto out; 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate } 6580Sstevel@tonic-gate } 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate if (oldvers && vers != oldvers) { 6610Sstevel@tonic-gate pr_err( 6620Sstevel@tonic-gate gettext("replicas must have the same version\n")); 6630Sstevel@tonic-gate last_error = RET_ERR; 6640Sstevel@tonic-gate goto out; 6650Sstevel@tonic-gate } 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate /* 6680Sstevel@tonic-gate * decide whether to use remote host's 6690Sstevel@tonic-gate * lockd or do local locking 6700Sstevel@tonic-gate */ 6710Sstevel@tonic-gate if (!(argp->flags & NFSMNT_LLOCK) && vers == NFS_VERSION && 6720Sstevel@tonic-gate remote_lock(host, argp->fh)) { 6730Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6740Sstevel@tonic-gate "WARNING: No network locking on %s:%s:"), 6750Sstevel@tonic-gate host, path); 6760Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6770Sstevel@tonic-gate " contact admin to install server change\n")); 6785302Sth199096 argp->flags |= NFSMNT_LLOCK; 6790Sstevel@tonic-gate } 6800Sstevel@tonic-gate 6810Sstevel@tonic-gate if (self_check(host)) 6820Sstevel@tonic-gate argp->flags |= NFSMNT_LOOPBACK; 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate if (use_pubfh == FALSE) { 6850Sstevel@tonic-gate /* 6860Sstevel@tonic-gate * Call to get_fh() above may have obtained the 6870Sstevel@tonic-gate * netconfig info and NULL proc'd the server. 6880Sstevel@tonic-gate * This would be the case with v4 6890Sstevel@tonic-gate */ 6900Sstevel@tonic-gate if (!(argp->flags & NFSMNT_KNCONF)) { 6910Sstevel@tonic-gate nconf = NULL; 6920Sstevel@tonic-gate if (r = getaddr_nfs(argp, host, &nconf, 6935302Sth199096 FALSE, path, port, retry_error, 6945302Sth199096 TRUE)) { 695489Soa138391 last_error = r; 696489Soa138391 goto out; 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate } 7000Sstevel@tonic-gate 7010Sstevel@tonic-gate if (make_secure(argp, host, nconf, use_pubfh, vers) < 0) { 7020Sstevel@tonic-gate last_error = RET_ERR; 7030Sstevel@tonic-gate goto out; 7040Sstevel@tonic-gate } 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate if ((url == TRUE) && (use_pubfh == FALSE)) { 7070Sstevel@tonic-gate /* 7080Sstevel@tonic-gate * Convert the special from 7090Sstevel@tonic-gate * nfs://host/path 7100Sstevel@tonic-gate * to 7110Sstevel@tonic-gate * host:path 7120Sstevel@tonic-gate */ 7130Sstevel@tonic-gate if (convert_special(&special, host, oldpath, path, 7140Sstevel@tonic-gate mntp->mnt_special) == -1) { 7150Sstevel@tonic-gate (void) fprintf(stderr, gettext( 7160Sstevel@tonic-gate "could not convert URL nfs:%s to %s:%s\n"), 7170Sstevel@tonic-gate oldpath, host, path); 7180Sstevel@tonic-gate last_error = RET_ERR; 7190Sstevel@tonic-gate goto out; 7200Sstevel@tonic-gate } else { 7210Sstevel@tonic-gate mntp->mnt_special = special; 7220Sstevel@tonic-gate } 7230Sstevel@tonic-gate } 7240Sstevel@tonic-gate 7250Sstevel@tonic-gate if (prev_argp == NULL) 7260Sstevel@tonic-gate args = argp; 7270Sstevel@tonic-gate else 7280Sstevel@tonic-gate prev_argp->nfs_ext_u.nfs_extB.next = argp; 7290Sstevel@tonic-gate prev_argp = argp; 7300Sstevel@tonic-gate 7310Sstevel@tonic-gate cont: 7320Sstevel@tonic-gate if (oldpath != NULL) { 7330Sstevel@tonic-gate free(oldpath); 7340Sstevel@tonic-gate oldpath = NULL; 7350Sstevel@tonic-gate } 7360Sstevel@tonic-gate 7370Sstevel@tonic-gate if (newpath != NULL) { 7380Sstevel@tonic-gate free(newpath); 7390Sstevel@tonic-gate newpath = NULL; 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate } 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate argp = NULL; 7440Sstevel@tonic-gate 7450Sstevel@tonic-gate if (args == NULL) { 7460Sstevel@tonic-gate last_error = RET_RETRY; 7470Sstevel@tonic-gate goto out; 7480Sstevel@tonic-gate } 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate /* Determine which services are appropriate for the NFS version */ 7510Sstevel@tonic-gate if (strcmp(fstype, MNTTYPE_NFS4) == 0) 7520Sstevel@tonic-gate sl = service_list_v4; 7530Sstevel@tonic-gate else 7540Sstevel@tonic-gate sl = service_list; 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate /* 7570Sstevel@tonic-gate * enable services as needed. 7580Sstevel@tonic-gate */ 7590Sstevel@tonic-gate _check_services(sl); 7600Sstevel@tonic-gate 7610Sstevel@tonic-gate mntflags |= MS_DATA | MS_OPTIONSTR; 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate if (mflg) 7640Sstevel@tonic-gate mntflags |= MS_NOMNTTAB; 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate if (!qflg) 7670Sstevel@tonic-gate saveopts = strdup(mntp->mnt_mntopts); 7680Sstevel@tonic-gate 7695302Sth199096 /* 7705302Sth199096 * And make sure that we have the ephemeral mount_to 7715302Sth199096 * set for this zone. 7725302Sth199096 */ 7735302Sth199096 set_nfsv4_ephemeral_mount_to(); 7745302Sth199096 7750Sstevel@tonic-gate if (mount(mntp->mnt_special, mntp->mnt_mountp, mntflags, fstype, args, 7765302Sth199096 sizeof (*args), mntp->mnt_mntopts, MAX_MNTOPT_STR) < 0) { 7770Sstevel@tonic-gate if (errno != ENOENT) { 7780Sstevel@tonic-gate pr_err(gettext("mount: %s: %s\n"), 7795302Sth199096 mntp->mnt_mountp, strerror(errno)); 7800Sstevel@tonic-gate } else { 7810Sstevel@tonic-gate struct stat sb; 7820Sstevel@tonic-gate if (stat(mntp->mnt_mountp, &sb) < 0 && errno == ENOENT) 7830Sstevel@tonic-gate pr_err(gettext("mount: %s: %s\n"), 7845302Sth199096 mntp->mnt_mountp, strerror(ENOENT)); 7850Sstevel@tonic-gate else 7860Sstevel@tonic-gate pr_err("%s: %s\n", mntp->mnt_special, 7875302Sth199096 strerror(ENOENT)); 7880Sstevel@tonic-gate } 7890Sstevel@tonic-gate 7900Sstevel@tonic-gate last_error = RET_ERR; 7910Sstevel@tonic-gate goto out; 7920Sstevel@tonic-gate } 7930Sstevel@tonic-gate 7940Sstevel@tonic-gate if (!qflg && saveopts != NULL) { 7950Sstevel@tonic-gate cmp_requested_to_actual_options(saveopts, mntp->mnt_mntopts, 7960Sstevel@tonic-gate mntp->mnt_special, mntp->mnt_mountp); 7970Sstevel@tonic-gate } 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate out: 8000Sstevel@tonic-gate if (saveopts != NULL) 8010Sstevel@tonic-gate free(saveopts); 8020Sstevel@tonic-gate if (special != NULL) 8030Sstevel@tonic-gate free(special); 8040Sstevel@tonic-gate if (oldpath != NULL) 8050Sstevel@tonic-gate free(oldpath); 8060Sstevel@tonic-gate if (newpath != NULL) 8070Sstevel@tonic-gate free(newpath); 8080Sstevel@tonic-gate 8090Sstevel@tonic-gate free_replica(list, n); 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate if (argp != NULL) { 8120Sstevel@tonic-gate /* 8130Sstevel@tonic-gate * If we had a new entry which was not added to the 8140Sstevel@tonic-gate * list yet, then add it now that it can be freed. 8150Sstevel@tonic-gate */ 8160Sstevel@tonic-gate if (prev_argp == NULL) 8170Sstevel@tonic-gate args = argp; 8180Sstevel@tonic-gate else 8190Sstevel@tonic-gate prev_argp->nfs_ext_u.nfs_extB.next = argp; 8200Sstevel@tonic-gate } 8210Sstevel@tonic-gate argp = args; 8220Sstevel@tonic-gate while (argp != NULL) { 8230Sstevel@tonic-gate if (argp->fh) 8240Sstevel@tonic-gate free(argp->fh); 8250Sstevel@tonic-gate if (argp->pathconf) 8260Sstevel@tonic-gate free(argp->pathconf); 8270Sstevel@tonic-gate if (argp->knconf) 8280Sstevel@tonic-gate free(argp->knconf); 8290Sstevel@tonic-gate if (argp->addr) { 8300Sstevel@tonic-gate free(argp->addr->buf); 8310Sstevel@tonic-gate free(argp->addr); 8320Sstevel@tonic-gate } 8330Sstevel@tonic-gate nfs_free_secdata(argp->nfs_ext_u.nfs_extB.secdata); 8340Sstevel@tonic-gate if (argp->syncaddr) { 8350Sstevel@tonic-gate free(argp->syncaddr->buf); 8360Sstevel@tonic-gate free(argp->syncaddr); 8370Sstevel@tonic-gate } 8380Sstevel@tonic-gate if (argp->netname) 8390Sstevel@tonic-gate free(argp->netname); 8400Sstevel@tonic-gate prev_argp = argp; 8410Sstevel@tonic-gate argp = argp->nfs_ext_u.nfs_extB.next; 8420Sstevel@tonic-gate free(prev_argp); 8430Sstevel@tonic-gate } 8440Sstevel@tonic-gate 8450Sstevel@tonic-gate return (last_error); 8460Sstevel@tonic-gate } 8470Sstevel@tonic-gate 8480Sstevel@tonic-gate /* 8490Sstevel@tonic-gate * These options are duplicated in uts/common/fs/nfs/nfs_dlinet.c 8500Sstevel@tonic-gate * Changes must be made to both lists. 8510Sstevel@tonic-gate */ 8520Sstevel@tonic-gate static char *optlist[] = { 8530Sstevel@tonic-gate #define OPT_RO 0 8540Sstevel@tonic-gate MNTOPT_RO, 8550Sstevel@tonic-gate #define OPT_RW 1 8560Sstevel@tonic-gate MNTOPT_RW, 8570Sstevel@tonic-gate #define OPT_QUOTA 2 8580Sstevel@tonic-gate MNTOPT_QUOTA, 8590Sstevel@tonic-gate #define OPT_NOQUOTA 3 8600Sstevel@tonic-gate MNTOPT_NOQUOTA, 8610Sstevel@tonic-gate #define OPT_SOFT 4 8620Sstevel@tonic-gate MNTOPT_SOFT, 8630Sstevel@tonic-gate #define OPT_HARD 5 8640Sstevel@tonic-gate MNTOPT_HARD, 8650Sstevel@tonic-gate #define OPT_SUID 6 8660Sstevel@tonic-gate MNTOPT_SUID, 8670Sstevel@tonic-gate #define OPT_NOSUID 7 8680Sstevel@tonic-gate MNTOPT_NOSUID, 8690Sstevel@tonic-gate #define OPT_GRPID 8 8700Sstevel@tonic-gate MNTOPT_GRPID, 8710Sstevel@tonic-gate #define OPT_REMOUNT 9 8720Sstevel@tonic-gate MNTOPT_REMOUNT, 8730Sstevel@tonic-gate #define OPT_NOSUB 10 8740Sstevel@tonic-gate MNTOPT_NOSUB, 8750Sstevel@tonic-gate #define OPT_INTR 11 8760Sstevel@tonic-gate MNTOPT_INTR, 8770Sstevel@tonic-gate #define OPT_NOINTR 12 8780Sstevel@tonic-gate MNTOPT_NOINTR, 8790Sstevel@tonic-gate #define OPT_PORT 13 8800Sstevel@tonic-gate MNTOPT_PORT, 8810Sstevel@tonic-gate #define OPT_SECURE 14 8820Sstevel@tonic-gate MNTOPT_SECURE, 8830Sstevel@tonic-gate #define OPT_RSIZE 15 8840Sstevel@tonic-gate MNTOPT_RSIZE, 8850Sstevel@tonic-gate #define OPT_WSIZE 16 8860Sstevel@tonic-gate MNTOPT_WSIZE, 8870Sstevel@tonic-gate #define OPT_TIMEO 17 8880Sstevel@tonic-gate MNTOPT_TIMEO, 8890Sstevel@tonic-gate #define OPT_RETRANS 18 8900Sstevel@tonic-gate MNTOPT_RETRANS, 8910Sstevel@tonic-gate #define OPT_ACTIMEO 19 8920Sstevel@tonic-gate MNTOPT_ACTIMEO, 8930Sstevel@tonic-gate #define OPT_ACREGMIN 20 8940Sstevel@tonic-gate MNTOPT_ACREGMIN, 8950Sstevel@tonic-gate #define OPT_ACREGMAX 21 8960Sstevel@tonic-gate MNTOPT_ACREGMAX, 8970Sstevel@tonic-gate #define OPT_ACDIRMIN 22 8980Sstevel@tonic-gate MNTOPT_ACDIRMIN, 8990Sstevel@tonic-gate #define OPT_ACDIRMAX 23 9000Sstevel@tonic-gate MNTOPT_ACDIRMAX, 9010Sstevel@tonic-gate #define OPT_BG 24 9020Sstevel@tonic-gate MNTOPT_BG, 9030Sstevel@tonic-gate #define OPT_FG 25 9040Sstevel@tonic-gate MNTOPT_FG, 9050Sstevel@tonic-gate #define OPT_RETRY 26 9060Sstevel@tonic-gate MNTOPT_RETRY, 9070Sstevel@tonic-gate #define OPT_NOAC 27 9080Sstevel@tonic-gate MNTOPT_NOAC, 9090Sstevel@tonic-gate #define OPT_NOCTO 28 9100Sstevel@tonic-gate MNTOPT_NOCTO, 9110Sstevel@tonic-gate #define OPT_LLOCK 29 9120Sstevel@tonic-gate MNTOPT_LLOCK, 9130Sstevel@tonic-gate #define OPT_POSIX 30 9140Sstevel@tonic-gate MNTOPT_POSIX, 9150Sstevel@tonic-gate #define OPT_VERS 31 9160Sstevel@tonic-gate MNTOPT_VERS, 9170Sstevel@tonic-gate #define OPT_PROTO 32 9180Sstevel@tonic-gate MNTOPT_PROTO, 9190Sstevel@tonic-gate #define OPT_SEMISOFT 33 9200Sstevel@tonic-gate MNTOPT_SEMISOFT, 9210Sstevel@tonic-gate #define OPT_NOPRINT 34 9220Sstevel@tonic-gate MNTOPT_NOPRINT, 9230Sstevel@tonic-gate #define OPT_SEC 35 9240Sstevel@tonic-gate MNTOPT_SEC, 9250Sstevel@tonic-gate #define OPT_LARGEFILES 36 9260Sstevel@tonic-gate MNTOPT_LARGEFILES, 9270Sstevel@tonic-gate #define OPT_NOLARGEFILES 37 9280Sstevel@tonic-gate MNTOPT_NOLARGEFILES, 9290Sstevel@tonic-gate #define OPT_PUBLIC 38 9300Sstevel@tonic-gate MNTOPT_PUBLIC, 9310Sstevel@tonic-gate #define OPT_DIRECTIO 39 9320Sstevel@tonic-gate MNTOPT_FORCEDIRECTIO, 9330Sstevel@tonic-gate #define OPT_NODIRECTIO 40 9340Sstevel@tonic-gate MNTOPT_NOFORCEDIRECTIO, 9350Sstevel@tonic-gate #define OPT_XATTR 41 9360Sstevel@tonic-gate MNTOPT_XATTR, 9370Sstevel@tonic-gate #define OPT_NOXATTR 42 9380Sstevel@tonic-gate MNTOPT_NOXATTR, 9390Sstevel@tonic-gate #define OPT_DEVICES 43 9400Sstevel@tonic-gate MNTOPT_DEVICES, 9410Sstevel@tonic-gate #define OPT_NODEVICES 44 9420Sstevel@tonic-gate MNTOPT_NODEVICES, 9430Sstevel@tonic-gate #define OPT_SETUID 45 9440Sstevel@tonic-gate MNTOPT_SETUID, 9450Sstevel@tonic-gate #define OPT_NOSETUID 46 9460Sstevel@tonic-gate MNTOPT_NOSETUID, 9470Sstevel@tonic-gate #define OPT_EXEC 47 9480Sstevel@tonic-gate MNTOPT_EXEC, 9490Sstevel@tonic-gate #define OPT_NOEXEC 48 9500Sstevel@tonic-gate MNTOPT_NOEXEC, 9510Sstevel@tonic-gate NULL 9520Sstevel@tonic-gate }; 9530Sstevel@tonic-gate 9540Sstevel@tonic-gate #define bad(val) (val == NULL || !isdigit(*val)) 9550Sstevel@tonic-gate 9560Sstevel@tonic-gate static int 9570Sstevel@tonic-gate set_args(int *mntflags, struct nfs_args *args, char *fshost, struct mnttab *mnt) 9580Sstevel@tonic-gate { 9590Sstevel@tonic-gate char *saveopt, *optstr, *opts, *newopts, *val; 9600Sstevel@tonic-gate int largefiles = 0; 9610Sstevel@tonic-gate int invalid = 0; 9620Sstevel@tonic-gate int attrpref = 0; 9630Sstevel@tonic-gate int optlen; 9640Sstevel@tonic-gate 9650Sstevel@tonic-gate args->flags = NFSMNT_INT; /* default is "intr" */ 9660Sstevel@tonic-gate args->flags |= NFSMNT_HOSTNAME; 9670Sstevel@tonic-gate args->flags |= NFSMNT_NEWARGS; /* using extented nfs_args structure */ 9680Sstevel@tonic-gate args->hostname = fshost; 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate optstr = opts = strdup(mnt->mnt_mntopts); 9710Sstevel@tonic-gate /* sizeof (MNTOPT_XXX) includes one extra byte we may need for "," */ 9720Sstevel@tonic-gate optlen = strlen(mnt->mnt_mntopts) + sizeof (MNTOPT_XATTR) + 1; 9730Sstevel@tonic-gate if (optlen > MAX_MNTOPT_STR) { 9740Sstevel@tonic-gate pr_err(gettext("option string too long")); 9750Sstevel@tonic-gate return (RET_ERR); 9760Sstevel@tonic-gate } 9770Sstevel@tonic-gate newopts = malloc(optlen); 9780Sstevel@tonic-gate if (opts == NULL || newopts == NULL) { 9790Sstevel@tonic-gate pr_err(gettext("no memory")); 9800Sstevel@tonic-gate if (opts) 9810Sstevel@tonic-gate free(opts); 9820Sstevel@tonic-gate if (newopts) 9830Sstevel@tonic-gate free(newopts); 9840Sstevel@tonic-gate return (RET_ERR); 9850Sstevel@tonic-gate } 9860Sstevel@tonic-gate newopts[0] = '\0'; 9870Sstevel@tonic-gate 9880Sstevel@tonic-gate while (*opts) { 9890Sstevel@tonic-gate invalid = 0; 9900Sstevel@tonic-gate saveopt = opts; 9910Sstevel@tonic-gate switch (getsubopt(&opts, optlist, &val)) { 9920Sstevel@tonic-gate case OPT_RO: 9930Sstevel@tonic-gate *mntflags |= MS_RDONLY; 9940Sstevel@tonic-gate break; 9950Sstevel@tonic-gate case OPT_RW: 9960Sstevel@tonic-gate *mntflags &= ~(MS_RDONLY); 9970Sstevel@tonic-gate break; 9980Sstevel@tonic-gate case OPT_QUOTA: 9990Sstevel@tonic-gate case OPT_NOQUOTA: 10000Sstevel@tonic-gate break; 10010Sstevel@tonic-gate case OPT_SOFT: 10020Sstevel@tonic-gate args->flags |= NFSMNT_SOFT; 10030Sstevel@tonic-gate args->flags &= ~(NFSMNT_SEMISOFT); 10040Sstevel@tonic-gate break; 10050Sstevel@tonic-gate case OPT_SEMISOFT: 10060Sstevel@tonic-gate args->flags |= NFSMNT_SOFT; 10070Sstevel@tonic-gate args->flags |= NFSMNT_SEMISOFT; 10080Sstevel@tonic-gate break; 10090Sstevel@tonic-gate case OPT_HARD: 10100Sstevel@tonic-gate args->flags &= ~(NFSMNT_SOFT); 10110Sstevel@tonic-gate args->flags &= ~(NFSMNT_SEMISOFT); 10120Sstevel@tonic-gate break; 10130Sstevel@tonic-gate case OPT_SUID: 10140Sstevel@tonic-gate *mntflags &= ~(MS_NOSUID); 10150Sstevel@tonic-gate break; 10160Sstevel@tonic-gate case OPT_NOSUID: 10170Sstevel@tonic-gate *mntflags |= MS_NOSUID; 10180Sstevel@tonic-gate break; 10190Sstevel@tonic-gate case OPT_GRPID: 10200Sstevel@tonic-gate args->flags |= NFSMNT_GRPID; 10210Sstevel@tonic-gate break; 10220Sstevel@tonic-gate case OPT_REMOUNT: 10230Sstevel@tonic-gate *mntflags |= MS_REMOUNT; 10240Sstevel@tonic-gate break; 10250Sstevel@tonic-gate case OPT_INTR: 10260Sstevel@tonic-gate args->flags |= NFSMNT_INT; 10270Sstevel@tonic-gate break; 10280Sstevel@tonic-gate case OPT_NOINTR: 10290Sstevel@tonic-gate args->flags &= ~(NFSMNT_INT); 10300Sstevel@tonic-gate break; 10310Sstevel@tonic-gate case OPT_NOAC: 10320Sstevel@tonic-gate args->flags |= NFSMNT_NOAC; 10330Sstevel@tonic-gate break; 10340Sstevel@tonic-gate case OPT_PORT: 10350Sstevel@tonic-gate if (bad(val)) 10360Sstevel@tonic-gate goto badopt; 10370Sstevel@tonic-gate nfs_port = htons((ushort_t)atoi(val)); 10380Sstevel@tonic-gate break; 10390Sstevel@tonic-gate 10400Sstevel@tonic-gate case OPT_SECURE: 10410Sstevel@tonic-gate if (nfs_getseconfig_byname("dh", &nfs_sec)) { 10425302Sth199096 pr_err(gettext("can not get \"dh\" from %s\n"), 10435302Sth199096 NFSSEC_CONF); 10445302Sth199096 goto badopt; 10450Sstevel@tonic-gate } 10460Sstevel@tonic-gate sec_opt++; 10470Sstevel@tonic-gate break; 10480Sstevel@tonic-gate 10490Sstevel@tonic-gate case OPT_NOCTO: 10500Sstevel@tonic-gate args->flags |= NFSMNT_NOCTO; 10510Sstevel@tonic-gate break; 10520Sstevel@tonic-gate 10530Sstevel@tonic-gate case OPT_RSIZE: 10540Sstevel@tonic-gate args->flags |= NFSMNT_RSIZE; 10550Sstevel@tonic-gate if (bad(val)) 10560Sstevel@tonic-gate goto badopt; 10570Sstevel@tonic-gate args->rsize = atoi(val); 10580Sstevel@tonic-gate break; 10590Sstevel@tonic-gate case OPT_WSIZE: 10600Sstevel@tonic-gate args->flags |= NFSMNT_WSIZE; 10610Sstevel@tonic-gate if (bad(val)) 10620Sstevel@tonic-gate goto badopt; 10630Sstevel@tonic-gate args->wsize = atoi(val); 10640Sstevel@tonic-gate break; 10650Sstevel@tonic-gate case OPT_TIMEO: 10660Sstevel@tonic-gate args->flags |= NFSMNT_TIMEO; 10670Sstevel@tonic-gate if (bad(val)) 10680Sstevel@tonic-gate goto badopt; 10690Sstevel@tonic-gate args->timeo = atoi(val); 10700Sstevel@tonic-gate break; 10710Sstevel@tonic-gate case OPT_RETRANS: 10720Sstevel@tonic-gate args->flags |= NFSMNT_RETRANS; 10730Sstevel@tonic-gate if (bad(val)) 10740Sstevel@tonic-gate goto badopt; 10750Sstevel@tonic-gate args->retrans = atoi(val); 10760Sstevel@tonic-gate break; 10770Sstevel@tonic-gate case OPT_ACTIMEO: 10780Sstevel@tonic-gate args->flags |= NFSMNT_ACDIRMAX; 10790Sstevel@tonic-gate args->flags |= NFSMNT_ACREGMAX; 10800Sstevel@tonic-gate args->flags |= NFSMNT_ACDIRMIN; 10810Sstevel@tonic-gate args->flags |= NFSMNT_ACREGMIN; 10820Sstevel@tonic-gate if (bad(val)) 10830Sstevel@tonic-gate goto badopt; 10840Sstevel@tonic-gate args->acdirmin = args->acregmin = args->acdirmax 10855302Sth199096 = args->acregmax = atoi(val); 10860Sstevel@tonic-gate break; 10870Sstevel@tonic-gate case OPT_ACREGMIN: 10880Sstevel@tonic-gate args->flags |= NFSMNT_ACREGMIN; 10890Sstevel@tonic-gate if (bad(val)) 10900Sstevel@tonic-gate goto badopt; 10910Sstevel@tonic-gate args->acregmin = atoi(val); 10920Sstevel@tonic-gate break; 10930Sstevel@tonic-gate case OPT_ACREGMAX: 10940Sstevel@tonic-gate args->flags |= NFSMNT_ACREGMAX; 10950Sstevel@tonic-gate if (bad(val)) 10960Sstevel@tonic-gate goto badopt; 10970Sstevel@tonic-gate args->acregmax = atoi(val); 10980Sstevel@tonic-gate break; 10990Sstevel@tonic-gate case OPT_ACDIRMIN: 11000Sstevel@tonic-gate args->flags |= NFSMNT_ACDIRMIN; 11010Sstevel@tonic-gate if (bad(val)) 11020Sstevel@tonic-gate goto badopt; 11030Sstevel@tonic-gate args->acdirmin = atoi(val); 11040Sstevel@tonic-gate break; 11050Sstevel@tonic-gate case OPT_ACDIRMAX: 11060Sstevel@tonic-gate args->flags |= NFSMNT_ACDIRMAX; 11070Sstevel@tonic-gate if (bad(val)) 11080Sstevel@tonic-gate goto badopt; 11090Sstevel@tonic-gate args->acdirmax = atoi(val); 11100Sstevel@tonic-gate break; 11110Sstevel@tonic-gate case OPT_BG: 11120Sstevel@tonic-gate bg++; 11130Sstevel@tonic-gate break; 11140Sstevel@tonic-gate case OPT_FG: 11150Sstevel@tonic-gate bg = 0; 11160Sstevel@tonic-gate break; 11170Sstevel@tonic-gate case OPT_RETRY: 11180Sstevel@tonic-gate if (bad(val)) 11190Sstevel@tonic-gate goto badopt; 11200Sstevel@tonic-gate retries = atoi(val); 11210Sstevel@tonic-gate break; 11220Sstevel@tonic-gate case OPT_LLOCK: 11230Sstevel@tonic-gate args->flags |= NFSMNT_LLOCK; 11240Sstevel@tonic-gate break; 11250Sstevel@tonic-gate case OPT_POSIX: 11260Sstevel@tonic-gate posix = 1; 11270Sstevel@tonic-gate break; 11280Sstevel@tonic-gate case OPT_VERS: 11290Sstevel@tonic-gate if (bad(val)) 11300Sstevel@tonic-gate goto badopt; 11310Sstevel@tonic-gate nfsvers = (rpcvers_t)atoi(val); 11320Sstevel@tonic-gate break; 11330Sstevel@tonic-gate case OPT_PROTO: 113477Soa138391 if (val == NULL) 113577Soa138391 goto badopt; 113677Soa138391 11370Sstevel@tonic-gate nfs_proto = (char *)malloc(strlen(val)+1); 113877Soa138391 if (!nfs_proto) { 113977Soa138391 pr_err(gettext("no memory")); 114077Soa138391 return (RET_ERR); 114177Soa138391 } 114277Soa138391 114377Soa138391 (void) strncpy(nfs_proto, val, strlen(val)+1); 11440Sstevel@tonic-gate break; 11455302Sth199096 11460Sstevel@tonic-gate case OPT_NOPRINT: 11470Sstevel@tonic-gate args->flags |= NFSMNT_NOPRINT; 11480Sstevel@tonic-gate break; 11495302Sth199096 11500Sstevel@tonic-gate case OPT_LARGEFILES: 11510Sstevel@tonic-gate largefiles = 1; 11520Sstevel@tonic-gate break; 11535302Sth199096 11540Sstevel@tonic-gate case OPT_NOLARGEFILES: 11550Sstevel@tonic-gate pr_err(gettext("NFS can't support \"nolargefiles\"\n")); 11560Sstevel@tonic-gate free(optstr); 11570Sstevel@tonic-gate return (RET_ERR); 11580Sstevel@tonic-gate 11590Sstevel@tonic-gate case OPT_SEC: 11600Sstevel@tonic-gate if (nfs_getseconfig_byname(val, &nfs_sec)) { 11615302Sth199096 pr_err(gettext("can not get \"%s\" from %s\n"), 11625302Sth199096 val, NFSSEC_CONF); 11635302Sth199096 return (RET_ERR); 11640Sstevel@tonic-gate } 11650Sstevel@tonic-gate sec_opt++; 11660Sstevel@tonic-gate break; 11670Sstevel@tonic-gate 11680Sstevel@tonic-gate case OPT_PUBLIC: 11690Sstevel@tonic-gate public_opt = TRUE; 11700Sstevel@tonic-gate break; 11710Sstevel@tonic-gate 11720Sstevel@tonic-gate case OPT_DIRECTIO: 11730Sstevel@tonic-gate args->flags |= NFSMNT_DIRECTIO; 11740Sstevel@tonic-gate break; 11750Sstevel@tonic-gate 11760Sstevel@tonic-gate case OPT_NODIRECTIO: 11770Sstevel@tonic-gate args->flags &= ~(NFSMNT_DIRECTIO); 11780Sstevel@tonic-gate break; 11790Sstevel@tonic-gate 11800Sstevel@tonic-gate case OPT_XATTR: 11810Sstevel@tonic-gate case OPT_NOXATTR: 11820Sstevel@tonic-gate /* 11830Sstevel@tonic-gate * VFS options; just need to get them into the 11840Sstevel@tonic-gate * new mount option string and note we've seen them 11850Sstevel@tonic-gate */ 11860Sstevel@tonic-gate attrpref = 1; 11870Sstevel@tonic-gate break; 11880Sstevel@tonic-gate default: 11890Sstevel@tonic-gate /* 11900Sstevel@tonic-gate * Note that this could be a valid OPT_* option so 11910Sstevel@tonic-gate * we can't use "val" but need to use "saveopt". 11920Sstevel@tonic-gate */ 11930Sstevel@tonic-gate if (fsisstdopt(saveopt)) 11940Sstevel@tonic-gate break; 11950Sstevel@tonic-gate invalid = 1; 11960Sstevel@tonic-gate if (!qflg) 11970Sstevel@tonic-gate (void) fprintf(stderr, gettext( 11980Sstevel@tonic-gate "mount: %s on %s - WARNING unknown option" 11990Sstevel@tonic-gate " \"%s\"\n"), mnt->mnt_special, 12000Sstevel@tonic-gate mnt->mnt_mountp, saveopt); 12010Sstevel@tonic-gate break; 12020Sstevel@tonic-gate } 12030Sstevel@tonic-gate if (!invalid) { 12040Sstevel@tonic-gate if (newopts[0]) 12050Sstevel@tonic-gate strcat(newopts, ","); 12060Sstevel@tonic-gate strcat(newopts, saveopt); 12070Sstevel@tonic-gate } 12080Sstevel@tonic-gate } 12090Sstevel@tonic-gate /* Default is to turn extended attrs on */ 12100Sstevel@tonic-gate if (!attrpref) { 12110Sstevel@tonic-gate if (newopts[0]) 12120Sstevel@tonic-gate strcat(newopts, ","); 12130Sstevel@tonic-gate strcat(newopts, MNTOPT_XATTR); 12140Sstevel@tonic-gate } 12150Sstevel@tonic-gate strcpy(mnt->mnt_mntopts, newopts); 12160Sstevel@tonic-gate free(newopts); 12170Sstevel@tonic-gate free(optstr); 12180Sstevel@tonic-gate 12190Sstevel@tonic-gate /* ensure that only one secure mode is requested */ 12200Sstevel@tonic-gate if (sec_opt > 1) { 12210Sstevel@tonic-gate pr_err(gettext("Security options conflict\n")); 12220Sstevel@tonic-gate return (RET_ERR); 12230Sstevel@tonic-gate } 12240Sstevel@tonic-gate 12250Sstevel@tonic-gate /* ensure that the user isn't trying to get large files over V2 */ 12260Sstevel@tonic-gate if (nfsvers == NFS_VERSION && largefiles) { 12270Sstevel@tonic-gate pr_err(gettext("NFS V2 can't support \"largefiles\"\n")); 12280Sstevel@tonic-gate return (RET_ERR); 12290Sstevel@tonic-gate } 12300Sstevel@tonic-gate 12310Sstevel@tonic-gate if (nfsvers == NFS_V4 && 12320Sstevel@tonic-gate nfs_proto != NULL && 12330Sstevel@tonic-gate strncasecmp(nfs_proto, NC_UDP, strlen(NC_UDP)) == 0) { 12340Sstevel@tonic-gate pr_err(gettext("NFS V4 does not support %s\n"), nfs_proto); 12350Sstevel@tonic-gate return (RET_ERR); 12360Sstevel@tonic-gate } 12370Sstevel@tonic-gate 12380Sstevel@tonic-gate return (RET_OK); 12390Sstevel@tonic-gate 12400Sstevel@tonic-gate badopt: 12410Sstevel@tonic-gate pr_err(gettext("invalid option: \"%s\"\n"), saveopt); 12420Sstevel@tonic-gate free(optstr); 12430Sstevel@tonic-gate return (RET_ERR); 12440Sstevel@tonic-gate } 12450Sstevel@tonic-gate 12460Sstevel@tonic-gate static int 12470Sstevel@tonic-gate make_secure(struct nfs_args *args, char *hostname, struct netconfig *nconf, 12480Sstevel@tonic-gate bool_t use_pubfh, rpcvers_t vers) 12490Sstevel@tonic-gate { 12500Sstevel@tonic-gate sec_data_t *secdata; 12510Sstevel@tonic-gate int flags; 12520Sstevel@tonic-gate struct netbuf *syncaddr = NULL; 12530Sstevel@tonic-gate struct nd_addrlist *retaddrs = NULL; 12540Sstevel@tonic-gate char netname[MAXNETNAMELEN+1]; 12550Sstevel@tonic-gate 12560Sstevel@tonic-gate /* 12570Sstevel@tonic-gate * check to see if any secure mode is requested. 12580Sstevel@tonic-gate * if not, use default security mode. 12590Sstevel@tonic-gate */ 12600Sstevel@tonic-gate if (!snego_done && !sec_opt) { 12610Sstevel@tonic-gate /* 12625302Sth199096 * Get default security mode. 12635302Sth199096 * AUTH_UNIX has been the default choice for a long time. 12645302Sth199096 * The better NFS security service becomes, the better chance 12655302Sth199096 * we will set stronger security service as the default NFS 12665302Sth199096 * security mode. 12670Sstevel@tonic-gate */ 12685302Sth199096 if (nfs_getseconfig_default(&nfs_sec)) { 12695302Sth199096 pr_err(gettext("error getting default" 12705302Sth199096 " security entry\n")); 12715302Sth199096 return (-1); 12725302Sth199096 } 12735302Sth199096 args->flags |= NFSMNT_SECDEFAULT; 12740Sstevel@tonic-gate } 12750Sstevel@tonic-gate 12760Sstevel@tonic-gate /* 12770Sstevel@tonic-gate * Get the network address for the time service on the server. 12780Sstevel@tonic-gate * If an RPC based time service is not available then try the 12790Sstevel@tonic-gate * IP time service. 12800Sstevel@tonic-gate * 12810Sstevel@tonic-gate * This is for AUTH_DH processing. We will also pass down syncaddr 12820Sstevel@tonic-gate * and netname for NFS V4 even if AUTH_DH is not requested right now. 12830Sstevel@tonic-gate * NFS V4 does security negotiation in the kernel via SECINFO. 12840Sstevel@tonic-gate * These information might be needed later in the kernel. 12850Sstevel@tonic-gate * 12860Sstevel@tonic-gate * Eventurally, we want to move this code to nfs_clnt_secdata() 12870Sstevel@tonic-gate * when autod_nfs.c and mount.c can share the same get_the_addr() 12880Sstevel@tonic-gate * routine. 12890Sstevel@tonic-gate */ 12900Sstevel@tonic-gate flags = 0; 12910Sstevel@tonic-gate syncaddr = NULL; 12920Sstevel@tonic-gate 12930Sstevel@tonic-gate if (nfs_sec.sc_rpcnum == AUTH_DH || vers == NFS_V4) { 12940Sstevel@tonic-gate /* 12950Sstevel@tonic-gate * If using the public fh or nfsv4, we will not contact the 12960Sstevel@tonic-gate * remote RPCBINDer, since it is possibly behind a firewall. 12970Sstevel@tonic-gate */ 12985302Sth199096 if (use_pubfh == FALSE && vers != NFS_V4) 12990Sstevel@tonic-gate syncaddr = get_the_addr(hostname, RPCBPROG, RPCBVERS, 13005302Sth199096 nconf, 0, NULL, NULL, FALSE, NULL, NULL); 13010Sstevel@tonic-gate 13020Sstevel@tonic-gate if (syncaddr != NULL) { 13030Sstevel@tonic-gate /* for flags in sec_data */ 13040Sstevel@tonic-gate flags |= AUTH_F_RPCTIMESYNC; 13050Sstevel@tonic-gate } else { 13060Sstevel@tonic-gate struct nd_hostserv hs; 13070Sstevel@tonic-gate int error; 13080Sstevel@tonic-gate 13090Sstevel@tonic-gate hs.h_host = hostname; 13100Sstevel@tonic-gate hs.h_serv = "timserver"; 13110Sstevel@tonic-gate 13120Sstevel@tonic-gate error = netdir_getbyname(nconf, &hs, &retaddrs); 13130Sstevel@tonic-gate 13140Sstevel@tonic-gate if (error != ND_OK && (nfs_sec.sc_rpcnum == AUTH_DH)) { 13155302Sth199096 pr_err(gettext("%s: secure: no time service\n"), 13165302Sth199096 hostname); 13175302Sth199096 return (-1); 13180Sstevel@tonic-gate } 13190Sstevel@tonic-gate 13200Sstevel@tonic-gate if (error == ND_OK) 13210Sstevel@tonic-gate syncaddr = retaddrs->n_addrs; 13220Sstevel@tonic-gate 13230Sstevel@tonic-gate /* 13240Sstevel@tonic-gate * For NFS_V4 if AUTH_DH is negotiated later in the 13250Sstevel@tonic-gate * kernel thru SECINFO, it will need syncaddr 13260Sstevel@tonic-gate * and netname data. 13270Sstevel@tonic-gate */ 13280Sstevel@tonic-gate if (vers == NFS_V4 && syncaddr && 13295302Sth199096 host2netname(netname, hostname, NULL)) { 13305302Sth199096 args->syncaddr = malloc(sizeof (struct netbuf)); 13315302Sth199096 args->syncaddr->buf = malloc(syncaddr->len); 13325302Sth199096 (void) memcpy(args->syncaddr->buf, 13335302Sth199096 syncaddr->buf, syncaddr->len); 13345302Sth199096 args->syncaddr->len = syncaddr->len; 13355302Sth199096 args->syncaddr->maxlen = syncaddr->maxlen; 13365302Sth199096 args->netname = strdup(netname); 13375302Sth199096 args->flags |= NFSMNT_SECURE; 13380Sstevel@tonic-gate } 13390Sstevel@tonic-gate } 13400Sstevel@tonic-gate } 13410Sstevel@tonic-gate 13420Sstevel@tonic-gate /* 13430Sstevel@tonic-gate * For the initial chosen flavor (any flavor defined in nfssec.conf), 13440Sstevel@tonic-gate * the data will be stored in the sec_data structure via 13450Sstevel@tonic-gate * nfs_clnt_secdata() and be passed to the kernel via nfs_args_* 13460Sstevel@tonic-gate * extended data structure. 13470Sstevel@tonic-gate */ 13480Sstevel@tonic-gate if (!(secdata = nfs_clnt_secdata(&nfs_sec, hostname, args->knconf, 13495302Sth199096 syncaddr, flags))) { 13500Sstevel@tonic-gate pr_err(gettext("errors constructing security related data\n")); 13510Sstevel@tonic-gate if (flags & AUTH_F_RPCTIMESYNC) { 13520Sstevel@tonic-gate free(syncaddr->buf); 13530Sstevel@tonic-gate free(syncaddr); 13540Sstevel@tonic-gate } else if (retaddrs) 13550Sstevel@tonic-gate netdir_free((void *)retaddrs, ND_ADDRLIST); 13560Sstevel@tonic-gate return (-1); 13570Sstevel@tonic-gate } 13580Sstevel@tonic-gate 13590Sstevel@tonic-gate NFS_ARGS_EXTB_secdata(args, secdata); 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 (0); 13660Sstevel@tonic-gate } 13670Sstevel@tonic-gate 13680Sstevel@tonic-gate /* 13690Sstevel@tonic-gate * Get the network address on "hostname" for program "prog" 13700Sstevel@tonic-gate * with version "vers" by using the nconf configuration data 13710Sstevel@tonic-gate * passed in. 13720Sstevel@tonic-gate * 13730Sstevel@tonic-gate * If the address of a netconfig pointer is null then 13740Sstevel@tonic-gate * information is not sufficient and no netbuf will be returned. 13750Sstevel@tonic-gate * 13760Sstevel@tonic-gate * Finally, ping the null procedure of that service. 13770Sstevel@tonic-gate * 13780Sstevel@tonic-gate * A similar routine is also defined in ../../autofs/autod_nfs.c. 13790Sstevel@tonic-gate * This is a potential routine to move to ../lib for common usage. 13800Sstevel@tonic-gate */ 13810Sstevel@tonic-gate static struct netbuf * 13820Sstevel@tonic-gate get_the_addr(char *hostname, ulong_t prog, ulong_t vers, 13830Sstevel@tonic-gate struct netconfig *nconf, ushort_t port, struct t_info *tinfo, 13840Sstevel@tonic-gate caddr_t *fhp, bool_t get_pubfh, char *fspath, err_ret_t *error) 13850Sstevel@tonic-gate { 13860Sstevel@tonic-gate struct netbuf *nb = NULL; 13870Sstevel@tonic-gate struct t_bind *tbind = NULL; 13880Sstevel@tonic-gate CLIENT *cl = NULL; 13890Sstevel@tonic-gate struct timeval tv; 13900Sstevel@tonic-gate int fd = -1; 13910Sstevel@tonic-gate AUTH *ah = NULL; 13920Sstevel@tonic-gate AUTH *new_ah = NULL; 13930Sstevel@tonic-gate struct snego_t snego; 13940Sstevel@tonic-gate 13950Sstevel@tonic-gate if (nconf == NULL) 13960Sstevel@tonic-gate return (NULL); 13970Sstevel@tonic-gate 13980Sstevel@tonic-gate if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) == -1) 13995302Sth199096 goto done; 14000Sstevel@tonic-gate 14010Sstevel@tonic-gate /* LINTED pointer alignment */ 14020Sstevel@tonic-gate if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR)) 14035302Sth199096 == NULL) 14040Sstevel@tonic-gate goto done; 14050Sstevel@tonic-gate 14060Sstevel@tonic-gate /* 14070Sstevel@tonic-gate * In the case of public filehandle usage or NFSv4 we want to 14080Sstevel@tonic-gate * avoid use of the rpcbind/portmap protocol 14090Sstevel@tonic-gate */ 14100Sstevel@tonic-gate if ((get_pubfh == TRUE) || (vers == NFS_V4)) { 14110Sstevel@tonic-gate struct nd_hostserv hs; 14120Sstevel@tonic-gate struct nd_addrlist *retaddrs; 14130Sstevel@tonic-gate int retval; 14140Sstevel@tonic-gate hs.h_host = hostname; 14150Sstevel@tonic-gate 14160Sstevel@tonic-gate /* NFS where vers==4 does not support UDP */ 14170Sstevel@tonic-gate if (vers == NFS_V4 && 14180Sstevel@tonic-gate strncasecmp(nconf->nc_proto, NC_UDP, 14195302Sth199096 strlen(NC_UDP)) == 0) { 142077Soa138391 SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0); 14210Sstevel@tonic-gate goto done; 14220Sstevel@tonic-gate } 14230Sstevel@tonic-gate 14240Sstevel@tonic-gate if (port == 0) 14250Sstevel@tonic-gate hs.h_serv = "nfs"; 14260Sstevel@tonic-gate else 14270Sstevel@tonic-gate hs.h_serv = NULL; 14280Sstevel@tonic-gate 14290Sstevel@tonic-gate if ((retval = netdir_getbyname(nconf, &hs, &retaddrs)) 14300Sstevel@tonic-gate != ND_OK) { 14310Sstevel@tonic-gate /* 14320Sstevel@tonic-gate * Carefully set the error value here. Want to signify 14330Sstevel@tonic-gate * that the error was an unknown host. 14340Sstevel@tonic-gate */ 14350Sstevel@tonic-gate if (retval == ND_NOHOST) { 14360Sstevel@tonic-gate SET_ERR_RET(error, ERR_NOHOST, retval); 14370Sstevel@tonic-gate } 14380Sstevel@tonic-gate 14390Sstevel@tonic-gate goto done; 14400Sstevel@tonic-gate } 14410Sstevel@tonic-gate memcpy(tbind->addr.buf, retaddrs->n_addrs->buf, 14425302Sth199096 retaddrs->n_addrs->len); 14430Sstevel@tonic-gate tbind->addr.len = retaddrs->n_addrs->len; 14440Sstevel@tonic-gate netdir_free((void *)retaddrs, ND_ADDRLIST); 14450Sstevel@tonic-gate (void) netdir_options(nconf, ND_SET_RESERVEDPORT, fd, NULL); 14460Sstevel@tonic-gate 14470Sstevel@tonic-gate } else { 14480Sstevel@tonic-gate if (rpcb_getaddr(prog, vers, nconf, &tbind->addr, 14490Sstevel@tonic-gate hostname) == FALSE) { 14500Sstevel@tonic-gate goto done; 14510Sstevel@tonic-gate } 14520Sstevel@tonic-gate } 14530Sstevel@tonic-gate 14540Sstevel@tonic-gate if (port) { 14550Sstevel@tonic-gate /* LINTED pointer alignment */ 14560Sstevel@tonic-gate if (strcmp(nconf->nc_protofmly, NC_INET) == 0) 14570Sstevel@tonic-gate ((struct sockaddr_in *)tbind->addr.buf)->sin_port 14585302Sth199096 = port; 14590Sstevel@tonic-gate else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) 14600Sstevel@tonic-gate ((struct sockaddr_in6 *)tbind->addr.buf)->sin6_port 14615302Sth199096 = port; 14620Sstevel@tonic-gate 14630Sstevel@tonic-gate } 14640Sstevel@tonic-gate 14650Sstevel@tonic-gate cl = clnt_tli_create(fd, nconf, &tbind->addr, prog, vers, 0, 0); 14660Sstevel@tonic-gate if (cl == NULL) { 146777Soa138391 /* 146877Soa138391 * clnt_tli_create() returns either RPC_SYSTEMERROR, 146977Soa138391 * RPC_UNKNOWNPROTO or RPC_TLIERROR. The RPC_TLIERROR translates 147077Soa138391 * to "Misc. TLI error". This is not too helpful. Most likely 147177Soa138391 * the connection to the remote server timed out, so this 147277Soa138391 * error is at least less perplexing. 147377Soa138391 * See: usr/src/cmd/rpcinfo/rpcinfo.c 147477Soa138391 */ 147577Soa138391 if (rpc_createerr.cf_stat == RPC_TLIERROR) { 147677Soa138391 SET_ERR_RET(error, ERR_RPCERROR, RPC_PMAPFAILURE); 147777Soa138391 } else { 147877Soa138391 SET_ERR_RET(error, ERR_RPCERROR, rpc_createerr.cf_stat); 147977Soa138391 } 14800Sstevel@tonic-gate goto done; 14810Sstevel@tonic-gate } 14820Sstevel@tonic-gate 14830Sstevel@tonic-gate ah = authsys_create_default(); 14840Sstevel@tonic-gate if (ah != NULL) 14850Sstevel@tonic-gate cl->cl_auth = ah; 14860Sstevel@tonic-gate 14870Sstevel@tonic-gate tv.tv_sec = 5; 14880Sstevel@tonic-gate tv.tv_usec = 0; 14890Sstevel@tonic-gate 14900Sstevel@tonic-gate (void) clnt_control(cl, CLSET_TIMEOUT, (char *)&tv); 14910Sstevel@tonic-gate 14920Sstevel@tonic-gate if ((get_pubfh == TRUE) && (vers != NFS_V4)) { 14935302Sth199096 enum snego_stat sec; 14940Sstevel@tonic-gate 14955302Sth199096 if (!snego_done) { 14965302Sth199096 /* 14975302Sth199096 * negotiate sec flavor. 14985302Sth199096 */ 14995302Sth199096 snego.cnt = 0; 15005302Sth199096 if ((sec = nfs_sec_nego(vers, cl, fspath, &snego)) == 15015302Sth199096 SNEGO_SUCCESS) { 15025302Sth199096 int jj; 15030Sstevel@tonic-gate 15045302Sth199096 /* 15055302Sth199096 * check if server supports the one 15065302Sth199096 * specified in the sec= option. 15075302Sth199096 */ 15080Sstevel@tonic-gate if (sec_opt) { 15095302Sth199096 for (jj = 0; jj < snego.cnt; jj++) { 15105302Sth199096 if (snego.array[jj] == 15115302Sth199096 nfs_sec.sc_nfsnum) { 15125302Sth199096 snego_done = TRUE; 15135302Sth199096 break; 15145302Sth199096 } 15155302Sth199096 } 15160Sstevel@tonic-gate } 15175302Sth199096 15185302Sth199096 /* 15195302Sth199096 * find a common sec flavor 15205302Sth199096 */ 15215302Sth199096 if (!snego_done) { 15225302Sth199096 if (sec_opt) { 15235302Sth199096 pr_err(gettext( 15245302Sth199096 "Server does not support" 15255302Sth199096 " the security flavor" 15265302Sth199096 " specified.\n")); 15275302Sth199096 } 15280Sstevel@tonic-gate 15295302Sth199096 for (jj = 0; jj < snego.cnt; jj++) { 15305302Sth199096 if (!nfs_getseconfig_bynumber( 15315302Sth199096 snego.array[jj], 15325302Sth199096 &nfs_sec)) { 15335302Sth199096 snego_done = TRUE; 15345302Sth199096 #define EMSG80SUX "Security flavor %d was negotiated and will be used.\n" 15355302Sth199096 if (sec_opt) 15365302Sth199096 pr_err(gettext( 15375302Sth199096 EMSG80SUX), 15385302Sth199096 nfs_sec. 15395302Sth199096 sc_nfsnum); 15405302Sth199096 break; 15415302Sth199096 } 15425302Sth199096 } 15435302Sth199096 } 15445302Sth199096 15455302Sth199096 if (!snego_done) 15465302Sth199096 return (NULL); 15470Sstevel@tonic-gate 15485302Sth199096 /* 15495302Sth199096 * Now that the flavor has been 15505302Sth199096 * negotiated, get the fh. 15515302Sth199096 * 15525302Sth199096 * First, create an auth handle using the 15535302Sth199096 * negotiated sec flavor in the next lookup to 15545302Sth199096 * fetch the filehandle. 15555302Sth199096 */ 15565302Sth199096 new_ah = nfs_create_ah(cl, hostname, &nfs_sec); 15575302Sth199096 if (new_ah == NULL) 15585302Sth199096 goto done; 15595302Sth199096 cl->cl_auth = new_ah; 15605302Sth199096 } else if (sec == SNEGO_ARRAY_TOO_SMALL || sec == 15615302Sth199096 SNEGO_FAILURE) { 15625302Sth199096 goto done; 15635302Sth199096 } 15640Sstevel@tonic-gate 15655302Sth199096 /* 15665302Sth199096 * Note that if sec == SNEGO_DEF_VALID 15675302Sth199096 * default sec flavor is acceptable. 15685302Sth199096 * Use it to get the filehandle. 15695302Sth199096 */ 15700Sstevel@tonic-gate } 15710Sstevel@tonic-gate 15725302Sth199096 if (vers == NFS_VERSION) { 15735302Sth199096 wnl_diropargs arg; 15745302Sth199096 wnl_diropres *res; 15755302Sth199096 15765302Sth199096 memset((char *)&arg.dir, 0, sizeof (wnl_fh)); 15775302Sth199096 arg.name = fspath; 15785302Sth199096 res = wnlproc_lookup_2(&arg, cl); 15795302Sth199096 15805302Sth199096 if (res == NULL || res->status != NFS_OK) 15815302Sth199096 goto done; 15825302Sth199096 *fhp = malloc(sizeof (wnl_fh)); 15830Sstevel@tonic-gate 15845302Sth199096 if (*fhp == NULL) { 15855302Sth199096 pr_err(gettext("no memory\n")); 15865302Sth199096 goto done; 15875302Sth199096 } 15880Sstevel@tonic-gate 15895302Sth199096 memcpy((char *)*fhp, 15905302Sth199096 (char *)&res->wnl_diropres_u.wnl_diropres.file, 15915302Sth199096 sizeof (wnl_fh)); 15925302Sth199096 } else { 15935302Sth199096 WNL_LOOKUP3args arg; 15945302Sth199096 WNL_LOOKUP3res *res; 15955302Sth199096 nfs_fh3 *fh3p; 15960Sstevel@tonic-gate 15975302Sth199096 memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3)); 15985302Sth199096 arg.what.name = fspath; 15995302Sth199096 res = wnlproc3_lookup_3(&arg, cl); 16005302Sth199096 16015302Sth199096 if (res == NULL || res->status != NFS3_OK) 16025302Sth199096 goto done; 16035302Sth199096 16045302Sth199096 fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p)); 16050Sstevel@tonic-gate 16065302Sth199096 if (fh3p == NULL) { 16075302Sth199096 pr_err(gettext("no memory\n")); 16085302Sth199096 CLNT_FREERES(cl, xdr_WNL_LOOKUP3res, 16095302Sth199096 (char *)res); 16105302Sth199096 goto done; 16115302Sth199096 } 16120Sstevel@tonic-gate 16135302Sth199096 fh3p->fh3_length = 16145302Sth199096 res->WNL_LOOKUP3res_u.res_ok.object.data.data_len; 16155302Sth199096 memcpy(fh3p->fh3_u.data, 16165302Sth199096 res->WNL_LOOKUP3res_u.res_ok.object.data.data_val, 16175302Sth199096 fh3p->fh3_length); 16180Sstevel@tonic-gate 16195302Sth199096 *fhp = (caddr_t)fh3p; 16205302Sth199096 CLNT_FREERES(cl, xdr_WNL_LOOKUP3res, (char *)res); 16215302Sth199096 } 16220Sstevel@tonic-gate } else { 16230Sstevel@tonic-gate void *res; 16240Sstevel@tonic-gate struct rpc_err r_err; 16250Sstevel@tonic-gate 16260Sstevel@tonic-gate if (vers == NFS_VERSION) 16275302Sth199096 res = wnlproc_null_2(NULL, cl); 16280Sstevel@tonic-gate else if (vers == NFS_V3) 16295302Sth199096 res = wnlproc3_null_3(NULL, cl); 16300Sstevel@tonic-gate else 16315302Sth199096 res = wnlproc4_null_4(NULL, cl); 16320Sstevel@tonic-gate 16330Sstevel@tonic-gate if (res == NULL) { 16340Sstevel@tonic-gate clnt_geterr(cl, &r_err); 16350Sstevel@tonic-gate if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { 16360Sstevel@tonic-gate switch (r_err.re_status) { 16370Sstevel@tonic-gate case RPC_TLIERROR: 16380Sstevel@tonic-gate case RPC_CANTRECV: 16390Sstevel@tonic-gate case RPC_CANTSEND: 16400Sstevel@tonic-gate r_err.re_status = RPC_PROGVERSMISMATCH; 16410Sstevel@tonic-gate } 16420Sstevel@tonic-gate } 16430Sstevel@tonic-gate SET_ERR_RET(error, ERR_RPCERROR, r_err.re_status); 16440Sstevel@tonic-gate goto done; 16450Sstevel@tonic-gate } 16460Sstevel@tonic-gate } 16470Sstevel@tonic-gate 16480Sstevel@tonic-gate /* 16490Sstevel@tonic-gate * Make a copy of the netbuf to return 16500Sstevel@tonic-gate */ 16510Sstevel@tonic-gate nb = (struct netbuf *)malloc(sizeof (*nb)); 16520Sstevel@tonic-gate if (nb == NULL) { 16530Sstevel@tonic-gate pr_err(gettext("no memory\n")); 16540Sstevel@tonic-gate goto done; 16550Sstevel@tonic-gate } 16560Sstevel@tonic-gate *nb = tbind->addr; 16570Sstevel@tonic-gate nb->buf = (char *)malloc(nb->maxlen); 16580Sstevel@tonic-gate if (nb->buf == NULL) { 16590Sstevel@tonic-gate pr_err(gettext("no memory\n")); 16600Sstevel@tonic-gate free(nb); 16610Sstevel@tonic-gate nb = NULL; 16620Sstevel@tonic-gate goto done; 16630Sstevel@tonic-gate } 16640Sstevel@tonic-gate (void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len); 16650Sstevel@tonic-gate 16660Sstevel@tonic-gate done: 16670Sstevel@tonic-gate if (cl) { 16685302Sth199096 if (ah != NULL) { 16695302Sth199096 if (new_ah != NULL) 16705302Sth199096 AUTH_DESTROY(ah); 16715302Sth199096 AUTH_DESTROY(cl->cl_auth); 16725302Sth199096 cl->cl_auth = NULL; 16735302Sth199096 } 16745302Sth199096 clnt_destroy(cl); 16755302Sth199096 cl = NULL; 16760Sstevel@tonic-gate } 16770Sstevel@tonic-gate if (tbind) { 16780Sstevel@tonic-gate t_free((char *)tbind, T_BIND); 16790Sstevel@tonic-gate tbind = NULL; 16800Sstevel@tonic-gate } 16810Sstevel@tonic-gate if (fd >= 0) 16820Sstevel@tonic-gate (void) t_close(fd); 16830Sstevel@tonic-gate return (nb); 16840Sstevel@tonic-gate } 16850Sstevel@tonic-gate 16865302Sth199096 static int 16875302Sth199096 check_nconf(struct netconfig *nconf, int nthtry, int *valid_proto) 16885302Sth199096 { 16895302Sth199096 int try_test = 0; 16905302Sth199096 int valid_family; 16915302Sth199096 char *proto = NULL; 16925302Sth199096 16935302Sth199096 16945302Sth199096 if (nthtry == FIRST_TRY) { 16955302Sth199096 try_test = ((nconf->nc_semantics == NC_TPI_COTS_ORD) || 16965302Sth199096 (nconf->nc_semantics == NC_TPI_COTS)); 16975302Sth199096 proto = NC_TCP; 16985302Sth199096 } else if (nthtry == SECOND_TRY) { 16995302Sth199096 try_test = (nconf->nc_semantics == NC_TPI_CLTS); 17005302Sth199096 proto = NC_UDP; 17015302Sth199096 } 17025302Sth199096 17035302Sth199096 if (proto && 17045302Sth199096 (strcmp(nconf->nc_protofmly, NC_INET) == 0 || 17055302Sth199096 strcmp(nconf->nc_protofmly, NC_INET6) == 0) && 17065302Sth199096 (strcmp(nconf->nc_proto, proto) == 0)) 17075302Sth199096 *valid_proto = TRUE; 17085302Sth199096 else 17095302Sth199096 *valid_proto = FALSE; 17105302Sth199096 17115302Sth199096 return (try_test); 17125302Sth199096 } 17135302Sth199096 17140Sstevel@tonic-gate /* 17150Sstevel@tonic-gate * Get a network address on "hostname" for program "prog" 17160Sstevel@tonic-gate * with version "vers". If the port number is specified (non zero) 17170Sstevel@tonic-gate * then try for a TCP/UDP transport and set the port number of the 17180Sstevel@tonic-gate * resulting IP address. 17190Sstevel@tonic-gate * 17200Sstevel@tonic-gate * If the address of a netconfig pointer was passed and 17210Sstevel@tonic-gate * if it's not null, use it as the netconfig otherwise 17220Sstevel@tonic-gate * assign the address of the netconfig that was used to 17230Sstevel@tonic-gate * establish contact with the service. 17240Sstevel@tonic-gate * 17250Sstevel@tonic-gate * A similar routine is also defined in ../../autofs/autod_nfs.c. 17260Sstevel@tonic-gate * This is a potential routine to move to ../lib for common usage. 17270Sstevel@tonic-gate * 17280Sstevel@tonic-gate * "error" refers to a more descriptive term when get_addr fails 17290Sstevel@tonic-gate * and returns NULL: ERR_PROTO_NONE if no error introduced by 17300Sstevel@tonic-gate * -o proto option, ERR_NETPATH if error found in NETPATH 17310Sstevel@tonic-gate * environment variable, ERR_PROTO_INVALID if an unrecognized 17320Sstevel@tonic-gate * protocol is specified by user, and ERR_PROTO_UNSUPP for a 17330Sstevel@tonic-gate * recognized but invalid protocol (eg. ticlts, ticots, etc.). 17340Sstevel@tonic-gate * "error" is ignored if get_addr returns non-NULL result. 17350Sstevel@tonic-gate * 17360Sstevel@tonic-gate */ 17370Sstevel@tonic-gate static struct netbuf * 17380Sstevel@tonic-gate get_addr(char *hostname, ulong_t prog, ulong_t vers, struct netconfig **nconfp, 17390Sstevel@tonic-gate char *proto, ushort_t port, struct t_info *tinfo, caddr_t *fhp, 17400Sstevel@tonic-gate bool_t get_pubfh, char *fspath, err_ret_t *error) 17410Sstevel@tonic-gate { 17420Sstevel@tonic-gate struct netbuf *nb = NULL; 17430Sstevel@tonic-gate struct netconfig *nconf = NULL; 17440Sstevel@tonic-gate NCONF_HANDLE *nc = NULL; 17450Sstevel@tonic-gate int nthtry = FIRST_TRY; 17460Sstevel@tonic-gate err_ret_t errsave_nohost, errsave_rpcerr; 17470Sstevel@tonic-gate 17480Sstevel@tonic-gate SET_ERR_RET(&errsave_nohost, ERR_PROTO_NONE, 0); 17490Sstevel@tonic-gate SET_ERR_RET(&errsave_rpcerr, ERR_PROTO_NONE, 0); 17500Sstevel@tonic-gate 17510Sstevel@tonic-gate SET_ERR_RET(error, ERR_PROTO_NONE, 0); 17520Sstevel@tonic-gate 17530Sstevel@tonic-gate if (nconfp && *nconfp) 17540Sstevel@tonic-gate return (get_the_addr(hostname, prog, vers, *nconfp, port, 17555302Sth199096 tinfo, fhp, get_pubfh, fspath, error)); 17560Sstevel@tonic-gate /* 17570Sstevel@tonic-gate * No nconf passed in. 17580Sstevel@tonic-gate * 17590Sstevel@tonic-gate * Try to get a nconf from /etc/netconfig filtered by 17600Sstevel@tonic-gate * the NETPATH environment variable. 17610Sstevel@tonic-gate * First search for COTS, second for CLTS unless proto 17620Sstevel@tonic-gate * is specified. When we retry, we reset the 17630Sstevel@tonic-gate * netconfig list so that we would search the whole list 17640Sstevel@tonic-gate * all over again. 17650Sstevel@tonic-gate */ 17660Sstevel@tonic-gate 17670Sstevel@tonic-gate if ((nc = setnetpath()) == NULL) { 17680Sstevel@tonic-gate /* should only return an error if problems with NETPATH */ 17690Sstevel@tonic-gate /* In which case you are hosed */ 17700Sstevel@tonic-gate SET_ERR_RET(error, ERR_NETPATH, 0); 17710Sstevel@tonic-gate goto done; 17720Sstevel@tonic-gate } 17730Sstevel@tonic-gate 17740Sstevel@tonic-gate /* 17750Sstevel@tonic-gate * If proto is specified, then only search for the match, 17760Sstevel@tonic-gate * otherwise try COTS first, if failed, try CLTS. 17770Sstevel@tonic-gate */ 17780Sstevel@tonic-gate if (proto) { 17790Sstevel@tonic-gate /* no matching proto name */ 17800Sstevel@tonic-gate SET_ERR_RET(error, ERR_PROTO_INVALID, 0); 17810Sstevel@tonic-gate 17820Sstevel@tonic-gate while (nconf = getnetpath(nc)) { 17830Sstevel@tonic-gate if (strcmp(nconf->nc_netid, proto)) 17840Sstevel@tonic-gate continue; 17850Sstevel@tonic-gate 17860Sstevel@tonic-gate /* may be unsupported */ 17870Sstevel@tonic-gate SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0); 17880Sstevel@tonic-gate 17890Sstevel@tonic-gate if ((port != 0) && 17905302Sth199096 ((strcmp(nconf->nc_protofmly, NC_INET) == 0 || 17915302Sth199096 strcmp(nconf->nc_protofmly, NC_INET6) == 0) && 17925302Sth199096 (strcmp(nconf->nc_proto, NC_TCP) != 0 && 17935302Sth199096 strcmp(nconf->nc_proto, NC_UDP) != 0))) { 17940Sstevel@tonic-gate continue; 17955302Sth199096 } else { 17960Sstevel@tonic-gate nb = get_the_addr(hostname, prog, 17975302Sth199096 vers, nconf, port, tinfo, 17985302Sth199096 fhp, get_pubfh, fspath, error); 17990Sstevel@tonic-gate 18000Sstevel@tonic-gate if (nb != NULL) 18010Sstevel@tonic-gate break; 18020Sstevel@tonic-gate 18030Sstevel@tonic-gate /* nb is NULL - deal with errors */ 18040Sstevel@tonic-gate if (error) { 18050Sstevel@tonic-gate if (error->error_type == ERR_NOHOST) 18060Sstevel@tonic-gate SET_ERR_RET(&errsave_nohost, 18075302Sth199096 error->error_type, 18085302Sth199096 error->error_value); 18090Sstevel@tonic-gate if (error->error_type == ERR_RPCERROR) 18100Sstevel@tonic-gate SET_ERR_RET(&errsave_rpcerr, 18115302Sth199096 error->error_type, 18125302Sth199096 error->error_value); 18130Sstevel@tonic-gate } 18140Sstevel@tonic-gate /* 18150Sstevel@tonic-gate * continue with same protocol 18160Sstevel@tonic-gate * selection 18170Sstevel@tonic-gate */ 18180Sstevel@tonic-gate continue; 18190Sstevel@tonic-gate } 18200Sstevel@tonic-gate } /* end of while */ 18210Sstevel@tonic-gate 18220Sstevel@tonic-gate if (nconf == NULL) 18230Sstevel@tonic-gate goto done; 18240Sstevel@tonic-gate 18250Sstevel@tonic-gate if ((nb = get_the_addr(hostname, prog, vers, nconf, port, 18265302Sth199096 tinfo, fhp, get_pubfh, fspath, error)) == NULL) 18270Sstevel@tonic-gate goto done; 18280Sstevel@tonic-gate } else { 18290Sstevel@tonic-gate retry: 18300Sstevel@tonic-gate SET_ERR_RET(error, ERR_NETPATH, 0); 18310Sstevel@tonic-gate while (nconf = getnetpath(nc)) { 18320Sstevel@tonic-gate SET_ERR_RET(error, ERR_PROTO_NONE, 0); 18335302Sth199096 18340Sstevel@tonic-gate if (nconf->nc_flag & NC_VISIBLE) { 18355302Sth199096 int valid_proto; 18360Sstevel@tonic-gate 18375302Sth199096 if (check_nconf(nconf, 18385302Sth199096 nthtry, &valid_proto)) { 18395302Sth199096 if (port == 0) 18405302Sth199096 break; 18415302Sth199096 18425302Sth199096 if (valid_proto == TRUE) 18435302Sth199096 break; 18440Sstevel@tonic-gate } 18450Sstevel@tonic-gate } 18460Sstevel@tonic-gate } /* while */ 18470Sstevel@tonic-gate if (nconf == NULL) { 18480Sstevel@tonic-gate if (++nthtry <= MNT_PREF_LISTLEN) { 18490Sstevel@tonic-gate endnetpath(nc); 18500Sstevel@tonic-gate if ((nc = setnetpath()) == NULL) 18510Sstevel@tonic-gate goto done; 18520Sstevel@tonic-gate goto retry; 18530Sstevel@tonic-gate } else 18540Sstevel@tonic-gate goto done; 18550Sstevel@tonic-gate } else { 18560Sstevel@tonic-gate if ((nb = get_the_addr(hostname, prog, vers, nconf, 18575302Sth199096 port, tinfo, fhp, get_pubfh, fspath, error)) 18585302Sth199096 == NULL) { 18590Sstevel@tonic-gate /* nb is NULL - deal with errors */ 18600Sstevel@tonic-gate if (error) { 18610Sstevel@tonic-gate if (error->error_type == ERR_NOHOST) 18620Sstevel@tonic-gate SET_ERR_RET(&errsave_nohost, 18635302Sth199096 error->error_type, 18645302Sth199096 error->error_value); 18650Sstevel@tonic-gate if (error->error_type == ERR_RPCERROR) 18660Sstevel@tonic-gate SET_ERR_RET(&errsave_rpcerr, 18675302Sth199096 error->error_type, 18685302Sth199096 error->error_value); 18690Sstevel@tonic-gate } 18700Sstevel@tonic-gate /* 18710Sstevel@tonic-gate * Continue the same search path in the 18720Sstevel@tonic-gate * netconfig db until no more matched 18730Sstevel@tonic-gate * nconf (nconf == NULL). 18740Sstevel@tonic-gate */ 18750Sstevel@tonic-gate goto retry; 18760Sstevel@tonic-gate } 18770Sstevel@tonic-gate } 18780Sstevel@tonic-gate } 18790Sstevel@tonic-gate SET_ERR_RET(error, ERR_PROTO_NONE, 0); 18800Sstevel@tonic-gate 18810Sstevel@tonic-gate /* 18820Sstevel@tonic-gate * Got nconf and nb. Now dup the netconfig structure (nconf) 18830Sstevel@tonic-gate * and return it thru nconfp. 18840Sstevel@tonic-gate */ 18850Sstevel@tonic-gate *nconfp = getnetconfigent(nconf->nc_netid); 18860Sstevel@tonic-gate if (*nconfp == NULL) { 18870Sstevel@tonic-gate syslog(LOG_ERR, "no memory\n"); 18880Sstevel@tonic-gate free(nb); 18890Sstevel@tonic-gate nb = NULL; 18900Sstevel@tonic-gate } 18910Sstevel@tonic-gate done: 18920Sstevel@tonic-gate if (nc) 18930Sstevel@tonic-gate endnetpath(nc); 18940Sstevel@tonic-gate 18950Sstevel@tonic-gate if (nb == NULL) { 189677Soa138391 /* 189777Soa138391 * Check the saved errors. The RPC error has * 189877Soa138391 * precedence over the no host error. 189977Soa138391 */ 190077Soa138391 if (errsave_nohost.error_type != ERR_PROTO_NONE) 190177Soa138391 SET_ERR_RET(error, errsave_nohost.error_type, 19025302Sth199096 errsave_nohost.error_value); 190377Soa138391 190477Soa138391 if (errsave_rpcerr.error_type != ERR_PROTO_NONE) 190577Soa138391 SET_ERR_RET(error, errsave_rpcerr.error_type, 19065302Sth199096 errsave_rpcerr.error_value); 19070Sstevel@tonic-gate } 190877Soa138391 19090Sstevel@tonic-gate return (nb); 19100Sstevel@tonic-gate } 19110Sstevel@tonic-gate 19120Sstevel@tonic-gate /* 19130Sstevel@tonic-gate * Get a file handle usinging multi-component lookup with the public 19140Sstevel@tonic-gate * file handle. 19150Sstevel@tonic-gate */ 19160Sstevel@tonic-gate static int 19170Sstevel@tonic-gate get_fh_via_pub(struct nfs_args *args, char *fshost, char *fspath, bool_t url, 19180Sstevel@tonic-gate bool_t loud, int *versp, struct netconfig **nconfp, ushort_t port) 19190Sstevel@tonic-gate { 19200Sstevel@tonic-gate uint_t vers_min; 19210Sstevel@tonic-gate uint_t vers_max; 19220Sstevel@tonic-gate int r; 19230Sstevel@tonic-gate char *path; 19240Sstevel@tonic-gate 19250Sstevel@tonic-gate if (nfsvers != 0) { 19260Sstevel@tonic-gate vers_max = vers_min = nfsvers; 19270Sstevel@tonic-gate } else { 19280Sstevel@tonic-gate vers_max = vers_max_default; 19290Sstevel@tonic-gate vers_min = vers_min_default; 19300Sstevel@tonic-gate } 19310Sstevel@tonic-gate 19320Sstevel@tonic-gate if (url == FALSE) { 19330Sstevel@tonic-gate path = malloc(strlen(fspath) + 2); 19340Sstevel@tonic-gate if (path == NULL) { 19355302Sth199096 if (loud == TRUE) 19360Sstevel@tonic-gate pr_err(gettext("no memory\n")); 19370Sstevel@tonic-gate return (RET_ERR); 19380Sstevel@tonic-gate } 19390Sstevel@tonic-gate 19400Sstevel@tonic-gate path[0] = (char)WNL_NATIVEPATH; 19410Sstevel@tonic-gate (void) strcpy(&path[1], fspath); 19420Sstevel@tonic-gate 19430Sstevel@tonic-gate } else { 19440Sstevel@tonic-gate path = fspath; 19450Sstevel@tonic-gate } 19460Sstevel@tonic-gate 19470Sstevel@tonic-gate for (nfsvers_to_use = vers_max; nfsvers_to_use >= vers_min; 19480Sstevel@tonic-gate nfsvers_to_use--) { 19490Sstevel@tonic-gate /* 19500Sstevel@tonic-gate * getaddr_nfs will also fill in the fh for us. 19510Sstevel@tonic-gate */ 19520Sstevel@tonic-gate r = getaddr_nfs(args, fshost, nconfp, 19535302Sth199096 TRUE, path, port, NULL, FALSE); 19540Sstevel@tonic-gate 19550Sstevel@tonic-gate if (r == RET_OK) { 19560Sstevel@tonic-gate /* 19570Sstevel@tonic-gate * Since we are using the public fh, and NLM is 19580Sstevel@tonic-gate * not firewall friendly, use local locking. 19590Sstevel@tonic-gate * Not the case for v4. 19600Sstevel@tonic-gate */ 19610Sstevel@tonic-gate *versp = nfsvers_to_use; 19620Sstevel@tonic-gate switch (nfsvers_to_use) { 19630Sstevel@tonic-gate case NFS_V4: 19640Sstevel@tonic-gate fstype = MNTTYPE_NFS4; 19650Sstevel@tonic-gate break; 19660Sstevel@tonic-gate case NFS_V3: 19670Sstevel@tonic-gate fstype = MNTTYPE_NFS3; 19680Sstevel@tonic-gate /* fall through to pick up llock option */ 19690Sstevel@tonic-gate default: 19700Sstevel@tonic-gate args->flags |= NFSMNT_LLOCK; 19710Sstevel@tonic-gate break; 19720Sstevel@tonic-gate } 19730Sstevel@tonic-gate if (fspath != path) 19740Sstevel@tonic-gate free(path); 19750Sstevel@tonic-gate 19760Sstevel@tonic-gate return (r); 19770Sstevel@tonic-gate } 19780Sstevel@tonic-gate } 19790Sstevel@tonic-gate 19805302Sth199096 if (fspath != path) 19810Sstevel@tonic-gate free(path); 19820Sstevel@tonic-gate 19830Sstevel@tonic-gate if (loud == TRUE) { 19840Sstevel@tonic-gate pr_err(gettext("Could not use public filehandle in request to" 19855302Sth199096 " server %s\n"), fshost); 19860Sstevel@tonic-gate } 19870Sstevel@tonic-gate 19880Sstevel@tonic-gate return (r); 19890Sstevel@tonic-gate } 19900Sstevel@tonic-gate 19910Sstevel@tonic-gate /* 19920Sstevel@tonic-gate * get fhandle of remote path from server's mountd 19930Sstevel@tonic-gate */ 19940Sstevel@tonic-gate static int 19950Sstevel@tonic-gate get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp, 19960Sstevel@tonic-gate bool_t loud_on_mnt_err, struct netconfig **nconfp, ushort_t port) 19970Sstevel@tonic-gate { 19980Sstevel@tonic-gate static struct fhstatus fhs; 19990Sstevel@tonic-gate static struct mountres3 mountres3; 20000Sstevel@tonic-gate static struct pathcnf p; 20010Sstevel@tonic-gate nfs_fh3 *fh3p; 20020Sstevel@tonic-gate struct timeval timeout = { 25, 0}; 20030Sstevel@tonic-gate CLIENT *cl; 20040Sstevel@tonic-gate enum clnt_stat rpc_stat; 20050Sstevel@tonic-gate rpcvers_t outvers = 0; 20060Sstevel@tonic-gate rpcvers_t vers_to_try; 20070Sstevel@tonic-gate rpcvers_t vers_min; 20080Sstevel@tonic-gate static int printed = 0; 20090Sstevel@tonic-gate int count, i, *auths; 20100Sstevel@tonic-gate char *msg; 20110Sstevel@tonic-gate 20120Sstevel@tonic-gate switch (nfsvers) { 20130Sstevel@tonic-gate case 2: /* version 2 specified try that only */ 20140Sstevel@tonic-gate vers_to_try = MOUNTVERS_POSIX; 20150Sstevel@tonic-gate vers_min = MOUNTVERS; 20160Sstevel@tonic-gate break; 20170Sstevel@tonic-gate case 3: /* version 3 specified try that only */ 20180Sstevel@tonic-gate vers_to_try = MOUNTVERS3; 20190Sstevel@tonic-gate vers_min = MOUNTVERS3; 20200Sstevel@tonic-gate break; 20210Sstevel@tonic-gate case 4: /* version 4 specified try that only */ 20220Sstevel@tonic-gate /* 20230Sstevel@tonic-gate * This assignment is in the wrong version sequence. 20240Sstevel@tonic-gate * The above are MOUNT program and this is NFS 20250Sstevel@tonic-gate * program. However, it happens to work out since the 20260Sstevel@tonic-gate * two don't collide for NFSv4. 20270Sstevel@tonic-gate */ 20280Sstevel@tonic-gate vers_to_try = NFS_V4; 20290Sstevel@tonic-gate vers_min = NFS_V4; 20300Sstevel@tonic-gate break; 20310Sstevel@tonic-gate default: /* no version specified, start with default */ 2032489Soa138391 /* 2033489Soa138391 * If the retry version is set, use that. This will 2034489Soa138391 * be set if the last mount attempt returned any other 2035489Soa138391 * besides an RPC error. 2036489Soa138391 */ 2037489Soa138391 if (nfsretry_vers) 2038489Soa138391 vers_to_try = nfsretry_vers; 2039489Soa138391 else { 2040489Soa138391 vers_to_try = vers_max_default; 2041489Soa138391 vers_min = vers_min_default; 2042489Soa138391 } 2043489Soa138391 20440Sstevel@tonic-gate break; 20450Sstevel@tonic-gate } 20460Sstevel@tonic-gate 20470Sstevel@tonic-gate /* 20480Sstevel@tonic-gate * In the case of version 4, just NULL proc the server since 20490Sstevel@tonic-gate * there is no MOUNT program. If this fails, then decrease 20500Sstevel@tonic-gate * vers_to_try and continue on with regular MOUNT program 20510Sstevel@tonic-gate * processing. 20520Sstevel@tonic-gate */ 20530Sstevel@tonic-gate if (vers_to_try == NFS_V4) { 20540Sstevel@tonic-gate int savevers = nfsvers_to_use; 20550Sstevel@tonic-gate err_ret_t error; 20560Sstevel@tonic-gate int retval; 20570Sstevel@tonic-gate SET_ERR_RET(&error, ERR_PROTO_NONE, 0); 20580Sstevel@tonic-gate 20590Sstevel@tonic-gate /* Let's hope for the best */ 20600Sstevel@tonic-gate nfsvers_to_use = NFS_V4; 20615302Sth199096 retval = getaddr_nfs(args, fshost, nconfp, FALSE, 20625302Sth199096 fspath, port, &error, vers_min == NFS_V4); 20630Sstevel@tonic-gate 20640Sstevel@tonic-gate if (retval == RET_OK) { 20650Sstevel@tonic-gate *versp = nfsvers_to_use = NFS_V4; 20660Sstevel@tonic-gate fstype = MNTTYPE_NFS4; 20670Sstevel@tonic-gate args->fh = strdup(fspath); 20680Sstevel@tonic-gate if (args->fh == NULL) { 20690Sstevel@tonic-gate pr_err(gettext("no memory\n")); 20700Sstevel@tonic-gate *versp = nfsvers_to_use = savevers; 20710Sstevel@tonic-gate return (RET_ERR); 20720Sstevel@tonic-gate } 20730Sstevel@tonic-gate return (RET_OK); 20740Sstevel@tonic-gate } 20750Sstevel@tonic-gate nfsvers_to_use = savevers; 20760Sstevel@tonic-gate 20770Sstevel@tonic-gate vers_to_try--; 20780Sstevel@tonic-gate /* If no more versions to try, let the user know. */ 20795302Sth199096 if (vers_to_try < vers_min) 20800Sstevel@tonic-gate return (retval); 20810Sstevel@tonic-gate 20820Sstevel@tonic-gate /* 20830Sstevel@tonic-gate * If we are here, there are more versions to try but 20840Sstevel@tonic-gate * there has been an error of some sort. If it is not 20850Sstevel@tonic-gate * an RPC error (e.g. host unknown), we just stop and 20860Sstevel@tonic-gate * return the error since the other versions would see 20870Sstevel@tonic-gate * the same error as well. 20880Sstevel@tonic-gate */ 20890Sstevel@tonic-gate if (retval == RET_ERR && error.error_type != ERR_RPCERROR) 20900Sstevel@tonic-gate return (retval); 20910Sstevel@tonic-gate } 20920Sstevel@tonic-gate 20930Sstevel@tonic-gate while ((cl = clnt_create_vers(fshost, MOUNTPROG, &outvers, 20945302Sth199096 vers_min, vers_to_try, "datagram_v")) == NULL) { 20950Sstevel@tonic-gate if (rpc_createerr.cf_stat == RPC_UNKNOWNHOST) { 20960Sstevel@tonic-gate pr_err(gettext("%s: %s\n"), fshost, 20970Sstevel@tonic-gate clnt_spcreateerror("")); 20980Sstevel@tonic-gate return (RET_ERR); 20990Sstevel@tonic-gate } 21000Sstevel@tonic-gate 21010Sstevel@tonic-gate /* 21020Sstevel@tonic-gate * We don't want to downgrade version on lost packets 21030Sstevel@tonic-gate */ 21040Sstevel@tonic-gate if ((rpc_createerr.cf_stat == RPC_TIMEDOUT) || 21055302Sth199096 (rpc_createerr.cf_stat == RPC_PMAPFAILURE)) { 21060Sstevel@tonic-gate pr_err(gettext("%s: %s\n"), fshost, 21070Sstevel@tonic-gate clnt_spcreateerror("")); 21080Sstevel@tonic-gate return (RET_RETRY); 21090Sstevel@tonic-gate } 21100Sstevel@tonic-gate 21110Sstevel@tonic-gate /* 21120Sstevel@tonic-gate * back off and try the previous version - patch to the 21130Sstevel@tonic-gate * problem of version numbers not being contigous and 21140Sstevel@tonic-gate * clnt_create_vers failing (SunOS4.1 clients & SGI servers) 21150Sstevel@tonic-gate * The problem happens with most non-Sun servers who 21160Sstevel@tonic-gate * don't support mountd protocol #2. So, in case the 21170Sstevel@tonic-gate * call fails, we re-try the call anyway. 21180Sstevel@tonic-gate */ 21190Sstevel@tonic-gate vers_to_try--; 21200Sstevel@tonic-gate if (vers_to_try < vers_min) { 21210Sstevel@tonic-gate if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH) { 21220Sstevel@tonic-gate if (nfsvers == 0) { 21230Sstevel@tonic-gate pr_err(gettext( 21240Sstevel@tonic-gate "%s:%s: no applicable versions of NFS supported\n"), 21250Sstevel@tonic-gate fshost, fspath); 21260Sstevel@tonic-gate } else { 21270Sstevel@tonic-gate pr_err(gettext( 21280Sstevel@tonic-gate "%s:%s: NFS Version %d not supported\n"), 21290Sstevel@tonic-gate fshost, fspath, nfsvers); 21300Sstevel@tonic-gate } 21310Sstevel@tonic-gate return (RET_ERR); 21320Sstevel@tonic-gate } 21330Sstevel@tonic-gate if (!printed) { 21340Sstevel@tonic-gate pr_err(gettext("%s: %s\n"), fshost, 21350Sstevel@tonic-gate clnt_spcreateerror("")); 21360Sstevel@tonic-gate printed = 1; 21370Sstevel@tonic-gate } 21380Sstevel@tonic-gate return (RET_RETRY); 21390Sstevel@tonic-gate } 21400Sstevel@tonic-gate } 21410Sstevel@tonic-gate if (posix && outvers < MOUNTVERS_POSIX) { 21420Sstevel@tonic-gate pr_err(gettext("%s: %s: no pathconf info\n"), 21430Sstevel@tonic-gate fshost, clnt_sperror(cl, "")); 21440Sstevel@tonic-gate clnt_destroy(cl); 21450Sstevel@tonic-gate return (RET_ERR); 21460Sstevel@tonic-gate } 21470Sstevel@tonic-gate 21480Sstevel@tonic-gate if (__clnt_bindresvport(cl) < 0) { 21490Sstevel@tonic-gate pr_err(gettext("Couldn't bind to reserved port\n")); 21500Sstevel@tonic-gate clnt_destroy(cl); 21510Sstevel@tonic-gate return (RET_RETRY); 21520Sstevel@tonic-gate } 21530Sstevel@tonic-gate 21540Sstevel@tonic-gate if ((cl->cl_auth = authsys_create_default()) == NULL) { 21550Sstevel@tonic-gate pr_err( 21560Sstevel@tonic-gate gettext("Couldn't create default authentication handle\n")); 21570Sstevel@tonic-gate clnt_destroy(cl); 21580Sstevel@tonic-gate return (RET_RETRY); 21590Sstevel@tonic-gate } 21600Sstevel@tonic-gate 21610Sstevel@tonic-gate switch (outvers) { 21620Sstevel@tonic-gate case MOUNTVERS: 21630Sstevel@tonic-gate case MOUNTVERS_POSIX: 21640Sstevel@tonic-gate *versp = nfsvers_to_use = NFS_VERSION; 21650Sstevel@tonic-gate rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath, 21665302Sth199096 (caddr_t)&fspath, xdr_fhstatus, (caddr_t)&fhs, timeout); 21670Sstevel@tonic-gate if (rpc_stat != RPC_SUCCESS) { 21680Sstevel@tonic-gate pr_err(gettext("%s:%s: server not responding %s\n"), 21690Sstevel@tonic-gate fshost, fspath, clnt_sperror(cl, "")); 21700Sstevel@tonic-gate clnt_destroy(cl); 21710Sstevel@tonic-gate return (RET_RETRY); 21720Sstevel@tonic-gate } 21730Sstevel@tonic-gate 21740Sstevel@tonic-gate if ((errno = fhs.fhs_status) != MNT_OK) { 21750Sstevel@tonic-gate if (loud_on_mnt_err) { 21765302Sth199096 if (errno == EACCES) { 21775302Sth199096 pr_err(gettext( 21785302Sth199096 "%s:%s: access denied\n"), 21795302Sth199096 fshost, fspath); 21805302Sth199096 } else { 21815302Sth199096 pr_err(gettext("%s:%s: %s\n"), fshost, 21825302Sth199096 fspath, strerror(errno)); 21835302Sth199096 } 21840Sstevel@tonic-gate } 21850Sstevel@tonic-gate clnt_destroy(cl); 21860Sstevel@tonic-gate return (RET_MNTERR); 21870Sstevel@tonic-gate } 21880Sstevel@tonic-gate args->fh = malloc(sizeof (fhs.fhstatus_u.fhs_fhandle)); 21890Sstevel@tonic-gate if (args->fh == NULL) { 21900Sstevel@tonic-gate pr_err(gettext("no memory\n")); 21910Sstevel@tonic-gate return (RET_ERR); 21920Sstevel@tonic-gate } 21930Sstevel@tonic-gate memcpy((caddr_t)args->fh, (caddr_t)&fhs.fhstatus_u.fhs_fhandle, 21945302Sth199096 sizeof (fhs.fhstatus_u.fhs_fhandle)); 21950Sstevel@tonic-gate if (!errno && posix) { 21960Sstevel@tonic-gate rpc_stat = clnt_call(cl, MOUNTPROC_PATHCONF, 21975302Sth199096 xdr_dirpath, (caddr_t)&fspath, xdr_ppathcnf, 21985302Sth199096 (caddr_t)&p, timeout); 21990Sstevel@tonic-gate if (rpc_stat != RPC_SUCCESS) { 22000Sstevel@tonic-gate pr_err(gettext( 22010Sstevel@tonic-gate "%s:%s: server not responding %s\n"), 22020Sstevel@tonic-gate fshost, fspath, clnt_sperror(cl, "")); 22030Sstevel@tonic-gate free(args->fh); 22040Sstevel@tonic-gate clnt_destroy(cl); 22050Sstevel@tonic-gate return (RET_RETRY); 22060Sstevel@tonic-gate } 22070Sstevel@tonic-gate if (_PC_ISSET(_PC_ERROR, p.pc_mask)) { 22080Sstevel@tonic-gate pr_err(gettext( 22090Sstevel@tonic-gate "%s:%s: no pathconf info\n"), 22100Sstevel@tonic-gate fshost, fspath); 22110Sstevel@tonic-gate free(args->fh); 22120Sstevel@tonic-gate clnt_destroy(cl); 22130Sstevel@tonic-gate return (RET_ERR); 22140Sstevel@tonic-gate } 22150Sstevel@tonic-gate args->flags |= NFSMNT_POSIX; 22160Sstevel@tonic-gate args->pathconf = malloc(sizeof (p)); 22170Sstevel@tonic-gate if (args->pathconf == NULL) { 22180Sstevel@tonic-gate pr_err(gettext("no memory\n")); 22190Sstevel@tonic-gate free(args->fh); 22200Sstevel@tonic-gate clnt_destroy(cl); 22210Sstevel@tonic-gate return (RET_ERR); 22220Sstevel@tonic-gate } 22230Sstevel@tonic-gate memcpy((caddr_t)args->pathconf, (caddr_t)&p, 22245302Sth199096 sizeof (p)); 22250Sstevel@tonic-gate } 22260Sstevel@tonic-gate break; 22270Sstevel@tonic-gate 22280Sstevel@tonic-gate case MOUNTVERS3: 22290Sstevel@tonic-gate *versp = nfsvers_to_use = NFS_V3; 22300Sstevel@tonic-gate rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath, 22315302Sth199096 (caddr_t)&fspath, xdr_mountres3, (caddr_t)&mountres3, 22325302Sth199096 timeout); 22330Sstevel@tonic-gate if (rpc_stat != RPC_SUCCESS) { 22340Sstevel@tonic-gate pr_err(gettext("%s:%s: server not responding %s\n"), 22350Sstevel@tonic-gate fshost, fspath, clnt_sperror(cl, "")); 22360Sstevel@tonic-gate clnt_destroy(cl); 22370Sstevel@tonic-gate return (RET_RETRY); 22380Sstevel@tonic-gate } 22390Sstevel@tonic-gate 22400Sstevel@tonic-gate /* 22410Sstevel@tonic-gate * Assume here that most of the MNT3ERR_* 22420Sstevel@tonic-gate * codes map into E* errors. 22430Sstevel@tonic-gate */ 22440Sstevel@tonic-gate if ((errno = mountres3.fhs_status) != MNT_OK) { 22455302Sth199096 if (loud_on_mnt_err) { 22465302Sth199096 switch (errno) { 22475302Sth199096 case MNT3ERR_NAMETOOLONG: 22485302Sth199096 msg = "path name is too long"; 22495302Sth199096 break; 22505302Sth199096 case MNT3ERR_NOTSUPP: 22515302Sth199096 msg = "operation not supported"; 22525302Sth199096 break; 22535302Sth199096 case MNT3ERR_SERVERFAULT: 22545302Sth199096 msg = "server fault"; 22555302Sth199096 break; 22565302Sth199096 default: 22575302Sth199096 msg = strerror(errno); 22585302Sth199096 break; 22595302Sth199096 } 22605302Sth199096 pr_err(gettext("%s:%s: %s\n"), fshost, 22615302Sth199096 fspath, msg); 22620Sstevel@tonic-gate } 22635302Sth199096 clnt_destroy(cl); 22645302Sth199096 return (RET_MNTERR); 22650Sstevel@tonic-gate } 22660Sstevel@tonic-gate 22670Sstevel@tonic-gate fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p)); 22680Sstevel@tonic-gate if (fh3p == NULL) { 22690Sstevel@tonic-gate pr_err(gettext("no memory\n")); 22700Sstevel@tonic-gate return (RET_ERR); 22710Sstevel@tonic-gate } 22720Sstevel@tonic-gate fh3p->fh3_length = 22735302Sth199096 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len; 22740Sstevel@tonic-gate (void) memcpy(fh3p->fh3_u.data, 22755302Sth199096 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val, 22765302Sth199096 fh3p->fh3_length); 22770Sstevel@tonic-gate args->fh = (caddr_t)fh3p; 22780Sstevel@tonic-gate fstype = MNTTYPE_NFS3; 22790Sstevel@tonic-gate 22800Sstevel@tonic-gate /* 22810Sstevel@tonic-gate * Check the security flavor to be used. 22820Sstevel@tonic-gate * 22830Sstevel@tonic-gate * If "secure" or "sec=flavor" is a mount 22840Sstevel@tonic-gate * option, check if the server supports the "flavor". 22850Sstevel@tonic-gate * If the server does not support the flavor, return 22860Sstevel@tonic-gate * error. 22870Sstevel@tonic-gate * 22880Sstevel@tonic-gate * If no mount option is given then use the first supported 22890Sstevel@tonic-gate * security flavor (by the client) in the auth list returned 22900Sstevel@tonic-gate * from the server. 22910Sstevel@tonic-gate * 22920Sstevel@tonic-gate */ 22930Sstevel@tonic-gate auths = 22945302Sth199096 mountres3.mountres3_u.mountinfo.auth_flavors 22955302Sth199096 .auth_flavors_val; 22960Sstevel@tonic-gate count = 22975302Sth199096 mountres3.mountres3_u.mountinfo.auth_flavors 22985302Sth199096 .auth_flavors_len; 22990Sstevel@tonic-gate 23000Sstevel@tonic-gate if (sec_opt) { 23010Sstevel@tonic-gate for (i = 0; i < count; i++) { 23020Sstevel@tonic-gate if (auths[i] == nfs_sec.sc_nfsnum) 23035302Sth199096 break; 23040Sstevel@tonic-gate } 23055302Sth199096 if (i >= count) 23060Sstevel@tonic-gate goto autherr; 23070Sstevel@tonic-gate } else { 23085302Sth199096 if (count < 0) 23095302Sth199096 break; 23105302Sth199096 23110Sstevel@tonic-gate for (i = 0; i < count; i++) { 23125302Sth199096 if (!nfs_getseconfig_bynumber(auths[i], 23135302Sth199096 &nfs_sec)) { 23145302Sth199096 sec_opt++; 23155302Sth199096 break; 23165302Sth199096 } 23170Sstevel@tonic-gate } 23185302Sth199096 23195302Sth199096 if (i >= count) 23205302Sth199096 goto autherr; 23210Sstevel@tonic-gate } 23220Sstevel@tonic-gate break; 23230Sstevel@tonic-gate default: 23240Sstevel@tonic-gate pr_err(gettext("%s:%s: Unknown MOUNT version %d\n"), 23250Sstevel@tonic-gate fshost, fspath, outvers); 23260Sstevel@tonic-gate clnt_destroy(cl); 23270Sstevel@tonic-gate return (RET_ERR); 23280Sstevel@tonic-gate } 23290Sstevel@tonic-gate 23300Sstevel@tonic-gate clnt_destroy(cl); 23310Sstevel@tonic-gate return (RET_OK); 23320Sstevel@tonic-gate 23330Sstevel@tonic-gate autherr: 23340Sstevel@tonic-gate pr_err(gettext( 23355302Sth199096 "security mode does not match the server exporting %s:%s\n"), 23365302Sth199096 fshost, fspath); 23370Sstevel@tonic-gate clnt_destroy(cl); 23380Sstevel@tonic-gate return (RET_ERR); 23390Sstevel@tonic-gate } 23400Sstevel@tonic-gate 23410Sstevel@tonic-gate /* 23420Sstevel@tonic-gate * Fill in the address for the server's NFS service and 23430Sstevel@tonic-gate * fill in a knetconfig structure for the transport that 23440Sstevel@tonic-gate * the service is available on. 23450Sstevel@tonic-gate */ 23460Sstevel@tonic-gate static int 23470Sstevel@tonic-gate getaddr_nfs(struct nfs_args *args, char *fshost, struct netconfig **nconfp, 23480Sstevel@tonic-gate bool_t get_pubfh, char *fspath, ushort_t port, err_ret_t *error, 23490Sstevel@tonic-gate bool_t print_rpcerror) 23500Sstevel@tonic-gate { 23510Sstevel@tonic-gate struct stat sb; 23520Sstevel@tonic-gate struct netconfig *nconf; 23530Sstevel@tonic-gate struct knetconfig *knconfp; 23540Sstevel@tonic-gate static int printed = 0; 23550Sstevel@tonic-gate struct t_info tinfo; 23560Sstevel@tonic-gate err_ret_t addr_error; 23570Sstevel@tonic-gate 23580Sstevel@tonic-gate SET_ERR_RET(error, ERR_PROTO_NONE, 0); 23590Sstevel@tonic-gate SET_ERR_RET(&addr_error, ERR_PROTO_NONE, 0); 23600Sstevel@tonic-gate 23610Sstevel@tonic-gate if (nfs_proto) { 23620Sstevel@tonic-gate /* 23630Sstevel@tonic-gate * If a proto is specified and its rdma try this. The kernel 23640Sstevel@tonic-gate * will later do the reachablity test and fail form there 23650Sstevel@tonic-gate * if rdma transport is not available to kernel rpc 23660Sstevel@tonic-gate */ 23670Sstevel@tonic-gate if (strcmp(nfs_proto, "rdma") == 0) { 23680Sstevel@tonic-gate args->addr = get_addr(fshost, NFS_PROGRAM, 23690Sstevel@tonic-gate nfsvers_to_use, nconfp, NULL, port, &tinfo, 23700Sstevel@tonic-gate &args->fh, get_pubfh, fspath, &addr_error); 23710Sstevel@tonic-gate 23720Sstevel@tonic-gate args->flags |= NFSMNT_DORDMA; 23730Sstevel@tonic-gate } else { 23740Sstevel@tonic-gate args->addr = get_addr(fshost, NFS_PROGRAM, 23750Sstevel@tonic-gate nfsvers_to_use, nconfp, nfs_proto, port, &tinfo, 23760Sstevel@tonic-gate &args->fh, get_pubfh, fspath, &addr_error); 23770Sstevel@tonic-gate } 23780Sstevel@tonic-gate } else { 23790Sstevel@tonic-gate args->addr = get_addr(fshost, NFS_PROGRAM, nfsvers_to_use, 23800Sstevel@tonic-gate nconfp, nfs_proto, port, &tinfo, &args->fh, get_pubfh, 23810Sstevel@tonic-gate fspath, &addr_error); 23820Sstevel@tonic-gate /* 23830Sstevel@tonic-gate * If no proto is specified set this flag. 23840Sstevel@tonic-gate * Kernel mount code will try to use RDMA if its on the 23850Sstevel@tonic-gate * system, otherwise it will keep on using the protocol 23860Sstevel@tonic-gate * selected here, through the above get_addr call. 23870Sstevel@tonic-gate */ 23880Sstevel@tonic-gate if (nfs_proto == NULL) 23890Sstevel@tonic-gate args->flags |= NFSMNT_TRYRDMA; 23900Sstevel@tonic-gate } 23910Sstevel@tonic-gate 23920Sstevel@tonic-gate if (args->addr == NULL) { 23930Sstevel@tonic-gate /* 23940Sstevel@tonic-gate * We could have failed because the server had no public 23950Sstevel@tonic-gate * file handle support. So don't print a message and don't 23960Sstevel@tonic-gate * retry. 23970Sstevel@tonic-gate */ 23980Sstevel@tonic-gate if (get_pubfh == TRUE) 23990Sstevel@tonic-gate return (RET_ERR); 24000Sstevel@tonic-gate 24010Sstevel@tonic-gate if (!printed) { 24020Sstevel@tonic-gate switch (addr_error.error_type) { 24030Sstevel@tonic-gate case 0: 2404489Soa138391 printed = 1; 24050Sstevel@tonic-gate break; 24060Sstevel@tonic-gate case ERR_RPCERROR: 24070Sstevel@tonic-gate if (!print_rpcerror) 24080Sstevel@tonic-gate /* no error print at this time */ 24090Sstevel@tonic-gate break; 24100Sstevel@tonic-gate pr_err(gettext("%s NFS service not" 24115302Sth199096 " available %s\n"), fshost, 24120Sstevel@tonic-gate clnt_sperrno(addr_error.error_value)); 2413489Soa138391 printed = 1; 24140Sstevel@tonic-gate break; 24150Sstevel@tonic-gate case ERR_NETPATH: 24160Sstevel@tonic-gate pr_err(gettext("%s: Error in NETPATH.\n"), 24175302Sth199096 fshost); 2418489Soa138391 printed = 1; 24190Sstevel@tonic-gate break; 24200Sstevel@tonic-gate case ERR_PROTO_INVALID: 24210Sstevel@tonic-gate pr_err(gettext("%s: NFS service does not" 24225302Sth199096 " recognize protocol: %s.\n"), fshost, 24235302Sth199096 nfs_proto); 2424489Soa138391 printed = 1; 24250Sstevel@tonic-gate break; 24260Sstevel@tonic-gate case ERR_PROTO_UNSUPP: 2427489Soa138391 if (nfsvers || nfsvers_to_use == NFS_VERSMIN) { 2428112Soa138391 /* 2429489Soa138391 * Don't set "printed" here. Since we 2430489Soa138391 * have to keep checking here till we 2431489Soa138391 * exhaust transport errors on all vers. 2432489Soa138391 * 2433489Soa138391 * Print this message if: 2434489Soa138391 * 1. After we have tried all versions 2435489Soa138391 * of NFS and none support the asked 2436489Soa138391 * transport. 2437489Soa138391 * 2438489Soa138391 * 2. If a version is specified and it 2439489Soa138391 * does'nt support the asked 2440489Soa138391 * transport. 2441489Soa138391 * 2442489Soa138391 * Otherwise we decrement the version 2443112Soa138391 * and retry below. 2444112Soa138391 */ 2445112Soa138391 pr_err(gettext("%s: NFS service does" 24465302Sth199096 " not support protocol: %s.\n"), 24475302Sth199096 fshost, nfs_proto); 2448112Soa138391 } 24490Sstevel@tonic-gate break; 24500Sstevel@tonic-gate case ERR_NOHOST: 245177Soa138391 pr_err("%s: %s\n", fshost, "Unknown host"); 2452489Soa138391 printed = 1; 24530Sstevel@tonic-gate break; 24540Sstevel@tonic-gate default: 24550Sstevel@tonic-gate /* case ERR_PROTO_NONE falls through */ 24560Sstevel@tonic-gate pr_err(gettext("%s: NFS service not responding" 24575302Sth199096 "\n"), fshost); 2458489Soa138391 printed = 1; 24590Sstevel@tonic-gate break; 24600Sstevel@tonic-gate } 24610Sstevel@tonic-gate } 24620Sstevel@tonic-gate SET_ERR_RET(error, 24635302Sth199096 addr_error.error_type, addr_error.error_value); 24640Sstevel@tonic-gate if (addr_error.error_type == ERR_PROTO_NONE) 24650Sstevel@tonic-gate return (RET_RETRY); 24660Sstevel@tonic-gate else if (addr_error.error_type == ERR_RPCERROR && 24675302Sth199096 !IS_UNRECOVERABLE_RPC(addr_error.error_value)) { 24680Sstevel@tonic-gate return (RET_RETRY); 2469112Soa138391 } else if (nfsvers == 0 && addr_error.error_type == 24705302Sth199096 ERR_PROTO_UNSUPP && nfsvers_to_use != NFS_VERSMIN) { 2471112Soa138391 /* 2472112Soa138391 * If no version is specified, and the error is due 2473489Soa138391 * to an unsupported transport, then decrement the 2474112Soa138391 * version and retry. 2475112Soa138391 */ 2476112Soa138391 return (RET_RETRY); 2477112Soa138391 } else 24780Sstevel@tonic-gate return (RET_ERR); 24790Sstevel@tonic-gate } 24800Sstevel@tonic-gate nconf = *nconfp; 24810Sstevel@tonic-gate 24820Sstevel@tonic-gate if (stat(nconf->nc_device, &sb) < 0) { 24830Sstevel@tonic-gate pr_err(gettext("getaddr_nfs: couldn't stat: %s: %s\n"), 24840Sstevel@tonic-gate nconf->nc_device, strerror(errno)); 24850Sstevel@tonic-gate return (RET_ERR); 24860Sstevel@tonic-gate } 24870Sstevel@tonic-gate 24880Sstevel@tonic-gate knconfp = (struct knetconfig *)malloc(sizeof (*knconfp)); 24890Sstevel@tonic-gate if (!knconfp) { 24900Sstevel@tonic-gate pr_err(gettext("no memory\n")); 24910Sstevel@tonic-gate return (RET_ERR); 24920Sstevel@tonic-gate } 24930Sstevel@tonic-gate knconfp->knc_semantics = nconf->nc_semantics; 24940Sstevel@tonic-gate knconfp->knc_protofmly = nconf->nc_protofmly; 24950Sstevel@tonic-gate knconfp->knc_proto = nconf->nc_proto; 24960Sstevel@tonic-gate knconfp->knc_rdev = sb.st_rdev; 24970Sstevel@tonic-gate 24980Sstevel@tonic-gate /* make sure we don't overload the transport */ 24990Sstevel@tonic-gate if (tinfo.tsdu > 0 && tinfo.tsdu < NFS_MAXDATA + NFS_RPC_HDR) { 25000Sstevel@tonic-gate args->flags |= (NFSMNT_RSIZE | NFSMNT_WSIZE); 25010Sstevel@tonic-gate if (args->rsize == 0 || args->rsize > tinfo.tsdu - NFS_RPC_HDR) 25020Sstevel@tonic-gate args->rsize = tinfo.tsdu - NFS_RPC_HDR; 25030Sstevel@tonic-gate if (args->wsize == 0 || args->wsize > tinfo.tsdu - NFS_RPC_HDR) 25040Sstevel@tonic-gate args->wsize = tinfo.tsdu - NFS_RPC_HDR; 25050Sstevel@tonic-gate } 25060Sstevel@tonic-gate 25070Sstevel@tonic-gate args->flags |= NFSMNT_KNCONF; 25080Sstevel@tonic-gate args->knconf = knconfp; 25090Sstevel@tonic-gate return (RET_OK); 25100Sstevel@tonic-gate } 25110Sstevel@tonic-gate 25120Sstevel@tonic-gate static int 25130Sstevel@tonic-gate retry(struct mnttab *mntp, int ro) 25140Sstevel@tonic-gate { 25150Sstevel@tonic-gate int delay = 5; 25160Sstevel@tonic-gate int count = retries; 25170Sstevel@tonic-gate int r; 25180Sstevel@tonic-gate 2519489Soa138391 /* 2520489Soa138391 * Please see comments on nfsretry_vers in the beginning of this file 2521489Soa138391 * and in main() routine. 2522489Soa138391 */ 2523489Soa138391 25240Sstevel@tonic-gate if (bg) { 25250Sstevel@tonic-gate if (fork() > 0) 25260Sstevel@tonic-gate return (RET_OK); 25270Sstevel@tonic-gate pr_err(gettext("backgrounding: %s\n"), mntp->mnt_mountp); 25280Sstevel@tonic-gate backgrounded = 1; 2529489Soa138391 } else { 2530489Soa138391 if (!nfsretry_vers) 2531489Soa138391 pr_err(gettext("retrying: %s\n"), mntp->mnt_mountp); 2532489Soa138391 } 25330Sstevel@tonic-gate 25340Sstevel@tonic-gate while (count--) { 2535489Soa138391 if ((r = mount_nfs(mntp, ro, NULL)) == RET_OK) { 25360Sstevel@tonic-gate pr_err(gettext("%s: mounted OK\n"), mntp->mnt_mountp); 25370Sstevel@tonic-gate return (RET_OK); 25380Sstevel@tonic-gate } 25390Sstevel@tonic-gate if (r != RET_RETRY) 25400Sstevel@tonic-gate break; 25410Sstevel@tonic-gate 25420Sstevel@tonic-gate if (count > 0) { 25435302Sth199096 (void) sleep(delay); 25445302Sth199096 delay *= 2; 25455302Sth199096 if (delay > 120) 25465302Sth199096 delay = 120; 25470Sstevel@tonic-gate } 25480Sstevel@tonic-gate } 2549489Soa138391 2550489Soa138391 if (!nfsretry_vers) 2551489Soa138391 pr_err(gettext("giving up on: %s\n"), mntp->mnt_mountp); 2552489Soa138391 25530Sstevel@tonic-gate return (RET_ERR); 25540Sstevel@tonic-gate } 25550Sstevel@tonic-gate 25560Sstevel@tonic-gate /* 25570Sstevel@tonic-gate * Read the /etc/default/nfs configuration file to determine if the 25580Sstevel@tonic-gate * client has been configured for a new min/max for the NFS version to 25590Sstevel@tonic-gate * use. 25600Sstevel@tonic-gate */ 25610Sstevel@tonic-gate static void 25620Sstevel@tonic-gate read_default(void) 25630Sstevel@tonic-gate { 25640Sstevel@tonic-gate char *defval; 25650Sstevel@tonic-gate int errno; 25660Sstevel@tonic-gate int tmp; 25670Sstevel@tonic-gate 25680Sstevel@tonic-gate /* Fail silently if error in opening the default nfs config file */ 25690Sstevel@tonic-gate if ((defopen(NFSADMIN)) == 0) { 25700Sstevel@tonic-gate if ((defval = defread("NFS_CLIENT_VERSMIN=")) != NULL) { 25710Sstevel@tonic-gate errno = 0; 25720Sstevel@tonic-gate tmp = strtol(defval, (char **)NULL, 10); 25730Sstevel@tonic-gate if (errno == 0) { 25740Sstevel@tonic-gate vers_min_default = tmp; 25750Sstevel@tonic-gate } 25760Sstevel@tonic-gate } 25770Sstevel@tonic-gate if ((defval = defread("NFS_CLIENT_VERSMAX=")) != NULL) { 25780Sstevel@tonic-gate errno = 0; 25790Sstevel@tonic-gate tmp = strtol(defval, (char **)NULL, 10); 25800Sstevel@tonic-gate if (errno == 0) { 25810Sstevel@tonic-gate vers_max_default = tmp; 25820Sstevel@tonic-gate } 25830Sstevel@tonic-gate } 25840Sstevel@tonic-gate /* close defaults file */ 25850Sstevel@tonic-gate defopen(NULL); 25860Sstevel@tonic-gate } 25870Sstevel@tonic-gate } 25880Sstevel@tonic-gate 25890Sstevel@tonic-gate static void 25900Sstevel@tonic-gate sigusr1(int s) 25910Sstevel@tonic-gate { 25920Sstevel@tonic-gate } 2593