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 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 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> 810Sstevel@tonic-gate #include "nfs_subr.h" 820Sstevel@tonic-gate #include "webnfs.h" 830Sstevel@tonic-gate #include <rpcsvc/nfs4_prot.h> 840Sstevel@tonic-gate 850Sstevel@tonic-gate #ifndef NFS_VERSMAX 860Sstevel@tonic-gate #define NFS_VERSMAX 4 870Sstevel@tonic-gate #endif 880Sstevel@tonic-gate #ifndef NFS_VERSMIN 890Sstevel@tonic-gate #define NFS_VERSMIN 2 900Sstevel@tonic-gate #endif 910Sstevel@tonic-gate 920Sstevel@tonic-gate #define RET_OK 0 930Sstevel@tonic-gate #define RET_RETRY 32 940Sstevel@tonic-gate #define RET_ERR 33 950Sstevel@tonic-gate #define RET_MNTERR 1000 960Sstevel@tonic-gate #define ERR_PROTO_NONE 0 970Sstevel@tonic-gate #define ERR_PROTO_INVALID 901 980Sstevel@tonic-gate #define ERR_PROTO_UNSUPP 902 990Sstevel@tonic-gate #define ERR_NETPATH 903 1000Sstevel@tonic-gate #define ERR_NOHOST 904 1010Sstevel@tonic-gate #define ERR_RPCERROR 905 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate typedef struct err_ret { 1040Sstevel@tonic-gate int error_type; 1050Sstevel@tonic-gate int error_value; 1060Sstevel@tonic-gate } err_ret_t; 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate #define SET_ERR_RET(errst, etype, eval) \ 1090Sstevel@tonic-gate if (errst) { \ 1100Sstevel@tonic-gate (errst)->error_type = etype; \ 1110Sstevel@tonic-gate (errst)->error_value = eval; \ 1120Sstevel@tonic-gate } 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate /* number of transports to try */ 1150Sstevel@tonic-gate #define MNT_PREF_LISTLEN 2 1160Sstevel@tonic-gate #define FIRST_TRY 1 1170Sstevel@tonic-gate #define SECOND_TRY 2 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate #define BIGRETRY 10000 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate /* maximum length of RPC header for NFS messages */ 1220Sstevel@tonic-gate #define NFS_RPC_HDR 432 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate #define NFS_ARGS_EXTB_secdata(args, secdata) \ 1250Sstevel@tonic-gate { (args)->nfs_args_ext = NFS_ARGS_EXTB, \ 1260Sstevel@tonic-gate (args)->nfs_ext_u.nfs_extB.secdata = secdata; } 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate extern int __clnt_bindresvport(); 1290Sstevel@tonic-gate extern char *nfs_get_qop_name(); 1300Sstevel@tonic-gate extern AUTH * nfs_create_ah(); 1310Sstevel@tonic-gate extern enum snego_stat nfs_sec_nego(); 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate static void usage(void); 1340Sstevel@tonic-gate static int retry(struct mnttab *, int); 1350Sstevel@tonic-gate static int set_args(int *, struct nfs_args *, char *, struct mnttab *); 1360Sstevel@tonic-gate static int get_fh_via_pub(struct nfs_args *, char *, char *, bool_t, bool_t, 1370Sstevel@tonic-gate int *, struct netconfig **, ushort_t); 1380Sstevel@tonic-gate static int get_fh(struct nfs_args *, char *, char *, int *, bool_t, 1390Sstevel@tonic-gate struct netconfig **, ushort_t); 1400Sstevel@tonic-gate static int make_secure(struct nfs_args *, char *, struct netconfig *, 1410Sstevel@tonic-gate bool_t, rpcvers_t); 1420Sstevel@tonic-gate static int mount_nfs(struct mnttab *, int); 1430Sstevel@tonic-gate static int getaddr_nfs(struct nfs_args *, char *, struct netconfig **, 1440Sstevel@tonic-gate bool_t, char *, ushort_t, err_ret_t *, bool_t); 1450Sstevel@tonic-gate static void pr_err(const char *fmt, ...); 1460Sstevel@tonic-gate static void usage(void); 1470Sstevel@tonic-gate static struct netbuf *get_addr(char *, rpcprog_t, rpcvers_t, 1480Sstevel@tonic-gate struct netconfig **, char *, ushort_t, struct t_info *, 1490Sstevel@tonic-gate caddr_t *, bool_t, char *, err_ret_t *); 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate static struct netbuf *get_the_addr(char *, rpcprog_t, rpcvers_t, 1520Sstevel@tonic-gate struct netconfig *, ushort_t, struct t_info *, caddr_t *, 1530Sstevel@tonic-gate bool_t, char *, err_ret_t *); 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate extern int self_check(char *); 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate static void read_default(void); 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate static char typename[64]; 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate static int bg = 0; 1620Sstevel@tonic-gate static int backgrounded = 0; 1630Sstevel@tonic-gate static int posix = 0; 1640Sstevel@tonic-gate static int retries = BIGRETRY; 1650Sstevel@tonic-gate static ushort_t nfs_port = 0; 1660Sstevel@tonic-gate static char *nfs_proto = NULL; 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate static int mflg = 0; 1690Sstevel@tonic-gate static int Oflg = 0; /* Overlay mounts */ 1700Sstevel@tonic-gate static int qflg = 0; /* quiet - don't print warnings on bad options */ 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate static char *fstype = MNTTYPE_NFS; 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate static seconfig_t nfs_sec; 1750Sstevel@tonic-gate static int sec_opt = 0; /* any security option ? */ 1760Sstevel@tonic-gate static bool_t snego_done; 1770Sstevel@tonic-gate static void sigusr1(int); 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate /* 1800Sstevel@tonic-gate * list of support services needed 1810Sstevel@tonic-gate */ 1820Sstevel@tonic-gate static char *service_list[] = { STATD, LOCKD, NULL }; 1830Sstevel@tonic-gate static char *service_list_v4[] = { STATD, LOCKD, NFS4CBD, NFSMAPID, NULL }; 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate /* 1860Sstevel@tonic-gate * These two variables control the NFS version number to be used. 1870Sstevel@tonic-gate * 1880Sstevel@tonic-gate * nfsvers defaults to 0 which means to use the highest number that 1890Sstevel@tonic-gate * both the client and the server support. It can also be set to 1900Sstevel@tonic-gate * a particular value, either 2, 3, or 4 to indicate the version 1910Sstevel@tonic-gate * number of choice. If the server (or the client) do not support 1920Sstevel@tonic-gate * the version indicated, then the mount attempt will be failed. 1930Sstevel@tonic-gate * 1940Sstevel@tonic-gate * nfsvers_to_use is the actual version number found to use. It 1950Sstevel@tonic-gate * is determined in get_fh by pinging the various versions of the 1960Sstevel@tonic-gate * NFS service on the server to see which responds positively. 1970Sstevel@tonic-gate */ 1980Sstevel@tonic-gate static rpcvers_t nfsvers = 0; 1990Sstevel@tonic-gate static rpcvers_t nfsvers_to_use = 0; 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate /* 2020Sstevel@tonic-gate * There are the defaults (range) for the client when determining 2030Sstevel@tonic-gate * which NFS version to use when probing the server (see above). 2040Sstevel@tonic-gate * These will only be used when the vers mount option is not used and 2050Sstevel@tonic-gate * these may be reset if /etc/default/nfs is configured to do so. 2060Sstevel@tonic-gate */ 2070Sstevel@tonic-gate static rpcvers_t vers_max_default = NFS_VERSMAX_DEFAULT; 2080Sstevel@tonic-gate static rpcvers_t vers_min_default = NFS_VERSMIN_DEFAULT; 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate /* 2110Sstevel@tonic-gate * This variable controls whether to try the public file handle. 2120Sstevel@tonic-gate */ 2130Sstevel@tonic-gate static bool_t public_opt; 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate main(int argc, char **argv) 2160Sstevel@tonic-gate { 2170Sstevel@tonic-gate struct mnttab mnt; 2180Sstevel@tonic-gate extern char *optarg; 2190Sstevel@tonic-gate extern int optind; 2200Sstevel@tonic-gate char optbuf[MAX_MNTOPT_STR]; 2210Sstevel@tonic-gate int ro = 0; 2220Sstevel@tonic-gate int r; 2230Sstevel@tonic-gate int c; 2240Sstevel@tonic-gate char *myname; 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 2270Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 2280Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 2290Sstevel@tonic-gate #endif 2300Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate myname = strrchr(argv[0], '/'); 2330Sstevel@tonic-gate myname = myname ? myname + 1 : argv[0]; 2340Sstevel@tonic-gate (void) snprintf(typename, sizeof (typename), "%s %s", 2350Sstevel@tonic-gate MNTTYPE_NFS, myname); 2360Sstevel@tonic-gate argv[0] = typename; 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate mnt.mnt_mntopts = optbuf; 2390Sstevel@tonic-gate (void) strcpy(optbuf, "rw"); 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate /* 2420Sstevel@tonic-gate * Set options 2430Sstevel@tonic-gate */ 2440Sstevel@tonic-gate while ((c = getopt(argc, argv, "ro:mOq")) != EOF) { 2450Sstevel@tonic-gate switch (c) { 2460Sstevel@tonic-gate case 'r': 2470Sstevel@tonic-gate ro++; 2480Sstevel@tonic-gate break; 2490Sstevel@tonic-gate case 'o': 2500Sstevel@tonic-gate if (strlen(optarg) >= MAX_MNTOPT_STR) { 2510Sstevel@tonic-gate pr_err(gettext("option string too long")); 2520Sstevel@tonic-gate return (RET_ERR); 2530Sstevel@tonic-gate } 2540Sstevel@tonic-gate (void) strcpy(mnt.mnt_mntopts, optarg); 2550Sstevel@tonic-gate #ifdef LATER /* XXX */ 2560Sstevel@tonic-gate if (strstr(optarg, MNTOPT_REMOUNT)) { 2570Sstevel@tonic-gate /* 2580Sstevel@tonic-gate * If remount is specified, only rw is allowed. 2590Sstevel@tonic-gate */ 2600Sstevel@tonic-gate if ((strcmp(optarg, MNTOPT_REMOUNT) != 0) && 2610Sstevel@tonic-gate (strcmp(optarg, "remount,rw") != 0) && 2620Sstevel@tonic-gate (strcmp(optarg, "rw,remount") != 0)) { 2630Sstevel@tonic-gate pr_err(gettext("Invalid options\n")); 2640Sstevel@tonic-gate exit(RET_ERR); 2650Sstevel@tonic-gate } 2660Sstevel@tonic-gate } 2670Sstevel@tonic-gate #endif /* LATER */ /* XXX */ 2680Sstevel@tonic-gate break; 2690Sstevel@tonic-gate case 'm': 2700Sstevel@tonic-gate mflg++; 2710Sstevel@tonic-gate break; 2720Sstevel@tonic-gate case 'O': 2730Sstevel@tonic-gate Oflg++; 2740Sstevel@tonic-gate break; 2750Sstevel@tonic-gate case 'q': 2760Sstevel@tonic-gate qflg++; 2770Sstevel@tonic-gate break; 2780Sstevel@tonic-gate default: 2790Sstevel@tonic-gate usage(); 2800Sstevel@tonic-gate exit(RET_ERR); 2810Sstevel@tonic-gate } 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate if (argc - optind != 2) { 2840Sstevel@tonic-gate usage(); 2850Sstevel@tonic-gate exit(RET_ERR); 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate mnt.mnt_special = argv[optind]; 2890Sstevel@tonic-gate mnt.mnt_mountp = argv[optind+1]; 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate if (!priv_ineffect(PRIV_SYS_MOUNT) || 2920Sstevel@tonic-gate !priv_ineffect(PRIV_NET_PRIVADDR)) { 2930Sstevel@tonic-gate pr_err(gettext("insufficient privileges\n")); 2940Sstevel@tonic-gate exit(RET_ERR); 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate /* 2980Sstevel@tonic-gate * Read the defaults file to see if the min/max versions have 2990Sstevel@tonic-gate * been set and therefore would override the encoded defaults. 3000Sstevel@tonic-gate * Then check to make sure that if they were set that the 3010Sstevel@tonic-gate * values are reasonable. 3020Sstevel@tonic-gate */ 3030Sstevel@tonic-gate read_default(); 3040Sstevel@tonic-gate if (vers_min_default > vers_max_default || 3050Sstevel@tonic-gate vers_min_default < NFS_VERSMIN || 3060Sstevel@tonic-gate vers_max_default > NFS_VERSMAX) { 3070Sstevel@tonic-gate pr_err("%s %s\n%s %s\n", 3080Sstevel@tonic-gate gettext("Incorrect configuration of client\'s"), 3090Sstevel@tonic-gate NFSADMIN, 3100Sstevel@tonic-gate gettext("NFS_CLIENT_VERSMIN or NFS_CLIENT_VERSMAX"), 3110Sstevel@tonic-gate gettext("is either out of range or overlaps.")); 3120Sstevel@tonic-gate } 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate r = mount_nfs(&mnt, ro); 3150Sstevel@tonic-gate if (r == RET_RETRY && retries) 3160Sstevel@tonic-gate r = retry(&mnt, ro); 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate /* 3190Sstevel@tonic-gate * exit(r); 3200Sstevel@tonic-gate */ 3210Sstevel@tonic-gate return (r); 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate static void 3250Sstevel@tonic-gate pr_err(const char *fmt, ...) 3260Sstevel@tonic-gate { 3270Sstevel@tonic-gate va_list ap; 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate va_start(ap, fmt); 3300Sstevel@tonic-gate if (backgrounded != 0) { 3310Sstevel@tonic-gate (void) vsyslog(LOG_ERR, fmt, ap); 3320Sstevel@tonic-gate } else { 3330Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", typename); 3340Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap); 3350Sstevel@tonic-gate (void) fflush(stderr); 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate va_end(ap); 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate static void 3410Sstevel@tonic-gate usage() 3420Sstevel@tonic-gate { 3430Sstevel@tonic-gate (void) fprintf(stderr, 3440Sstevel@tonic-gate gettext("Usage: nfs mount [-r] [-o opts] [server:]path dir\n")); 3450Sstevel@tonic-gate exit(RET_ERR); 3460Sstevel@tonic-gate } 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate static int 3490Sstevel@tonic-gate mount_nfs(struct mnttab *mntp, int ro) 3500Sstevel@tonic-gate { 3510Sstevel@tonic-gate struct nfs_args *args = NULL, *argp = NULL, *prev_argp = NULL; 3520Sstevel@tonic-gate struct netconfig *nconf = NULL; 3530Sstevel@tonic-gate struct replica *list = NULL; 3540Sstevel@tonic-gate int mntflags = 0; 3550Sstevel@tonic-gate int i, r, n; 3560Sstevel@tonic-gate int oldvers = 0, vers = 0; 3570Sstevel@tonic-gate int last_error = RET_OK; 3580Sstevel@tonic-gate int replicated = 0; 3590Sstevel@tonic-gate char *p; 3600Sstevel@tonic-gate bool_t url; 3610Sstevel@tonic-gate bool_t use_pubfh; 3620Sstevel@tonic-gate char *special = NULL; 3630Sstevel@tonic-gate char *oldpath = NULL; 3640Sstevel@tonic-gate char *newpath = NULL; 3650Sstevel@tonic-gate char *service; 3660Sstevel@tonic-gate pid_t pi; 3670Sstevel@tonic-gate struct flock f; 3680Sstevel@tonic-gate char *saveopts = NULL; 3690Sstevel@tonic-gate char **sl = NULL; 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate mntp->mnt_fstype = MNTTYPE_NFS; 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate if (ro) { 3740Sstevel@tonic-gate mntflags |= MS_RDONLY; 3750Sstevel@tonic-gate /* convert "rw"->"ro" */ 3760Sstevel@tonic-gate if (p = strstr(mntp->mnt_mntopts, "rw")) { 3770Sstevel@tonic-gate if (*(p+2) == ',' || *(p+2) == '\0') 3780Sstevel@tonic-gate *(p+1) = 'o'; 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate if (Oflg) 3830Sstevel@tonic-gate mntflags |= MS_OVERLAY; 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate list = parse_replica(mntp->mnt_special, &n); 3860Sstevel@tonic-gate if (list == NULL) { 3870Sstevel@tonic-gate if (n < 0) 3880Sstevel@tonic-gate pr_err(gettext("nfs file system; use [host:]path\n")); 3890Sstevel@tonic-gate else 3900Sstevel@tonic-gate pr_err(gettext("no memory\n")); 3910Sstevel@tonic-gate return (RET_ERR); 3920Sstevel@tonic-gate } 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate replicated = (n > 1); 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate /* 3970Sstevel@tonic-gate * There are some free() calls at the bottom of this loop, so be 3980Sstevel@tonic-gate * careful about adding continue statements. 3990Sstevel@tonic-gate */ 4000Sstevel@tonic-gate for (i = 0; i < n; i++) { 4010Sstevel@tonic-gate char *path; 4020Sstevel@tonic-gate char *host; 4030Sstevel@tonic-gate ushort_t port; 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate argp = (struct nfs_args *)malloc(sizeof (*argp)); 4060Sstevel@tonic-gate if (argp == NULL) { 4070Sstevel@tonic-gate pr_err(gettext("no memory\n")); 4080Sstevel@tonic-gate last_error = RET_ERR; 4090Sstevel@tonic-gate goto out; 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate memset(argp, 0, sizeof (*argp)); 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate memset(&nfs_sec, 0, sizeof (nfs_sec)); 4140Sstevel@tonic-gate sec_opt = 0; 4150Sstevel@tonic-gate use_pubfh = FALSE; 4160Sstevel@tonic-gate url = FALSE; 4170Sstevel@tonic-gate port = 0; 4180Sstevel@tonic-gate snego_done = FALSE; 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate /* 4210Sstevel@tonic-gate * Looking for resources of the form 4220Sstevel@tonic-gate * nfs://server_host[:port_number]/path_name 4230Sstevel@tonic-gate */ 4240Sstevel@tonic-gate if (strcmp(list[i].host, "nfs") == 0 && strncmp(list[i].path, 4250Sstevel@tonic-gate "//", 2) == 0) { 4260Sstevel@tonic-gate char *sport, *cb; 4270Sstevel@tonic-gate url = TRUE; 4280Sstevel@tonic-gate oldpath = strdup(list[i].path); 4290Sstevel@tonic-gate if (oldpath == NULL) { 4300Sstevel@tonic-gate pr_err(gettext("memory allocation failure\n")); 4310Sstevel@tonic-gate last_error = RET_ERR; 4320Sstevel@tonic-gate goto out; 4330Sstevel@tonic-gate } 4340Sstevel@tonic-gate host = list[i].path+2; 4350Sstevel@tonic-gate path = strchr(host, '/'); 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate if (path == NULL) { 4380Sstevel@tonic-gate pr_err(gettext( 4390Sstevel@tonic-gate "illegal nfs url syntax\n")); 4400Sstevel@tonic-gate last_error = RET_ERR; 4410Sstevel@tonic-gate goto out; 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate 4440Sstevel@tonic-gate *path = '\0'; 4450Sstevel@tonic-gate if (*host == '[') { 4460Sstevel@tonic-gate cb = strchr(host, ']'); 4470Sstevel@tonic-gate if (cb == NULL) { 4480Sstevel@tonic-gate pr_err(gettext( 4490Sstevel@tonic-gate "illegal nfs url syntax\n")); 4500Sstevel@tonic-gate last_error = RET_ERR; 4510Sstevel@tonic-gate goto out; 4520Sstevel@tonic-gate } else { 4530Sstevel@tonic-gate *cb = '\0'; 4540Sstevel@tonic-gate host++; 4550Sstevel@tonic-gate cb++; 4560Sstevel@tonic-gate if (*cb == ':') 4570Sstevel@tonic-gate port = htons((ushort_t) 4580Sstevel@tonic-gate atoi(cb+1)); 4590Sstevel@tonic-gate } 4600Sstevel@tonic-gate } else { 4610Sstevel@tonic-gate sport = strchr(host, ':'); 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate if (sport != NULL && sport < path) { 4640Sstevel@tonic-gate *sport = '\0'; 4650Sstevel@tonic-gate port = htons((ushort_t)atoi(sport+1)); 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate } 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate path++; 4700Sstevel@tonic-gate if (*path == '\0') 4710Sstevel@tonic-gate path = "."; 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate } else { 4740Sstevel@tonic-gate host = list[i].host; 4750Sstevel@tonic-gate path = list[i].path; 4760Sstevel@tonic-gate } 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate if (r = set_args(&mntflags, argp, host, mntp)) { 4790Sstevel@tonic-gate last_error = r; 4800Sstevel@tonic-gate goto out; 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate if (public_opt == TRUE) 4840Sstevel@tonic-gate use_pubfh = TRUE; 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate if (port == 0) { 4870Sstevel@tonic-gate port = nfs_port; 4880Sstevel@tonic-gate } else if (nfs_port != 0 && nfs_port != port) { 4890Sstevel@tonic-gate pr_err(gettext( 4900Sstevel@tonic-gate "port (%u) in nfs URL not the same" 4910Sstevel@tonic-gate " as port (%u) in port option\n"), 4920Sstevel@tonic-gate (unsigned int)ntohs(port), 4930Sstevel@tonic-gate (unsigned int)ntohs(nfs_port)); 4940Sstevel@tonic-gate last_error = RET_ERR; 4950Sstevel@tonic-gate goto out; 4960Sstevel@tonic-gate } 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate if (replicated && !(mntflags & MS_RDONLY)) { 5000Sstevel@tonic-gate pr_err(gettext( 5010Sstevel@tonic-gate "replicated mounts must be read-only\n")); 5020Sstevel@tonic-gate last_error = RET_ERR; 5030Sstevel@tonic-gate goto out; 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate if (replicated && (argp->flags & NFSMNT_SOFT)) { 5070Sstevel@tonic-gate pr_err(gettext( 5080Sstevel@tonic-gate "replicated mounts must not be soft\n")); 5090Sstevel@tonic-gate last_error = RET_ERR; 5100Sstevel@tonic-gate goto out; 5110Sstevel@tonic-gate } 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate oldvers = vers; 5140Sstevel@tonic-gate nconf = NULL; 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate r = RET_ERR; 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate /* 5190Sstevel@tonic-gate * If -o public was specified, and/or a URL was specified, 5200Sstevel@tonic-gate * then try the public file handle method. 5210Sstevel@tonic-gate */ 5220Sstevel@tonic-gate if ((use_pubfh == TRUE) || (url == TRUE)) { 5230Sstevel@tonic-gate r = get_fh_via_pub(argp, host, path, url, use_pubfh, 5240Sstevel@tonic-gate &vers, &nconf, port); 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate if (r != RET_OK) { 5270Sstevel@tonic-gate /* 5280Sstevel@tonic-gate * If -o public was specified, then return the 5290Sstevel@tonic-gate * error now. 5300Sstevel@tonic-gate */ 5310Sstevel@tonic-gate if (use_pubfh == TRUE) { 5320Sstevel@tonic-gate last_error = r; 5330Sstevel@tonic-gate goto out; 5340Sstevel@tonic-gate } 5350Sstevel@tonic-gate } else 5360Sstevel@tonic-gate use_pubfh = TRUE; 5370Sstevel@tonic-gate argp->flags |= NFSMNT_PUBLIC; 5380Sstevel@tonic-gate } 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate if ((r != RET_OK) || (vers == NFS_V4)) { 5410Sstevel@tonic-gate bool_t loud_on_mnt_err; 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate /* 5440Sstevel@tonic-gate * This can happen if -o public is not specified, 5450Sstevel@tonic-gate * special is a URL, and server doesn't support 5460Sstevel@tonic-gate * public file handle. 5470Sstevel@tonic-gate */ 5480Sstevel@tonic-gate if (url) { 5490Sstevel@tonic-gate URLparse(path); 5500Sstevel@tonic-gate } 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate /* 5530Sstevel@tonic-gate * If the path portion of the URL didn't have 5540Sstevel@tonic-gate * a leading / then there is good possibility 5550Sstevel@tonic-gate * that a mount without a leading slash will 5560Sstevel@tonic-gate * fail. 5570Sstevel@tonic-gate */ 5580Sstevel@tonic-gate if (url == TRUE && *path != '/') 5590Sstevel@tonic-gate loud_on_mnt_err = FALSE; 5600Sstevel@tonic-gate else 5610Sstevel@tonic-gate loud_on_mnt_err = TRUE; 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate r = get_fh(argp, host, path, &vers, 5640Sstevel@tonic-gate loud_on_mnt_err, &nconf, port); 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate if (r != RET_OK) { 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate /* 5690Sstevel@tonic-gate * If there was no leading / and the path was 5700Sstevel@tonic-gate * derived from a URL, then try again 5710Sstevel@tonic-gate * with a leading /. 5720Sstevel@tonic-gate */ 5730Sstevel@tonic-gate if ((r == RET_MNTERR) && 5740Sstevel@tonic-gate (loud_on_mnt_err == FALSE)) { 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate newpath = malloc(strlen(path)+2); 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate if (newpath == NULL) { 5790Sstevel@tonic-gate pr_err(gettext("memory " 5800Sstevel@tonic-gate "allocation failure\n")); 5810Sstevel@tonic-gate last_error = RET_ERR; 5820Sstevel@tonic-gate goto out; 5830Sstevel@tonic-gate } 5840Sstevel@tonic-gate 5850Sstevel@tonic-gate strcpy(newpath, "/"); 5860Sstevel@tonic-gate strcat(newpath, path); 5870Sstevel@tonic-gate 5880Sstevel@tonic-gate r = get_fh(argp, host, newpath, &vers, 5890Sstevel@tonic-gate TRUE, &nconf, port); 5900Sstevel@tonic-gate 5910Sstevel@tonic-gate if (r == RET_OK) 5920Sstevel@tonic-gate path = newpath; 5930Sstevel@tonic-gate } 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate /* 5960Sstevel@tonic-gate * map exit code back to RET_ERR. 5970Sstevel@tonic-gate */ 5980Sstevel@tonic-gate if (r == RET_MNTERR) 5990Sstevel@tonic-gate r = RET_ERR; 6000Sstevel@tonic-gate 6010Sstevel@tonic-gate if (r != RET_OK) { 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate if (replicated) { 6040Sstevel@tonic-gate if (argp->fh) 6050Sstevel@tonic-gate free(argp->fh); 6060Sstevel@tonic-gate if (argp->pathconf) 6070Sstevel@tonic-gate free(argp->pathconf); 6080Sstevel@tonic-gate free(argp); 6090Sstevel@tonic-gate goto cont; 6100Sstevel@tonic-gate } 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate last_error = r; 6130Sstevel@tonic-gate goto out; 6140Sstevel@tonic-gate } 6150Sstevel@tonic-gate } 6160Sstevel@tonic-gate } 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate if (oldvers && vers != oldvers) { 6190Sstevel@tonic-gate pr_err( 6200Sstevel@tonic-gate gettext("replicas must have the same version\n")); 6210Sstevel@tonic-gate last_error = RET_ERR; 6220Sstevel@tonic-gate goto out; 6230Sstevel@tonic-gate } 6240Sstevel@tonic-gate 6250Sstevel@tonic-gate /* 6260Sstevel@tonic-gate * decide whether to use remote host's 6270Sstevel@tonic-gate * lockd or do local locking 6280Sstevel@tonic-gate */ 6290Sstevel@tonic-gate if (!(argp->flags & NFSMNT_LLOCK) && vers == NFS_VERSION && 6300Sstevel@tonic-gate remote_lock(host, argp->fh)) { 6310Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6320Sstevel@tonic-gate "WARNING: No network locking on %s:%s:"), 6330Sstevel@tonic-gate host, path); 6340Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6350Sstevel@tonic-gate " contact admin to install server change\n")); 6360Sstevel@tonic-gate argp->flags |= NFSMNT_LLOCK; 6370Sstevel@tonic-gate } 6380Sstevel@tonic-gate 6390Sstevel@tonic-gate if (self_check(host)) 6400Sstevel@tonic-gate argp->flags |= NFSMNT_LOOPBACK; 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate if (use_pubfh == FALSE) { 6430Sstevel@tonic-gate /* 6440Sstevel@tonic-gate * Call to get_fh() above may have obtained the 6450Sstevel@tonic-gate * netconfig info and NULL proc'd the server. 6460Sstevel@tonic-gate * This would be the case with v4 6470Sstevel@tonic-gate */ 6480Sstevel@tonic-gate if (!(argp->flags & NFSMNT_KNCONF)) { 6490Sstevel@tonic-gate nconf = NULL; 6500Sstevel@tonic-gate if (r = getaddr_nfs(argp, host, &nconf, 6510Sstevel@tonic-gate FALSE, path, port, NULL, TRUE)) { 6520Sstevel@tonic-gate last_error = r; 6530Sstevel@tonic-gate goto out; 6540Sstevel@tonic-gate } 6550Sstevel@tonic-gate } 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate if (make_secure(argp, host, nconf, use_pubfh, vers) < 0) { 6590Sstevel@tonic-gate last_error = RET_ERR; 6600Sstevel@tonic-gate goto out; 6610Sstevel@tonic-gate } 6620Sstevel@tonic-gate 6630Sstevel@tonic-gate if ((url == TRUE) && (use_pubfh == FALSE)) { 6640Sstevel@tonic-gate /* 6650Sstevel@tonic-gate * Convert the special from 6660Sstevel@tonic-gate * nfs://host/path 6670Sstevel@tonic-gate * to 6680Sstevel@tonic-gate * host:path 6690Sstevel@tonic-gate */ 6700Sstevel@tonic-gate if (convert_special(&special, host, oldpath, path, 6710Sstevel@tonic-gate mntp->mnt_special) == -1) { 6720Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6730Sstevel@tonic-gate "could not convert URL nfs:%s to %s:%s\n"), 6740Sstevel@tonic-gate oldpath, host, path); 6750Sstevel@tonic-gate last_error = RET_ERR; 6760Sstevel@tonic-gate goto out; 6770Sstevel@tonic-gate } else { 6780Sstevel@tonic-gate mntp->mnt_special = special; 6790Sstevel@tonic-gate } 6800Sstevel@tonic-gate } 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate if (prev_argp == NULL) 6830Sstevel@tonic-gate args = argp; 6840Sstevel@tonic-gate else 6850Sstevel@tonic-gate prev_argp->nfs_ext_u.nfs_extB.next = argp; 6860Sstevel@tonic-gate prev_argp = argp; 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate cont: 6890Sstevel@tonic-gate if (oldpath != NULL) { 6900Sstevel@tonic-gate free(oldpath); 6910Sstevel@tonic-gate oldpath = NULL; 6920Sstevel@tonic-gate } 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate if (newpath != NULL) { 6950Sstevel@tonic-gate free(newpath); 6960Sstevel@tonic-gate newpath = NULL; 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate argp = NULL; 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate if (args == NULL) { 7030Sstevel@tonic-gate last_error = RET_RETRY; 7040Sstevel@tonic-gate goto out; 7050Sstevel@tonic-gate } 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate /* Determine which services are appropriate for the NFS version */ 7080Sstevel@tonic-gate if (strcmp(fstype, MNTTYPE_NFS4) == 0) 7090Sstevel@tonic-gate sl = service_list_v4; 7100Sstevel@tonic-gate else 7110Sstevel@tonic-gate sl = service_list; 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate /* 7140Sstevel@tonic-gate * enable services as needed. 7150Sstevel@tonic-gate */ 7160Sstevel@tonic-gate _check_services(sl); 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate mntflags |= MS_DATA | MS_OPTIONSTR; 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate if (mflg) 7210Sstevel@tonic-gate mntflags |= MS_NOMNTTAB; 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate if (!qflg) 7240Sstevel@tonic-gate saveopts = strdup(mntp->mnt_mntopts); 7250Sstevel@tonic-gate 7260Sstevel@tonic-gate if (mount(mntp->mnt_special, mntp->mnt_mountp, mntflags, fstype, args, 7270Sstevel@tonic-gate sizeof (*args), mntp->mnt_mntopts, MAX_MNTOPT_STR) < 0) { 7280Sstevel@tonic-gate if (errno != ENOENT) { 7290Sstevel@tonic-gate pr_err(gettext("mount: %s: %s\n"), 7300Sstevel@tonic-gate mntp->mnt_mountp, strerror(errno)); 7310Sstevel@tonic-gate } else { 7320Sstevel@tonic-gate struct stat sb; 7330Sstevel@tonic-gate if (stat(mntp->mnt_mountp, &sb) < 0 && errno == ENOENT) 7340Sstevel@tonic-gate pr_err(gettext("mount: %s: %s\n"), 7350Sstevel@tonic-gate mntp->mnt_mountp, strerror(ENOENT)); 7360Sstevel@tonic-gate else 7370Sstevel@tonic-gate pr_err("%s: %s\n", mntp->mnt_special, 7380Sstevel@tonic-gate strerror(ENOENT)); 7390Sstevel@tonic-gate } 7400Sstevel@tonic-gate 7410Sstevel@tonic-gate last_error = RET_ERR; 7420Sstevel@tonic-gate goto out; 7430Sstevel@tonic-gate } 7440Sstevel@tonic-gate 7450Sstevel@tonic-gate if (!qflg && saveopts != NULL) { 7460Sstevel@tonic-gate cmp_requested_to_actual_options(saveopts, mntp->mnt_mntopts, 7470Sstevel@tonic-gate mntp->mnt_special, mntp->mnt_mountp); 7480Sstevel@tonic-gate } 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate out: 7510Sstevel@tonic-gate if (saveopts != NULL) 7520Sstevel@tonic-gate free(saveopts); 7530Sstevel@tonic-gate if (special != NULL) 7540Sstevel@tonic-gate free(special); 7550Sstevel@tonic-gate if (oldpath != NULL) 7560Sstevel@tonic-gate free(oldpath); 7570Sstevel@tonic-gate if (newpath != NULL) 7580Sstevel@tonic-gate free(newpath); 7590Sstevel@tonic-gate 7600Sstevel@tonic-gate free_replica(list, n); 7610Sstevel@tonic-gate 7620Sstevel@tonic-gate if (argp != NULL) { 7630Sstevel@tonic-gate /* 7640Sstevel@tonic-gate * If we had a new entry which was not added to the 7650Sstevel@tonic-gate * list yet, then add it now that it can be freed. 7660Sstevel@tonic-gate */ 7670Sstevel@tonic-gate if (prev_argp == NULL) 7680Sstevel@tonic-gate args = argp; 7690Sstevel@tonic-gate else 7700Sstevel@tonic-gate prev_argp->nfs_ext_u.nfs_extB.next = argp; 7710Sstevel@tonic-gate } 7720Sstevel@tonic-gate argp = args; 7730Sstevel@tonic-gate while (argp != NULL) { 7740Sstevel@tonic-gate if (argp->fh) 7750Sstevel@tonic-gate free(argp->fh); 7760Sstevel@tonic-gate if (argp->pathconf) 7770Sstevel@tonic-gate free(argp->pathconf); 7780Sstevel@tonic-gate if (argp->knconf) 7790Sstevel@tonic-gate free(argp->knconf); 7800Sstevel@tonic-gate if (argp->addr) { 7810Sstevel@tonic-gate free(argp->addr->buf); 7820Sstevel@tonic-gate free(argp->addr); 7830Sstevel@tonic-gate } 7840Sstevel@tonic-gate nfs_free_secdata(argp->nfs_ext_u.nfs_extB.secdata); 7850Sstevel@tonic-gate if (argp->syncaddr) { 7860Sstevel@tonic-gate free(argp->syncaddr->buf); 7870Sstevel@tonic-gate free(argp->syncaddr); 7880Sstevel@tonic-gate } 7890Sstevel@tonic-gate if (argp->netname) 7900Sstevel@tonic-gate free(argp->netname); 7910Sstevel@tonic-gate prev_argp = argp; 7920Sstevel@tonic-gate argp = argp->nfs_ext_u.nfs_extB.next; 7930Sstevel@tonic-gate free(prev_argp); 7940Sstevel@tonic-gate } 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate return (last_error); 7970Sstevel@tonic-gate } 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate /* 8000Sstevel@tonic-gate * These options are duplicated in uts/common/fs/nfs/nfs_dlinet.c 8010Sstevel@tonic-gate * Changes must be made to both lists. 8020Sstevel@tonic-gate */ 8030Sstevel@tonic-gate static char *optlist[] = { 8040Sstevel@tonic-gate #define OPT_RO 0 8050Sstevel@tonic-gate MNTOPT_RO, 8060Sstevel@tonic-gate #define OPT_RW 1 8070Sstevel@tonic-gate MNTOPT_RW, 8080Sstevel@tonic-gate #define OPT_QUOTA 2 8090Sstevel@tonic-gate MNTOPT_QUOTA, 8100Sstevel@tonic-gate #define OPT_NOQUOTA 3 8110Sstevel@tonic-gate MNTOPT_NOQUOTA, 8120Sstevel@tonic-gate #define OPT_SOFT 4 8130Sstevel@tonic-gate MNTOPT_SOFT, 8140Sstevel@tonic-gate #define OPT_HARD 5 8150Sstevel@tonic-gate MNTOPT_HARD, 8160Sstevel@tonic-gate #define OPT_SUID 6 8170Sstevel@tonic-gate MNTOPT_SUID, 8180Sstevel@tonic-gate #define OPT_NOSUID 7 8190Sstevel@tonic-gate MNTOPT_NOSUID, 8200Sstevel@tonic-gate #define OPT_GRPID 8 8210Sstevel@tonic-gate MNTOPT_GRPID, 8220Sstevel@tonic-gate #define OPT_REMOUNT 9 8230Sstevel@tonic-gate MNTOPT_REMOUNT, 8240Sstevel@tonic-gate #define OPT_NOSUB 10 8250Sstevel@tonic-gate MNTOPT_NOSUB, 8260Sstevel@tonic-gate #define OPT_INTR 11 8270Sstevel@tonic-gate MNTOPT_INTR, 8280Sstevel@tonic-gate #define OPT_NOINTR 12 8290Sstevel@tonic-gate MNTOPT_NOINTR, 8300Sstevel@tonic-gate #define OPT_PORT 13 8310Sstevel@tonic-gate MNTOPT_PORT, 8320Sstevel@tonic-gate #define OPT_SECURE 14 8330Sstevel@tonic-gate MNTOPT_SECURE, 8340Sstevel@tonic-gate #define OPT_RSIZE 15 8350Sstevel@tonic-gate MNTOPT_RSIZE, 8360Sstevel@tonic-gate #define OPT_WSIZE 16 8370Sstevel@tonic-gate MNTOPT_WSIZE, 8380Sstevel@tonic-gate #define OPT_TIMEO 17 8390Sstevel@tonic-gate MNTOPT_TIMEO, 8400Sstevel@tonic-gate #define OPT_RETRANS 18 8410Sstevel@tonic-gate MNTOPT_RETRANS, 8420Sstevel@tonic-gate #define OPT_ACTIMEO 19 8430Sstevel@tonic-gate MNTOPT_ACTIMEO, 8440Sstevel@tonic-gate #define OPT_ACREGMIN 20 8450Sstevel@tonic-gate MNTOPT_ACREGMIN, 8460Sstevel@tonic-gate #define OPT_ACREGMAX 21 8470Sstevel@tonic-gate MNTOPT_ACREGMAX, 8480Sstevel@tonic-gate #define OPT_ACDIRMIN 22 8490Sstevel@tonic-gate MNTOPT_ACDIRMIN, 8500Sstevel@tonic-gate #define OPT_ACDIRMAX 23 8510Sstevel@tonic-gate MNTOPT_ACDIRMAX, 8520Sstevel@tonic-gate #define OPT_BG 24 8530Sstevel@tonic-gate MNTOPT_BG, 8540Sstevel@tonic-gate #define OPT_FG 25 8550Sstevel@tonic-gate MNTOPT_FG, 8560Sstevel@tonic-gate #define OPT_RETRY 26 8570Sstevel@tonic-gate MNTOPT_RETRY, 8580Sstevel@tonic-gate #define OPT_NOAC 27 8590Sstevel@tonic-gate MNTOPT_NOAC, 8600Sstevel@tonic-gate #define OPT_NOCTO 28 8610Sstevel@tonic-gate MNTOPT_NOCTO, 8620Sstevel@tonic-gate #define OPT_LLOCK 29 8630Sstevel@tonic-gate MNTOPT_LLOCK, 8640Sstevel@tonic-gate #define OPT_POSIX 30 8650Sstevel@tonic-gate MNTOPT_POSIX, 8660Sstevel@tonic-gate #define OPT_VERS 31 8670Sstevel@tonic-gate MNTOPT_VERS, 8680Sstevel@tonic-gate #define OPT_PROTO 32 8690Sstevel@tonic-gate MNTOPT_PROTO, 8700Sstevel@tonic-gate #define OPT_SEMISOFT 33 8710Sstevel@tonic-gate MNTOPT_SEMISOFT, 8720Sstevel@tonic-gate #define OPT_NOPRINT 34 8730Sstevel@tonic-gate MNTOPT_NOPRINT, 8740Sstevel@tonic-gate #define OPT_SEC 35 8750Sstevel@tonic-gate MNTOPT_SEC, 8760Sstevel@tonic-gate #define OPT_LARGEFILES 36 8770Sstevel@tonic-gate MNTOPT_LARGEFILES, 8780Sstevel@tonic-gate #define OPT_NOLARGEFILES 37 8790Sstevel@tonic-gate MNTOPT_NOLARGEFILES, 8800Sstevel@tonic-gate #define OPT_PUBLIC 38 8810Sstevel@tonic-gate MNTOPT_PUBLIC, 8820Sstevel@tonic-gate #define OPT_DIRECTIO 39 8830Sstevel@tonic-gate MNTOPT_FORCEDIRECTIO, 8840Sstevel@tonic-gate #define OPT_NODIRECTIO 40 8850Sstevel@tonic-gate MNTOPT_NOFORCEDIRECTIO, 8860Sstevel@tonic-gate #define OPT_XATTR 41 8870Sstevel@tonic-gate MNTOPT_XATTR, 8880Sstevel@tonic-gate #define OPT_NOXATTR 42 8890Sstevel@tonic-gate MNTOPT_NOXATTR, 8900Sstevel@tonic-gate #define OPT_DEVICES 43 8910Sstevel@tonic-gate MNTOPT_DEVICES, 8920Sstevel@tonic-gate #define OPT_NODEVICES 44 8930Sstevel@tonic-gate MNTOPT_NODEVICES, 8940Sstevel@tonic-gate #define OPT_SETUID 45 8950Sstevel@tonic-gate MNTOPT_SETUID, 8960Sstevel@tonic-gate #define OPT_NOSETUID 46 8970Sstevel@tonic-gate MNTOPT_NOSETUID, 8980Sstevel@tonic-gate #define OPT_EXEC 47 8990Sstevel@tonic-gate MNTOPT_EXEC, 9000Sstevel@tonic-gate #define OPT_NOEXEC 48 9010Sstevel@tonic-gate MNTOPT_NOEXEC, 9020Sstevel@tonic-gate NULL 9030Sstevel@tonic-gate }; 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate #define bad(val) (val == NULL || !isdigit(*val)) 9060Sstevel@tonic-gate 9070Sstevel@tonic-gate static int 9080Sstevel@tonic-gate set_args(int *mntflags, struct nfs_args *args, char *fshost, struct mnttab *mnt) 9090Sstevel@tonic-gate { 9100Sstevel@tonic-gate char *saveopt, *optstr, *opts, *newopts, *val; 9110Sstevel@tonic-gate int largefiles = 0; 9120Sstevel@tonic-gate int invalid = 0; 9130Sstevel@tonic-gate int attrpref = 0; 9140Sstevel@tonic-gate int optlen; 9150Sstevel@tonic-gate 9160Sstevel@tonic-gate args->flags = NFSMNT_INT; /* default is "intr" */ 9170Sstevel@tonic-gate args->flags |= NFSMNT_HOSTNAME; 9180Sstevel@tonic-gate args->flags |= NFSMNT_NEWARGS; /* using extented nfs_args structure */ 9190Sstevel@tonic-gate args->hostname = fshost; 9200Sstevel@tonic-gate 9210Sstevel@tonic-gate optstr = opts = strdup(mnt->mnt_mntopts); 9220Sstevel@tonic-gate /* sizeof (MNTOPT_XXX) includes one extra byte we may need for "," */ 9230Sstevel@tonic-gate optlen = strlen(mnt->mnt_mntopts) + sizeof (MNTOPT_XATTR) + 1; 9240Sstevel@tonic-gate if (optlen > MAX_MNTOPT_STR) { 9250Sstevel@tonic-gate pr_err(gettext("option string too long")); 9260Sstevel@tonic-gate return (RET_ERR); 9270Sstevel@tonic-gate } 9280Sstevel@tonic-gate newopts = malloc(optlen); 9290Sstevel@tonic-gate if (opts == NULL || newopts == NULL) { 9300Sstevel@tonic-gate pr_err(gettext("no memory")); 9310Sstevel@tonic-gate if (opts) 9320Sstevel@tonic-gate free(opts); 9330Sstevel@tonic-gate if (newopts) 9340Sstevel@tonic-gate free(newopts); 9350Sstevel@tonic-gate return (RET_ERR); 9360Sstevel@tonic-gate } 9370Sstevel@tonic-gate newopts[0] = '\0'; 9380Sstevel@tonic-gate 9390Sstevel@tonic-gate while (*opts) { 9400Sstevel@tonic-gate invalid = 0; 9410Sstevel@tonic-gate saveopt = opts; 9420Sstevel@tonic-gate switch (getsubopt(&opts, optlist, &val)) { 9430Sstevel@tonic-gate case OPT_RO: 9440Sstevel@tonic-gate *mntflags |= MS_RDONLY; 9450Sstevel@tonic-gate break; 9460Sstevel@tonic-gate case OPT_RW: 9470Sstevel@tonic-gate *mntflags &= ~(MS_RDONLY); 9480Sstevel@tonic-gate break; 9490Sstevel@tonic-gate case OPT_QUOTA: 9500Sstevel@tonic-gate case OPT_NOQUOTA: 9510Sstevel@tonic-gate break; 9520Sstevel@tonic-gate case OPT_SOFT: 9530Sstevel@tonic-gate args->flags |= NFSMNT_SOFT; 9540Sstevel@tonic-gate args->flags &= ~(NFSMNT_SEMISOFT); 9550Sstevel@tonic-gate break; 9560Sstevel@tonic-gate case OPT_SEMISOFT: 9570Sstevel@tonic-gate args->flags |= NFSMNT_SOFT; 9580Sstevel@tonic-gate args->flags |= NFSMNT_SEMISOFT; 9590Sstevel@tonic-gate break; 9600Sstevel@tonic-gate case OPT_HARD: 9610Sstevel@tonic-gate args->flags &= ~(NFSMNT_SOFT); 9620Sstevel@tonic-gate args->flags &= ~(NFSMNT_SEMISOFT); 9630Sstevel@tonic-gate break; 9640Sstevel@tonic-gate case OPT_SUID: 9650Sstevel@tonic-gate *mntflags &= ~(MS_NOSUID); 9660Sstevel@tonic-gate break; 9670Sstevel@tonic-gate case OPT_NOSUID: 9680Sstevel@tonic-gate *mntflags |= MS_NOSUID; 9690Sstevel@tonic-gate break; 9700Sstevel@tonic-gate case OPT_GRPID: 9710Sstevel@tonic-gate args->flags |= NFSMNT_GRPID; 9720Sstevel@tonic-gate break; 9730Sstevel@tonic-gate case OPT_REMOUNT: 9740Sstevel@tonic-gate *mntflags |= MS_REMOUNT; 9750Sstevel@tonic-gate break; 9760Sstevel@tonic-gate case OPT_INTR: 9770Sstevel@tonic-gate args->flags |= NFSMNT_INT; 9780Sstevel@tonic-gate break; 9790Sstevel@tonic-gate case OPT_NOINTR: 9800Sstevel@tonic-gate args->flags &= ~(NFSMNT_INT); 9810Sstevel@tonic-gate break; 9820Sstevel@tonic-gate case OPT_NOAC: 9830Sstevel@tonic-gate args->flags |= NFSMNT_NOAC; 9840Sstevel@tonic-gate break; 9850Sstevel@tonic-gate case OPT_PORT: 9860Sstevel@tonic-gate if (bad(val)) 9870Sstevel@tonic-gate goto badopt; 9880Sstevel@tonic-gate nfs_port = htons((ushort_t)atoi(val)); 9890Sstevel@tonic-gate break; 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate case OPT_SECURE: 9920Sstevel@tonic-gate if (nfs_getseconfig_byname("dh", &nfs_sec)) { 9930Sstevel@tonic-gate pr_err(gettext("can not get \"dh\" from %s\n"), 9940Sstevel@tonic-gate NFSSEC_CONF); 9950Sstevel@tonic-gate goto badopt; 9960Sstevel@tonic-gate } 9970Sstevel@tonic-gate sec_opt++; 9980Sstevel@tonic-gate break; 9990Sstevel@tonic-gate 10000Sstevel@tonic-gate case OPT_NOCTO: 10010Sstevel@tonic-gate args->flags |= NFSMNT_NOCTO; 10020Sstevel@tonic-gate break; 10030Sstevel@tonic-gate 10040Sstevel@tonic-gate case OPT_RSIZE: 10050Sstevel@tonic-gate args->flags |= NFSMNT_RSIZE; 10060Sstevel@tonic-gate if (bad(val)) 10070Sstevel@tonic-gate goto badopt; 10080Sstevel@tonic-gate args->rsize = atoi(val); 10090Sstevel@tonic-gate break; 10100Sstevel@tonic-gate case OPT_WSIZE: 10110Sstevel@tonic-gate args->flags |= NFSMNT_WSIZE; 10120Sstevel@tonic-gate if (bad(val)) 10130Sstevel@tonic-gate goto badopt; 10140Sstevel@tonic-gate args->wsize = atoi(val); 10150Sstevel@tonic-gate break; 10160Sstevel@tonic-gate case OPT_TIMEO: 10170Sstevel@tonic-gate args->flags |= NFSMNT_TIMEO; 10180Sstevel@tonic-gate if (bad(val)) 10190Sstevel@tonic-gate goto badopt; 10200Sstevel@tonic-gate args->timeo = atoi(val); 10210Sstevel@tonic-gate break; 10220Sstevel@tonic-gate case OPT_RETRANS: 10230Sstevel@tonic-gate args->flags |= NFSMNT_RETRANS; 10240Sstevel@tonic-gate if (bad(val)) 10250Sstevel@tonic-gate goto badopt; 10260Sstevel@tonic-gate args->retrans = atoi(val); 10270Sstevel@tonic-gate break; 10280Sstevel@tonic-gate case OPT_ACTIMEO: 10290Sstevel@tonic-gate args->flags |= NFSMNT_ACDIRMAX; 10300Sstevel@tonic-gate args->flags |= NFSMNT_ACREGMAX; 10310Sstevel@tonic-gate args->flags |= NFSMNT_ACDIRMIN; 10320Sstevel@tonic-gate args->flags |= NFSMNT_ACREGMIN; 10330Sstevel@tonic-gate if (bad(val)) 10340Sstevel@tonic-gate goto badopt; 10350Sstevel@tonic-gate args->acdirmin = args->acregmin = args->acdirmax 10360Sstevel@tonic-gate = args->acregmax = atoi(val); 10370Sstevel@tonic-gate break; 10380Sstevel@tonic-gate case OPT_ACREGMIN: 10390Sstevel@tonic-gate args->flags |= NFSMNT_ACREGMIN; 10400Sstevel@tonic-gate if (bad(val)) 10410Sstevel@tonic-gate goto badopt; 10420Sstevel@tonic-gate args->acregmin = atoi(val); 10430Sstevel@tonic-gate break; 10440Sstevel@tonic-gate case OPT_ACREGMAX: 10450Sstevel@tonic-gate args->flags |= NFSMNT_ACREGMAX; 10460Sstevel@tonic-gate if (bad(val)) 10470Sstevel@tonic-gate goto badopt; 10480Sstevel@tonic-gate args->acregmax = atoi(val); 10490Sstevel@tonic-gate break; 10500Sstevel@tonic-gate case OPT_ACDIRMIN: 10510Sstevel@tonic-gate args->flags |= NFSMNT_ACDIRMIN; 10520Sstevel@tonic-gate if (bad(val)) 10530Sstevel@tonic-gate goto badopt; 10540Sstevel@tonic-gate args->acdirmin = atoi(val); 10550Sstevel@tonic-gate break; 10560Sstevel@tonic-gate case OPT_ACDIRMAX: 10570Sstevel@tonic-gate args->flags |= NFSMNT_ACDIRMAX; 10580Sstevel@tonic-gate if (bad(val)) 10590Sstevel@tonic-gate goto badopt; 10600Sstevel@tonic-gate args->acdirmax = atoi(val); 10610Sstevel@tonic-gate break; 10620Sstevel@tonic-gate case OPT_BG: 10630Sstevel@tonic-gate bg++; 10640Sstevel@tonic-gate break; 10650Sstevel@tonic-gate case OPT_FG: 10660Sstevel@tonic-gate bg = 0; 10670Sstevel@tonic-gate break; 10680Sstevel@tonic-gate case OPT_RETRY: 10690Sstevel@tonic-gate if (bad(val)) 10700Sstevel@tonic-gate goto badopt; 10710Sstevel@tonic-gate retries = atoi(val); 10720Sstevel@tonic-gate break; 10730Sstevel@tonic-gate case OPT_LLOCK: 10740Sstevel@tonic-gate args->flags |= NFSMNT_LLOCK; 10750Sstevel@tonic-gate break; 10760Sstevel@tonic-gate case OPT_POSIX: 10770Sstevel@tonic-gate posix = 1; 10780Sstevel@tonic-gate break; 10790Sstevel@tonic-gate case OPT_VERS: 10800Sstevel@tonic-gate if (bad(val)) 10810Sstevel@tonic-gate goto badopt; 10820Sstevel@tonic-gate nfsvers = (rpcvers_t)atoi(val); 10830Sstevel@tonic-gate break; 10840Sstevel@tonic-gate case OPT_PROTO: 108577Soa138391 if (val == NULL) 108677Soa138391 goto badopt; 108777Soa138391 10880Sstevel@tonic-gate nfs_proto = (char *)malloc(strlen(val)+1); 108977Soa138391 if (!nfs_proto) { 109077Soa138391 pr_err(gettext("no memory")); 109177Soa138391 return (RET_ERR); 109277Soa138391 } 109377Soa138391 109477Soa138391 (void) strncpy(nfs_proto, val, strlen(val)+1); 10950Sstevel@tonic-gate break; 10960Sstevel@tonic-gate case OPT_NOPRINT: 10970Sstevel@tonic-gate args->flags |= NFSMNT_NOPRINT; 10980Sstevel@tonic-gate break; 10990Sstevel@tonic-gate case OPT_LARGEFILES: 11000Sstevel@tonic-gate largefiles = 1; 11010Sstevel@tonic-gate break; 11020Sstevel@tonic-gate case OPT_NOLARGEFILES: 11030Sstevel@tonic-gate pr_err(gettext("NFS can't support \"nolargefiles\"\n")); 11040Sstevel@tonic-gate free(optstr); 11050Sstevel@tonic-gate return (RET_ERR); 11060Sstevel@tonic-gate 11070Sstevel@tonic-gate case OPT_SEC: 11080Sstevel@tonic-gate if (nfs_getseconfig_byname(val, &nfs_sec)) { 11090Sstevel@tonic-gate pr_err(gettext("can not get \"%s\" from %s\n"), 11100Sstevel@tonic-gate val, NFSSEC_CONF); 11110Sstevel@tonic-gate return (RET_ERR); 11120Sstevel@tonic-gate } 11130Sstevel@tonic-gate sec_opt++; 11140Sstevel@tonic-gate break; 11150Sstevel@tonic-gate 11160Sstevel@tonic-gate case OPT_PUBLIC: 11170Sstevel@tonic-gate public_opt = TRUE; 11180Sstevel@tonic-gate break; 11190Sstevel@tonic-gate 11200Sstevel@tonic-gate case OPT_DIRECTIO: 11210Sstevel@tonic-gate args->flags |= NFSMNT_DIRECTIO; 11220Sstevel@tonic-gate break; 11230Sstevel@tonic-gate 11240Sstevel@tonic-gate case OPT_NODIRECTIO: 11250Sstevel@tonic-gate args->flags &= ~(NFSMNT_DIRECTIO); 11260Sstevel@tonic-gate break; 11270Sstevel@tonic-gate 11280Sstevel@tonic-gate case OPT_XATTR: 11290Sstevel@tonic-gate case OPT_NOXATTR: 11300Sstevel@tonic-gate /* 11310Sstevel@tonic-gate * VFS options; just need to get them into the 11320Sstevel@tonic-gate * new mount option string and note we've seen them 11330Sstevel@tonic-gate */ 11340Sstevel@tonic-gate attrpref = 1; 11350Sstevel@tonic-gate break; 11360Sstevel@tonic-gate default: 11370Sstevel@tonic-gate /* 11380Sstevel@tonic-gate * Note that this could be a valid OPT_* option so 11390Sstevel@tonic-gate * we can't use "val" but need to use "saveopt". 11400Sstevel@tonic-gate */ 11410Sstevel@tonic-gate if (fsisstdopt(saveopt)) 11420Sstevel@tonic-gate break; 11430Sstevel@tonic-gate invalid = 1; 11440Sstevel@tonic-gate if (!qflg) 11450Sstevel@tonic-gate (void) fprintf(stderr, gettext( 11460Sstevel@tonic-gate "mount: %s on %s - WARNING unknown option" 11470Sstevel@tonic-gate " \"%s\"\n"), mnt->mnt_special, 11480Sstevel@tonic-gate mnt->mnt_mountp, saveopt); 11490Sstevel@tonic-gate break; 11500Sstevel@tonic-gate } 11510Sstevel@tonic-gate if (!invalid) { 11520Sstevel@tonic-gate if (newopts[0]) 11530Sstevel@tonic-gate strcat(newopts, ","); 11540Sstevel@tonic-gate strcat(newopts, saveopt); 11550Sstevel@tonic-gate } 11560Sstevel@tonic-gate } 11570Sstevel@tonic-gate /* Default is to turn extended attrs on */ 11580Sstevel@tonic-gate if (!attrpref) { 11590Sstevel@tonic-gate if (newopts[0]) 11600Sstevel@tonic-gate strcat(newopts, ","); 11610Sstevel@tonic-gate strcat(newopts, MNTOPT_XATTR); 11620Sstevel@tonic-gate } 11630Sstevel@tonic-gate strcpy(mnt->mnt_mntopts, newopts); 11640Sstevel@tonic-gate free(newopts); 11650Sstevel@tonic-gate free(optstr); 11660Sstevel@tonic-gate 11670Sstevel@tonic-gate /* ensure that only one secure mode is requested */ 11680Sstevel@tonic-gate if (sec_opt > 1) { 11690Sstevel@tonic-gate pr_err(gettext("Security options conflict\n")); 11700Sstevel@tonic-gate return (RET_ERR); 11710Sstevel@tonic-gate } 11720Sstevel@tonic-gate 11730Sstevel@tonic-gate /* ensure that the user isn't trying to get large files over V2 */ 11740Sstevel@tonic-gate if (nfsvers == NFS_VERSION && largefiles) { 11750Sstevel@tonic-gate pr_err(gettext("NFS V2 can't support \"largefiles\"\n")); 11760Sstevel@tonic-gate return (RET_ERR); 11770Sstevel@tonic-gate } 11780Sstevel@tonic-gate 11790Sstevel@tonic-gate if (nfsvers == NFS_V4 && 11800Sstevel@tonic-gate nfs_proto != NULL && 11810Sstevel@tonic-gate strncasecmp(nfs_proto, NC_UDP, strlen(NC_UDP)) == 0) { 11820Sstevel@tonic-gate pr_err(gettext("NFS V4 does not support %s\n"), nfs_proto); 11830Sstevel@tonic-gate return (RET_ERR); 11840Sstevel@tonic-gate } 11850Sstevel@tonic-gate 11860Sstevel@tonic-gate return (RET_OK); 11870Sstevel@tonic-gate 11880Sstevel@tonic-gate badopt: 11890Sstevel@tonic-gate pr_err(gettext("invalid option: \"%s\"\n"), saveopt); 11900Sstevel@tonic-gate free(optstr); 11910Sstevel@tonic-gate return (RET_ERR); 11920Sstevel@tonic-gate } 11930Sstevel@tonic-gate 11940Sstevel@tonic-gate static int 11950Sstevel@tonic-gate make_secure(struct nfs_args *args, char *hostname, struct netconfig *nconf, 11960Sstevel@tonic-gate bool_t use_pubfh, rpcvers_t vers) 11970Sstevel@tonic-gate { 11980Sstevel@tonic-gate sec_data_t *secdata; 11990Sstevel@tonic-gate int flags; 12000Sstevel@tonic-gate struct netbuf *syncaddr = NULL; 12010Sstevel@tonic-gate struct nd_addrlist *retaddrs = NULL; 12020Sstevel@tonic-gate char netname[MAXNETNAMELEN+1]; 12030Sstevel@tonic-gate 12040Sstevel@tonic-gate /* 12050Sstevel@tonic-gate * check to see if any secure mode is requested. 12060Sstevel@tonic-gate * if not, use default security mode. 12070Sstevel@tonic-gate */ 12080Sstevel@tonic-gate if (!snego_done && !sec_opt) { 12090Sstevel@tonic-gate /* 12100Sstevel@tonic-gate * Get default security mode. 12110Sstevel@tonic-gate * AUTH_UNIX has been the default choice for a long time. 12120Sstevel@tonic-gate * The better NFS security service becomes, the better chance 12130Sstevel@tonic-gate * we will set stronger security service as the default NFS 12140Sstevel@tonic-gate * security mode. 12150Sstevel@tonic-gate * 12160Sstevel@tonic-gate */ 12170Sstevel@tonic-gate if (nfs_getseconfig_default(&nfs_sec)) { 12180Sstevel@tonic-gate pr_err(gettext("error getting default security entry\n")); 12190Sstevel@tonic-gate return (-1); 12200Sstevel@tonic-gate } 12210Sstevel@tonic-gate args->flags |= NFSMNT_SECDEFAULT; 12220Sstevel@tonic-gate } 12230Sstevel@tonic-gate 12240Sstevel@tonic-gate /* 12250Sstevel@tonic-gate * Get the network address for the time service on the server. 12260Sstevel@tonic-gate * If an RPC based time service is not available then try the 12270Sstevel@tonic-gate * IP time service. 12280Sstevel@tonic-gate * 12290Sstevel@tonic-gate * This is for AUTH_DH processing. We will also pass down syncaddr 12300Sstevel@tonic-gate * and netname for NFS V4 even if AUTH_DH is not requested right now. 12310Sstevel@tonic-gate * NFS V4 does security negotiation in the kernel via SECINFO. 12320Sstevel@tonic-gate * These information might be needed later in the kernel. 12330Sstevel@tonic-gate * 12340Sstevel@tonic-gate * Eventurally, we want to move this code to nfs_clnt_secdata() 12350Sstevel@tonic-gate * when autod_nfs.c and mount.c can share the same get_the_addr() 12360Sstevel@tonic-gate * routine. 12370Sstevel@tonic-gate */ 12380Sstevel@tonic-gate flags = 0; 12390Sstevel@tonic-gate syncaddr = NULL; 12400Sstevel@tonic-gate 12410Sstevel@tonic-gate if (nfs_sec.sc_rpcnum == AUTH_DH || vers == NFS_V4) { 12420Sstevel@tonic-gate /* 12430Sstevel@tonic-gate * If using the public fh or nfsv4, we will not contact the 12440Sstevel@tonic-gate * remote RPCBINDer, since it is possibly behind a firewall. 12450Sstevel@tonic-gate */ 12460Sstevel@tonic-gate if (use_pubfh == FALSE && vers != NFS_V4) { 12470Sstevel@tonic-gate syncaddr = get_the_addr(hostname, RPCBPROG, RPCBVERS, 12480Sstevel@tonic-gate nconf, 0, NULL, NULL, FALSE, NULL, NULL); 12490Sstevel@tonic-gate } 12500Sstevel@tonic-gate 12510Sstevel@tonic-gate if (syncaddr != NULL) { 12520Sstevel@tonic-gate /* for flags in sec_data */ 12530Sstevel@tonic-gate flags |= AUTH_F_RPCTIMESYNC; 12540Sstevel@tonic-gate } else { 12550Sstevel@tonic-gate struct nd_hostserv hs; 12560Sstevel@tonic-gate int error; 12570Sstevel@tonic-gate 12580Sstevel@tonic-gate hs.h_host = hostname; 12590Sstevel@tonic-gate hs.h_serv = "timserver"; 12600Sstevel@tonic-gate 12610Sstevel@tonic-gate error = netdir_getbyname(nconf, &hs, &retaddrs); 12620Sstevel@tonic-gate 12630Sstevel@tonic-gate if (error != ND_OK && (nfs_sec.sc_rpcnum == AUTH_DH)) { 12640Sstevel@tonic-gate pr_err(gettext("%s: secure: no time service\n"), 12650Sstevel@tonic-gate hostname); 12660Sstevel@tonic-gate return (-1); 12670Sstevel@tonic-gate } 12680Sstevel@tonic-gate 12690Sstevel@tonic-gate if (error == ND_OK) 12700Sstevel@tonic-gate syncaddr = retaddrs->n_addrs; 12710Sstevel@tonic-gate 12720Sstevel@tonic-gate /* 12730Sstevel@tonic-gate * For NFS_V4 if AUTH_DH is negotiated later in the 12740Sstevel@tonic-gate * kernel thru SECINFO, it will need syncaddr 12750Sstevel@tonic-gate * and netname data. 12760Sstevel@tonic-gate */ 12770Sstevel@tonic-gate if (vers == NFS_V4 && syncaddr && 12780Sstevel@tonic-gate host2netname(netname, hostname, NULL)) { 12790Sstevel@tonic-gate args->syncaddr = malloc(sizeof (struct netbuf)); 12800Sstevel@tonic-gate args->syncaddr->buf = malloc(syncaddr->len); 12810Sstevel@tonic-gate (void) memcpy(args->syncaddr->buf, syncaddr->buf, 12820Sstevel@tonic-gate syncaddr->len); 12830Sstevel@tonic-gate args->syncaddr->len = syncaddr->len; 12840Sstevel@tonic-gate args->syncaddr->maxlen = syncaddr->maxlen; 12850Sstevel@tonic-gate args->netname = strdup(netname); 12860Sstevel@tonic-gate args->flags |= NFSMNT_SECURE; 12870Sstevel@tonic-gate } 12880Sstevel@tonic-gate } 12890Sstevel@tonic-gate } 12900Sstevel@tonic-gate 12910Sstevel@tonic-gate /* 12920Sstevel@tonic-gate * For the initial chosen flavor (any flavor defined in nfssec.conf), 12930Sstevel@tonic-gate * the data will be stored in the sec_data structure via 12940Sstevel@tonic-gate * nfs_clnt_secdata() and be passed to the kernel via nfs_args_* 12950Sstevel@tonic-gate * extended data structure. 12960Sstevel@tonic-gate */ 12970Sstevel@tonic-gate if (!(secdata = nfs_clnt_secdata(&nfs_sec, hostname, args->knconf, 12980Sstevel@tonic-gate syncaddr, flags))) { 12990Sstevel@tonic-gate pr_err(gettext("errors constructing security related data\n")); 13000Sstevel@tonic-gate if (flags & AUTH_F_RPCTIMESYNC) { 13010Sstevel@tonic-gate free(syncaddr->buf); 13020Sstevel@tonic-gate free(syncaddr); 13030Sstevel@tonic-gate } else if (retaddrs) 13040Sstevel@tonic-gate netdir_free((void *)retaddrs, ND_ADDRLIST); 13050Sstevel@tonic-gate return (-1); 13060Sstevel@tonic-gate } 13070Sstevel@tonic-gate 13080Sstevel@tonic-gate NFS_ARGS_EXTB_secdata(args, secdata); 13090Sstevel@tonic-gate if (flags & AUTH_F_RPCTIMESYNC) { 13100Sstevel@tonic-gate free(syncaddr->buf); 13110Sstevel@tonic-gate free(syncaddr); 13120Sstevel@tonic-gate } else if (retaddrs) 13130Sstevel@tonic-gate netdir_free((void *)retaddrs, ND_ADDRLIST); 13140Sstevel@tonic-gate return (0); 13150Sstevel@tonic-gate } 13160Sstevel@tonic-gate 13170Sstevel@tonic-gate /* 13180Sstevel@tonic-gate * Get the network address on "hostname" for program "prog" 13190Sstevel@tonic-gate * with version "vers" by using the nconf configuration data 13200Sstevel@tonic-gate * passed in. 13210Sstevel@tonic-gate * 13220Sstevel@tonic-gate * If the address of a netconfig pointer is null then 13230Sstevel@tonic-gate * information is not sufficient and no netbuf will be returned. 13240Sstevel@tonic-gate * 13250Sstevel@tonic-gate * Finally, ping the null procedure of that service. 13260Sstevel@tonic-gate * 13270Sstevel@tonic-gate * A similar routine is also defined in ../../autofs/autod_nfs.c. 13280Sstevel@tonic-gate * This is a potential routine to move to ../lib for common usage. 13290Sstevel@tonic-gate */ 13300Sstevel@tonic-gate static struct netbuf * 13310Sstevel@tonic-gate get_the_addr(char *hostname, ulong_t prog, ulong_t vers, 13320Sstevel@tonic-gate struct netconfig *nconf, ushort_t port, struct t_info *tinfo, 13330Sstevel@tonic-gate caddr_t *fhp, bool_t get_pubfh, char *fspath, err_ret_t *error) 13340Sstevel@tonic-gate { 13350Sstevel@tonic-gate struct netbuf *nb = NULL; 13360Sstevel@tonic-gate struct t_bind *tbind = NULL; 13370Sstevel@tonic-gate CLIENT *cl = NULL; 13380Sstevel@tonic-gate struct timeval tv; 13390Sstevel@tonic-gate int fd = -1; 13400Sstevel@tonic-gate AUTH *ah = NULL; 13410Sstevel@tonic-gate AUTH *new_ah = NULL; 13420Sstevel@tonic-gate struct snego_t snego; 13430Sstevel@tonic-gate 13440Sstevel@tonic-gate if (nconf == NULL) 13450Sstevel@tonic-gate return (NULL); 13460Sstevel@tonic-gate 13470Sstevel@tonic-gate if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) == -1) 13480Sstevel@tonic-gate goto done; 13490Sstevel@tonic-gate 13500Sstevel@tonic-gate /* LINTED pointer alignment */ 13510Sstevel@tonic-gate if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR)) 13520Sstevel@tonic-gate == NULL) 13530Sstevel@tonic-gate goto done; 13540Sstevel@tonic-gate 13550Sstevel@tonic-gate /* 13560Sstevel@tonic-gate * In the case of public filehandle usage or NFSv4 we want to 13570Sstevel@tonic-gate * avoid use of the rpcbind/portmap protocol 13580Sstevel@tonic-gate */ 13590Sstevel@tonic-gate if ((get_pubfh == TRUE) || (vers == NFS_V4)) { 13600Sstevel@tonic-gate struct nd_hostserv hs; 13610Sstevel@tonic-gate struct nd_addrlist *retaddrs; 13620Sstevel@tonic-gate int retval; 13630Sstevel@tonic-gate hs.h_host = hostname; 13640Sstevel@tonic-gate 13650Sstevel@tonic-gate /* NFS where vers==4 does not support UDP */ 13660Sstevel@tonic-gate if (vers == NFS_V4 && 13670Sstevel@tonic-gate strncasecmp(nconf->nc_proto, NC_UDP, 13680Sstevel@tonic-gate strlen(NC_UDP)) == 0) { 136977Soa138391 SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0); 13700Sstevel@tonic-gate goto done; 13710Sstevel@tonic-gate } 13720Sstevel@tonic-gate 13730Sstevel@tonic-gate if (port == 0) 13740Sstevel@tonic-gate hs.h_serv = "nfs"; 13750Sstevel@tonic-gate else 13760Sstevel@tonic-gate hs.h_serv = NULL; 13770Sstevel@tonic-gate 13780Sstevel@tonic-gate if ((retval = netdir_getbyname(nconf, &hs, &retaddrs)) 13790Sstevel@tonic-gate != ND_OK) { 13800Sstevel@tonic-gate /* 13810Sstevel@tonic-gate * Carefully set the error value here. Want to signify 13820Sstevel@tonic-gate * that the error was an unknown host. 13830Sstevel@tonic-gate */ 13840Sstevel@tonic-gate if (retval == ND_NOHOST) { 13850Sstevel@tonic-gate SET_ERR_RET(error, ERR_NOHOST, retval); 13860Sstevel@tonic-gate } 13870Sstevel@tonic-gate 13880Sstevel@tonic-gate goto done; 13890Sstevel@tonic-gate } 13900Sstevel@tonic-gate memcpy(tbind->addr.buf, retaddrs->n_addrs->buf, 13910Sstevel@tonic-gate retaddrs->n_addrs->len); 13920Sstevel@tonic-gate tbind->addr.len = retaddrs->n_addrs->len; 13930Sstevel@tonic-gate netdir_free((void *)retaddrs, ND_ADDRLIST); 13940Sstevel@tonic-gate (void) netdir_options(nconf, ND_SET_RESERVEDPORT, fd, NULL); 13950Sstevel@tonic-gate 13960Sstevel@tonic-gate } else { 13970Sstevel@tonic-gate if (rpcb_getaddr(prog, vers, nconf, &tbind->addr, 13980Sstevel@tonic-gate hostname) == FALSE) { 13990Sstevel@tonic-gate goto done; 14000Sstevel@tonic-gate } 14010Sstevel@tonic-gate } 14020Sstevel@tonic-gate 14030Sstevel@tonic-gate if (port) { 14040Sstevel@tonic-gate /* LINTED pointer alignment */ 14050Sstevel@tonic-gate if (strcmp(nconf->nc_protofmly, NC_INET) == 0) 14060Sstevel@tonic-gate ((struct sockaddr_in *)tbind->addr.buf)->sin_port 14070Sstevel@tonic-gate = port; 14080Sstevel@tonic-gate else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) 14090Sstevel@tonic-gate ((struct sockaddr_in6 *)tbind->addr.buf)->sin6_port 14100Sstevel@tonic-gate = port; 14110Sstevel@tonic-gate 14120Sstevel@tonic-gate } 14130Sstevel@tonic-gate 14140Sstevel@tonic-gate cl = clnt_tli_create(fd, nconf, &tbind->addr, prog, vers, 0, 0); 14150Sstevel@tonic-gate if (cl == NULL) { 141677Soa138391 /* 141777Soa138391 * clnt_tli_create() returns either RPC_SYSTEMERROR, 141877Soa138391 * RPC_UNKNOWNPROTO or RPC_TLIERROR. The RPC_TLIERROR translates 141977Soa138391 * to "Misc. TLI error". This is not too helpful. Most likely 142077Soa138391 * the connection to the remote server timed out, so this 142177Soa138391 * error is at least less perplexing. 142277Soa138391 * See: usr/src/cmd/rpcinfo/rpcinfo.c 142377Soa138391 */ 142477Soa138391 if (rpc_createerr.cf_stat == RPC_TLIERROR) { 142577Soa138391 SET_ERR_RET(error, ERR_RPCERROR, RPC_PMAPFAILURE); 142677Soa138391 } else { 142777Soa138391 SET_ERR_RET(error, ERR_RPCERROR, rpc_createerr.cf_stat); 142877Soa138391 } 14290Sstevel@tonic-gate goto done; 14300Sstevel@tonic-gate } 14310Sstevel@tonic-gate 14320Sstevel@tonic-gate ah = authsys_create_default(); 14330Sstevel@tonic-gate if (ah != NULL) 14340Sstevel@tonic-gate cl->cl_auth = ah; 14350Sstevel@tonic-gate 14360Sstevel@tonic-gate tv.tv_sec = 5; 14370Sstevel@tonic-gate tv.tv_usec = 0; 14380Sstevel@tonic-gate 14390Sstevel@tonic-gate (void) clnt_control(cl, CLSET_TIMEOUT, (char *)&tv); 14400Sstevel@tonic-gate 14410Sstevel@tonic-gate if ((get_pubfh == TRUE) && (vers != NFS_V4)) { 14420Sstevel@tonic-gate enum snego_stat sec; 14430Sstevel@tonic-gate 14440Sstevel@tonic-gate if (!snego_done) { 14450Sstevel@tonic-gate /* 14460Sstevel@tonic-gate * negotiate sec flavor. 14470Sstevel@tonic-gate */ 14480Sstevel@tonic-gate snego.cnt = 0; 14490Sstevel@tonic-gate if ((sec = nfs_sec_nego(vers, cl, fspath, &snego)) == 14500Sstevel@tonic-gate SNEGO_SUCCESS) { 14510Sstevel@tonic-gate int jj; 14520Sstevel@tonic-gate 14530Sstevel@tonic-gate /* 14540Sstevel@tonic-gate * check if server supports the one 14550Sstevel@tonic-gate * specified in the sec= option. 14560Sstevel@tonic-gate */ 14570Sstevel@tonic-gate if (sec_opt) { 14580Sstevel@tonic-gate for (jj = 0; jj < snego.cnt; jj++) { 14590Sstevel@tonic-gate if (snego.array[jj] == nfs_sec.sc_nfsnum) { 14600Sstevel@tonic-gate snego_done = TRUE; 14610Sstevel@tonic-gate break; 14620Sstevel@tonic-gate } 14630Sstevel@tonic-gate } 14640Sstevel@tonic-gate } 14650Sstevel@tonic-gate 14660Sstevel@tonic-gate /* 14670Sstevel@tonic-gate * find a common sec flavor 14680Sstevel@tonic-gate */ 14690Sstevel@tonic-gate if (!snego_done) { 14700Sstevel@tonic-gate if (sec_opt) { 14710Sstevel@tonic-gate pr_err(gettext( 14720Sstevel@tonic-gate "Server does not support the security" 14730Sstevel@tonic-gate " flavor specified.\n")); 14740Sstevel@tonic-gate } 14750Sstevel@tonic-gate for (jj = 0; jj < snego.cnt; jj++) { 14760Sstevel@tonic-gate if (!nfs_getseconfig_bynumber(snego.array[jj], 14770Sstevel@tonic-gate &nfs_sec)) { 14780Sstevel@tonic-gate snego_done = TRUE; 14790Sstevel@tonic-gate if (sec_opt) { 14800Sstevel@tonic-gate pr_err(gettext( 14810Sstevel@tonic-gate "Security flavor %d was negotiated and" 14820Sstevel@tonic-gate " will be used.\n"), 14830Sstevel@tonic-gate nfs_sec.sc_nfsnum); 14840Sstevel@tonic-gate } 14850Sstevel@tonic-gate break; 14860Sstevel@tonic-gate } 14870Sstevel@tonic-gate } 14880Sstevel@tonic-gate } 14890Sstevel@tonic-gate if (!snego_done) 14900Sstevel@tonic-gate return (NULL); 14910Sstevel@tonic-gate 14920Sstevel@tonic-gate /* 14930Sstevel@tonic-gate * Now that the flavor has been 14940Sstevel@tonic-gate * negotiated, get the fh. 14950Sstevel@tonic-gate * 14960Sstevel@tonic-gate * First, create an auth handle using the negotiated 14970Sstevel@tonic-gate * sec flavor in the next lookup to 14980Sstevel@tonic-gate * fetch the filehandle. 14990Sstevel@tonic-gate */ 15000Sstevel@tonic-gate new_ah = nfs_create_ah(cl, hostname, &nfs_sec); 15010Sstevel@tonic-gate if (new_ah == NULL) 15020Sstevel@tonic-gate goto done; 15030Sstevel@tonic-gate cl->cl_auth = new_ah; 15040Sstevel@tonic-gate } else if (sec == SNEGO_ARRAY_TOO_SMALL || sec == 15050Sstevel@tonic-gate SNEGO_FAILURE) { 15060Sstevel@tonic-gate goto done; 15070Sstevel@tonic-gate } 15080Sstevel@tonic-gate /* 15090Sstevel@tonic-gate * Note that if sec == SNEGO_DEF_VALID 15100Sstevel@tonic-gate * default sec flavor is acceptable. 15110Sstevel@tonic-gate * Use it to get the filehandle. 15120Sstevel@tonic-gate */ 15130Sstevel@tonic-gate } 15140Sstevel@tonic-gate 15150Sstevel@tonic-gate if (vers == NFS_VERSION) { 15160Sstevel@tonic-gate wnl_diropargs arg; 15170Sstevel@tonic-gate wnl_diropres *res; 15180Sstevel@tonic-gate 15190Sstevel@tonic-gate memset((char *)&arg.dir, 0, sizeof (wnl_fh)); 15200Sstevel@tonic-gate arg.name = fspath; 15210Sstevel@tonic-gate res = wnlproc_lookup_2(&arg, cl); 15220Sstevel@tonic-gate 15230Sstevel@tonic-gate if (res == NULL || res->status != NFS_OK) 15240Sstevel@tonic-gate goto done; 15250Sstevel@tonic-gate *fhp = malloc(sizeof (wnl_fh)); 15260Sstevel@tonic-gate 15270Sstevel@tonic-gate if (*fhp == NULL) { 15280Sstevel@tonic-gate pr_err(gettext("no memory\n")); 15290Sstevel@tonic-gate goto done; 15300Sstevel@tonic-gate } 15310Sstevel@tonic-gate 15320Sstevel@tonic-gate memcpy((char *)*fhp, 15330Sstevel@tonic-gate (char *)&res->wnl_diropres_u.wnl_diropres.file, 15340Sstevel@tonic-gate sizeof (wnl_fh)); 15350Sstevel@tonic-gate } else { 15360Sstevel@tonic-gate WNL_LOOKUP3args arg; 15370Sstevel@tonic-gate WNL_LOOKUP3res *res; 15380Sstevel@tonic-gate nfs_fh3 *fh3p; 15390Sstevel@tonic-gate 15400Sstevel@tonic-gate memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3)); 15410Sstevel@tonic-gate arg.what.name = fspath; 15420Sstevel@tonic-gate res = wnlproc3_lookup_3(&arg, cl); 15430Sstevel@tonic-gate 15440Sstevel@tonic-gate if (res == NULL || res->status != NFS3_OK) 15450Sstevel@tonic-gate goto done; 15460Sstevel@tonic-gate 15470Sstevel@tonic-gate fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p)); 15480Sstevel@tonic-gate 15490Sstevel@tonic-gate if (fh3p == NULL) { 15500Sstevel@tonic-gate pr_err(gettext("no memory\n")); 15510Sstevel@tonic-gate CLNT_FREERES(cl, xdr_WNL_LOOKUP3res, (char *)res); 15520Sstevel@tonic-gate goto done; 15530Sstevel@tonic-gate } 15540Sstevel@tonic-gate 15550Sstevel@tonic-gate fh3p->fh3_length = 15560Sstevel@tonic-gate res->WNL_LOOKUP3res_u.res_ok.object.data.data_len; 15570Sstevel@tonic-gate memcpy(fh3p->fh3_u.data, 15580Sstevel@tonic-gate res->WNL_LOOKUP3res_u.res_ok.object.data.data_val, 15590Sstevel@tonic-gate fh3p->fh3_length); 15600Sstevel@tonic-gate 15610Sstevel@tonic-gate *fhp = (caddr_t)fh3p; 15620Sstevel@tonic-gate 15630Sstevel@tonic-gate CLNT_FREERES(cl, xdr_WNL_LOOKUP3res, (char *)res); 15640Sstevel@tonic-gate } 15650Sstevel@tonic-gate } else { 15660Sstevel@tonic-gate void *res; 15670Sstevel@tonic-gate struct rpc_err r_err; 15680Sstevel@tonic-gate 15690Sstevel@tonic-gate if (vers == NFS_VERSION) 15700Sstevel@tonic-gate res = wnlproc_null_2(NULL, cl); 15710Sstevel@tonic-gate else if (vers == NFS_V3) 15720Sstevel@tonic-gate res = wnlproc3_null_3(NULL, cl); 15730Sstevel@tonic-gate else 15740Sstevel@tonic-gate res = wnlproc4_null_4(NULL, cl); 15750Sstevel@tonic-gate 15760Sstevel@tonic-gate if (res == NULL) { 15770Sstevel@tonic-gate clnt_geterr(cl, &r_err); 15780Sstevel@tonic-gate if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { 15790Sstevel@tonic-gate switch (r_err.re_status) { 15800Sstevel@tonic-gate case RPC_TLIERROR: 15810Sstevel@tonic-gate case RPC_CANTRECV: 15820Sstevel@tonic-gate case RPC_CANTSEND: 15830Sstevel@tonic-gate r_err.re_status = RPC_PROGVERSMISMATCH; 15840Sstevel@tonic-gate } 15850Sstevel@tonic-gate } 15860Sstevel@tonic-gate SET_ERR_RET(error, ERR_RPCERROR, r_err.re_status); 15870Sstevel@tonic-gate goto done; 15880Sstevel@tonic-gate } 15890Sstevel@tonic-gate } 15900Sstevel@tonic-gate 15910Sstevel@tonic-gate /* 15920Sstevel@tonic-gate * Make a copy of the netbuf to return 15930Sstevel@tonic-gate */ 15940Sstevel@tonic-gate nb = (struct netbuf *)malloc(sizeof (*nb)); 15950Sstevel@tonic-gate if (nb == NULL) { 15960Sstevel@tonic-gate pr_err(gettext("no memory\n")); 15970Sstevel@tonic-gate goto done; 15980Sstevel@tonic-gate } 15990Sstevel@tonic-gate *nb = tbind->addr; 16000Sstevel@tonic-gate nb->buf = (char *)malloc(nb->maxlen); 16010Sstevel@tonic-gate if (nb->buf == NULL) { 16020Sstevel@tonic-gate pr_err(gettext("no memory\n")); 16030Sstevel@tonic-gate free(nb); 16040Sstevel@tonic-gate nb = NULL; 16050Sstevel@tonic-gate goto done; 16060Sstevel@tonic-gate } 16070Sstevel@tonic-gate (void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len); 16080Sstevel@tonic-gate 16090Sstevel@tonic-gate done: 16100Sstevel@tonic-gate if (cl) { 16110Sstevel@tonic-gate if (ah != NULL) { 16120Sstevel@tonic-gate if (new_ah != NULL) 16130Sstevel@tonic-gate AUTH_DESTROY(ah); 16140Sstevel@tonic-gate AUTH_DESTROY(cl->cl_auth); 16150Sstevel@tonic-gate cl->cl_auth = NULL; 16160Sstevel@tonic-gate } 16170Sstevel@tonic-gate clnt_destroy(cl); 16180Sstevel@tonic-gate cl = NULL; 16190Sstevel@tonic-gate } 16200Sstevel@tonic-gate if (tbind) { 16210Sstevel@tonic-gate t_free((char *)tbind, T_BIND); 16220Sstevel@tonic-gate tbind = NULL; 16230Sstevel@tonic-gate } 16240Sstevel@tonic-gate if (fd >= 0) 16250Sstevel@tonic-gate (void) t_close(fd); 16260Sstevel@tonic-gate return (nb); 16270Sstevel@tonic-gate } 16280Sstevel@tonic-gate 16290Sstevel@tonic-gate /* 16300Sstevel@tonic-gate * Get a network address on "hostname" for program "prog" 16310Sstevel@tonic-gate * with version "vers". If the port number is specified (non zero) 16320Sstevel@tonic-gate * then try for a TCP/UDP transport and set the port number of the 16330Sstevel@tonic-gate * resulting IP address. 16340Sstevel@tonic-gate * 16350Sstevel@tonic-gate * If the address of a netconfig pointer was passed and 16360Sstevel@tonic-gate * if it's not null, use it as the netconfig otherwise 16370Sstevel@tonic-gate * assign the address of the netconfig that was used to 16380Sstevel@tonic-gate * establish contact with the service. 16390Sstevel@tonic-gate * 16400Sstevel@tonic-gate * A similar routine is also defined in ../../autofs/autod_nfs.c. 16410Sstevel@tonic-gate * This is a potential routine to move to ../lib for common usage. 16420Sstevel@tonic-gate * 16430Sstevel@tonic-gate * "error" refers to a more descriptive term when get_addr fails 16440Sstevel@tonic-gate * and returns NULL: ERR_PROTO_NONE if no error introduced by 16450Sstevel@tonic-gate * -o proto option, ERR_NETPATH if error found in NETPATH 16460Sstevel@tonic-gate * environment variable, ERR_PROTO_INVALID if an unrecognized 16470Sstevel@tonic-gate * protocol is specified by user, and ERR_PROTO_UNSUPP for a 16480Sstevel@tonic-gate * recognized but invalid protocol (eg. ticlts, ticots, etc.). 16490Sstevel@tonic-gate * "error" is ignored if get_addr returns non-NULL result. 16500Sstevel@tonic-gate * 16510Sstevel@tonic-gate */ 16520Sstevel@tonic-gate static struct netbuf * 16530Sstevel@tonic-gate get_addr(char *hostname, ulong_t prog, ulong_t vers, struct netconfig **nconfp, 16540Sstevel@tonic-gate char *proto, ushort_t port, struct t_info *tinfo, caddr_t *fhp, 16550Sstevel@tonic-gate bool_t get_pubfh, char *fspath, err_ret_t *error) 16560Sstevel@tonic-gate { 16570Sstevel@tonic-gate struct netbuf *nb = NULL; 16580Sstevel@tonic-gate struct netconfig *nconf = NULL; 16590Sstevel@tonic-gate NCONF_HANDLE *nc = NULL; 16600Sstevel@tonic-gate int nthtry = FIRST_TRY; 16610Sstevel@tonic-gate err_ret_t errsave_nohost, errsave_rpcerr; 16620Sstevel@tonic-gate 16630Sstevel@tonic-gate SET_ERR_RET(&errsave_nohost, ERR_PROTO_NONE, 0); 16640Sstevel@tonic-gate SET_ERR_RET(&errsave_rpcerr, ERR_PROTO_NONE, 0); 16650Sstevel@tonic-gate 16660Sstevel@tonic-gate SET_ERR_RET(error, ERR_PROTO_NONE, 0); 16670Sstevel@tonic-gate 16680Sstevel@tonic-gate if (nconfp && *nconfp) 16690Sstevel@tonic-gate return (get_the_addr(hostname, prog, vers, *nconfp, port, 16700Sstevel@tonic-gate tinfo, fhp, get_pubfh, fspath, error)); 16710Sstevel@tonic-gate /* 16720Sstevel@tonic-gate * No nconf passed in. 16730Sstevel@tonic-gate * 16740Sstevel@tonic-gate * Try to get a nconf from /etc/netconfig filtered by 16750Sstevel@tonic-gate * the NETPATH environment variable. 16760Sstevel@tonic-gate * First search for COTS, second for CLTS unless proto 16770Sstevel@tonic-gate * is specified. When we retry, we reset the 16780Sstevel@tonic-gate * netconfig list so that we would search the whole list 16790Sstevel@tonic-gate * all over again. 16800Sstevel@tonic-gate */ 16810Sstevel@tonic-gate 16820Sstevel@tonic-gate if ((nc = setnetpath()) == NULL) { 16830Sstevel@tonic-gate /* should only return an error if problems with NETPATH */ 16840Sstevel@tonic-gate /* In which case you are hosed */ 16850Sstevel@tonic-gate SET_ERR_RET(error, ERR_NETPATH, 0); 16860Sstevel@tonic-gate goto done; 16870Sstevel@tonic-gate } 16880Sstevel@tonic-gate 16890Sstevel@tonic-gate /* 16900Sstevel@tonic-gate * If proto is specified, then only search for the match, 16910Sstevel@tonic-gate * otherwise try COTS first, if failed, try CLTS. 16920Sstevel@tonic-gate */ 16930Sstevel@tonic-gate if (proto) { 16940Sstevel@tonic-gate /* no matching proto name */ 16950Sstevel@tonic-gate SET_ERR_RET(error, ERR_PROTO_INVALID, 0); 16960Sstevel@tonic-gate 16970Sstevel@tonic-gate while (nconf = getnetpath(nc)) { 16980Sstevel@tonic-gate if (strcmp(nconf->nc_netid, proto)) 16990Sstevel@tonic-gate continue; 17000Sstevel@tonic-gate 17010Sstevel@tonic-gate /* may be unsupported */ 17020Sstevel@tonic-gate SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0); 17030Sstevel@tonic-gate 17040Sstevel@tonic-gate if ((port != 0) && 17050Sstevel@tonic-gate ((strcmp(nconf->nc_protofmly, NC_INET) == 0 || 17060Sstevel@tonic-gate strcmp(nconf->nc_protofmly, NC_INET6) == 0) && 17070Sstevel@tonic-gate (strcmp(nconf->nc_proto, NC_TCP) != 0 && 17080Sstevel@tonic-gate strcmp(nconf->nc_proto, NC_UDP) != 0))) 17090Sstevel@tonic-gate 17100Sstevel@tonic-gate continue; 17110Sstevel@tonic-gate 17120Sstevel@tonic-gate else { 17130Sstevel@tonic-gate nb = get_the_addr(hostname, prog, 17140Sstevel@tonic-gate vers, nconf, port, tinfo, 17150Sstevel@tonic-gate fhp, get_pubfh, fspath, error); 17160Sstevel@tonic-gate 17170Sstevel@tonic-gate if (nb != NULL) 17180Sstevel@tonic-gate break; 17190Sstevel@tonic-gate 17200Sstevel@tonic-gate /* nb is NULL - deal with errors */ 17210Sstevel@tonic-gate if (error) { 17220Sstevel@tonic-gate if (error->error_type == ERR_NOHOST) 17230Sstevel@tonic-gate SET_ERR_RET(&errsave_nohost, 17240Sstevel@tonic-gate error->error_type, 17250Sstevel@tonic-gate error->error_value); 17260Sstevel@tonic-gate if (error->error_type == ERR_RPCERROR) 17270Sstevel@tonic-gate SET_ERR_RET(&errsave_rpcerr, 17280Sstevel@tonic-gate error->error_type, 17290Sstevel@tonic-gate error->error_value); 17300Sstevel@tonic-gate } 17310Sstevel@tonic-gate /* 17320Sstevel@tonic-gate * continue with same protocol 17330Sstevel@tonic-gate * selection 17340Sstevel@tonic-gate */ 17350Sstevel@tonic-gate continue; 17360Sstevel@tonic-gate } 17370Sstevel@tonic-gate } /* end of while */ 17380Sstevel@tonic-gate 17390Sstevel@tonic-gate if (nconf == NULL) 17400Sstevel@tonic-gate goto done; 17410Sstevel@tonic-gate 17420Sstevel@tonic-gate if ((nb = get_the_addr(hostname, prog, vers, nconf, port, 17430Sstevel@tonic-gate tinfo, fhp, get_pubfh, fspath, error)) == NULL) 17440Sstevel@tonic-gate goto done; 17450Sstevel@tonic-gate 17460Sstevel@tonic-gate 17470Sstevel@tonic-gate } else { 17480Sstevel@tonic-gate retry: 17490Sstevel@tonic-gate SET_ERR_RET(error, ERR_NETPATH, 0); 17500Sstevel@tonic-gate while (nconf = getnetpath(nc)) { 17510Sstevel@tonic-gate SET_ERR_RET(error, ERR_PROTO_NONE, 0); 17520Sstevel@tonic-gate if (nconf->nc_flag & NC_VISIBLE) { 17530Sstevel@tonic-gate if (nthtry == FIRST_TRY) { 17540Sstevel@tonic-gate if ((nconf->nc_semantics == 17550Sstevel@tonic-gate NC_TPI_COTS_ORD) || 17560Sstevel@tonic-gate (nconf->nc_semantics == 17570Sstevel@tonic-gate NC_TPI_COTS)) { 17580Sstevel@tonic-gate 17590Sstevel@tonic-gate if (port == 0) 17600Sstevel@tonic-gate break; 17610Sstevel@tonic-gate 17620Sstevel@tonic-gate if ((strcmp(nconf->nc_protofmly, 17630Sstevel@tonic-gate NC_INET) == 0 || 17640Sstevel@tonic-gate strcmp(nconf-> 17650Sstevel@tonic-gate nc_protofmly, 17660Sstevel@tonic-gate NC_INET6) == 0) && 17670Sstevel@tonic-gate (strcmp(nconf->nc_proto, 17680Sstevel@tonic-gate NC_TCP) == 0)) 17690Sstevel@tonic-gate 17700Sstevel@tonic-gate break; 17710Sstevel@tonic-gate } 17720Sstevel@tonic-gate } 17730Sstevel@tonic-gate if (nthtry == SECOND_TRY) { 17740Sstevel@tonic-gate if (nconf->nc_semantics == 17750Sstevel@tonic-gate NC_TPI_CLTS) { 17760Sstevel@tonic-gate if (port == 0) 17770Sstevel@tonic-gate break; 17780Sstevel@tonic-gate if ((strcmp(nconf->nc_protofmly, 17790Sstevel@tonic-gate NC_INET) == 0 || 17800Sstevel@tonic-gate strcmp(nconf-> 17810Sstevel@tonic-gate nc_protofmly, NC_INET6) 17820Sstevel@tonic-gate == 0) && 17830Sstevel@tonic-gate (strcmp( 17840Sstevel@tonic-gate nconf->nc_proto, 17850Sstevel@tonic-gate NC_UDP) == 0)) 17860Sstevel@tonic-gate break; 17870Sstevel@tonic-gate } 17880Sstevel@tonic-gate } 17890Sstevel@tonic-gate } 17900Sstevel@tonic-gate } /* while */ 17910Sstevel@tonic-gate if (nconf == NULL) { 17920Sstevel@tonic-gate if (++nthtry <= MNT_PREF_LISTLEN) { 17930Sstevel@tonic-gate endnetpath(nc); 17940Sstevel@tonic-gate if ((nc = setnetpath()) == NULL) 17950Sstevel@tonic-gate goto done; 17960Sstevel@tonic-gate goto retry; 17970Sstevel@tonic-gate } else 17980Sstevel@tonic-gate goto done; 17990Sstevel@tonic-gate } else { 18000Sstevel@tonic-gate if ((nb = get_the_addr(hostname, prog, vers, nconf, 18010Sstevel@tonic-gate port, tinfo, fhp, get_pubfh, fspath, error)) 18020Sstevel@tonic-gate == NULL) { 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, 18070Sstevel@tonic-gate error->error_type, 18080Sstevel@tonic-gate error->error_value); 18090Sstevel@tonic-gate if (error->error_type == ERR_RPCERROR) 18100Sstevel@tonic-gate SET_ERR_RET(&errsave_rpcerr, 18110Sstevel@tonic-gate error->error_type, 18120Sstevel@tonic-gate error->error_value); 18130Sstevel@tonic-gate } 18140Sstevel@tonic-gate /* 18150Sstevel@tonic-gate * Continue the same search path in the 18160Sstevel@tonic-gate * netconfig db until no more matched 18170Sstevel@tonic-gate * nconf (nconf == NULL). 18180Sstevel@tonic-gate */ 18190Sstevel@tonic-gate goto retry; 18200Sstevel@tonic-gate } 18210Sstevel@tonic-gate } 18220Sstevel@tonic-gate } 18230Sstevel@tonic-gate SET_ERR_RET(error, ERR_PROTO_NONE, 0); 18240Sstevel@tonic-gate 18250Sstevel@tonic-gate /* 18260Sstevel@tonic-gate * Got nconf and nb. Now dup the netconfig structure (nconf) 18270Sstevel@tonic-gate * and return it thru nconfp. 18280Sstevel@tonic-gate */ 18290Sstevel@tonic-gate *nconfp = getnetconfigent(nconf->nc_netid); 18300Sstevel@tonic-gate if (*nconfp == NULL) { 18310Sstevel@tonic-gate syslog(LOG_ERR, "no memory\n"); 18320Sstevel@tonic-gate free(nb); 18330Sstevel@tonic-gate nb = NULL; 18340Sstevel@tonic-gate } 18350Sstevel@tonic-gate done: 18360Sstevel@tonic-gate if (nc) 18370Sstevel@tonic-gate endnetpath(nc); 18380Sstevel@tonic-gate 18390Sstevel@tonic-gate if (nb == NULL) { 184077Soa138391 /* 184177Soa138391 * Check the saved errors. The RPC error has * 184277Soa138391 * precedence over the no host error. 184377Soa138391 */ 184477Soa138391 if (errsave_nohost.error_type != ERR_PROTO_NONE) 184577Soa138391 SET_ERR_RET(error, errsave_nohost.error_type, 18460Sstevel@tonic-gate errsave_nohost.error_value); 184777Soa138391 184877Soa138391 if (errsave_rpcerr.error_type != ERR_PROTO_NONE) 184977Soa138391 SET_ERR_RET(error, errsave_rpcerr.error_type, 18500Sstevel@tonic-gate errsave_rpcerr.error_value); 18510Sstevel@tonic-gate } 185277Soa138391 18530Sstevel@tonic-gate return (nb); 18540Sstevel@tonic-gate } 18550Sstevel@tonic-gate 18560Sstevel@tonic-gate /* 18570Sstevel@tonic-gate * Get a file handle usinging multi-component lookup with the public 18580Sstevel@tonic-gate * file handle. 18590Sstevel@tonic-gate */ 18600Sstevel@tonic-gate static int 18610Sstevel@tonic-gate get_fh_via_pub(struct nfs_args *args, char *fshost, char *fspath, bool_t url, 18620Sstevel@tonic-gate bool_t loud, int *versp, struct netconfig **nconfp, ushort_t port) 18630Sstevel@tonic-gate { 18640Sstevel@tonic-gate uint_t vers_min; 18650Sstevel@tonic-gate uint_t vers_max; 18660Sstevel@tonic-gate int r; 18670Sstevel@tonic-gate char *path; 18680Sstevel@tonic-gate 18690Sstevel@tonic-gate if (nfsvers != 0) { 18700Sstevel@tonic-gate vers_max = vers_min = nfsvers; 18710Sstevel@tonic-gate } else { 18720Sstevel@tonic-gate vers_max = vers_max_default; 18730Sstevel@tonic-gate vers_min = vers_min_default; 18740Sstevel@tonic-gate } 18750Sstevel@tonic-gate 18760Sstevel@tonic-gate if (url == FALSE) { 18770Sstevel@tonic-gate path = malloc(strlen(fspath) + 2); 18780Sstevel@tonic-gate if (path == NULL) { 18790Sstevel@tonic-gate if (loud == TRUE) { 18800Sstevel@tonic-gate pr_err(gettext("no memory\n")); 18810Sstevel@tonic-gate } 18820Sstevel@tonic-gate return (RET_ERR); 18830Sstevel@tonic-gate } 18840Sstevel@tonic-gate 18850Sstevel@tonic-gate path[0] = (char)WNL_NATIVEPATH; 18860Sstevel@tonic-gate (void) strcpy(&path[1], fspath); 18870Sstevel@tonic-gate 18880Sstevel@tonic-gate } else { 18890Sstevel@tonic-gate path = fspath; 18900Sstevel@tonic-gate } 18910Sstevel@tonic-gate 18920Sstevel@tonic-gate for (nfsvers_to_use = vers_max; nfsvers_to_use >= vers_min; 18930Sstevel@tonic-gate nfsvers_to_use--) { 18940Sstevel@tonic-gate /* 18950Sstevel@tonic-gate * getaddr_nfs will also fill in the fh for us. 18960Sstevel@tonic-gate */ 18970Sstevel@tonic-gate r = getaddr_nfs(args, fshost, nconfp, 18980Sstevel@tonic-gate TRUE, path, port, NULL, FALSE); 18990Sstevel@tonic-gate 19000Sstevel@tonic-gate if (r == RET_OK) { 19010Sstevel@tonic-gate /* 19020Sstevel@tonic-gate * Since we are using the public fh, and NLM is 19030Sstevel@tonic-gate * not firewall friendly, use local locking. 19040Sstevel@tonic-gate * Not the case for v4. 19050Sstevel@tonic-gate */ 19060Sstevel@tonic-gate *versp = nfsvers_to_use; 19070Sstevel@tonic-gate switch (nfsvers_to_use) { 19080Sstevel@tonic-gate case NFS_V4: 19090Sstevel@tonic-gate fstype = MNTTYPE_NFS4; 19100Sstevel@tonic-gate break; 19110Sstevel@tonic-gate case NFS_V3: 19120Sstevel@tonic-gate fstype = MNTTYPE_NFS3; 19130Sstevel@tonic-gate /* fall through to pick up llock option */ 19140Sstevel@tonic-gate default: 19150Sstevel@tonic-gate args->flags |= NFSMNT_LLOCK; 19160Sstevel@tonic-gate break; 19170Sstevel@tonic-gate } 19180Sstevel@tonic-gate if (fspath != path) 19190Sstevel@tonic-gate free(path); 19200Sstevel@tonic-gate 19210Sstevel@tonic-gate return (r); 19220Sstevel@tonic-gate } 19230Sstevel@tonic-gate } 19240Sstevel@tonic-gate 19250Sstevel@tonic-gate if (fspath != path) { 19260Sstevel@tonic-gate free(path); 19270Sstevel@tonic-gate } 19280Sstevel@tonic-gate 19290Sstevel@tonic-gate if (loud == TRUE) { 19300Sstevel@tonic-gate pr_err(gettext("Could not use public filehandle in request to" 19310Sstevel@tonic-gate " server %s\n"), fshost); 19320Sstevel@tonic-gate } 19330Sstevel@tonic-gate 19340Sstevel@tonic-gate return (r); 19350Sstevel@tonic-gate } 19360Sstevel@tonic-gate 19370Sstevel@tonic-gate /* 19380Sstevel@tonic-gate * get fhandle of remote path from server's mountd 19390Sstevel@tonic-gate */ 19400Sstevel@tonic-gate static int 19410Sstevel@tonic-gate get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp, 19420Sstevel@tonic-gate bool_t loud_on_mnt_err, struct netconfig **nconfp, ushort_t port) 19430Sstevel@tonic-gate { 19440Sstevel@tonic-gate static struct fhstatus fhs; 19450Sstevel@tonic-gate static struct mountres3 mountres3; 19460Sstevel@tonic-gate static struct pathcnf p; 19470Sstevel@tonic-gate nfs_fh3 *fh3p; 19480Sstevel@tonic-gate struct timeval timeout = { 25, 0}; 19490Sstevel@tonic-gate CLIENT *cl; 19500Sstevel@tonic-gate enum clnt_stat rpc_stat; 19510Sstevel@tonic-gate rpcvers_t outvers = 0; 19520Sstevel@tonic-gate rpcvers_t vers_to_try; 19530Sstevel@tonic-gate rpcvers_t vers_min; 19540Sstevel@tonic-gate static int printed = 0; 19550Sstevel@tonic-gate int count, i, *auths; 19560Sstevel@tonic-gate char *msg; 19570Sstevel@tonic-gate 19580Sstevel@tonic-gate switch (nfsvers) { 19590Sstevel@tonic-gate case 2: /* version 2 specified try that only */ 19600Sstevel@tonic-gate vers_to_try = MOUNTVERS_POSIX; 19610Sstevel@tonic-gate vers_min = MOUNTVERS; 19620Sstevel@tonic-gate break; 19630Sstevel@tonic-gate case 3: /* version 3 specified try that only */ 19640Sstevel@tonic-gate vers_to_try = MOUNTVERS3; 19650Sstevel@tonic-gate vers_min = MOUNTVERS3; 19660Sstevel@tonic-gate break; 19670Sstevel@tonic-gate case 4: /* version 4 specified try that only */ 19680Sstevel@tonic-gate /* 19690Sstevel@tonic-gate * This assignment is in the wrong version sequence. 19700Sstevel@tonic-gate * The above are MOUNT program and this is NFS 19710Sstevel@tonic-gate * program. However, it happens to work out since the 19720Sstevel@tonic-gate * two don't collide for NFSv4. 19730Sstevel@tonic-gate */ 19740Sstevel@tonic-gate vers_to_try = NFS_V4; 19750Sstevel@tonic-gate vers_min = NFS_V4; 19760Sstevel@tonic-gate break; 19770Sstevel@tonic-gate default: /* no version specified, start with default */ 19780Sstevel@tonic-gate vers_to_try = vers_max_default; 19790Sstevel@tonic-gate vers_min = vers_min_default; 19800Sstevel@tonic-gate break; 19810Sstevel@tonic-gate } 19820Sstevel@tonic-gate 19830Sstevel@tonic-gate /* 19840Sstevel@tonic-gate * In the case of version 4, just NULL proc the server since 19850Sstevel@tonic-gate * there is no MOUNT program. If this fails, then decrease 19860Sstevel@tonic-gate * vers_to_try and continue on with regular MOUNT program 19870Sstevel@tonic-gate * processing. 19880Sstevel@tonic-gate */ 19890Sstevel@tonic-gate if (vers_to_try == NFS_V4) { 19900Sstevel@tonic-gate int savevers = nfsvers_to_use; 19910Sstevel@tonic-gate err_ret_t error; 19920Sstevel@tonic-gate int retval; 19930Sstevel@tonic-gate SET_ERR_RET(&error, ERR_PROTO_NONE, 0); 19940Sstevel@tonic-gate 19950Sstevel@tonic-gate /* Let's hope for the best */ 19960Sstevel@tonic-gate nfsvers_to_use = NFS_V4; 19970Sstevel@tonic-gate retval = 19980Sstevel@tonic-gate getaddr_nfs(args, fshost, nconfp, FALSE, 19990Sstevel@tonic-gate fspath, port, &error, vers_min == NFS_V4); 20000Sstevel@tonic-gate 20010Sstevel@tonic-gate if (retval == RET_OK) { 20020Sstevel@tonic-gate *versp = nfsvers_to_use = NFS_V4; 20030Sstevel@tonic-gate fstype = MNTTYPE_NFS4; 20040Sstevel@tonic-gate args->fh = strdup(fspath); 20050Sstevel@tonic-gate if (args->fh == NULL) { 20060Sstevel@tonic-gate pr_err(gettext("no memory\n")); 20070Sstevel@tonic-gate *versp = nfsvers_to_use = savevers; 20080Sstevel@tonic-gate return (RET_ERR); 20090Sstevel@tonic-gate } 20100Sstevel@tonic-gate return (RET_OK); 20110Sstevel@tonic-gate } 20120Sstevel@tonic-gate nfsvers_to_use = savevers; 20130Sstevel@tonic-gate 20140Sstevel@tonic-gate vers_to_try--; 20150Sstevel@tonic-gate /* If no more versions to try, let the user know. */ 20160Sstevel@tonic-gate if (vers_to_try < vers_min) { 20170Sstevel@tonic-gate return (retval); 20180Sstevel@tonic-gate } 20190Sstevel@tonic-gate 20200Sstevel@tonic-gate /* 20210Sstevel@tonic-gate * If we are here, there are more versions to try but 20220Sstevel@tonic-gate * there has been an error of some sort. If it is not 20230Sstevel@tonic-gate * an RPC error (e.g. host unknown), we just stop and 20240Sstevel@tonic-gate * return the error since the other versions would see 20250Sstevel@tonic-gate * the same error as well. 20260Sstevel@tonic-gate */ 20270Sstevel@tonic-gate if (retval == RET_ERR && error.error_type != ERR_RPCERROR) 20280Sstevel@tonic-gate return (retval); 20290Sstevel@tonic-gate } 20300Sstevel@tonic-gate 20310Sstevel@tonic-gate while ((cl = clnt_create_vers(fshost, MOUNTPROG, &outvers, 20320Sstevel@tonic-gate vers_min, vers_to_try, "datagram_v")) == NULL) { 20330Sstevel@tonic-gate if (rpc_createerr.cf_stat == RPC_UNKNOWNHOST) { 20340Sstevel@tonic-gate pr_err(gettext("%s: %s\n"), fshost, 20350Sstevel@tonic-gate clnt_spcreateerror("")); 20360Sstevel@tonic-gate return (RET_ERR); 20370Sstevel@tonic-gate } 20380Sstevel@tonic-gate 20390Sstevel@tonic-gate /* 20400Sstevel@tonic-gate * We don't want to downgrade version on lost packets 20410Sstevel@tonic-gate */ 20420Sstevel@tonic-gate if ((rpc_createerr.cf_stat == RPC_TIMEDOUT) || 20430Sstevel@tonic-gate (rpc_createerr.cf_stat == RPC_PMAPFAILURE)) { 20440Sstevel@tonic-gate pr_err(gettext("%s: %s\n"), fshost, 20450Sstevel@tonic-gate clnt_spcreateerror("")); 20460Sstevel@tonic-gate return (RET_RETRY); 20470Sstevel@tonic-gate } 20480Sstevel@tonic-gate 20490Sstevel@tonic-gate /* 20500Sstevel@tonic-gate * back off and try the previous version - patch to the 20510Sstevel@tonic-gate * problem of version numbers not being contigous and 20520Sstevel@tonic-gate * clnt_create_vers failing (SunOS4.1 clients & SGI servers) 20530Sstevel@tonic-gate * The problem happens with most non-Sun servers who 20540Sstevel@tonic-gate * don't support mountd protocol #2. So, in case the 20550Sstevel@tonic-gate * call fails, we re-try the call anyway. 20560Sstevel@tonic-gate */ 20570Sstevel@tonic-gate vers_to_try--; 20580Sstevel@tonic-gate if (vers_to_try < vers_min) { 20590Sstevel@tonic-gate if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH) { 20600Sstevel@tonic-gate if (nfsvers == 0) { 20610Sstevel@tonic-gate pr_err(gettext( 20620Sstevel@tonic-gate "%s:%s: no applicable versions of NFS supported\n"), 20630Sstevel@tonic-gate fshost, fspath); 20640Sstevel@tonic-gate } else { 20650Sstevel@tonic-gate pr_err(gettext( 20660Sstevel@tonic-gate "%s:%s: NFS Version %d not supported\n"), 20670Sstevel@tonic-gate fshost, fspath, nfsvers); 20680Sstevel@tonic-gate } 20690Sstevel@tonic-gate return (RET_ERR); 20700Sstevel@tonic-gate } 20710Sstevel@tonic-gate if (!printed) { 20720Sstevel@tonic-gate pr_err(gettext("%s: %s\n"), fshost, 20730Sstevel@tonic-gate clnt_spcreateerror("")); 20740Sstevel@tonic-gate printed = 1; 20750Sstevel@tonic-gate } 20760Sstevel@tonic-gate return (RET_RETRY); 20770Sstevel@tonic-gate } 20780Sstevel@tonic-gate } 20790Sstevel@tonic-gate if (posix && outvers < MOUNTVERS_POSIX) { 20800Sstevel@tonic-gate pr_err(gettext("%s: %s: no pathconf info\n"), 20810Sstevel@tonic-gate fshost, clnt_sperror(cl, "")); 20820Sstevel@tonic-gate clnt_destroy(cl); 20830Sstevel@tonic-gate return (RET_ERR); 20840Sstevel@tonic-gate } 20850Sstevel@tonic-gate 20860Sstevel@tonic-gate if (__clnt_bindresvport(cl) < 0) { 20870Sstevel@tonic-gate pr_err(gettext("Couldn't bind to reserved port\n")); 20880Sstevel@tonic-gate clnt_destroy(cl); 20890Sstevel@tonic-gate return (RET_RETRY); 20900Sstevel@tonic-gate } 20910Sstevel@tonic-gate 20920Sstevel@tonic-gate if ((cl->cl_auth = authsys_create_default()) == NULL) { 20930Sstevel@tonic-gate pr_err( 20940Sstevel@tonic-gate gettext("Couldn't create default authentication handle\n")); 20950Sstevel@tonic-gate clnt_destroy(cl); 20960Sstevel@tonic-gate return (RET_RETRY); 20970Sstevel@tonic-gate } 20980Sstevel@tonic-gate 20990Sstevel@tonic-gate switch (outvers) { 21000Sstevel@tonic-gate case MOUNTVERS: 21010Sstevel@tonic-gate case MOUNTVERS_POSIX: 21020Sstevel@tonic-gate *versp = nfsvers_to_use = NFS_VERSION; 21030Sstevel@tonic-gate rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath, 21040Sstevel@tonic-gate (caddr_t)&fspath, xdr_fhstatus, (caddr_t)&fhs, timeout); 21050Sstevel@tonic-gate if (rpc_stat != RPC_SUCCESS) { 21060Sstevel@tonic-gate pr_err(gettext("%s:%s: server not responding %s\n"), 21070Sstevel@tonic-gate fshost, fspath, clnt_sperror(cl, "")); 21080Sstevel@tonic-gate clnt_destroy(cl); 21090Sstevel@tonic-gate return (RET_RETRY); 21100Sstevel@tonic-gate } 21110Sstevel@tonic-gate 21120Sstevel@tonic-gate if ((errno = fhs.fhs_status) != MNT_OK) { 21130Sstevel@tonic-gate if (loud_on_mnt_err) { 21140Sstevel@tonic-gate if (errno == EACCES) { 21150Sstevel@tonic-gate pr_err(gettext("%s:%s: access denied\n"), 21160Sstevel@tonic-gate fshost, fspath); 21170Sstevel@tonic-gate } else { 21180Sstevel@tonic-gate pr_err(gettext("%s:%s: %s\n"), fshost, fspath, 21190Sstevel@tonic-gate strerror(errno)); 21200Sstevel@tonic-gate } 21210Sstevel@tonic-gate } 21220Sstevel@tonic-gate clnt_destroy(cl); 21230Sstevel@tonic-gate return (RET_MNTERR); 21240Sstevel@tonic-gate } 21250Sstevel@tonic-gate args->fh = malloc(sizeof (fhs.fhstatus_u.fhs_fhandle)); 21260Sstevel@tonic-gate if (args->fh == NULL) { 21270Sstevel@tonic-gate pr_err(gettext("no memory\n")); 21280Sstevel@tonic-gate return (RET_ERR); 21290Sstevel@tonic-gate } 21300Sstevel@tonic-gate memcpy((caddr_t)args->fh, (caddr_t)&fhs.fhstatus_u.fhs_fhandle, 21310Sstevel@tonic-gate sizeof (fhs.fhstatus_u.fhs_fhandle)); 21320Sstevel@tonic-gate if (!errno && posix) { 21330Sstevel@tonic-gate rpc_stat = clnt_call(cl, MOUNTPROC_PATHCONF, 21340Sstevel@tonic-gate xdr_dirpath, (caddr_t)&fspath, xdr_ppathcnf, 21350Sstevel@tonic-gate (caddr_t)&p, timeout); 21360Sstevel@tonic-gate if (rpc_stat != RPC_SUCCESS) { 21370Sstevel@tonic-gate pr_err(gettext( 21380Sstevel@tonic-gate "%s:%s: server not responding %s\n"), 21390Sstevel@tonic-gate fshost, fspath, clnt_sperror(cl, "")); 21400Sstevel@tonic-gate free(args->fh); 21410Sstevel@tonic-gate clnt_destroy(cl); 21420Sstevel@tonic-gate return (RET_RETRY); 21430Sstevel@tonic-gate } 21440Sstevel@tonic-gate if (_PC_ISSET(_PC_ERROR, p.pc_mask)) { 21450Sstevel@tonic-gate pr_err(gettext( 21460Sstevel@tonic-gate "%s:%s: no pathconf info\n"), 21470Sstevel@tonic-gate fshost, fspath); 21480Sstevel@tonic-gate free(args->fh); 21490Sstevel@tonic-gate clnt_destroy(cl); 21500Sstevel@tonic-gate return (RET_ERR); 21510Sstevel@tonic-gate } 21520Sstevel@tonic-gate args->flags |= NFSMNT_POSIX; 21530Sstevel@tonic-gate args->pathconf = malloc(sizeof (p)); 21540Sstevel@tonic-gate if (args->pathconf == NULL) { 21550Sstevel@tonic-gate pr_err(gettext("no memory\n")); 21560Sstevel@tonic-gate free(args->fh); 21570Sstevel@tonic-gate clnt_destroy(cl); 21580Sstevel@tonic-gate return (RET_ERR); 21590Sstevel@tonic-gate } 21600Sstevel@tonic-gate memcpy((caddr_t)args->pathconf, (caddr_t)&p, 21610Sstevel@tonic-gate sizeof (p)); 21620Sstevel@tonic-gate } 21630Sstevel@tonic-gate break; 21640Sstevel@tonic-gate 21650Sstevel@tonic-gate case MOUNTVERS3: 21660Sstevel@tonic-gate *versp = nfsvers_to_use = NFS_V3; 21670Sstevel@tonic-gate rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath, 21680Sstevel@tonic-gate (caddr_t)&fspath, 21690Sstevel@tonic-gate xdr_mountres3, (caddr_t)&mountres3, timeout); 21700Sstevel@tonic-gate if (rpc_stat != RPC_SUCCESS) { 21710Sstevel@tonic-gate pr_err(gettext("%s:%s: server not responding %s\n"), 21720Sstevel@tonic-gate fshost, fspath, clnt_sperror(cl, "")); 21730Sstevel@tonic-gate clnt_destroy(cl); 21740Sstevel@tonic-gate return (RET_RETRY); 21750Sstevel@tonic-gate } 21760Sstevel@tonic-gate 21770Sstevel@tonic-gate /* 21780Sstevel@tonic-gate * Assume here that most of the MNT3ERR_* 21790Sstevel@tonic-gate * codes map into E* errors. 21800Sstevel@tonic-gate */ 21810Sstevel@tonic-gate if ((errno = mountres3.fhs_status) != MNT_OK) { 21820Sstevel@tonic-gate if (loud_on_mnt_err) { 21830Sstevel@tonic-gate switch (errno) { 21840Sstevel@tonic-gate case MNT3ERR_NAMETOOLONG: 21850Sstevel@tonic-gate msg = "path name is too long"; 21860Sstevel@tonic-gate break; 21870Sstevel@tonic-gate case MNT3ERR_NOTSUPP: 21880Sstevel@tonic-gate msg = "operation not supported"; 21890Sstevel@tonic-gate break; 21900Sstevel@tonic-gate case MNT3ERR_SERVERFAULT: 21910Sstevel@tonic-gate msg = "server fault"; 21920Sstevel@tonic-gate break; 21930Sstevel@tonic-gate default: 21940Sstevel@tonic-gate msg = strerror(errno); 21950Sstevel@tonic-gate break; 21960Sstevel@tonic-gate } 21970Sstevel@tonic-gate pr_err(gettext("%s:%s: %s\n"), fshost, fspath, msg); 21980Sstevel@tonic-gate } 21990Sstevel@tonic-gate clnt_destroy(cl); 22000Sstevel@tonic-gate return (RET_MNTERR); 22010Sstevel@tonic-gate } 22020Sstevel@tonic-gate 22030Sstevel@tonic-gate fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p)); 22040Sstevel@tonic-gate if (fh3p == NULL) { 22050Sstevel@tonic-gate pr_err(gettext("no memory\n")); 22060Sstevel@tonic-gate return (RET_ERR); 22070Sstevel@tonic-gate } 22080Sstevel@tonic-gate fh3p->fh3_length = 22090Sstevel@tonic-gate mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len; 22100Sstevel@tonic-gate (void) memcpy(fh3p->fh3_u.data, 22110Sstevel@tonic-gate mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val, 22120Sstevel@tonic-gate fh3p->fh3_length); 22130Sstevel@tonic-gate args->fh = (caddr_t)fh3p; 22140Sstevel@tonic-gate fstype = MNTTYPE_NFS3; 22150Sstevel@tonic-gate 22160Sstevel@tonic-gate /* 22170Sstevel@tonic-gate * Check the security flavor to be used. 22180Sstevel@tonic-gate * 22190Sstevel@tonic-gate * If "secure" or "sec=flavor" is a mount 22200Sstevel@tonic-gate * option, check if the server supports the "flavor". 22210Sstevel@tonic-gate * If the server does not support the flavor, return 22220Sstevel@tonic-gate * error. 22230Sstevel@tonic-gate * 22240Sstevel@tonic-gate * If no mount option is given then use the first supported 22250Sstevel@tonic-gate * security flavor (by the client) in the auth list returned 22260Sstevel@tonic-gate * from the server. 22270Sstevel@tonic-gate * 22280Sstevel@tonic-gate */ 22290Sstevel@tonic-gate auths = 22300Sstevel@tonic-gate mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val; 22310Sstevel@tonic-gate count = 22320Sstevel@tonic-gate mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len; 22330Sstevel@tonic-gate 22340Sstevel@tonic-gate if (sec_opt) { 22350Sstevel@tonic-gate for (i = 0; i < count; i++) { 22360Sstevel@tonic-gate if (auths[i] == nfs_sec.sc_nfsnum) 22370Sstevel@tonic-gate break; 22380Sstevel@tonic-gate } 22390Sstevel@tonic-gate if (i >= count) { 22400Sstevel@tonic-gate goto autherr; 22410Sstevel@tonic-gate } 22420Sstevel@tonic-gate } else { 22430Sstevel@tonic-gate if (count > 0) { 22440Sstevel@tonic-gate for (i = 0; i < count; i++) { 22450Sstevel@tonic-gate if (!nfs_getseconfig_bynumber(auths[i], &nfs_sec)) { 22460Sstevel@tonic-gate sec_opt++; 22470Sstevel@tonic-gate break; 22480Sstevel@tonic-gate } 22490Sstevel@tonic-gate } 22500Sstevel@tonic-gate if (i >= count) { 22510Sstevel@tonic-gate goto autherr; 22520Sstevel@tonic-gate } 22530Sstevel@tonic-gate } 22540Sstevel@tonic-gate } 22550Sstevel@tonic-gate break; 22560Sstevel@tonic-gate default: 22570Sstevel@tonic-gate pr_err(gettext("%s:%s: Unknown MOUNT version %d\n"), 22580Sstevel@tonic-gate fshost, fspath, outvers); 22590Sstevel@tonic-gate clnt_destroy(cl); 22600Sstevel@tonic-gate return (RET_ERR); 22610Sstevel@tonic-gate } 22620Sstevel@tonic-gate 22630Sstevel@tonic-gate clnt_destroy(cl); 22640Sstevel@tonic-gate return (RET_OK); 22650Sstevel@tonic-gate 22660Sstevel@tonic-gate autherr: 22670Sstevel@tonic-gate pr_err(gettext( 22680Sstevel@tonic-gate "security mode does not match the server exporting %s:%s\n"), 22690Sstevel@tonic-gate fshost, fspath); 22700Sstevel@tonic-gate clnt_destroy(cl); 22710Sstevel@tonic-gate return (RET_ERR); 22720Sstevel@tonic-gate } 22730Sstevel@tonic-gate 22740Sstevel@tonic-gate /* 22750Sstevel@tonic-gate * Fill in the address for the server's NFS service and 22760Sstevel@tonic-gate * fill in a knetconfig structure for the transport that 22770Sstevel@tonic-gate * the service is available on. 22780Sstevel@tonic-gate */ 22790Sstevel@tonic-gate static int 22800Sstevel@tonic-gate getaddr_nfs(struct nfs_args *args, char *fshost, struct netconfig **nconfp, 22810Sstevel@tonic-gate bool_t get_pubfh, char *fspath, ushort_t port, err_ret_t *error, 22820Sstevel@tonic-gate bool_t print_rpcerror) 22830Sstevel@tonic-gate { 22840Sstevel@tonic-gate struct stat sb; 22850Sstevel@tonic-gate struct netconfig *nconf; 22860Sstevel@tonic-gate struct knetconfig *knconfp; 22870Sstevel@tonic-gate static int printed = 0; 22880Sstevel@tonic-gate struct t_info tinfo; 22890Sstevel@tonic-gate err_ret_t addr_error; 22900Sstevel@tonic-gate 22910Sstevel@tonic-gate SET_ERR_RET(error, ERR_PROTO_NONE, 0); 22920Sstevel@tonic-gate SET_ERR_RET(&addr_error, ERR_PROTO_NONE, 0); 22930Sstevel@tonic-gate 22940Sstevel@tonic-gate if (nfs_proto) { 22950Sstevel@tonic-gate /* 22960Sstevel@tonic-gate * If a proto is specified and its rdma try this. The kernel 22970Sstevel@tonic-gate * will later do the reachablity test and fail form there 22980Sstevel@tonic-gate * if rdma transport is not available to kernel rpc 22990Sstevel@tonic-gate */ 23000Sstevel@tonic-gate if (strcmp(nfs_proto, "rdma") == 0) { 23010Sstevel@tonic-gate args->addr = get_addr(fshost, NFS_PROGRAM, 23020Sstevel@tonic-gate nfsvers_to_use, nconfp, NULL, port, &tinfo, 23030Sstevel@tonic-gate &args->fh, get_pubfh, fspath, &addr_error); 23040Sstevel@tonic-gate 23050Sstevel@tonic-gate args->flags |= NFSMNT_DORDMA; 23060Sstevel@tonic-gate } else { 23070Sstevel@tonic-gate args->addr = get_addr(fshost, NFS_PROGRAM, 23080Sstevel@tonic-gate nfsvers_to_use, nconfp, nfs_proto, port, &tinfo, 23090Sstevel@tonic-gate &args->fh, get_pubfh, fspath, &addr_error); 23100Sstevel@tonic-gate } 23110Sstevel@tonic-gate } else { 23120Sstevel@tonic-gate args->addr = get_addr(fshost, NFS_PROGRAM, nfsvers_to_use, 23130Sstevel@tonic-gate nconfp, nfs_proto, port, &tinfo, &args->fh, get_pubfh, 23140Sstevel@tonic-gate fspath, &addr_error); 23150Sstevel@tonic-gate /* 23160Sstevel@tonic-gate * If no proto is specified set this flag. 23170Sstevel@tonic-gate * Kernel mount code will try to use RDMA if its on the 23180Sstevel@tonic-gate * system, otherwise it will keep on using the protocol 23190Sstevel@tonic-gate * selected here, through the above get_addr call. 23200Sstevel@tonic-gate */ 23210Sstevel@tonic-gate if (nfs_proto == NULL) 23220Sstevel@tonic-gate args->flags |= NFSMNT_TRYRDMA; 23230Sstevel@tonic-gate } 23240Sstevel@tonic-gate 23250Sstevel@tonic-gate if (args->addr == NULL) { 23260Sstevel@tonic-gate /* 23270Sstevel@tonic-gate * We could have failed because the server had no public 23280Sstevel@tonic-gate * file handle support. So don't print a message and don't 23290Sstevel@tonic-gate * retry. 23300Sstevel@tonic-gate */ 23310Sstevel@tonic-gate if (get_pubfh == TRUE) 23320Sstevel@tonic-gate return (RET_ERR); 23330Sstevel@tonic-gate 23340Sstevel@tonic-gate if (!printed) { 23350Sstevel@tonic-gate switch (addr_error.error_type) { 23360Sstevel@tonic-gate case 0: 23370Sstevel@tonic-gate break; 23380Sstevel@tonic-gate case ERR_RPCERROR: 23390Sstevel@tonic-gate if (!print_rpcerror) 23400Sstevel@tonic-gate /* no error print at this time */ 23410Sstevel@tonic-gate break; 23420Sstevel@tonic-gate pr_err(gettext("%s NFS service not" 23430Sstevel@tonic-gate " available %s\n"), fshost, 23440Sstevel@tonic-gate clnt_sperrno(addr_error.error_value)); 23450Sstevel@tonic-gate break; 23460Sstevel@tonic-gate case ERR_NETPATH: 23470Sstevel@tonic-gate pr_err(gettext("%s: Error in NETPATH.\n"), 23480Sstevel@tonic-gate fshost); 23490Sstevel@tonic-gate break; 23500Sstevel@tonic-gate case ERR_PROTO_INVALID: 23510Sstevel@tonic-gate pr_err(gettext("%s: NFS service does not" 23520Sstevel@tonic-gate " recognize protocol: %s.\n"), fshost, 23530Sstevel@tonic-gate nfs_proto); 23540Sstevel@tonic-gate break; 23550Sstevel@tonic-gate case ERR_PROTO_UNSUPP: 2356*112Soa138391 if (nfsvers_to_use == NFS_VERSMIN) { 2357*112Soa138391 /* 2358*112Soa138391 * Print this message after we have 2359*112Soa138391 * tried all versions of NFS and none 2360*112Soa138391 * support the asked transport. 2361*112Soa138391 * Otherwise we depricate the version 2362*112Soa138391 * and retry below. 2363*112Soa138391 */ 2364*112Soa138391 pr_err(gettext("%s: NFS service does" 2365*112Soa138391 " not support protocol: %s.\n"), 2366*112Soa138391 fshost, nfs_proto); 2367*112Soa138391 } 23680Sstevel@tonic-gate break; 23690Sstevel@tonic-gate case ERR_NOHOST: 237077Soa138391 pr_err("%s: %s\n", fshost, "Unknown host"); 23710Sstevel@tonic-gate break; 23720Sstevel@tonic-gate default: 23730Sstevel@tonic-gate /* case ERR_PROTO_NONE falls through */ 23740Sstevel@tonic-gate pr_err(gettext("%s: NFS service not responding" 23750Sstevel@tonic-gate "\n"), fshost); 23760Sstevel@tonic-gate break; 23770Sstevel@tonic-gate } 23780Sstevel@tonic-gate printed = 1; 23790Sstevel@tonic-gate } 23800Sstevel@tonic-gate SET_ERR_RET(error, 23810Sstevel@tonic-gate addr_error.error_type, addr_error.error_value); 23820Sstevel@tonic-gate if (addr_error.error_type == ERR_PROTO_NONE) 23830Sstevel@tonic-gate return (RET_RETRY); 23840Sstevel@tonic-gate else if (addr_error.error_type == ERR_RPCERROR && 23850Sstevel@tonic-gate ! IS_UNRECOVERABLE_RPC(addr_error.error_value)) { 23860Sstevel@tonic-gate return (RET_RETRY); 2387*112Soa138391 } else if (nfsvers == 0 && addr_error.error_type == 2388*112Soa138391 ERR_PROTO_UNSUPP && nfsvers_to_use != NFS_VERSMIN) { 2389*112Soa138391 /* 2390*112Soa138391 * If no version is specified, and the error is due 2391*112Soa138391 * to an unsupported transport, then depricate the 2392*112Soa138391 * version and retry. 2393*112Soa138391 */ 2394*112Soa138391 return (RET_RETRY); 2395*112Soa138391 } else 23960Sstevel@tonic-gate return (RET_ERR); 23970Sstevel@tonic-gate } 23980Sstevel@tonic-gate nconf = *nconfp; 23990Sstevel@tonic-gate 24000Sstevel@tonic-gate if (stat(nconf->nc_device, &sb) < 0) { 24010Sstevel@tonic-gate pr_err(gettext("getaddr_nfs: couldn't stat: %s: %s\n"), 24020Sstevel@tonic-gate nconf->nc_device, strerror(errno)); 24030Sstevel@tonic-gate return (RET_ERR); 24040Sstevel@tonic-gate } 24050Sstevel@tonic-gate 24060Sstevel@tonic-gate knconfp = (struct knetconfig *)malloc(sizeof (*knconfp)); 24070Sstevel@tonic-gate if (!knconfp) { 24080Sstevel@tonic-gate pr_err(gettext("no memory\n")); 24090Sstevel@tonic-gate return (RET_ERR); 24100Sstevel@tonic-gate } 24110Sstevel@tonic-gate knconfp->knc_semantics = nconf->nc_semantics; 24120Sstevel@tonic-gate knconfp->knc_protofmly = nconf->nc_protofmly; 24130Sstevel@tonic-gate knconfp->knc_proto = nconf->nc_proto; 24140Sstevel@tonic-gate knconfp->knc_rdev = sb.st_rdev; 24150Sstevel@tonic-gate 24160Sstevel@tonic-gate /* make sure we don't overload the transport */ 24170Sstevel@tonic-gate if (tinfo.tsdu > 0 && tinfo.tsdu < NFS_MAXDATA + NFS_RPC_HDR) { 24180Sstevel@tonic-gate args->flags |= (NFSMNT_RSIZE | NFSMNT_WSIZE); 24190Sstevel@tonic-gate if (args->rsize == 0 || args->rsize > tinfo.tsdu - NFS_RPC_HDR) 24200Sstevel@tonic-gate args->rsize = tinfo.tsdu - NFS_RPC_HDR; 24210Sstevel@tonic-gate if (args->wsize == 0 || args->wsize > tinfo.tsdu - NFS_RPC_HDR) 24220Sstevel@tonic-gate args->wsize = tinfo.tsdu - NFS_RPC_HDR; 24230Sstevel@tonic-gate } 24240Sstevel@tonic-gate 24250Sstevel@tonic-gate args->flags |= NFSMNT_KNCONF; 24260Sstevel@tonic-gate args->knconf = knconfp; 24270Sstevel@tonic-gate return (RET_OK); 24280Sstevel@tonic-gate } 24290Sstevel@tonic-gate 24300Sstevel@tonic-gate static int 24310Sstevel@tonic-gate retry(struct mnttab *mntp, int ro) 24320Sstevel@tonic-gate { 24330Sstevel@tonic-gate int delay = 5; 24340Sstevel@tonic-gate int count = retries; 24350Sstevel@tonic-gate int r; 24360Sstevel@tonic-gate 24370Sstevel@tonic-gate if (bg) { 24380Sstevel@tonic-gate if (fork() > 0) 24390Sstevel@tonic-gate return (RET_OK); 24400Sstevel@tonic-gate pr_err(gettext("backgrounding: %s\n"), mntp->mnt_mountp); 24410Sstevel@tonic-gate backgrounded = 1; 24420Sstevel@tonic-gate } else 24430Sstevel@tonic-gate pr_err(gettext("retrying: %s\n"), mntp->mnt_mountp); 24440Sstevel@tonic-gate 24450Sstevel@tonic-gate while (count--) { 24460Sstevel@tonic-gate if ((r = mount_nfs(mntp, ro)) == RET_OK) { 24470Sstevel@tonic-gate pr_err(gettext("%s: mounted OK\n"), mntp->mnt_mountp); 24480Sstevel@tonic-gate return (RET_OK); 24490Sstevel@tonic-gate } 24500Sstevel@tonic-gate if (r != RET_RETRY) 24510Sstevel@tonic-gate break; 24520Sstevel@tonic-gate 24530Sstevel@tonic-gate if (count > 0) { 24540Sstevel@tonic-gate (void) sleep(delay); 24550Sstevel@tonic-gate delay *= 2; 24560Sstevel@tonic-gate if (delay > 120) 24570Sstevel@tonic-gate delay = 120; 24580Sstevel@tonic-gate } 24590Sstevel@tonic-gate } 24600Sstevel@tonic-gate pr_err(gettext("giving up on: %s\n"), mntp->mnt_mountp); 24610Sstevel@tonic-gate return (RET_ERR); 24620Sstevel@tonic-gate } 24630Sstevel@tonic-gate 24640Sstevel@tonic-gate /* 24650Sstevel@tonic-gate * Read the /etc/default/nfs configuration file to determine if the 24660Sstevel@tonic-gate * client has been configured for a new min/max for the NFS version to 24670Sstevel@tonic-gate * use. 24680Sstevel@tonic-gate */ 24690Sstevel@tonic-gate static void 24700Sstevel@tonic-gate read_default(void) 24710Sstevel@tonic-gate { 24720Sstevel@tonic-gate char *defval; 24730Sstevel@tonic-gate int errno; 24740Sstevel@tonic-gate int tmp; 24750Sstevel@tonic-gate 24760Sstevel@tonic-gate /* Fail silently if error in opening the default nfs config file */ 24770Sstevel@tonic-gate if ((defopen(NFSADMIN)) == 0) { 24780Sstevel@tonic-gate if ((defval = defread("NFS_CLIENT_VERSMIN=")) != NULL) { 24790Sstevel@tonic-gate errno = 0; 24800Sstevel@tonic-gate tmp = strtol(defval, (char **)NULL, 10); 24810Sstevel@tonic-gate if (errno == 0) { 24820Sstevel@tonic-gate vers_min_default = tmp; 24830Sstevel@tonic-gate } 24840Sstevel@tonic-gate } 24850Sstevel@tonic-gate if ((defval = defread("NFS_CLIENT_VERSMAX=")) != NULL) { 24860Sstevel@tonic-gate errno = 0; 24870Sstevel@tonic-gate tmp = strtol(defval, (char **)NULL, 10); 24880Sstevel@tonic-gate if (errno == 0) { 24890Sstevel@tonic-gate vers_max_default = tmp; 24900Sstevel@tonic-gate } 24910Sstevel@tonic-gate } 24920Sstevel@tonic-gate /* close defaults file */ 24930Sstevel@tonic-gate defopen(NULL); 24940Sstevel@tonic-gate } 24950Sstevel@tonic-gate } 24960Sstevel@tonic-gate 24970Sstevel@tonic-gate static void 24980Sstevel@tonic-gate sigusr1(int s) 24990Sstevel@tonic-gate { 25000Sstevel@tonic-gate } 2501