17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 545916cd2Sjpk * Common Development and Distribution License (the "License"). 645916cd2Sjpk * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21bbe876c0SMarcel Telka 227c478bd9Sstevel@tonic-gate /* 23bbe876c0SMarcel Telka * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 24a05556d6SNagakiran Rajashekar * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <stdio.h> 287c478bd9Sstevel@tonic-gate #include <unistd.h> 297c478bd9Sstevel@tonic-gate #include <stdlib.h> 307c478bd9Sstevel@tonic-gate #include <ctype.h> 317c478bd9Sstevel@tonic-gate #include <syslog.h> 327c478bd9Sstevel@tonic-gate #include <string.h> 337c478bd9Sstevel@tonic-gate #include <deflt.h> 347c478bd9Sstevel@tonic-gate #include <kstat.h> 357c478bd9Sstevel@tonic-gate #include <sys/param.h> 367c478bd9Sstevel@tonic-gate #include <sys/types.h> 377c478bd9Sstevel@tonic-gate #include <sys/time.h> 387c478bd9Sstevel@tonic-gate #include <sys/stat.h> 397c478bd9Sstevel@tonic-gate #include <sys/wait.h> 407c478bd9Sstevel@tonic-gate #include <sys/socket.h> 417c478bd9Sstevel@tonic-gate #include <netinet/in.h> 427c478bd9Sstevel@tonic-gate #include <signal.h> 437c478bd9Sstevel@tonic-gate #include <sys/signal.h> 447c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 457c478bd9Sstevel@tonic-gate #include <rpc/pmap_clnt.h> 467c478bd9Sstevel@tonic-gate #include <sys/mount.h> 477c478bd9Sstevel@tonic-gate #include <sys/mntent.h> 487c478bd9Sstevel@tonic-gate #include <sys/mnttab.h> 497c478bd9Sstevel@tonic-gate #include <sys/fstyp.h> 507c478bd9Sstevel@tonic-gate #include <sys/fsid.h> 517c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 527c478bd9Sstevel@tonic-gate #include <netdb.h> 537c478bd9Sstevel@tonic-gate #include <netconfig.h> 547c478bd9Sstevel@tonic-gate #include <netdir.h> 557c478bd9Sstevel@tonic-gate #include <errno.h> 567c478bd9Sstevel@tonic-gate #define NFSCLIENT 577c478bd9Sstevel@tonic-gate #include <nfs/nfs.h> 587c478bd9Sstevel@tonic-gate #include <nfs/mount.h> 597c478bd9Sstevel@tonic-gate #include <rpcsvc/mount.h> 607c478bd9Sstevel@tonic-gate #include <rpc/nettype.h> 617c478bd9Sstevel@tonic-gate #include <locale.h> 627c478bd9Sstevel@tonic-gate #include <setjmp.h> 637c478bd9Sstevel@tonic-gate #include <sys/socket.h> 647c478bd9Sstevel@tonic-gate #include <thread.h> 657c478bd9Sstevel@tonic-gate #include <limits.h> 667c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h> /* for NSS_BUFLEN_HOSTS */ 677c478bd9Sstevel@tonic-gate #include <nfs/nfs_sec.h> 687c478bd9Sstevel@tonic-gate #include <sys/sockio.h> 697c478bd9Sstevel@tonic-gate #include <net/if.h> 707c478bd9Sstevel@tonic-gate #include <assert.h> 717c478bd9Sstevel@tonic-gate #include <nfs/nfs_clnt.h> 727c478bd9Sstevel@tonic-gate #include <rpcsvc/nfs4_prot.h> 73bbe876c0SMarcel Telka #include <nfs/nfs4.h> 747c478bd9Sstevel@tonic-gate #define NO_RDDIR_CACHE 757c478bd9Sstevel@tonic-gate #include "automount.h" 767c478bd9Sstevel@tonic-gate #include "replica.h" 777c478bd9Sstevel@tonic-gate #include "nfs_subr.h" 787c478bd9Sstevel@tonic-gate #include "webnfs.h" 792f172c55SRobert Thurlow #include "nfs_resolve.h" 807c478bd9Sstevel@tonic-gate #include <sys/sockio.h> 817c478bd9Sstevel@tonic-gate #include <net/if.h> 827c478bd9Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h> 8345916cd2Sjpk #include <pwd.h> 8445916cd2Sjpk #include <strings.h> 8545916cd2Sjpk #include <tsol/label.h> 8645916cd2Sjpk #include <zone.h> 87dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <limits.h> 88dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <libscf.h> 89dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <libshare.h> 90dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include "smfcfg.h" 917c478bd9Sstevel@tonic-gate 92b9238976Sth199096 extern void set_nfsv4_ephemeral_mount_to(void); 93b9238976Sth199096 947c478bd9Sstevel@tonic-gate extern char *nfs_get_qop_name(); 957c478bd9Sstevel@tonic-gate extern AUTH *nfs_create_ah(); 967c478bd9Sstevel@tonic-gate extern enum snego_stat nfs_sec_nego(); 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate #define MAXHOSTS 512 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate /* 1017c478bd9Sstevel@tonic-gate * host cache states 1027c478bd9Sstevel@tonic-gate */ 1037c478bd9Sstevel@tonic-gate #define NOHOST 0 1047c478bd9Sstevel@tonic-gate #define GOODHOST 1 1057c478bd9Sstevel@tonic-gate #define DEADHOST 2 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate #define NFS_ARGS_EXTB_secdata(args, secdata) \ 1087c478bd9Sstevel@tonic-gate { (args).nfs_args_ext = NFS_ARGS_EXTB, \ 1097c478bd9Sstevel@tonic-gate (args).nfs_ext_u.nfs_extB.secdata = secdata; } 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate struct cache_entry { 1127c478bd9Sstevel@tonic-gate struct cache_entry *cache_next; 1137c478bd9Sstevel@tonic-gate char *cache_host; 1147c478bd9Sstevel@tonic-gate time_t cache_time; 1157c478bd9Sstevel@tonic-gate int cache_state; 1167c478bd9Sstevel@tonic-gate rpcvers_t cache_reqvers; 1177c478bd9Sstevel@tonic-gate rpcvers_t cache_outvers; 1187c478bd9Sstevel@tonic-gate char *cache_proto; 1197c478bd9Sstevel@tonic-gate }; 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate struct mfs_snego_t { 1227c478bd9Sstevel@tonic-gate int sec_opt; 1237c478bd9Sstevel@tonic-gate bool_t snego_done; 1247c478bd9Sstevel@tonic-gate char *nfs_flavor; 1257c478bd9Sstevel@tonic-gate seconfig_t nfs_sec; 1267c478bd9Sstevel@tonic-gate }; 1277c478bd9Sstevel@tonic-gate typedef struct mfs_snego_t mfs_snego_t; 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate static struct cache_entry *cache_head = NULL; 1307c478bd9Sstevel@tonic-gate rwlock_t cache_lock; /* protect the cache chain */ 1317c478bd9Sstevel@tonic-gate 132*bd93c05dSAlexander Eremin static enum nfsstat nfsmount(struct mapfs *, char *, char *, int, uid_t, 1333bfb48feSsemery action_list *); 1347c478bd9Sstevel@tonic-gate static int is_nfs_port(char *); 1357c478bd9Sstevel@tonic-gate 1362f172c55SRobert Thurlow static void netbuf_free(struct netbuf *); 1377c478bd9Sstevel@tonic-gate static int get_pathconf(CLIENT *, char *, char *, struct pathcnf **, int); 1387c478bd9Sstevel@tonic-gate static struct mapfs *enum_servers(struct mapent *, char *); 1397c478bd9Sstevel@tonic-gate static struct mapfs *get_mysubnet_servers(struct mapfs *); 1407c478bd9Sstevel@tonic-gate static int subnet_test(int af, struct sioc_addrreq *); 1417c478bd9Sstevel@tonic-gate static struct netbuf *get_addr(char *, rpcprog_t, rpcvers_t, 1427c478bd9Sstevel@tonic-gate struct netconfig **, char *, ushort_t, struct t_info *); 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate static struct netbuf *get_pubfh(char *, rpcvers_t, mfs_snego_t *, 1457c478bd9Sstevel@tonic-gate struct netconfig **, char *, ushort_t, struct t_info *, caddr_t *, 1467c478bd9Sstevel@tonic-gate bool_t, char *); 1477c478bd9Sstevel@tonic-gate 14845916cd2Sjpk static int create_homedir(const char *, const char *); 14945916cd2Sjpk 1507c478bd9Sstevel@tonic-gate enum type_of_stuff { 1517c478bd9Sstevel@tonic-gate SERVER_ADDR = 0, 1527c478bd9Sstevel@tonic-gate SERVER_PING = 1, 1537c478bd9Sstevel@tonic-gate SERVER_FH = 2 1547c478bd9Sstevel@tonic-gate }; 1557c478bd9Sstevel@tonic-gate 1562f172c55SRobert Thurlow static void *get_server_netinfo(enum type_of_stuff, char *, rpcprog_t, 1577c478bd9Sstevel@tonic-gate rpcvers_t, mfs_snego_t *, struct netconfig **, char *, ushort_t, 1587c478bd9Sstevel@tonic-gate struct t_info *, caddr_t *, bool_t, char *, enum clnt_stat *); 1592f172c55SRobert Thurlow static void *get_netconfig_info(enum type_of_stuff, char *, rpcprog_t, 1602f172c55SRobert Thurlow rpcvers_t, struct netconfig *, ushort_t, struct t_info *, 1612f172c55SRobert Thurlow struct t_bind *, caddr_t *, bool_t, char *, enum clnt_stat *, 1622f172c55SRobert Thurlow mfs_snego_t *); 1632f172c55SRobert Thurlow static void *get_server_addrorping(char *, rpcprog_t, rpcvers_t, 1642f172c55SRobert Thurlow struct netconfig *, ushort_t, struct t_info *, struct t_bind *, 1652f172c55SRobert Thurlow caddr_t *, bool_t, char *, enum clnt_stat *, int); 1662f172c55SRobert Thurlow static void *get_server_fh(char *, rpcprog_t, rpcvers_t, mfs_snego_t *, 1672f172c55SRobert Thurlow struct netconfig *, ushort_t, struct t_info *, struct t_bind *, 1687c478bd9Sstevel@tonic-gate caddr_t *, bool_t, char *, enum clnt_stat *); 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate struct mapfs *add_mfs(struct mapfs *, int, struct mapfs **, struct mapfs **); 1717c478bd9Sstevel@tonic-gate void free_mfs(struct mapfs *); 1727c478bd9Sstevel@tonic-gate static void dump_mfs(struct mapfs *, char *, int); 1737c478bd9Sstevel@tonic-gate static char *dump_distance(struct mapfs *); 1747c478bd9Sstevel@tonic-gate static void cache_free(struct cache_entry *); 1757c478bd9Sstevel@tonic-gate static int cache_check(char *, rpcvers_t *, char *); 1767c478bd9Sstevel@tonic-gate static void cache_enter(char *, rpcvers_t, rpcvers_t, char *, int); 17739d3e169Sevanl void destroy_auth_client_handle(CLIENT *cl); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate #ifdef CACHE_DEBUG 1807c478bd9Sstevel@tonic-gate static void trace_host_cache(); 1817c478bd9Sstevel@tonic-gate static void trace_portmap_cache(); 1827c478bd9Sstevel@tonic-gate #endif /* CACHE_DEBUG */ 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate static int rpc_timeout = 20; 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate #ifdef CACHE_DEBUG 1877c478bd9Sstevel@tonic-gate /* 1887c478bd9Sstevel@tonic-gate * host cache counters. These variables do not need to be protected 1897c478bd9Sstevel@tonic-gate * by mutex's. They have been added to measure the utility of the 1907c478bd9Sstevel@tonic-gate * goodhost/deadhost cache in the lazy hierarchical mounting scheme. 1917c478bd9Sstevel@tonic-gate */ 1927c478bd9Sstevel@tonic-gate static int host_cache_accesses = 0; 1937c478bd9Sstevel@tonic-gate static int host_cache_lookups = 0; 1947c478bd9Sstevel@tonic-gate static int deadhost_cache_hits = 0; 1957c478bd9Sstevel@tonic-gate static int goodhost_cache_hits = 0; 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate /* 1987c478bd9Sstevel@tonic-gate * portmap cache counters. These variables do not need to be protected 1997c478bd9Sstevel@tonic-gate * by mutex's. They have been added to measure the utility of the portmap 2007c478bd9Sstevel@tonic-gate * cache in the lazy hierarchical mounting scheme. 2017c478bd9Sstevel@tonic-gate */ 2027c478bd9Sstevel@tonic-gate static int portmap_cache_accesses = 0; 2037c478bd9Sstevel@tonic-gate static int portmap_cache_lookups = 0; 2047c478bd9Sstevel@tonic-gate static int portmap_cache_hits = 0; 2057c478bd9Sstevel@tonic-gate #endif /* CACHE_DEBUG */ 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate /* 2087c478bd9Sstevel@tonic-gate * There are the defaults (range) for the client when determining 2097c478bd9Sstevel@tonic-gate * which NFS version to use when probing the server (see above). 2107c478bd9Sstevel@tonic-gate * These will only be used when the vers mount option is not used and 2117c478bd9Sstevel@tonic-gate * these may be reset if /etc/default/nfs is configured to do so. 2127c478bd9Sstevel@tonic-gate */ 2137c478bd9Sstevel@tonic-gate static rpcvers_t vers_max_default = NFS_VERSMAX_DEFAULT; 2147c478bd9Sstevel@tonic-gate static rpcvers_t vers_min_default = NFS_VERSMIN_DEFAULT; 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate /* 2177c478bd9Sstevel@tonic-gate * list of support services needed 2187c478bd9Sstevel@tonic-gate */ 2197c478bd9Sstevel@tonic-gate static char *service_list[] = { STATD, LOCKD, NULL }; 2207c478bd9Sstevel@tonic-gate static char *service_list_v4[] = { STATD, LOCKD, NFS4CBD, NFSMAPID, NULL }; 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate static void read_default_nfs(void); 2237c478bd9Sstevel@tonic-gate static int is_v4_mount(char *); 2247c478bd9Sstevel@tonic-gate static void start_nfs4cbd(void); 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate int 22739d3e169Sevanl mount_nfs( 22839d3e169Sevanl struct mapent *me, 22939d3e169Sevanl char *mntpnt, 23039d3e169Sevanl char *prevhost, 23139d3e169Sevanl int overlay, 2323bfb48feSsemery uid_t uid, 23339d3e169Sevanl action_list **alpp) 2347c478bd9Sstevel@tonic-gate { 2357c478bd9Sstevel@tonic-gate struct mapfs *mfs, *mp; 2367c478bd9Sstevel@tonic-gate int err = -1; 23739d3e169Sevanl action_list *alp; 238a05556d6SNagakiran Rajashekar char *dir; 23939d3e169Sevanl 24039d3e169Sevanl 24139d3e169Sevanl alp = *alpp; 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate read_default_nfs(); 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate mfs = enum_servers(me, prevhost); 2467c478bd9Sstevel@tonic-gate if (mfs == NULL) 2477c478bd9Sstevel@tonic-gate return (ENOENT); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate /* 2507c478bd9Sstevel@tonic-gate * Try loopback if we have something on localhost; if nothing 2517c478bd9Sstevel@tonic-gate * works, we will fall back to NFS 2527c478bd9Sstevel@tonic-gate */ 2537c478bd9Sstevel@tonic-gate if (is_nfs_port(me->map_mntopts)) { 2547c478bd9Sstevel@tonic-gate for (mp = mfs; mp; mp = mp->mfs_next) { 2557c478bd9Sstevel@tonic-gate if (self_check(mp->mfs_host)) { 2567c478bd9Sstevel@tonic-gate err = loopbackmount(mp->mfs_dir, 2577c478bd9Sstevel@tonic-gate mntpnt, me->map_mntopts, overlay); 2587c478bd9Sstevel@tonic-gate if (err) { 2597c478bd9Sstevel@tonic-gate mp->mfs_ignore = 1; 2607c478bd9Sstevel@tonic-gate } else { 26139d3e169Sevanl /* 26239d3e169Sevanl * Free action_list if there 26339d3e169Sevanl * is one as it is not needed. 26439d3e169Sevanl * Make sure to set alpp to null 26539d3e169Sevanl * so caller doesn't try to free it 26639d3e169Sevanl * again. 26739d3e169Sevanl */ 26839d3e169Sevanl if (*alpp) { 26939d3e169Sevanl free(*alpp); 27039d3e169Sevanl *alpp = NULL; 27139d3e169Sevanl } 2727c478bd9Sstevel@tonic-gate break; 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate if (err) { 278a05556d6SNagakiran Rajashekar dir = strdup(mfs->mfs_dir); 2797c478bd9Sstevel@tonic-gate err = nfsmount(mfs, mntpnt, me->map_mntopts, 280*bd93c05dSAlexander Eremin overlay, uid, alp); 2817c478bd9Sstevel@tonic-gate if (err && trace > 1) { 2827c478bd9Sstevel@tonic-gate trace_prt(1, " Couldn't mount %s:%s, err=%d\n", 283a05556d6SNagakiran Rajashekar mfs->mfs_host ? mfs->mfs_host : "", 284a05556d6SNagakiran Rajashekar mfs->mfs_dir ? mfs->mfs_dir : dir, err); 2857c478bd9Sstevel@tonic-gate } 286a05556d6SNagakiran Rajashekar free(dir); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate free_mfs(mfs); 2897c478bd9Sstevel@tonic-gate return (err); 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate /* 2947c478bd9Sstevel@tonic-gate * Using the new ioctl SIOCTONLINK to determine if a host is on the same 2957c478bd9Sstevel@tonic-gate * subnet. Remove the old network, subnet check. 2967c478bd9Sstevel@tonic-gate */ 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate static struct mapfs * 2997c478bd9Sstevel@tonic-gate get_mysubnet_servers(struct mapfs *mfs_in) 3007c478bd9Sstevel@tonic-gate { 3017c478bd9Sstevel@tonic-gate int s; 3027c478bd9Sstevel@tonic-gate struct mapfs *mfs, *p, *mfs_head = NULL, *mfs_tail = NULL; 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate struct netconfig *nconf; 3057c478bd9Sstevel@tonic-gate NCONF_HANDLE *nc = NULL; 3067c478bd9Sstevel@tonic-gate struct nd_hostserv hs; 3077c478bd9Sstevel@tonic-gate struct nd_addrlist *retaddrs; 3087c478bd9Sstevel@tonic-gate struct netbuf *nb; 3097c478bd9Sstevel@tonic-gate struct sioc_addrreq areq; 3107c478bd9Sstevel@tonic-gate int res; 3117c478bd9Sstevel@tonic-gate int af; 3127c478bd9Sstevel@tonic-gate int i; 3137c478bd9Sstevel@tonic-gate int sa_size; 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate hs.h_serv = "rpcbind"; 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate for (mfs = mfs_in; mfs; mfs = mfs->mfs_next) { 3187c478bd9Sstevel@tonic-gate nc = setnetconfig(); 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate while (nconf = getnetconfig(nc)) { 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate /* 3237c478bd9Sstevel@tonic-gate * Care about INET family only. proto_done flag 3247c478bd9Sstevel@tonic-gate * indicates if we have already covered this 3257c478bd9Sstevel@tonic-gate * protocol family. If so skip it 3267c478bd9Sstevel@tonic-gate */ 3277c478bd9Sstevel@tonic-gate if (((strcmp(nconf->nc_protofmly, NC_INET6) == 0) || 3287c478bd9Sstevel@tonic-gate (strcmp(nconf->nc_protofmly, NC_INET) == 0)) && 3297c478bd9Sstevel@tonic-gate (nconf->nc_semantics == NC_TPI_CLTS)) { 3307c478bd9Sstevel@tonic-gate } else 3317c478bd9Sstevel@tonic-gate continue; 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate hs.h_host = mfs->mfs_host; 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate if (netdir_getbyname(nconf, &hs, &retaddrs) != ND_OK) 3367c478bd9Sstevel@tonic-gate continue; 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate /* 3397c478bd9Sstevel@tonic-gate * For each host address see if it's on our 3407c478bd9Sstevel@tonic-gate * local subnet. 3417c478bd9Sstevel@tonic-gate */ 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) 3447c478bd9Sstevel@tonic-gate af = AF_INET6; 3457c478bd9Sstevel@tonic-gate else 3467c478bd9Sstevel@tonic-gate af = AF_INET; 3477c478bd9Sstevel@tonic-gate nb = retaddrs->n_addrs; 3487c478bd9Sstevel@tonic-gate for (i = 0; i < retaddrs->n_cnt; i++, nb++) { 3497c478bd9Sstevel@tonic-gate memset(&areq.sa_addr, 0, sizeof (areq.sa_addr)); 3507c478bd9Sstevel@tonic-gate memcpy(&areq.sa_addr, nb->buf, MIN(nb->len, 3517c478bd9Sstevel@tonic-gate sizeof (areq.sa_addr))); 3527c478bd9Sstevel@tonic-gate if (res = subnet_test(af, &areq)) { 3537c478bd9Sstevel@tonic-gate p = add_mfs(mfs, DIST_MYNET, 3547c478bd9Sstevel@tonic-gate &mfs_head, &mfs_tail); 3557c478bd9Sstevel@tonic-gate if (!p) { 3567c478bd9Sstevel@tonic-gate netdir_free(retaddrs, 3577c478bd9Sstevel@tonic-gate ND_ADDRLIST); 3587c478bd9Sstevel@tonic-gate endnetconfig(nc); 3597c478bd9Sstevel@tonic-gate return (NULL); 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate break; 3627c478bd9Sstevel@tonic-gate } 3637c478bd9Sstevel@tonic-gate } /* end of every host */ 3647c478bd9Sstevel@tonic-gate if (trace > 2) { 3657c478bd9Sstevel@tonic-gate trace_prt(1, "get_mysubnet_servers: host=%s " 3667c478bd9Sstevel@tonic-gate "netid=%s res=%s\n", mfs->mfs_host, 3677c478bd9Sstevel@tonic-gate nconf->nc_netid, res == 1?"SUC":"FAIL"); 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate netdir_free(retaddrs, ND_ADDRLIST); 3717c478bd9Sstevel@tonic-gate } /* end of while */ 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate endnetconfig(nc); 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate } /* end of every map */ 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate return (mfs_head); 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate int 3827c478bd9Sstevel@tonic-gate subnet_test(int af, struct sioc_addrreq *areq) 3837c478bd9Sstevel@tonic-gate { 3847c478bd9Sstevel@tonic-gate int s; 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate if ((s = socket(af, SOCK_DGRAM, 0)) < 0) { 3877c478bd9Sstevel@tonic-gate return (0); 3887c478bd9Sstevel@tonic-gate } 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate areq->sa_res = -1; 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate if (ioctl(s, SIOCTONLINK, (caddr_t)areq) < 0) { 3937c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "subnet_test:SIOCTONLINK failed"); 3947c478bd9Sstevel@tonic-gate return (0); 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate close(s); 3977c478bd9Sstevel@tonic-gate if (areq->sa_res == 1) 3987c478bd9Sstevel@tonic-gate return (1); 3997c478bd9Sstevel@tonic-gate else 4007c478bd9Sstevel@tonic-gate return (0); 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate } 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate /* 4067c478bd9Sstevel@tonic-gate * ping a bunch of hosts at once and sort by who responds first 4077c478bd9Sstevel@tonic-gate */ 4087c478bd9Sstevel@tonic-gate static struct mapfs * 4097c478bd9Sstevel@tonic-gate sort_servers(struct mapfs *mfs_in, int timeout) 4107c478bd9Sstevel@tonic-gate { 4117c478bd9Sstevel@tonic-gate struct mapfs *m1 = NULL; 4127c478bd9Sstevel@tonic-gate enum clnt_stat clnt_stat; 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate if (!mfs_in) 4157c478bd9Sstevel@tonic-gate return (NULL); 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate clnt_stat = nfs_cast(mfs_in, &m1, timeout); 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate if (!m1) { 4207c478bd9Sstevel@tonic-gate char buff[2048] = {'\0'}; 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate for (m1 = mfs_in; m1; m1 = m1->mfs_next) { 4237c478bd9Sstevel@tonic-gate (void) strcat(buff, m1->mfs_host); 4247c478bd9Sstevel@tonic-gate if (m1->mfs_next) 4257c478bd9Sstevel@tonic-gate (void) strcat(buff, ","); 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "servers %s not responding: %s", 4297c478bd9Sstevel@tonic-gate buff, clnt_sperrno(clnt_stat)); 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate return (m1); 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate /* 4367c478bd9Sstevel@tonic-gate * Add a mapfs entry to the list described by *mfs_head and *mfs_tail, 4377c478bd9Sstevel@tonic-gate * provided it is not marked "ignored" and isn't a dupe of ones we've 4387c478bd9Sstevel@tonic-gate * already seen. 4397c478bd9Sstevel@tonic-gate */ 4407c478bd9Sstevel@tonic-gate struct mapfs * 4417c478bd9Sstevel@tonic-gate add_mfs(struct mapfs *mfs, int distance, struct mapfs **mfs_head, 4427c478bd9Sstevel@tonic-gate struct mapfs **mfs_tail) 4437c478bd9Sstevel@tonic-gate { 4447c478bd9Sstevel@tonic-gate struct mapfs *tmp, *new; 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate for (tmp = *mfs_head; tmp; tmp = tmp->mfs_next) 4477c478bd9Sstevel@tonic-gate if ((strcmp(tmp->mfs_host, mfs->mfs_host) == 0 && 4487c478bd9Sstevel@tonic-gate strcmp(tmp->mfs_dir, mfs->mfs_dir) == 0) || 4497c478bd9Sstevel@tonic-gate mfs->mfs_ignore) 4507c478bd9Sstevel@tonic-gate return (*mfs_head); 4517c478bd9Sstevel@tonic-gate new = (struct mapfs *)malloc(sizeof (struct mapfs)); 4527c478bd9Sstevel@tonic-gate if (!new) { 4537c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Memory allocation failed: %m"); 4547c478bd9Sstevel@tonic-gate return (NULL); 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate bcopy(mfs, new, sizeof (struct mapfs)); 4577c478bd9Sstevel@tonic-gate new->mfs_next = NULL; 4587c478bd9Sstevel@tonic-gate if (distance) 4597c478bd9Sstevel@tonic-gate new->mfs_distance = distance; 4607c478bd9Sstevel@tonic-gate if (!*mfs_head) 4617c478bd9Sstevel@tonic-gate *mfs_tail = *mfs_head = new; 4627c478bd9Sstevel@tonic-gate else { 4637c478bd9Sstevel@tonic-gate (*mfs_tail)->mfs_next = new; 4647c478bd9Sstevel@tonic-gate *mfs_tail = new; 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate return (*mfs_head); 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate static void 4707c478bd9Sstevel@tonic-gate dump_mfs(struct mapfs *mfs, char *message, int level) 4717c478bd9Sstevel@tonic-gate { 4727c478bd9Sstevel@tonic-gate struct mapfs *m1; 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate if (trace <= level) 4757c478bd9Sstevel@tonic-gate return; 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate trace_prt(1, "%s", message); 4787c478bd9Sstevel@tonic-gate if (!mfs) { 4797c478bd9Sstevel@tonic-gate trace_prt(0, "mfs is null\n"); 4807c478bd9Sstevel@tonic-gate return; 4817c478bd9Sstevel@tonic-gate } 4827c478bd9Sstevel@tonic-gate for (m1 = mfs; m1; m1 = m1->mfs_next) 4837c478bd9Sstevel@tonic-gate trace_prt(0, "%s[%s] ", m1->mfs_host, dump_distance(m1)); 4847c478bd9Sstevel@tonic-gate trace_prt(0, "\n"); 4857c478bd9Sstevel@tonic-gate } 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate static char * 4887c478bd9Sstevel@tonic-gate dump_distance(struct mapfs *mfs) 4897c478bd9Sstevel@tonic-gate { 4907c478bd9Sstevel@tonic-gate switch (mfs->mfs_distance) { 4917c478bd9Sstevel@tonic-gate case 0: return ("zero"); 4927c478bd9Sstevel@tonic-gate case DIST_SELF: return ("self"); 4937c478bd9Sstevel@tonic-gate case DIST_MYSUB: return ("mysub"); 4947c478bd9Sstevel@tonic-gate case DIST_MYNET: return ("mynet"); 4957c478bd9Sstevel@tonic-gate case DIST_OTHER: return ("other"); 4967c478bd9Sstevel@tonic-gate default: return ("other"); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate /* 5017c478bd9Sstevel@tonic-gate * Walk linked list "raw", building a new list consisting of members 5027c478bd9Sstevel@tonic-gate * NOT found in list "filter", returning the result. 5037c478bd9Sstevel@tonic-gate */ 5047c478bd9Sstevel@tonic-gate static struct mapfs * 5057c478bd9Sstevel@tonic-gate filter_mfs(struct mapfs *raw, struct mapfs *filter) 5067c478bd9Sstevel@tonic-gate { 5077c478bd9Sstevel@tonic-gate struct mapfs *mfs, *p, *mfs_head = NULL, *mfs_tail = NULL; 5087c478bd9Sstevel@tonic-gate int skip; 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate if (!raw) 5117c478bd9Sstevel@tonic-gate return (NULL); 5127c478bd9Sstevel@tonic-gate for (mfs = raw; mfs; mfs = mfs->mfs_next) { 5137c478bd9Sstevel@tonic-gate for (skip = 0, p = filter; p; p = p->mfs_next) { 5147c478bd9Sstevel@tonic-gate if (strcmp(p->mfs_host, mfs->mfs_host) == 0 && 5157c478bd9Sstevel@tonic-gate strcmp(p->mfs_dir, mfs->mfs_dir) == 0) { 5167c478bd9Sstevel@tonic-gate skip = 1; 5177c478bd9Sstevel@tonic-gate break; 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate if (skip) 5217c478bd9Sstevel@tonic-gate continue; 5227c478bd9Sstevel@tonic-gate p = add_mfs(mfs, 0, &mfs_head, &mfs_tail); 5237c478bd9Sstevel@tonic-gate if (!p) 5247c478bd9Sstevel@tonic-gate return (NULL); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate return (mfs_head); 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate /* 5307c478bd9Sstevel@tonic-gate * Walk a linked list of mapfs structs, freeing each member. 5317c478bd9Sstevel@tonic-gate */ 5327c478bd9Sstevel@tonic-gate void 5337c478bd9Sstevel@tonic-gate free_mfs(struct mapfs *mfs) 5347c478bd9Sstevel@tonic-gate { 5357c478bd9Sstevel@tonic-gate struct mapfs *tmp; 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate while (mfs) { 5387c478bd9Sstevel@tonic-gate tmp = mfs->mfs_next; 5397c478bd9Sstevel@tonic-gate free(mfs); 5407c478bd9Sstevel@tonic-gate mfs = tmp; 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate } 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate /* 5457c478bd9Sstevel@tonic-gate * New code for NFS client failover: we need to carry and sort 5467c478bd9Sstevel@tonic-gate * lists of server possibilities rather than return a single 5477c478bd9Sstevel@tonic-gate * entry. It preserves previous behaviour of sorting first by 5487c478bd9Sstevel@tonic-gate * locality (loopback-or-preferred/subnet/net/other) and then 5497c478bd9Sstevel@tonic-gate * by ping times. We'll short-circuit this process when we 5507c478bd9Sstevel@tonic-gate * have ENOUGH or more entries. 5517c478bd9Sstevel@tonic-gate */ 5527c478bd9Sstevel@tonic-gate static struct mapfs * 5537c478bd9Sstevel@tonic-gate enum_servers(struct mapent *me, char *preferred) 5547c478bd9Sstevel@tonic-gate { 5557c478bd9Sstevel@tonic-gate struct mapfs *p, *m1, *m2, *mfs_head = NULL, *mfs_tail = NULL; 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate /* 5587c478bd9Sstevel@tonic-gate * Short-circuit for simple cases. 5597c478bd9Sstevel@tonic-gate */ 5607c478bd9Sstevel@tonic-gate if (!me->map_fs->mfs_next) { 5617c478bd9Sstevel@tonic-gate p = add_mfs(me->map_fs, DIST_OTHER, &mfs_head, &mfs_tail); 5627c478bd9Sstevel@tonic-gate if (!p) 5637c478bd9Sstevel@tonic-gate return (NULL); 5647c478bd9Sstevel@tonic-gate return (mfs_head); 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate dump_mfs(me->map_fs, " enum_servers: mapent: ", 2); 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate /* 5707c478bd9Sstevel@tonic-gate * get addresses & see if any are myself 5717c478bd9Sstevel@tonic-gate * or were mounted from previously in a 5727c478bd9Sstevel@tonic-gate * hierarchical mount. 5737c478bd9Sstevel@tonic-gate */ 5747c478bd9Sstevel@tonic-gate if (trace > 2) 5757c478bd9Sstevel@tonic-gate trace_prt(1, " enum_servers: looking for pref/self\n"); 5767c478bd9Sstevel@tonic-gate for (m1 = me->map_fs; m1; m1 = m1->mfs_next) { 5777c478bd9Sstevel@tonic-gate if (m1->mfs_ignore) 5787c478bd9Sstevel@tonic-gate continue; 5797c478bd9Sstevel@tonic-gate if (self_check(m1->mfs_host) || 5807c478bd9Sstevel@tonic-gate strcmp(m1->mfs_host, preferred) == 0) { 5817c478bd9Sstevel@tonic-gate p = add_mfs(m1, DIST_SELF, &mfs_head, &mfs_tail); 5827c478bd9Sstevel@tonic-gate if (!p) 5837c478bd9Sstevel@tonic-gate return (NULL); 5847c478bd9Sstevel@tonic-gate } 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate if (trace > 2 && m1) 5877c478bd9Sstevel@tonic-gate trace_prt(1, " enum_servers: pref/self found, %s\n", 5887c478bd9Sstevel@tonic-gate m1->mfs_host); 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate /* 5917c478bd9Sstevel@tonic-gate * look for entries on this subnet 5927c478bd9Sstevel@tonic-gate */ 5937c478bd9Sstevel@tonic-gate dump_mfs(m1, " enum_servers: input of get_mysubnet_servers: ", 2); 5947c478bd9Sstevel@tonic-gate m1 = get_mysubnet_servers(me->map_fs); 5957c478bd9Sstevel@tonic-gate dump_mfs(m1, " enum_servers: output of get_mysubnet_servers: ", 3); 5967c478bd9Sstevel@tonic-gate if (m1 && m1->mfs_next) { 5977c478bd9Sstevel@tonic-gate m2 = sort_servers(m1, rpc_timeout / 2); 5987c478bd9Sstevel@tonic-gate dump_mfs(m2, " enum_servers: output of sort_servers: ", 3); 5997c478bd9Sstevel@tonic-gate free_mfs(m1); 6007c478bd9Sstevel@tonic-gate m1 = m2; 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate for (m2 = m1; m2; m2 = m2->mfs_next) { 6047c478bd9Sstevel@tonic-gate p = add_mfs(m2, 0, &mfs_head, &mfs_tail); 6057c478bd9Sstevel@tonic-gate if (!p) 6067c478bd9Sstevel@tonic-gate return (NULL); 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate if (m1) 6097c478bd9Sstevel@tonic-gate free_mfs(m1); 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate /* 6127c478bd9Sstevel@tonic-gate * add the rest of the entries at the end 6137c478bd9Sstevel@tonic-gate */ 6147c478bd9Sstevel@tonic-gate m1 = filter_mfs(me->map_fs, mfs_head); 6157c478bd9Sstevel@tonic-gate dump_mfs(m1, " enum_servers: etc: output of filter_mfs: ", 3); 6167c478bd9Sstevel@tonic-gate m2 = sort_servers(m1, rpc_timeout / 2); 6177c478bd9Sstevel@tonic-gate dump_mfs(m2, " enum_servers: etc: output of sort_servers: ", 3); 6187c478bd9Sstevel@tonic-gate if (m1) 6197c478bd9Sstevel@tonic-gate free_mfs(m1); 6207c478bd9Sstevel@tonic-gate m1 = m2; 6217c478bd9Sstevel@tonic-gate for (m2 = m1; m2; m2 = m2->mfs_next) { 6227c478bd9Sstevel@tonic-gate p = add_mfs(m2, DIST_OTHER, &mfs_head, &mfs_tail); 6237c478bd9Sstevel@tonic-gate if (!p) 6247c478bd9Sstevel@tonic-gate return (NULL); 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate if (m1) 6277c478bd9Sstevel@tonic-gate free_mfs(m1); 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate done: 6307c478bd9Sstevel@tonic-gate dump_mfs(mfs_head, " enum_servers: output: ", 1); 6317c478bd9Sstevel@tonic-gate return (mfs_head); 6327c478bd9Sstevel@tonic-gate } 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate static enum nfsstat 63539d3e169Sevanl nfsmount( 63639d3e169Sevanl struct mapfs *mfs_in, 63739d3e169Sevanl char *mntpnt, char *opts, 638*bd93c05dSAlexander Eremin int overlay, 6393bfb48feSsemery uid_t uid, 64039d3e169Sevanl action_list *alp) 6417c478bd9Sstevel@tonic-gate { 6427c478bd9Sstevel@tonic-gate CLIENT *cl; 6437c478bd9Sstevel@tonic-gate char remname[MAXPATHLEN], *mnttabtext = NULL; 6447c478bd9Sstevel@tonic-gate char mopts[MAX_MNTOPT_STR]; 6457c478bd9Sstevel@tonic-gate char netname[MAXNETNAMELEN+1]; 64639d3e169Sevanl char *mntopts = NULL; 6477c478bd9Sstevel@tonic-gate int mnttabcnt = 0; 6487c478bd9Sstevel@tonic-gate int loglevel; 6497c478bd9Sstevel@tonic-gate struct mnttab m; 6507c478bd9Sstevel@tonic-gate struct nfs_args *argp = NULL, *head = NULL, *tail = NULL, 6517c478bd9Sstevel@tonic-gate *prevhead, *prevtail; 6527c478bd9Sstevel@tonic-gate int flags; 6537c478bd9Sstevel@tonic-gate struct fhstatus fhs; 6547c478bd9Sstevel@tonic-gate struct timeval timeout; 6557c478bd9Sstevel@tonic-gate enum clnt_stat rpc_stat; 6567c478bd9Sstevel@tonic-gate enum nfsstat status; 6577c478bd9Sstevel@tonic-gate struct stat stbuf; 6587c478bd9Sstevel@tonic-gate struct netconfig *nconf; 6597c478bd9Sstevel@tonic-gate rpcvers_t vers, versmin; /* used to negotiate nfs version in pingnfs */ 6607c478bd9Sstevel@tonic-gate /* and mount version with mountd */ 6617c478bd9Sstevel@tonic-gate rpcvers_t outvers; /* final version to be used during mount() */ 6627c478bd9Sstevel@tonic-gate rpcvers_t nfsvers; /* version in map options, 0 if not there */ 6637c478bd9Sstevel@tonic-gate rpcvers_t mountversmax; /* tracks the max mountvers during retries */ 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate /* used to negotiate nfs version using webnfs */ 6667c478bd9Sstevel@tonic-gate rpcvers_t pubvers, pubversmin, pubversmax; 6677c478bd9Sstevel@tonic-gate int posix; 6687c478bd9Sstevel@tonic-gate struct nd_addrlist *retaddrs; 6697c478bd9Sstevel@tonic-gate struct mountres3 res3; 6707c478bd9Sstevel@tonic-gate nfs_fh3 fh3; 6717c478bd9Sstevel@tonic-gate char *fstype; 6727c478bd9Sstevel@tonic-gate int count, i; 6737c478bd9Sstevel@tonic-gate char scerror_msg[MAXMSGLEN]; 6747c478bd9Sstevel@tonic-gate int *auths; 6757c478bd9Sstevel@tonic-gate int delay; 6767c478bd9Sstevel@tonic-gate int retries; 6777c478bd9Sstevel@tonic-gate char *nfs_proto = NULL; 6787c478bd9Sstevel@tonic-gate uint_t nfs_port = 0; 6796a6d3e5eSjs195444 char *p, *host, *rhost, *dir; 6807c478bd9Sstevel@tonic-gate struct mapfs *mfs = NULL; 6817c478bd9Sstevel@tonic-gate int error, last_error = 0; 6827c478bd9Sstevel@tonic-gate int replicated; 6837c478bd9Sstevel@tonic-gate int entries = 0; 6847c478bd9Sstevel@tonic-gate int v2cnt = 0, v3cnt = 0, v4cnt = 0; 6857c478bd9Sstevel@tonic-gate int v2near = 0, v3near = 0, v4near = 0; 6867c478bd9Sstevel@tonic-gate int skipentry = 0; 6877c478bd9Sstevel@tonic-gate char *nfs_flavor; 6887c478bd9Sstevel@tonic-gate seconfig_t nfs_sec; 6897c478bd9Sstevel@tonic-gate int sec_opt, scerror; 6907c478bd9Sstevel@tonic-gate struct sec_data *secdata; 6917c478bd9Sstevel@tonic-gate int secflags; 6927c478bd9Sstevel@tonic-gate struct netbuf *syncaddr; 6937c478bd9Sstevel@tonic-gate bool_t use_pubfh; 6947c478bd9Sstevel@tonic-gate ushort_t thisport; 6957c478bd9Sstevel@tonic-gate int got_val; 6967c478bd9Sstevel@tonic-gate mfs_snego_t mfssnego_init, mfssnego; 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate dump_mfs(mfs_in, " nfsmount: input: ", 2); 6997c478bd9Sstevel@tonic-gate replicated = (mfs_in->mfs_next != NULL); 7007c478bd9Sstevel@tonic-gate m.mnt_mntopts = opts; 7017c478bd9Sstevel@tonic-gate if (replicated && hasmntopt(&m, MNTOPT_SOFT)) { 7027c478bd9Sstevel@tonic-gate if (verbose) 7037c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, 7047c478bd9Sstevel@tonic-gate "mount on %s is soft and will not be replicated.", mntpnt); 7057c478bd9Sstevel@tonic-gate replicated = 0; 7067c478bd9Sstevel@tonic-gate } 7077c478bd9Sstevel@tonic-gate if (replicated && !hasmntopt(&m, MNTOPT_RO)) { 7087c478bd9Sstevel@tonic-gate if (verbose) 7097c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, 7107c478bd9Sstevel@tonic-gate "mount on %s is not read-only and will not be replicated.", 7117c478bd9Sstevel@tonic-gate mntpnt); 7127c478bd9Sstevel@tonic-gate replicated = 0; 7137c478bd9Sstevel@tonic-gate } 7147c478bd9Sstevel@tonic-gate if (replicated) 7157c478bd9Sstevel@tonic-gate loglevel = LOG_WARNING; 7167c478bd9Sstevel@tonic-gate else 7177c478bd9Sstevel@tonic-gate loglevel = LOG_ERR; 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate if (trace > 1) { 7207c478bd9Sstevel@tonic-gate if (replicated) 7217c478bd9Sstevel@tonic-gate trace_prt(1, " nfsmount: replicated mount on %s %s:\n", 7227c478bd9Sstevel@tonic-gate mntpnt, opts); 7237c478bd9Sstevel@tonic-gate else 7247c478bd9Sstevel@tonic-gate trace_prt(1, " nfsmount: standard mount on %s %s:\n", 7257c478bd9Sstevel@tonic-gate mntpnt, opts); 7267c478bd9Sstevel@tonic-gate for (mfs = mfs_in; mfs; mfs = mfs->mfs_next) 7277c478bd9Sstevel@tonic-gate trace_prt(1, " %s:%s\n", 7287c478bd9Sstevel@tonic-gate mfs->mfs_host, mfs->mfs_dir); 7297c478bd9Sstevel@tonic-gate } 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate /* 7327c478bd9Sstevel@tonic-gate * Make sure mountpoint is safe to mount on 7337c478bd9Sstevel@tonic-gate */ 7347c478bd9Sstevel@tonic-gate if (lstat(mntpnt, &stbuf) < 0) { 7357c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Couldn't stat %s: %m", mntpnt); 7367c478bd9Sstevel@tonic-gate return (NFSERR_NOENT); 7377c478bd9Sstevel@tonic-gate } 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate /* 7407c478bd9Sstevel@tonic-gate * Get protocol specified in options list, if any. 7417c478bd9Sstevel@tonic-gate */ 7427c478bd9Sstevel@tonic-gate if ((str_opt(&m, "proto", &nfs_proto)) == -1) { 7437c478bd9Sstevel@tonic-gate return (NFSERR_NOENT); 7447c478bd9Sstevel@tonic-gate } 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate /* 7477c478bd9Sstevel@tonic-gate * Get port specified in options list, if any. 7487c478bd9Sstevel@tonic-gate */ 7497c478bd9Sstevel@tonic-gate got_val = nopt(&m, MNTOPT_PORT, (int *)&nfs_port); 7507c478bd9Sstevel@tonic-gate if (!got_val) 7517c478bd9Sstevel@tonic-gate nfs_port = 0; /* "unspecified" */ 7527c478bd9Sstevel@tonic-gate if (nfs_port > USHRT_MAX) { 7537c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s: invalid port number %d", mntpnt, nfs_port); 7547c478bd9Sstevel@tonic-gate return (NFSERR_NOENT); 7557c478bd9Sstevel@tonic-gate } 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate /* 7587c478bd9Sstevel@tonic-gate * Set mount(2) flags here, outside of the loop. 7597c478bd9Sstevel@tonic-gate */ 7607c478bd9Sstevel@tonic-gate flags = MS_OPTIONSTR; 7617c478bd9Sstevel@tonic-gate flags |= (hasmntopt(&m, MNTOPT_RO) == NULL) ? 0 : MS_RDONLY; 7627c478bd9Sstevel@tonic-gate flags |= (hasmntopt(&m, MNTOPT_NOSUID) == NULL) ? 0 : MS_NOSUID; 7637c478bd9Sstevel@tonic-gate flags |= overlay ? MS_OVERLAY : 0; 7647c478bd9Sstevel@tonic-gate if (mntpnt[strlen(mntpnt) - 1] != ' ') 7657c478bd9Sstevel@tonic-gate /* direct mount point without offsets */ 7667c478bd9Sstevel@tonic-gate flags |= MS_OVERLAY; 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate use_pubfh = (hasmntopt(&m, MNTOPT_PUBLIC) == NULL) ? FALSE : TRUE; 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate (void) memset(&mfssnego_init, 0, sizeof (mfs_snego_t)); 7717c478bd9Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_SECURE) != NULL) { 7727c478bd9Sstevel@tonic-gate if (++mfssnego_init.sec_opt > 1) { 7737c478bd9Sstevel@tonic-gate syslog(loglevel, 7747c478bd9Sstevel@tonic-gate "conflicting security options"); 7757c478bd9Sstevel@tonic-gate return (NFSERR_IO); 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate if (nfs_getseconfig_byname("dh", &mfssnego_init.nfs_sec)) { 7787c478bd9Sstevel@tonic-gate syslog(loglevel, 7797c478bd9Sstevel@tonic-gate "error getting dh information from %s", 7807c478bd9Sstevel@tonic-gate NFSSEC_CONF); 7817c478bd9Sstevel@tonic-gate return (NFSERR_IO); 7827c478bd9Sstevel@tonic-gate } 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate 785d7c6abe8Sjasmith if (hasmntopt(&m, MNTOPT_SEC) != NULL) { 7867c478bd9Sstevel@tonic-gate if ((str_opt(&m, MNTOPT_SEC, 7877c478bd9Sstevel@tonic-gate &mfssnego_init.nfs_flavor)) == -1) { 7887c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 7897c478bd9Sstevel@tonic-gate return (NFSERR_IO); 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate } 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate if (mfssnego_init.nfs_flavor) { 7947c478bd9Sstevel@tonic-gate if (++mfssnego_init.sec_opt > 1) { 7957c478bd9Sstevel@tonic-gate syslog(loglevel, 7967c478bd9Sstevel@tonic-gate "conflicting security options"); 7977c478bd9Sstevel@tonic-gate free(mfssnego_init.nfs_flavor); 7987c478bd9Sstevel@tonic-gate return (NFSERR_IO); 7997c478bd9Sstevel@tonic-gate } 8007c478bd9Sstevel@tonic-gate if (nfs_getseconfig_byname(mfssnego_init.nfs_flavor, 8017c478bd9Sstevel@tonic-gate &mfssnego_init.nfs_sec)) { 8027c478bd9Sstevel@tonic-gate syslog(loglevel, 8037c478bd9Sstevel@tonic-gate "error getting %s information from %s", 8047c478bd9Sstevel@tonic-gate mfssnego_init.nfs_flavor, NFSSEC_CONF); 8057c478bd9Sstevel@tonic-gate free(mfssnego_init.nfs_flavor); 8067c478bd9Sstevel@tonic-gate return (NFSERR_IO); 8077c478bd9Sstevel@tonic-gate } 8087c478bd9Sstevel@tonic-gate free(mfssnego_init.nfs_flavor); 8097c478bd9Sstevel@tonic-gate } 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate nextentry: 8127c478bd9Sstevel@tonic-gate skipentry = 0; 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate got_val = nopt(&m, MNTOPT_VERS, (int *)&nfsvers); 8157c478bd9Sstevel@tonic-gate if (!got_val) 8167c478bd9Sstevel@tonic-gate nfsvers = 0; /* "unspecified" */ 8177c478bd9Sstevel@tonic-gate if (set_versrange(nfsvers, &vers, &versmin) != 0) { 8187c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Incorrect NFS version specified for %s", 8197c478bd9Sstevel@tonic-gate mntpnt); 8207c478bd9Sstevel@tonic-gate last_error = NFSERR_NOENT; 8217c478bd9Sstevel@tonic-gate goto ret; 8227c478bd9Sstevel@tonic-gate } 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate if (nfsvers != 0) { 8257c478bd9Sstevel@tonic-gate pubversmax = pubversmin = nfsvers; 8267c478bd9Sstevel@tonic-gate } else { 8277c478bd9Sstevel@tonic-gate pubversmax = vers; 8287c478bd9Sstevel@tonic-gate pubversmin = versmin; 8297c478bd9Sstevel@tonic-gate } 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate /* 8327c478bd9Sstevel@tonic-gate * Walk the whole list, pinging and collecting version 8337c478bd9Sstevel@tonic-gate * info so that we can make sure the mount will be 8347c478bd9Sstevel@tonic-gate * homogeneous with respect to version. 8357c478bd9Sstevel@tonic-gate * 8367c478bd9Sstevel@tonic-gate * If we have a version preference, this is easy; we'll 8377c478bd9Sstevel@tonic-gate * just reject anything that doesn't match. 8387c478bd9Sstevel@tonic-gate * 8397c478bd9Sstevel@tonic-gate * If not, we want to try to provide the best compromise 8407c478bd9Sstevel@tonic-gate * that considers proximity, preference for a higher version, 8417c478bd9Sstevel@tonic-gate * sorted order, and number of replicas. We will count 8427c478bd9Sstevel@tonic-gate * the number of V2 and V3 replicas and also the number 8437c478bd9Sstevel@tonic-gate * which are "near", i.e. the localhost or on the same 8447c478bd9Sstevel@tonic-gate * subnet. 8457c478bd9Sstevel@tonic-gate */ 8467c478bd9Sstevel@tonic-gate for (mfs = mfs_in; mfs; mfs = mfs->mfs_next) { 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate if (mfs->mfs_ignore) 8507c478bd9Sstevel@tonic-gate continue; 8517c478bd9Sstevel@tonic-gate 8526a6d3e5eSjs195444 /* 8536a6d3e5eSjs195444 * If the host is '[a:d:d:r:e:s:s'], 8546a6d3e5eSjs195444 * only use 'a:d:d:r:e:s:s' for communication 8556a6d3e5eSjs195444 */ 8566a6d3e5eSjs195444 host = strdup(mfs->mfs_host); 8576a6d3e5eSjs195444 if (host == NULL) { 8586a6d3e5eSjs195444 syslog(LOG_ERR, "nfsmount: no memory"); 8596a6d3e5eSjs195444 last_error = NFSERR_IO; 8606a6d3e5eSjs195444 goto out; 8616a6d3e5eSjs195444 } 8626a6d3e5eSjs195444 unbracket(&host); 8636a6d3e5eSjs195444 8647c478bd9Sstevel@tonic-gate (void) memcpy(&mfssnego, &mfssnego_init, sizeof (mfs_snego_t)); 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate if (use_pubfh == TRUE || mfs->mfs_flags & MFS_URL) { 8677c478bd9Sstevel@tonic-gate char *path; 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate if (nfs_port != 0 && mfs->mfs_port != 0 && 8707c478bd9Sstevel@tonic-gate nfs_port != mfs->mfs_port) { 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: port (%u) in nfs URL" 8737c478bd9Sstevel@tonic-gate " not the same as port (%d) in port " 8747c478bd9Sstevel@tonic-gate "option\n", mfs->mfs_port, nfs_port); 8757c478bd9Sstevel@tonic-gate last_error = NFSERR_IO; 8767c478bd9Sstevel@tonic-gate goto out; 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate } else if (nfs_port != 0) 8797c478bd9Sstevel@tonic-gate thisport = nfs_port; 8807c478bd9Sstevel@tonic-gate else 8817c478bd9Sstevel@tonic-gate thisport = mfs->mfs_port; 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate dir = mfs->mfs_dir; 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate if ((mfs->mfs_flags & MFS_URL) == 0) { 8867c478bd9Sstevel@tonic-gate path = malloc(strlen(dir) + 2); 8877c478bd9Sstevel@tonic-gate if (path == NULL) { 8887c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 8897c478bd9Sstevel@tonic-gate last_error = NFSERR_IO; 8907c478bd9Sstevel@tonic-gate goto out; 8917c478bd9Sstevel@tonic-gate } 8927c478bd9Sstevel@tonic-gate path[0] = (char)WNL_NATIVEPATH; 8937c478bd9Sstevel@tonic-gate (void) strcpy(&path[1], dir); 8947c478bd9Sstevel@tonic-gate } else { 8957c478bd9Sstevel@tonic-gate path = dir; 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate argp = (struct nfs_args *) 8997c478bd9Sstevel@tonic-gate malloc(sizeof (struct nfs_args)); 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate if (!argp) { 9027c478bd9Sstevel@tonic-gate if (path != dir) 9037c478bd9Sstevel@tonic-gate free(path); 9047c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 9057c478bd9Sstevel@tonic-gate last_error = NFSERR_IO; 9067c478bd9Sstevel@tonic-gate goto out; 9077c478bd9Sstevel@tonic-gate } 9087c478bd9Sstevel@tonic-gate (void) memset(argp, 0, sizeof (*argp)); 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate /* 9117c478bd9Sstevel@tonic-gate * RDMA support 9127c478bd9Sstevel@tonic-gate * By now Mount argument struct has been allocated, 9137c478bd9Sstevel@tonic-gate * either a pub_fh path will be taken or the regular 9147c478bd9Sstevel@tonic-gate * one. So here if a protocol was specified and it 9157c478bd9Sstevel@tonic-gate * was not rdma we let it be, else we set DO_RDMA. 9167c478bd9Sstevel@tonic-gate * If no proto was there we advise on trying RDMA. 9177c478bd9Sstevel@tonic-gate */ 9187c478bd9Sstevel@tonic-gate if (nfs_proto) { 9197c478bd9Sstevel@tonic-gate if (strcmp(nfs_proto, "rdma") == 0) { 9207c478bd9Sstevel@tonic-gate free(nfs_proto); 9217c478bd9Sstevel@tonic-gate nfs_proto = NULL; 9227c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_DORDMA; 9237c478bd9Sstevel@tonic-gate } 9247c478bd9Sstevel@tonic-gate } else 9257c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_TRYRDMA; 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate for (pubvers = pubversmax; pubvers >= pubversmin; 9287c478bd9Sstevel@tonic-gate pubvers--) { 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate nconf = NULL; 9317c478bd9Sstevel@tonic-gate argp->addr = get_pubfh(host, pubvers, &mfssnego, 9327c478bd9Sstevel@tonic-gate &nconf, nfs_proto, thisport, NULL, 9337c478bd9Sstevel@tonic-gate &argp->fh, TRUE, path); 9347c478bd9Sstevel@tonic-gate 9357c478bd9Sstevel@tonic-gate if (argp->addr != NULL) 9367c478bd9Sstevel@tonic-gate break; 9377c478bd9Sstevel@tonic-gate 9387c478bd9Sstevel@tonic-gate if (nconf != NULL) 9397c478bd9Sstevel@tonic-gate freenetconfigent(nconf); 9407c478bd9Sstevel@tonic-gate } 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate if (path != dir) 9437c478bd9Sstevel@tonic-gate free(path); 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate if (argp->addr != NULL) { 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate /* 9487c478bd9Sstevel@tonic-gate * The use of llock option for NFSv4 9497c478bd9Sstevel@tonic-gate * mounts is not required since file 9507c478bd9Sstevel@tonic-gate * locking is included within the protocol 9517c478bd9Sstevel@tonic-gate */ 9527c478bd9Sstevel@tonic-gate if (pubvers != NFS_V4) 9537c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_LLOCK; 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_PUBLIC; 9567c478bd9Sstevel@tonic-gate 9571bbc88acSrm15945 vers = pubvers; 9587c478bd9Sstevel@tonic-gate mfs->mfs_args = argp; 9597c478bd9Sstevel@tonic-gate mfs->mfs_version = pubvers; 9607c478bd9Sstevel@tonic-gate mfs->mfs_nconf = nconf; 9617c478bd9Sstevel@tonic-gate mfs->mfs_flags |= MFS_FH_VIA_WEBNFS; 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate } else { 9647c478bd9Sstevel@tonic-gate free(argp); 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate /* 9677c478bd9Sstevel@tonic-gate * If -public was specified, give up 9687c478bd9Sstevel@tonic-gate * on this entry now. 9697c478bd9Sstevel@tonic-gate */ 9707c478bd9Sstevel@tonic-gate if (use_pubfh == TRUE) { 9717c478bd9Sstevel@tonic-gate syslog(loglevel, 9727c478bd9Sstevel@tonic-gate "%s: no public file handle support", 9737c478bd9Sstevel@tonic-gate host); 9747c478bd9Sstevel@tonic-gate last_error = NFSERR_NOENT; 9757c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 9767c478bd9Sstevel@tonic-gate continue; 9777c478bd9Sstevel@tonic-gate } 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate /* 9807c478bd9Sstevel@tonic-gate * Back off to a conventional mount. 9817c478bd9Sstevel@tonic-gate * 9827c478bd9Sstevel@tonic-gate * URL's can contain escape characters. Get 9837c478bd9Sstevel@tonic-gate * rid of them. 9847c478bd9Sstevel@tonic-gate */ 9857c478bd9Sstevel@tonic-gate path = malloc(strlen(dir) + 2); 9867c478bd9Sstevel@tonic-gate 9877c478bd9Sstevel@tonic-gate if (path == NULL) { 9887c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 9897c478bd9Sstevel@tonic-gate last_error = NFSERR_IO; 9907c478bd9Sstevel@tonic-gate goto out; 9917c478bd9Sstevel@tonic-gate } 9927c478bd9Sstevel@tonic-gate 9937c478bd9Sstevel@tonic-gate strcpy(path, dir); 9947c478bd9Sstevel@tonic-gate URLparse(path); 9957c478bd9Sstevel@tonic-gate mfs->mfs_dir = path; 9967c478bd9Sstevel@tonic-gate mfs->mfs_flags |= MFS_ALLOC_DIR; 9977c478bd9Sstevel@tonic-gate mfs->mfs_flags &= ~MFS_URL; 9987c478bd9Sstevel@tonic-gate } 9997c478bd9Sstevel@tonic-gate } 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) == 0) { 10027c478bd9Sstevel@tonic-gate i = pingnfs(host, get_retry(opts) + 1, &vers, versmin, 10037c478bd9Sstevel@tonic-gate 0, FALSE, NULL, nfs_proto); 10047c478bd9Sstevel@tonic-gate if (i != RPC_SUCCESS) { 10057c478bd9Sstevel@tonic-gate if (i == RPC_PROGVERSMISMATCH) { 10067c478bd9Sstevel@tonic-gate syslog(loglevel, "server %s: NFS " 10077c478bd9Sstevel@tonic-gate "protocol version mismatch", 10087c478bd9Sstevel@tonic-gate host); 10097c478bd9Sstevel@tonic-gate } else { 10107c478bd9Sstevel@tonic-gate syslog(loglevel, "server %s not " 10117c478bd9Sstevel@tonic-gate "responding", host); 10127c478bd9Sstevel@tonic-gate } 10137c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 10147c478bd9Sstevel@tonic-gate last_error = NFSERR_NOENT; 10157c478bd9Sstevel@tonic-gate continue; 10167c478bd9Sstevel@tonic-gate } 10177c478bd9Sstevel@tonic-gate if (nfsvers != 0 && nfsvers != vers) { 10187c478bd9Sstevel@tonic-gate if (nfs_proto == NULL) 10197c478bd9Sstevel@tonic-gate syslog(loglevel, 10207c478bd9Sstevel@tonic-gate "NFS version %d " 10217c478bd9Sstevel@tonic-gate "not supported by %s", 10227c478bd9Sstevel@tonic-gate nfsvers, host); 10237c478bd9Sstevel@tonic-gate else 10247c478bd9Sstevel@tonic-gate syslog(loglevel, 10257c478bd9Sstevel@tonic-gate "NFS version %d " 10267c478bd9Sstevel@tonic-gate "with proto %s " 10277c478bd9Sstevel@tonic-gate "not supported by %s", 10287c478bd9Sstevel@tonic-gate nfsvers, nfs_proto, host); 10297c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 10307c478bd9Sstevel@tonic-gate last_error = NFSERR_NOENT; 10317c478bd9Sstevel@tonic-gate continue; 10327c478bd9Sstevel@tonic-gate } 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate 10356a6d3e5eSjs195444 free(host); 10366a6d3e5eSjs195444 10377c478bd9Sstevel@tonic-gate switch (vers) { 10387c478bd9Sstevel@tonic-gate case NFS_V4: v4cnt++; break; 10397c478bd9Sstevel@tonic-gate case NFS_V3: v3cnt++; break; 10407c478bd9Sstevel@tonic-gate case NFS_VERSION: v2cnt++; break; 10417c478bd9Sstevel@tonic-gate default: break; 10427c478bd9Sstevel@tonic-gate } 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate /* 10457c478bd9Sstevel@tonic-gate * It's not clear how useful this stuff is if 10467c478bd9Sstevel@tonic-gate * we are using webnfs across the internet, but it 10477c478bd9Sstevel@tonic-gate * can't hurt. 10487c478bd9Sstevel@tonic-gate */ 10497c478bd9Sstevel@tonic-gate if (mfs->mfs_distance && 10507c478bd9Sstevel@tonic-gate mfs->mfs_distance <= DIST_MYSUB) { 10517c478bd9Sstevel@tonic-gate switch (vers) { 10527c478bd9Sstevel@tonic-gate case NFS_V4: v4near++; break; 10537c478bd9Sstevel@tonic-gate case NFS_V3: v3near++; break; 10547c478bd9Sstevel@tonic-gate case NFS_VERSION: v2near++; break; 10557c478bd9Sstevel@tonic-gate default: break; 10567c478bd9Sstevel@tonic-gate } 10577c478bd9Sstevel@tonic-gate } 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate /* 10607c478bd9Sstevel@tonic-gate * If the mount is not replicated, we don't want to 10617c478bd9Sstevel@tonic-gate * ping every entry, so we'll stop here. This means 10627c478bd9Sstevel@tonic-gate * that we may have to go back to "nextentry" above 10636a6d3e5eSjs195444 * to consider another entry if we can't get 10647c478bd9Sstevel@tonic-gate * all the way to mount(2) with this one. 10657c478bd9Sstevel@tonic-gate */ 10667c478bd9Sstevel@tonic-gate if (!replicated) 10677c478bd9Sstevel@tonic-gate break; 10686a6d3e5eSjs195444 10697c478bd9Sstevel@tonic-gate } 10707c478bd9Sstevel@tonic-gate 10717c478bd9Sstevel@tonic-gate if (nfsvers == 0) { 10727c478bd9Sstevel@tonic-gate /* 10737c478bd9Sstevel@tonic-gate * Choose the NFS version. 10747c478bd9Sstevel@tonic-gate * We prefer higher versions, but will choose a one- 10757c478bd9Sstevel@tonic-gate * version downgrade in service if we can use a local 10767c478bd9Sstevel@tonic-gate * network interface and avoid a router. 10777c478bd9Sstevel@tonic-gate */ 10787c478bd9Sstevel@tonic-gate if (v4cnt && v4cnt >= v3cnt && (v4near || !v3near)) 10797c478bd9Sstevel@tonic-gate nfsvers = NFS_V4; 10807c478bd9Sstevel@tonic-gate else if (v3cnt && v3cnt >= v2cnt && (v3near || !v2near)) 10817c478bd9Sstevel@tonic-gate nfsvers = NFS_V3; 10827c478bd9Sstevel@tonic-gate else 10837c478bd9Sstevel@tonic-gate nfsvers = NFS_VERSION; 10847c478bd9Sstevel@tonic-gate if (trace > 2) 10857c478bd9Sstevel@tonic-gate trace_prt(1, 10867c478bd9Sstevel@tonic-gate " nfsmount: v4=%d[%d]v3=%d[%d],v2=%d[%d] => v%d.\n", 10877c478bd9Sstevel@tonic-gate v4cnt, v4near, v3cnt, v3near, 10887c478bd9Sstevel@tonic-gate v2cnt, v2near, nfsvers); 10897c478bd9Sstevel@tonic-gate } 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate /* 10927c478bd9Sstevel@tonic-gate * Since we don't support different NFS versions in replicated 10937c478bd9Sstevel@tonic-gate * mounts, set fstype now. 10947c478bd9Sstevel@tonic-gate * Also take the opportunity to set 10957c478bd9Sstevel@tonic-gate * the mount protocol version as appropriate. 10967c478bd9Sstevel@tonic-gate */ 10977c478bd9Sstevel@tonic-gate switch (nfsvers) { 10987c478bd9Sstevel@tonic-gate case NFS_V4: 10997c478bd9Sstevel@tonic-gate fstype = MNTTYPE_NFS4; 11007c478bd9Sstevel@tonic-gate break; 11017c478bd9Sstevel@tonic-gate case NFS_V3: 11027c478bd9Sstevel@tonic-gate fstype = MNTTYPE_NFS3; 11037c478bd9Sstevel@tonic-gate if (use_pubfh == FALSE) { 11047c478bd9Sstevel@tonic-gate mountversmax = MOUNTVERS3; 11057c478bd9Sstevel@tonic-gate versmin = MOUNTVERS3; 11067c478bd9Sstevel@tonic-gate } 11077c478bd9Sstevel@tonic-gate break; 11087c478bd9Sstevel@tonic-gate case NFS_VERSION: 11097c478bd9Sstevel@tonic-gate fstype = MNTTYPE_NFS; 11107c478bd9Sstevel@tonic-gate if (use_pubfh == FALSE) { 11117c478bd9Sstevel@tonic-gate mountversmax = MOUNTVERS_POSIX; 11127c478bd9Sstevel@tonic-gate versmin = MOUNTVERS; 11137c478bd9Sstevel@tonic-gate } 11147c478bd9Sstevel@tonic-gate break; 11157c478bd9Sstevel@tonic-gate } 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate /* 11187c478bd9Sstevel@tonic-gate * Our goal here is to evaluate each of several possible 11197c478bd9Sstevel@tonic-gate * replicas and try to come up with a list we can hand 11207c478bd9Sstevel@tonic-gate * to mount(2). If we don't have a valid "head" at the 11217c478bd9Sstevel@tonic-gate * end of this process, it means we have rejected all 11227c478bd9Sstevel@tonic-gate * potential server:/path tuples. We will fail quietly 11237c478bd9Sstevel@tonic-gate * in front of mount(2), and will have printed errors 11247c478bd9Sstevel@tonic-gate * where we found them. 11257c478bd9Sstevel@tonic-gate * XXX - do option work outside loop w careful design 11267c478bd9Sstevel@tonic-gate * XXX - use macro for error condition free handling 11277c478bd9Sstevel@tonic-gate */ 11287c478bd9Sstevel@tonic-gate for (mfs = mfs_in; mfs; mfs = mfs->mfs_next) { 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate /* 11317c478bd9Sstevel@tonic-gate * Initialize retry and delay values on a per-server basis. 11327c478bd9Sstevel@tonic-gate */ 11337c478bd9Sstevel@tonic-gate retries = get_retry(opts); 11347c478bd9Sstevel@tonic-gate delay = INITDELAY; 11357c478bd9Sstevel@tonic-gate retry: 11367c478bd9Sstevel@tonic-gate if (mfs->mfs_ignore) 11377c478bd9Sstevel@tonic-gate continue; 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate /* 11407c478bd9Sstevel@tonic-gate * If we don't have a fh yet, and if this is not a replicated 11417c478bd9Sstevel@tonic-gate * mount, we haven't done a pingnfs() on the next entry, 11427c478bd9Sstevel@tonic-gate * so we don't know if the next entry is up or if it 11437c478bd9Sstevel@tonic-gate * supports an NFS version we like. So if we had a problem 11447c478bd9Sstevel@tonic-gate * with an entry, we need to go back and run through some new 11457c478bd9Sstevel@tonic-gate * code. 11467c478bd9Sstevel@tonic-gate */ 11477c478bd9Sstevel@tonic-gate if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) == 0 && 11487c478bd9Sstevel@tonic-gate !replicated && skipentry) 11497c478bd9Sstevel@tonic-gate goto nextentry; 11507c478bd9Sstevel@tonic-gate 11517c478bd9Sstevel@tonic-gate vers = mountversmax; 11527c478bd9Sstevel@tonic-gate host = mfs->mfs_host; 11537c478bd9Sstevel@tonic-gate dir = mfs->mfs_dir; 11546a6d3e5eSjs195444 11556a6d3e5eSjs195444 /* 11566a6d3e5eSjs195444 * Remember the possible '[a:d:d:r:e:s:s]' as the address to be 11576a6d3e5eSjs195444 * later passed to mount(2) and used in the mnttab line, but 11586a6d3e5eSjs195444 * only use 'a:d:d:r:e:s:s' for communication 11596a6d3e5eSjs195444 */ 11606a6d3e5eSjs195444 rhost = strdup(host); 11616a6d3e5eSjs195444 if (rhost == NULL) { 11626a6d3e5eSjs195444 syslog(LOG_ERR, "nfsmount: no memory"); 11636a6d3e5eSjs195444 last_error = NFSERR_IO; 11646a6d3e5eSjs195444 goto out; 11656a6d3e5eSjs195444 } 11666a6d3e5eSjs195444 unbracket(&host); 11676a6d3e5eSjs195444 11686a6d3e5eSjs195444 (void) sprintf(remname, "%s:%s", rhost, dir); 11697c478bd9Sstevel@tonic-gate if (trace > 4 && replicated) 11707c478bd9Sstevel@tonic-gate trace_prt(1, " nfsmount: examining %s\n", remname); 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate if (mfs->mfs_args == NULL) { 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate /* 11757c478bd9Sstevel@tonic-gate * Allocate nfs_args structure 11767c478bd9Sstevel@tonic-gate */ 11777c478bd9Sstevel@tonic-gate argp = (struct nfs_args *) 11787c478bd9Sstevel@tonic-gate malloc(sizeof (struct nfs_args)); 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate if (!argp) { 11817c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 11827c478bd9Sstevel@tonic-gate last_error = NFSERR_IO; 11837c478bd9Sstevel@tonic-gate goto out; 11847c478bd9Sstevel@tonic-gate } 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate (void) memset(argp, 0, sizeof (*argp)); 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate /* 11897c478bd9Sstevel@tonic-gate * RDMA support 11907c478bd9Sstevel@tonic-gate * By now Mount argument struct has been allocated, 11917c478bd9Sstevel@tonic-gate * either a pub_fh path will be taken or the regular 11927c478bd9Sstevel@tonic-gate * one. So here if a protocol was specified and it 11937c478bd9Sstevel@tonic-gate * was not rdma we let it be, else we set DO_RDMA. 11947c478bd9Sstevel@tonic-gate * If no proto was there we advise on trying RDMA. 11957c478bd9Sstevel@tonic-gate */ 11967c478bd9Sstevel@tonic-gate if (nfs_proto) { 11977c478bd9Sstevel@tonic-gate if (strcmp(nfs_proto, "rdma") == 0) { 11987c478bd9Sstevel@tonic-gate free(nfs_proto); 11997c478bd9Sstevel@tonic-gate nfs_proto = NULL; 12007c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_DORDMA; 12017c478bd9Sstevel@tonic-gate } 12027c478bd9Sstevel@tonic-gate } else 12037c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_TRYRDMA; 12047c478bd9Sstevel@tonic-gate } else { 12057c478bd9Sstevel@tonic-gate argp = mfs->mfs_args; 12067c478bd9Sstevel@tonic-gate mfs->mfs_args = NULL; 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate /* 12097c478bd9Sstevel@tonic-gate * Skip entry if we already have file handle but the 12107c478bd9Sstevel@tonic-gate * NFS version is wrong. 12117c478bd9Sstevel@tonic-gate */ 12127c478bd9Sstevel@tonic-gate if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) && 12137c478bd9Sstevel@tonic-gate mfs->mfs_version != nfsvers) { 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate free(argp); 12167c478bd9Sstevel@tonic-gate skipentry = 1; 12177c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 12187c478bd9Sstevel@tonic-gate continue; 12197c478bd9Sstevel@tonic-gate } 12207c478bd9Sstevel@tonic-gate } 12217c478bd9Sstevel@tonic-gate 12227c478bd9Sstevel@tonic-gate prevhead = head; 12237c478bd9Sstevel@tonic-gate prevtail = tail; 12247c478bd9Sstevel@tonic-gate if (!head) 12257c478bd9Sstevel@tonic-gate head = tail = argp; 12267c478bd9Sstevel@tonic-gate else 12277c478bd9Sstevel@tonic-gate tail = tail->nfs_ext_u.nfs_extB.next = argp; 12287c478bd9Sstevel@tonic-gate 12297c478bd9Sstevel@tonic-gate /* 12307c478bd9Sstevel@tonic-gate * WebNFS and NFSv4 behave similarly in that they 12317c478bd9Sstevel@tonic-gate * don't use the mount protocol. Therefore, avoid 12327c478bd9Sstevel@tonic-gate * mount protocol like things when version 4 is being 12337c478bd9Sstevel@tonic-gate * used. 12347c478bd9Sstevel@tonic-gate */ 12357c478bd9Sstevel@tonic-gate if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) == 0 && 12367c478bd9Sstevel@tonic-gate nfsvers != NFS_V4) { 12377c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 12387c478bd9Sstevel@tonic-gate timeout.tv_sec = rpc_timeout; 12397c478bd9Sstevel@tonic-gate rpc_stat = RPC_TIMEDOUT; 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate /* Create the client handle. */ 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate if (trace > 1) { 12441bbc88acSrm15945 trace_prt(1, 12451bbc88acSrm15945 " nfsmount: Get mount version: request " 12467c478bd9Sstevel@tonic-gate "vers=%d min=%d\n", vers, versmin); 12477c478bd9Sstevel@tonic-gate } 12487c478bd9Sstevel@tonic-gate 12497c478bd9Sstevel@tonic-gate while ((cl = clnt_create_vers(host, MOUNTPROG, &outvers, 12507c478bd9Sstevel@tonic-gate versmin, vers, "udp")) == NULL) { 12517c478bd9Sstevel@tonic-gate if (trace > 4) { 12527c478bd9Sstevel@tonic-gate trace_prt(1, 12531bbc88acSrm15945 " nfsmount: Can't get mount " 12541bbc88acSrm15945 "version: rpcerr=%d\n", 12557c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat); 12567c478bd9Sstevel@tonic-gate } 12577c478bd9Sstevel@tonic-gate if (rpc_createerr.cf_stat == RPC_UNKNOWNHOST || 12587c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat == RPC_TIMEDOUT) 12597c478bd9Sstevel@tonic-gate break; 12607c478bd9Sstevel@tonic-gate 12617c478bd9Sstevel@tonic-gate /* 12627c478bd9Sstevel@tonic-gate * backoff and return lower version to retry the ping. 12637c478bd9Sstevel@tonic-gate * XXX we should be more careful and handle 12647c478bd9Sstevel@tonic-gate * RPC_PROGVERSMISMATCH here, because that error 12657c478bd9Sstevel@tonic-gate * is handled in clnt_create_vers(). It's not done to 12667c478bd9Sstevel@tonic-gate * stay in sync with the nfs mount command. 12677c478bd9Sstevel@tonic-gate */ 12687c478bd9Sstevel@tonic-gate vers--; 12697c478bd9Sstevel@tonic-gate if (vers < versmin) 12707c478bd9Sstevel@tonic-gate break; 12717c478bd9Sstevel@tonic-gate if (trace > 4) { 12721bbc88acSrm15945 trace_prt(1, 12731bbc88acSrm15945 " nfsmount: Try version=%d\n", 12741bbc88acSrm15945 vers); 12757c478bd9Sstevel@tonic-gate } 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate if (cl == NULL) { 12797c478bd9Sstevel@tonic-gate free(argp); 12807c478bd9Sstevel@tonic-gate head = prevhead; 12817c478bd9Sstevel@tonic-gate tail = prevtail; 12827c478bd9Sstevel@tonic-gate if (tail) 12837c478bd9Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 12847c478bd9Sstevel@tonic-gate last_error = NFSERR_NOENT; 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate if (rpc_createerr.cf_stat != RPC_UNKNOWNHOST && 12871bbc88acSrm15945 rpc_createerr.cf_stat != 12881bbc88acSrm15945 RPC_PROGVERSMISMATCH && 12897c478bd9Sstevel@tonic-gate retries-- > 0) { 12901bbc88acSrm15945 DELAY(delay); 12917c478bd9Sstevel@tonic-gate goto retry; 12927c478bd9Sstevel@tonic-gate } 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate syslog(loglevel, "%s %s", host, 12951bbc88acSrm15945 clnt_spcreateerror( 12961bbc88acSrm15945 "server not responding")); 12977c478bd9Sstevel@tonic-gate skipentry = 1; 12987c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 12997c478bd9Sstevel@tonic-gate continue; 13007c478bd9Sstevel@tonic-gate } 13017c478bd9Sstevel@tonic-gate if (trace > 1) { 13021bbc88acSrm15945 trace_prt(1, 13031bbc88acSrm15945 " nfsmount: mount version=%d\n", outvers); 13047c478bd9Sstevel@tonic-gate } 13057c478bd9Sstevel@tonic-gate #ifdef MALLOC_DEBUG 13067c478bd9Sstevel@tonic-gate add_alloc("CLNT_HANDLE", cl, 0, __FILE__, __LINE__); 13077c478bd9Sstevel@tonic-gate add_alloc("AUTH_HANDLE", cl->cl_auth, 0, 13087c478bd9Sstevel@tonic-gate __FILE__, __LINE__); 13097c478bd9Sstevel@tonic-gate #endif 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate if (__clnt_bindresvport(cl) < 0) { 13127c478bd9Sstevel@tonic-gate free(argp); 13137c478bd9Sstevel@tonic-gate head = prevhead; 13147c478bd9Sstevel@tonic-gate tail = prevtail; 13157c478bd9Sstevel@tonic-gate if (tail) 13167c478bd9Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 13177c478bd9Sstevel@tonic-gate last_error = NFSERR_NOENT; 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate if (retries-- > 0) { 13207c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 13217c478bd9Sstevel@tonic-gate DELAY(delay); 13227c478bd9Sstevel@tonic-gate goto retry; 13237c478bd9Sstevel@tonic-gate } 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate syslog(loglevel, "mount %s: %s", host, 13267c478bd9Sstevel@tonic-gate "Couldn't bind to reserved port"); 13277c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 13287c478bd9Sstevel@tonic-gate skipentry = 1; 13297c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 13307c478bd9Sstevel@tonic-gate continue; 13317c478bd9Sstevel@tonic-gate } 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate #ifdef MALLOC_DEBUG 13341bbc88acSrm15945 drop_alloc("AUTH_HANDLE", cl->cl_auth, 13351bbc88acSrm15945 __FILE__, __LINE__); 13367c478bd9Sstevel@tonic-gate #endif 13377c478bd9Sstevel@tonic-gate AUTH_DESTROY(cl->cl_auth); 13387c478bd9Sstevel@tonic-gate if ((cl->cl_auth = authsys_create_default()) == NULL) { 13397c478bd9Sstevel@tonic-gate free(argp); 13407c478bd9Sstevel@tonic-gate head = prevhead; 13417c478bd9Sstevel@tonic-gate tail = prevtail; 13427c478bd9Sstevel@tonic-gate if (tail) 13437c478bd9Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 13447c478bd9Sstevel@tonic-gate last_error = NFSERR_NOENT; 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate if (retries-- > 0) { 13477c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 13487c478bd9Sstevel@tonic-gate DELAY(delay); 13497c478bd9Sstevel@tonic-gate goto retry; 13507c478bd9Sstevel@tonic-gate } 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate syslog(loglevel, "mount %s: %s", host, 13537c478bd9Sstevel@tonic-gate "Failed creating default auth handle"); 13547c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 13557c478bd9Sstevel@tonic-gate skipentry = 1; 13567c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 13577c478bd9Sstevel@tonic-gate continue; 13587c478bd9Sstevel@tonic-gate } 13597c478bd9Sstevel@tonic-gate #ifdef MALLOC_DEBUG 13607c478bd9Sstevel@tonic-gate add_alloc("AUTH_HANDLE", cl->cl_auth, 0, 13617c478bd9Sstevel@tonic-gate __FILE__, __LINE__); 13627c478bd9Sstevel@tonic-gate #endif 13637c478bd9Sstevel@tonic-gate } else 13647c478bd9Sstevel@tonic-gate cl = NULL; 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate /* 13677c478bd9Sstevel@tonic-gate * set security options 13687c478bd9Sstevel@tonic-gate */ 13697c478bd9Sstevel@tonic-gate sec_opt = 0; 13707c478bd9Sstevel@tonic-gate (void) memset(&nfs_sec, 0, sizeof (nfs_sec)); 13717c478bd9Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_SECURE) != NULL) { 13727c478bd9Sstevel@tonic-gate if (++sec_opt > 1) { 13737c478bd9Sstevel@tonic-gate syslog(loglevel, 13747c478bd9Sstevel@tonic-gate "conflicting security options for %s", 13757c478bd9Sstevel@tonic-gate remname); 13767c478bd9Sstevel@tonic-gate free(argp); 13777c478bd9Sstevel@tonic-gate head = prevhead; 13787c478bd9Sstevel@tonic-gate tail = prevtail; 13797c478bd9Sstevel@tonic-gate if (tail) 13807c478bd9Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 13817c478bd9Sstevel@tonic-gate last_error = NFSERR_IO; 13827c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 13837c478bd9Sstevel@tonic-gate skipentry = 1; 13847c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 13857c478bd9Sstevel@tonic-gate continue; 13867c478bd9Sstevel@tonic-gate } 13877c478bd9Sstevel@tonic-gate if (nfs_getseconfig_byname("dh", &nfs_sec)) { 13887c478bd9Sstevel@tonic-gate syslog(loglevel, 13897c478bd9Sstevel@tonic-gate "error getting dh information from %s", 13907c478bd9Sstevel@tonic-gate NFSSEC_CONF); 13917c478bd9Sstevel@tonic-gate free(argp); 13927c478bd9Sstevel@tonic-gate head = prevhead; 13937c478bd9Sstevel@tonic-gate tail = prevtail; 13947c478bd9Sstevel@tonic-gate if (tail) 13957c478bd9Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 13967c478bd9Sstevel@tonic-gate last_error = NFSERR_IO; 13977c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 13987c478bd9Sstevel@tonic-gate skipentry = 1; 13997c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 14007c478bd9Sstevel@tonic-gate continue; 14017c478bd9Sstevel@tonic-gate } 14027c478bd9Sstevel@tonic-gate } 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate nfs_flavor = NULL; 1405d7c6abe8Sjasmith if (hasmntopt(&m, MNTOPT_SEC) != NULL) { 14067c478bd9Sstevel@tonic-gate if ((str_opt(&m, MNTOPT_SEC, &nfs_flavor)) == -1) { 14077c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 14087c478bd9Sstevel@tonic-gate last_error = NFSERR_IO; 14097c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 14107c478bd9Sstevel@tonic-gate goto out; 14117c478bd9Sstevel@tonic-gate } 14127c478bd9Sstevel@tonic-gate } 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate if (nfs_flavor) { 14157c478bd9Sstevel@tonic-gate if (++sec_opt > 1) { 14167c478bd9Sstevel@tonic-gate syslog(loglevel, 14177c478bd9Sstevel@tonic-gate "conflicting security options for %s", 14187c478bd9Sstevel@tonic-gate remname); 14197c478bd9Sstevel@tonic-gate free(nfs_flavor); 14207c478bd9Sstevel@tonic-gate free(argp); 14217c478bd9Sstevel@tonic-gate head = prevhead; 14227c478bd9Sstevel@tonic-gate tail = prevtail; 14237c478bd9Sstevel@tonic-gate if (tail) 14247c478bd9Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 14257c478bd9Sstevel@tonic-gate last_error = NFSERR_IO; 14267c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 14277c478bd9Sstevel@tonic-gate skipentry = 1; 14287c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 14297c478bd9Sstevel@tonic-gate continue; 14307c478bd9Sstevel@tonic-gate } 14317c478bd9Sstevel@tonic-gate if (nfs_getseconfig_byname(nfs_flavor, &nfs_sec)) { 14327c478bd9Sstevel@tonic-gate syslog(loglevel, 14337c478bd9Sstevel@tonic-gate "error getting %s information from %s", 14347c478bd9Sstevel@tonic-gate nfs_flavor, NFSSEC_CONF); 14357c478bd9Sstevel@tonic-gate free(nfs_flavor); 14367c478bd9Sstevel@tonic-gate free(argp); 14377c478bd9Sstevel@tonic-gate head = prevhead; 14387c478bd9Sstevel@tonic-gate tail = prevtail; 14397c478bd9Sstevel@tonic-gate if (tail) 14407c478bd9Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 14417c478bd9Sstevel@tonic-gate last_error = NFSERR_IO; 14427c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 14437c478bd9Sstevel@tonic-gate skipentry = 1; 14447c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 14457c478bd9Sstevel@tonic-gate continue; 14467c478bd9Sstevel@tonic-gate } 14477c478bd9Sstevel@tonic-gate free(nfs_flavor); 14487c478bd9Sstevel@tonic-gate } 14497c478bd9Sstevel@tonic-gate 14507c478bd9Sstevel@tonic-gate posix = (nfsvers != NFS_V4 && 14517c478bd9Sstevel@tonic-gate hasmntopt(&m, MNTOPT_POSIX) != NULL) ? 1 : 0; 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) == 0 && 14547c478bd9Sstevel@tonic-gate nfsvers != NFS_V4) { 14557c478bd9Sstevel@tonic-gate bool_t give_up_on_mnt; 14567c478bd9Sstevel@tonic-gate bool_t got_mnt_error; 14577c478bd9Sstevel@tonic-gate /* 14587c478bd9Sstevel@tonic-gate * If we started with a URL, if first byte of path is not "/", 14597c478bd9Sstevel@tonic-gate * then the mount will likely fail, so we should try again 14607c478bd9Sstevel@tonic-gate * with a prepended "/". 14617c478bd9Sstevel@tonic-gate */ 14627c478bd9Sstevel@tonic-gate if (mfs->mfs_flags & MFS_ALLOC_DIR && *dir != '/') 14637c478bd9Sstevel@tonic-gate give_up_on_mnt = FALSE; 14647c478bd9Sstevel@tonic-gate else 14657c478bd9Sstevel@tonic-gate give_up_on_mnt = TRUE; 14667c478bd9Sstevel@tonic-gate 14677c478bd9Sstevel@tonic-gate got_mnt_error = FALSE; 14687c478bd9Sstevel@tonic-gate 14697c478bd9Sstevel@tonic-gate try_mnt_slash: 14707c478bd9Sstevel@tonic-gate if (got_mnt_error == TRUE) { 14717c478bd9Sstevel@tonic-gate int i, l; 14727c478bd9Sstevel@tonic-gate 14737c478bd9Sstevel@tonic-gate give_up_on_mnt = TRUE; 14747c478bd9Sstevel@tonic-gate l = strlen(dir); 14757c478bd9Sstevel@tonic-gate 14767c478bd9Sstevel@tonic-gate /* 14777c478bd9Sstevel@tonic-gate * Insert a "/" to front of mfs_dir. 14787c478bd9Sstevel@tonic-gate */ 14797c478bd9Sstevel@tonic-gate for (i = l; i > 0; i--) 14807c478bd9Sstevel@tonic-gate dir[i] = dir[i-1]; 14817c478bd9Sstevel@tonic-gate 14827c478bd9Sstevel@tonic-gate dir[0] = '/'; 14837c478bd9Sstevel@tonic-gate } 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate /* Get fhandle of remote path from server's mountd */ 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate switch (outvers) { 14887c478bd9Sstevel@tonic-gate case MOUNTVERS: 14897c478bd9Sstevel@tonic-gate if (posix) { 14907c478bd9Sstevel@tonic-gate free(argp); 14917c478bd9Sstevel@tonic-gate head = prevhead; 14927c478bd9Sstevel@tonic-gate tail = prevtail; 14937c478bd9Sstevel@tonic-gate if (tail) 14941bbc88acSrm15945 tail->nfs_ext_u.nfs_extB.next = 14951bbc88acSrm15945 NULL; 14967c478bd9Sstevel@tonic-gate last_error = NFSERR_NOENT; 14971bbc88acSrm15945 syslog(loglevel, 14981bbc88acSrm15945 "can't get posix info for %s", 14997c478bd9Sstevel@tonic-gate host); 15007c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 15017c478bd9Sstevel@tonic-gate skipentry = 1; 15027c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 15037c478bd9Sstevel@tonic-gate continue; 15047c478bd9Sstevel@tonic-gate } 15057c478bd9Sstevel@tonic-gate /* FALLTHRU */ 15067c478bd9Sstevel@tonic-gate case MOUNTVERS_POSIX: 15077c478bd9Sstevel@tonic-gate if (nfsvers == NFS_V3) { 15087c478bd9Sstevel@tonic-gate free(argp); 15097c478bd9Sstevel@tonic-gate head = prevhead; 15107c478bd9Sstevel@tonic-gate tail = prevtail; 15117c478bd9Sstevel@tonic-gate if (tail) 15121bbc88acSrm15945 tail->nfs_ext_u.nfs_extB.next = 15131bbc88acSrm15945 NULL; 15147c478bd9Sstevel@tonic-gate last_error = NFSERR_NOENT; 15157c478bd9Sstevel@tonic-gate syslog(loglevel, 15167c478bd9Sstevel@tonic-gate "%s doesn't support NFS Version 3", 15177c478bd9Sstevel@tonic-gate host); 15187c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 15197c478bd9Sstevel@tonic-gate skipentry = 1; 15207c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 15217c478bd9Sstevel@tonic-gate continue; 15227c478bd9Sstevel@tonic-gate } 15237c478bd9Sstevel@tonic-gate rpc_stat = clnt_call(cl, MOUNTPROC_MNT, 15247c478bd9Sstevel@tonic-gate xdr_dirpath, (caddr_t)&dir, 15257c478bd9Sstevel@tonic-gate xdr_fhstatus, (caddr_t)&fhs, timeout); 15267c478bd9Sstevel@tonic-gate if (rpc_stat != RPC_SUCCESS) { 15277c478bd9Sstevel@tonic-gate 15287c478bd9Sstevel@tonic-gate if (give_up_on_mnt == FALSE) { 15297c478bd9Sstevel@tonic-gate got_mnt_error = TRUE; 15307c478bd9Sstevel@tonic-gate goto try_mnt_slash; 15317c478bd9Sstevel@tonic-gate } 15327c478bd9Sstevel@tonic-gate 15337c478bd9Sstevel@tonic-gate /* 15347c478bd9Sstevel@tonic-gate * Given the way "clnt_sperror" works, the "%s" 15357c478bd9Sstevel@tonic-gate * immediately following the "not responding" 15367c478bd9Sstevel@tonic-gate * is correct. 15377c478bd9Sstevel@tonic-gate */ 15387c478bd9Sstevel@tonic-gate free(argp); 15397c478bd9Sstevel@tonic-gate head = prevhead; 15407c478bd9Sstevel@tonic-gate tail = prevtail; 15417c478bd9Sstevel@tonic-gate if (tail) 15421bbc88acSrm15945 tail->nfs_ext_u.nfs_extB.next = 15431bbc88acSrm15945 NULL; 15447c478bd9Sstevel@tonic-gate last_error = NFSERR_NOENT; 15457c478bd9Sstevel@tonic-gate 15467c478bd9Sstevel@tonic-gate if (retries-- > 0) { 15477c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 15487c478bd9Sstevel@tonic-gate DELAY(delay); 15497c478bd9Sstevel@tonic-gate goto retry; 15507c478bd9Sstevel@tonic-gate } 15517c478bd9Sstevel@tonic-gate 15527c478bd9Sstevel@tonic-gate if (trace > 3) { 15537c478bd9Sstevel@tonic-gate trace_prt(1, 15541bbc88acSrm15945 " nfsmount: mount RPC " 15551bbc88acSrm15945 "failed for %s\n", 15567c478bd9Sstevel@tonic-gate host); 15577c478bd9Sstevel@tonic-gate } 15581bbc88acSrm15945 syslog(loglevel, 15591bbc88acSrm15945 "%s server not responding%s", 15607c478bd9Sstevel@tonic-gate host, clnt_sperror(cl, "")); 15617c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 15627c478bd9Sstevel@tonic-gate skipentry = 1; 15637c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 15647c478bd9Sstevel@tonic-gate continue; 15657c478bd9Sstevel@tonic-gate } 15667c478bd9Sstevel@tonic-gate if ((errno = fhs.fhs_status) != MNT_OK) { 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate if (give_up_on_mnt == FALSE) { 15697c478bd9Sstevel@tonic-gate got_mnt_error = TRUE; 15707c478bd9Sstevel@tonic-gate goto try_mnt_slash; 15717c478bd9Sstevel@tonic-gate } 15727c478bd9Sstevel@tonic-gate 15737c478bd9Sstevel@tonic-gate free(argp); 15747c478bd9Sstevel@tonic-gate head = prevhead; 15757c478bd9Sstevel@tonic-gate tail = prevtail; 15767c478bd9Sstevel@tonic-gate if (tail) 15771bbc88acSrm15945 tail->nfs_ext_u.nfs_extB.next = 15781bbc88acSrm15945 NULL; 15797c478bd9Sstevel@tonic-gate if (errno == EACCES) { 15807c478bd9Sstevel@tonic-gate status = NFSERR_ACCES; 15817c478bd9Sstevel@tonic-gate } else { 15821bbc88acSrm15945 syslog(loglevel, "%s: %m", 15831bbc88acSrm15945 host); 15847c478bd9Sstevel@tonic-gate status = NFSERR_IO; 15857c478bd9Sstevel@tonic-gate } 15867c478bd9Sstevel@tonic-gate if (trace > 3) { 15871bbc88acSrm15945 trace_prt(1, 15881bbc88acSrm15945 " nfsmount: mount RPC gave" 15897c478bd9Sstevel@tonic-gate " %d for %s:%s\n", 15907c478bd9Sstevel@tonic-gate errno, host, dir); 15917c478bd9Sstevel@tonic-gate } 15927c478bd9Sstevel@tonic-gate last_error = status; 15937c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 15947c478bd9Sstevel@tonic-gate skipentry = 1; 15957c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 15967c478bd9Sstevel@tonic-gate continue; 15977c478bd9Sstevel@tonic-gate } 15987c478bd9Sstevel@tonic-gate argp->fh = malloc((sizeof (fhandle))); 15997c478bd9Sstevel@tonic-gate if (!argp->fh) { 16007c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 16017c478bd9Sstevel@tonic-gate last_error = NFSERR_IO; 16027c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 16037c478bd9Sstevel@tonic-gate goto out; 16047c478bd9Sstevel@tonic-gate } 16051bbc88acSrm15945 (void) memcpy(argp->fh, 16061bbc88acSrm15945 &fhs.fhstatus_u.fhs_fhandle, 16077c478bd9Sstevel@tonic-gate sizeof (fhandle)); 16087c478bd9Sstevel@tonic-gate break; 16097c478bd9Sstevel@tonic-gate case MOUNTVERS3: 16107c478bd9Sstevel@tonic-gate posix = 0; 16111bbc88acSrm15945 (void) memset((char *)&res3, '\0', 16121bbc88acSrm15945 sizeof (res3)); 16137c478bd9Sstevel@tonic-gate rpc_stat = clnt_call(cl, MOUNTPROC_MNT, 16147c478bd9Sstevel@tonic-gate xdr_dirpath, (caddr_t)&dir, 16157c478bd9Sstevel@tonic-gate xdr_mountres3, (caddr_t)&res3, timeout); 16167c478bd9Sstevel@tonic-gate if (rpc_stat != RPC_SUCCESS) { 16177c478bd9Sstevel@tonic-gate 16187c478bd9Sstevel@tonic-gate if (give_up_on_mnt == FALSE) { 16197c478bd9Sstevel@tonic-gate got_mnt_error = TRUE; 16207c478bd9Sstevel@tonic-gate goto try_mnt_slash; 16217c478bd9Sstevel@tonic-gate } 16227c478bd9Sstevel@tonic-gate 16237c478bd9Sstevel@tonic-gate /* 16247c478bd9Sstevel@tonic-gate * Given the way "clnt_sperror" works, the "%s" 16257c478bd9Sstevel@tonic-gate * immediately following the "not responding" 16267c478bd9Sstevel@tonic-gate * is correct. 16277c478bd9Sstevel@tonic-gate */ 16287c478bd9Sstevel@tonic-gate free(argp); 16297c478bd9Sstevel@tonic-gate head = prevhead; 16307c478bd9Sstevel@tonic-gate tail = prevtail; 16317c478bd9Sstevel@tonic-gate if (tail) 16321bbc88acSrm15945 tail->nfs_ext_u.nfs_extB.next = 16331bbc88acSrm15945 NULL; 16347c478bd9Sstevel@tonic-gate last_error = NFSERR_NOENT; 16357c478bd9Sstevel@tonic-gate 16367c478bd9Sstevel@tonic-gate if (retries-- > 0) { 16377c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 16387c478bd9Sstevel@tonic-gate DELAY(delay); 16397c478bd9Sstevel@tonic-gate goto retry; 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate 16427c478bd9Sstevel@tonic-gate if (trace > 3) { 16437c478bd9Sstevel@tonic-gate trace_prt(1, 16441bbc88acSrm15945 " nfsmount: mount RPC " 16451bbc88acSrm15945 "failed for %s\n", 16467c478bd9Sstevel@tonic-gate host); 16477c478bd9Sstevel@tonic-gate } 16481bbc88acSrm15945 syslog(loglevel, 16491bbc88acSrm15945 "%s server not responding%s", 16507c478bd9Sstevel@tonic-gate remname, clnt_sperror(cl, "")); 16517c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 16527c478bd9Sstevel@tonic-gate skipentry = 1; 16537c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 16547c478bd9Sstevel@tonic-gate continue; 16557c478bd9Sstevel@tonic-gate } 16567c478bd9Sstevel@tonic-gate if ((errno = res3.fhs_status) != MNT_OK) { 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate if (give_up_on_mnt == FALSE) { 16597c478bd9Sstevel@tonic-gate got_mnt_error = TRUE; 16607c478bd9Sstevel@tonic-gate goto try_mnt_slash; 16617c478bd9Sstevel@tonic-gate } 16627c478bd9Sstevel@tonic-gate 16637c478bd9Sstevel@tonic-gate free(argp); 16647c478bd9Sstevel@tonic-gate head = prevhead; 16657c478bd9Sstevel@tonic-gate tail = prevtail; 16667c478bd9Sstevel@tonic-gate if (tail) 16671bbc88acSrm15945 tail->nfs_ext_u.nfs_extB.next = 16681bbc88acSrm15945 NULL; 16697c478bd9Sstevel@tonic-gate if (errno == EACCES) { 16707c478bd9Sstevel@tonic-gate status = NFSERR_ACCES; 16717c478bd9Sstevel@tonic-gate } else { 16721bbc88acSrm15945 syslog(loglevel, "%s: %m", 16731bbc88acSrm15945 remname); 16747c478bd9Sstevel@tonic-gate status = NFSERR_IO; 16757c478bd9Sstevel@tonic-gate } 16767c478bd9Sstevel@tonic-gate if (trace > 3) { 16771bbc88acSrm15945 trace_prt(1, 16781bbc88acSrm15945 " nfsmount: mount RPC gave" 16797c478bd9Sstevel@tonic-gate " %d for %s:%s\n", 16807c478bd9Sstevel@tonic-gate errno, host, dir); 16817c478bd9Sstevel@tonic-gate } 16827c478bd9Sstevel@tonic-gate last_error = status; 16837c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 16847c478bd9Sstevel@tonic-gate skipentry = 1; 16857c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 16867c478bd9Sstevel@tonic-gate continue; 16877c478bd9Sstevel@tonic-gate } 16887c478bd9Sstevel@tonic-gate 16897c478bd9Sstevel@tonic-gate /* 16907c478bd9Sstevel@tonic-gate * Negotiate the security flavor for nfs_mount 16917c478bd9Sstevel@tonic-gate */ 16921bbc88acSrm15945 auths = res3.mountres3_u.mountinfo. 16931bbc88acSrm15945 auth_flavors.auth_flavors_val; 16941bbc88acSrm15945 count = res3.mountres3_u.mountinfo. 16951bbc88acSrm15945 auth_flavors.auth_flavors_len; 16967c478bd9Sstevel@tonic-gate 16977c478bd9Sstevel@tonic-gate if (sec_opt) { 16987c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) 16991bbc88acSrm15945 if (auths[i] == 17001bbc88acSrm15945 nfs_sec.sc_nfsnum) { 17017c478bd9Sstevel@tonic-gate break; 17027c478bd9Sstevel@tonic-gate } 17037c478bd9Sstevel@tonic-gate if (i >= count) { 17047c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 17051bbc88acSrm15945 "%s: does not support " 17061bbc88acSrm15945 "security \"%s\"\n", 17077c478bd9Sstevel@tonic-gate remname, nfs_sec.sc_name); 17087c478bd9Sstevel@tonic-gate clnt_freeres(cl, xdr_mountres3, 17097c478bd9Sstevel@tonic-gate (caddr_t)&res3); 17107c478bd9Sstevel@tonic-gate free(argp); 17117c478bd9Sstevel@tonic-gate head = prevhead; 17127c478bd9Sstevel@tonic-gate tail = prevtail; 17137c478bd9Sstevel@tonic-gate if (tail) 17141bbc88acSrm15945 tail->nfs_ext_u. 17151bbc88acSrm15945 nfs_extB.next = 17161bbc88acSrm15945 NULL; 17177c478bd9Sstevel@tonic-gate last_error = NFSERR_IO; 17187c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 17197c478bd9Sstevel@tonic-gate skipentry = 1; 17207c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 17217c478bd9Sstevel@tonic-gate continue; 17227c478bd9Sstevel@tonic-gate } 17231bbc88acSrm15945 } else if (count > 0) { 17247c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) { 17257c478bd9Sstevel@tonic-gate if (!(scerror = 17261bbc88acSrm15945 nfs_getseconfig_bynumber( 17271bbc88acSrm15945 auths[i], &nfs_sec))) { 17287c478bd9Sstevel@tonic-gate sec_opt++; 17297c478bd9Sstevel@tonic-gate break; 17307c478bd9Sstevel@tonic-gate } 17317c478bd9Sstevel@tonic-gate } 17327c478bd9Sstevel@tonic-gate if (i >= count) { 17337c478bd9Sstevel@tonic-gate if (nfs_syslog_scerr(scerror, 17347c478bd9Sstevel@tonic-gate scerror_msg) 17357c478bd9Sstevel@tonic-gate != -1) { 17367c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 17371bbc88acSrm15945 "%s cannot be " 17381bbc88acSrm15945 "mounted because it" 17391bbc88acSrm15945 " is shared with " 17401bbc88acSrm15945 "security flavor %d" 17411bbc88acSrm15945 " which %s", 17427c478bd9Sstevel@tonic-gate remname, 17437c478bd9Sstevel@tonic-gate auths[i-1], 17447c478bd9Sstevel@tonic-gate scerror_msg); 17457c478bd9Sstevel@tonic-gate } 17467c478bd9Sstevel@tonic-gate clnt_freeres(cl, xdr_mountres3, 17477c478bd9Sstevel@tonic-gate (caddr_t)&res3); 17487c478bd9Sstevel@tonic-gate free(argp); 17497c478bd9Sstevel@tonic-gate head = prevhead; 17507c478bd9Sstevel@tonic-gate tail = prevtail; 17517c478bd9Sstevel@tonic-gate if (tail) 17521bbc88acSrm15945 tail->nfs_ext_u. 17531bbc88acSrm15945 nfs_extB.next = 17541bbc88acSrm15945 NULL; 17557c478bd9Sstevel@tonic-gate last_error = NFSERR_IO; 17567c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 17577c478bd9Sstevel@tonic-gate skipentry = 1; 17587c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 17597c478bd9Sstevel@tonic-gate continue; 17607c478bd9Sstevel@tonic-gate } 17617c478bd9Sstevel@tonic-gate } 17627c478bd9Sstevel@tonic-gate 17637c478bd9Sstevel@tonic-gate fh3.fh3_length = 17641bbc88acSrm15945 res3.mountres3_u.mountinfo.fhandle. 17651bbc88acSrm15945 fhandle3_len; 17667c478bd9Sstevel@tonic-gate (void) memcpy(fh3.fh3_u.data, 17671bbc88acSrm15945 res3.mountres3_u.mountinfo.fhandle. 17681bbc88acSrm15945 fhandle3_val, 17697c478bd9Sstevel@tonic-gate fh3.fh3_length); 17707c478bd9Sstevel@tonic-gate clnt_freeres(cl, xdr_mountres3, 17717c478bd9Sstevel@tonic-gate (caddr_t)&res3); 17727c478bd9Sstevel@tonic-gate argp->fh = malloc(sizeof (nfs_fh3)); 17737c478bd9Sstevel@tonic-gate if (!argp->fh) { 17747c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 17757c478bd9Sstevel@tonic-gate last_error = NFSERR_IO; 17767c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 17777c478bd9Sstevel@tonic-gate goto out; 17787c478bd9Sstevel@tonic-gate } 17797c478bd9Sstevel@tonic-gate (void) memcpy(argp->fh, &fh3, sizeof (nfs_fh3)); 17807c478bd9Sstevel@tonic-gate break; 17817c478bd9Sstevel@tonic-gate default: 17827c478bd9Sstevel@tonic-gate free(argp); 17837c478bd9Sstevel@tonic-gate head = prevhead; 17847c478bd9Sstevel@tonic-gate tail = prevtail; 17857c478bd9Sstevel@tonic-gate if (tail) 17867c478bd9Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 17877c478bd9Sstevel@tonic-gate last_error = NFSERR_NOENT; 17881bbc88acSrm15945 syslog(loglevel, 17891bbc88acSrm15945 "unknown MOUNT version %ld on %s", 17907c478bd9Sstevel@tonic-gate vers, remname); 17917c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 17927c478bd9Sstevel@tonic-gate skipentry = 1; 17937c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 17947c478bd9Sstevel@tonic-gate continue; 17957c478bd9Sstevel@tonic-gate } /* switch */ 17967c478bd9Sstevel@tonic-gate } 17977c478bd9Sstevel@tonic-gate if (nfsvers == NFS_V4) { 17987c478bd9Sstevel@tonic-gate argp->fh = strdup(dir); 17997c478bd9Sstevel@tonic-gate if (argp->fh == NULL) { 18007c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 18017c478bd9Sstevel@tonic-gate last_error = NFSERR_IO; 18027c478bd9Sstevel@tonic-gate goto out; 18037c478bd9Sstevel@tonic-gate } 18047c478bd9Sstevel@tonic-gate } 18057c478bd9Sstevel@tonic-gate 18067c478bd9Sstevel@tonic-gate if (trace > 4) 18077c478bd9Sstevel@tonic-gate trace_prt(1, " nfsmount: have %s filehandle for %s\n", 18087c478bd9Sstevel@tonic-gate fstype, remname); 18097c478bd9Sstevel@tonic-gate 18107c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_NEWARGS; 18117c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_INT; /* default is "intr" */ 18127c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_HOSTNAME; 18136a6d3e5eSjs195444 argp->hostname = strdup(host); 18146a6d3e5eSjs195444 if (argp->hostname == NULL) { 18156a6d3e5eSjs195444 syslog(LOG_ERR, "nfsmount: no memory"); 18166a6d3e5eSjs195444 last_error = NFSERR_IO; 18176a6d3e5eSjs195444 goto out; 18186a6d3e5eSjs195444 } 18197c478bd9Sstevel@tonic-gate 18207c478bd9Sstevel@tonic-gate /* 18217c478bd9Sstevel@tonic-gate * In this case, we want NFSv4 to behave like 18227c478bd9Sstevel@tonic-gate * non-WebNFS so that we get the server address. 18237c478bd9Sstevel@tonic-gate */ 18247c478bd9Sstevel@tonic-gate if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) == 0) { 18257c478bd9Sstevel@tonic-gate nconf = NULL; 18267c478bd9Sstevel@tonic-gate 18277c478bd9Sstevel@tonic-gate if (nfs_port != 0) 18287c478bd9Sstevel@tonic-gate thisport = nfs_port; 18297c478bd9Sstevel@tonic-gate else 18307c478bd9Sstevel@tonic-gate thisport = mfs->mfs_port; 18317c478bd9Sstevel@tonic-gate 18327c478bd9Sstevel@tonic-gate /* 18337c478bd9Sstevel@tonic-gate * For NFSv4, we want to avoid rpcbind, so call 18342f172c55SRobert Thurlow * get_server_netinfo() directly to tell it that 18357c478bd9Sstevel@tonic-gate * we want to go "direct_to_server". Otherwise, 18367c478bd9Sstevel@tonic-gate * do what has always been done. 18377c478bd9Sstevel@tonic-gate */ 18387c478bd9Sstevel@tonic-gate if (nfsvers == NFS_V4) { 18397c478bd9Sstevel@tonic-gate enum clnt_stat cstat; 18402f172c55SRobert Thurlow 18412f172c55SRobert Thurlow argp->addr = get_server_netinfo(SERVER_ADDR, 18427c478bd9Sstevel@tonic-gate host, NFS_PROGRAM, nfsvers, NULL, 18437c478bd9Sstevel@tonic-gate &nconf, nfs_proto, thisport, NULL, 18447c478bd9Sstevel@tonic-gate NULL, TRUE, NULL, &cstat); 18457c478bd9Sstevel@tonic-gate } else { 18467c478bd9Sstevel@tonic-gate argp->addr = get_addr(host, NFS_PROGRAM, 18477c478bd9Sstevel@tonic-gate nfsvers, &nconf, nfs_proto, 18487c478bd9Sstevel@tonic-gate thisport, NULL); 18497c478bd9Sstevel@tonic-gate } 18507c478bd9Sstevel@tonic-gate 18517c478bd9Sstevel@tonic-gate if (argp->addr == NULL) { 185239d3e169Sevanl if (argp->hostname) 185339d3e169Sevanl free(argp->hostname); 18547c478bd9Sstevel@tonic-gate free(argp->fh); 18557c478bd9Sstevel@tonic-gate free(argp); 18567c478bd9Sstevel@tonic-gate head = prevhead; 18577c478bd9Sstevel@tonic-gate tail = prevtail; 18587c478bd9Sstevel@tonic-gate if (tail) 18597c478bd9Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 18607c478bd9Sstevel@tonic-gate last_error = NFSERR_NOENT; 18617c478bd9Sstevel@tonic-gate 18627c478bd9Sstevel@tonic-gate if (retries-- > 0) { 18637c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 18647c478bd9Sstevel@tonic-gate DELAY(delay); 18657c478bd9Sstevel@tonic-gate goto retry; 18667c478bd9Sstevel@tonic-gate } 18677c478bd9Sstevel@tonic-gate 18687c478bd9Sstevel@tonic-gate syslog(loglevel, "%s: no NFS service", host); 18697c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 18707c478bd9Sstevel@tonic-gate skipentry = 1; 18717c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 18727c478bd9Sstevel@tonic-gate continue; 18737c478bd9Sstevel@tonic-gate } 18747c478bd9Sstevel@tonic-gate if (trace > 4) 18757c478bd9Sstevel@tonic-gate trace_prt(1, 18767c478bd9Sstevel@tonic-gate "\tnfsmount: have net address for %s\n", 18777c478bd9Sstevel@tonic-gate remname); 18787c478bd9Sstevel@tonic-gate 18797c478bd9Sstevel@tonic-gate } else { 18807c478bd9Sstevel@tonic-gate nconf = mfs->mfs_nconf; 18817c478bd9Sstevel@tonic-gate mfs->mfs_nconf = NULL; 18827c478bd9Sstevel@tonic-gate } 18837c478bd9Sstevel@tonic-gate 18847c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_KNCONF; 18857c478bd9Sstevel@tonic-gate argp->knconf = get_knconf(nconf); 18867c478bd9Sstevel@tonic-gate if (argp->knconf == NULL) { 18877c478bd9Sstevel@tonic-gate netbuf_free(argp->addr); 18887c478bd9Sstevel@tonic-gate freenetconfigent(nconf); 188939d3e169Sevanl if (argp->hostname) 189039d3e169Sevanl free(argp->hostname); 18917c478bd9Sstevel@tonic-gate free(argp->fh); 18927c478bd9Sstevel@tonic-gate free(argp); 18937c478bd9Sstevel@tonic-gate head = prevhead; 18947c478bd9Sstevel@tonic-gate tail = prevtail; 18957c478bd9Sstevel@tonic-gate if (tail) 18967c478bd9Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 18977c478bd9Sstevel@tonic-gate last_error = NFSERR_NOSPC; 18987c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 18997c478bd9Sstevel@tonic-gate skipentry = 1; 19007c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 19017c478bd9Sstevel@tonic-gate continue; 19027c478bd9Sstevel@tonic-gate } 19037c478bd9Sstevel@tonic-gate if (trace > 4) 19047c478bd9Sstevel@tonic-gate trace_prt(1, 19057c478bd9Sstevel@tonic-gate "\tnfsmount: have net config for %s\n", 19067c478bd9Sstevel@tonic-gate remname); 19077c478bd9Sstevel@tonic-gate 19087c478bd9Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_SOFT) != NULL) { 19097c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_SOFT; 19107c478bd9Sstevel@tonic-gate } 19117c478bd9Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_NOINTR) != NULL) { 19127c478bd9Sstevel@tonic-gate argp->flags &= ~(NFSMNT_INT); 19137c478bd9Sstevel@tonic-gate } 19147c478bd9Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_NOAC) != NULL) { 19157c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_NOAC; 19167c478bd9Sstevel@tonic-gate } 19177c478bd9Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_NOCTO) != NULL) { 19187c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_NOCTO; 19197c478bd9Sstevel@tonic-gate } 19207c478bd9Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_FORCEDIRECTIO) != NULL) { 19217c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_DIRECTIO; 19227c478bd9Sstevel@tonic-gate } 19237c478bd9Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_NOFORCEDIRECTIO) != NULL) { 19247c478bd9Sstevel@tonic-gate argp->flags &= ~(NFSMNT_DIRECTIO); 19257c478bd9Sstevel@tonic-gate } 19267c478bd9Sstevel@tonic-gate 19277c478bd9Sstevel@tonic-gate /* 19287c478bd9Sstevel@tonic-gate * Set up security data for argp->nfs_ext_u.nfs_extB.secdata. 19297c478bd9Sstevel@tonic-gate */ 19307c478bd9Sstevel@tonic-gate if (mfssnego.snego_done) { 19317c478bd9Sstevel@tonic-gate memcpy(&nfs_sec, &mfssnego.nfs_sec, 19327c478bd9Sstevel@tonic-gate sizeof (seconfig_t)); 19337c478bd9Sstevel@tonic-gate } else if (!sec_opt) { 19347c478bd9Sstevel@tonic-gate /* 19357c478bd9Sstevel@tonic-gate * Get default security mode. 19367c478bd9Sstevel@tonic-gate */ 19377c478bd9Sstevel@tonic-gate if (nfs_getseconfig_default(&nfs_sec)) { 19387c478bd9Sstevel@tonic-gate syslog(loglevel, 19397c478bd9Sstevel@tonic-gate "error getting default security entry\n"); 19407c478bd9Sstevel@tonic-gate free_knconf(argp->knconf); 19417c478bd9Sstevel@tonic-gate netbuf_free(argp->addr); 19427c478bd9Sstevel@tonic-gate freenetconfigent(nconf); 194339d3e169Sevanl if (argp->hostname) 194439d3e169Sevanl free(argp->hostname); 19457c478bd9Sstevel@tonic-gate free(argp->fh); 19467c478bd9Sstevel@tonic-gate free(argp); 19477c478bd9Sstevel@tonic-gate head = prevhead; 19487c478bd9Sstevel@tonic-gate tail = prevtail; 19497c478bd9Sstevel@tonic-gate if (tail) 19507c478bd9Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 19517c478bd9Sstevel@tonic-gate last_error = NFSERR_NOSPC; 19527c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 19537c478bd9Sstevel@tonic-gate skipentry = 1; 19547c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 19557c478bd9Sstevel@tonic-gate continue; 19567c478bd9Sstevel@tonic-gate } 19577c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_SECDEFAULT; 19587c478bd9Sstevel@tonic-gate } 19597c478bd9Sstevel@tonic-gate 19607c478bd9Sstevel@tonic-gate /* 19617c478bd9Sstevel@tonic-gate * For AUTH_DH 19627c478bd9Sstevel@tonic-gate * get the network address for the time service on 19637c478bd9Sstevel@tonic-gate * the server. If an RPC based time service is 19647c478bd9Sstevel@tonic-gate * not available then try the IP time service. 19657c478bd9Sstevel@tonic-gate * 19667c478bd9Sstevel@tonic-gate * Eventurally, we want to move this code to nfs_clnt_secdata() 19677c478bd9Sstevel@tonic-gate * when autod_nfs.c and mount.c can share the same 19682f172c55SRobert Thurlow * get_the_addr/get_netconfig_info routine. 19697c478bd9Sstevel@tonic-gate */ 19707c478bd9Sstevel@tonic-gate secflags = 0; 19717c478bd9Sstevel@tonic-gate syncaddr = NULL; 19727c478bd9Sstevel@tonic-gate retaddrs = NULL; 19737c478bd9Sstevel@tonic-gate 19747c478bd9Sstevel@tonic-gate if (nfs_sec.sc_rpcnum == AUTH_DH || nfsvers == NFS_V4) { 19757c478bd9Sstevel@tonic-gate /* 19767c478bd9Sstevel@tonic-gate * If not using the public fh and not NFS_V4, we can try 19777c478bd9Sstevel@tonic-gate * talking RPCBIND. Otherwise, assume that firewalls 19787c478bd9Sstevel@tonic-gate * prevent us from doing that. 19797c478bd9Sstevel@tonic-gate */ 19807c478bd9Sstevel@tonic-gate if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) == 0 && 19817c478bd9Sstevel@tonic-gate nfsvers != NFS_V4) { 19822f172c55SRobert Thurlow enum clnt_stat cstat; 19832f172c55SRobert Thurlow syncaddr = get_server_netinfo(SERVER_ADDR, 19842f172c55SRobert Thurlow host, RPCBPROG, RPCBVERS, NULL, &nconf, 19852f172c55SRobert Thurlow NULL, 0, NULL, NULL, FALSE, NULL, &cstat); 19867c478bd9Sstevel@tonic-gate } 19877c478bd9Sstevel@tonic-gate 19887c478bd9Sstevel@tonic-gate if (syncaddr != NULL) { 19897c478bd9Sstevel@tonic-gate /* for flags in sec_data */ 19907c478bd9Sstevel@tonic-gate secflags |= AUTH_F_RPCTIMESYNC; 19917c478bd9Sstevel@tonic-gate } else { 19927c478bd9Sstevel@tonic-gate struct nd_hostserv hs; 19937c478bd9Sstevel@tonic-gate int error; 19947c478bd9Sstevel@tonic-gate 19957c478bd9Sstevel@tonic-gate hs.h_host = host; 19967c478bd9Sstevel@tonic-gate hs.h_serv = "timserver"; 19977c478bd9Sstevel@tonic-gate error = netdir_getbyname(nconf, &hs, &retaddrs); 19987c478bd9Sstevel@tonic-gate 19991bbc88acSrm15945 if (error != ND_OK && 20001bbc88acSrm15945 nfs_sec.sc_rpcnum == AUTH_DH) { 20017c478bd9Sstevel@tonic-gate syslog(loglevel, 20021bbc88acSrm15945 "%s: secure: no time service\n", 20031bbc88acSrm15945 host); 20047c478bd9Sstevel@tonic-gate free_knconf(argp->knconf); 20057c478bd9Sstevel@tonic-gate netbuf_free(argp->addr); 20067c478bd9Sstevel@tonic-gate freenetconfigent(nconf); 200739d3e169Sevanl if (argp->hostname) 200839d3e169Sevanl free(argp->hostname); 20097c478bd9Sstevel@tonic-gate free(argp->fh); 20107c478bd9Sstevel@tonic-gate free(argp); 20117c478bd9Sstevel@tonic-gate head = prevhead; 20127c478bd9Sstevel@tonic-gate tail = prevtail; 20137c478bd9Sstevel@tonic-gate if (tail) 20141bbc88acSrm15945 tail->nfs_ext_u.nfs_extB.next = 20151bbc88acSrm15945 NULL; 20167c478bd9Sstevel@tonic-gate last_error = NFSERR_IO; 20177c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 20187c478bd9Sstevel@tonic-gate skipentry = 1; 20197c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 20207c478bd9Sstevel@tonic-gate continue; 20217c478bd9Sstevel@tonic-gate } 20227c478bd9Sstevel@tonic-gate 20237c478bd9Sstevel@tonic-gate if (error == ND_OK) 20247c478bd9Sstevel@tonic-gate syncaddr = retaddrs->n_addrs; 20257c478bd9Sstevel@tonic-gate 20267c478bd9Sstevel@tonic-gate /* 20277c478bd9Sstevel@tonic-gate * For potential usage by NFS V4 when AUTH_DH 20287c478bd9Sstevel@tonic-gate * is negotiated via SECINFO in the kernel. 20297c478bd9Sstevel@tonic-gate */ 20307c478bd9Sstevel@tonic-gate if (nfsvers == NFS_V4 && syncaddr && 20317c478bd9Sstevel@tonic-gate host2netname(netname, host, NULL)) { 20321bbc88acSrm15945 argp->syncaddr = 20331bbc88acSrm15945 malloc(sizeof (struct netbuf)); 20341bbc88acSrm15945 argp->syncaddr->buf = 20351bbc88acSrm15945 malloc(syncaddr->len); 20367c478bd9Sstevel@tonic-gate (void) memcpy(argp->syncaddr->buf, 20377c478bd9Sstevel@tonic-gate syncaddr->buf, syncaddr->len); 20387c478bd9Sstevel@tonic-gate argp->syncaddr->len = syncaddr->len; 20391bbc88acSrm15945 argp->syncaddr->maxlen = 20401bbc88acSrm15945 syncaddr->maxlen; 20417c478bd9Sstevel@tonic-gate argp->netname = strdup(netname); 20427c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_SECURE; 20437c478bd9Sstevel@tonic-gate } 20447c478bd9Sstevel@tonic-gate } /* syncaddr */ 20457c478bd9Sstevel@tonic-gate } /* AUTH_DH */ 20467c478bd9Sstevel@tonic-gate 204745916cd2Sjpk /* 204845916cd2Sjpk * TSOL notes: automountd in tsol extension 204945916cd2Sjpk * has "read down" capability, i.e. we allow 205045916cd2Sjpk * a user to trigger an nfs mount into a lower 205145916cd2Sjpk * labeled zone. We achieve this by always having 205245916cd2Sjpk * root issue the mount request so that the 205345916cd2Sjpk * lookup ops can go past /zone/<zone_name> 205445916cd2Sjpk * on the server side. 205545916cd2Sjpk */ 205645916cd2Sjpk if (is_system_labeled()) 205745916cd2Sjpk nfs_sec.sc_uid = (uid_t)0; 205845916cd2Sjpk else 20593bfb48feSsemery nfs_sec.sc_uid = uid; 20607c478bd9Sstevel@tonic-gate /* 20617c478bd9Sstevel@tonic-gate * If AUTH_DH is a chosen flavor now, its data will be stored 20627c478bd9Sstevel@tonic-gate * in the sec_data structure via nfs_clnt_secdata(). 20637c478bd9Sstevel@tonic-gate */ 20647c478bd9Sstevel@tonic-gate if (!(secdata = nfs_clnt_secdata(&nfs_sec, host, argp->knconf, 20657c478bd9Sstevel@tonic-gate syncaddr, secflags))) { 20667c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 20677c478bd9Sstevel@tonic-gate "errors constructing security related data\n"); 20687c478bd9Sstevel@tonic-gate if (secflags & AUTH_F_RPCTIMESYNC) 20697c478bd9Sstevel@tonic-gate netbuf_free(syncaddr); 20707c478bd9Sstevel@tonic-gate else if (retaddrs) 20717c478bd9Sstevel@tonic-gate netdir_free(retaddrs, ND_ADDRLIST); 20727c478bd9Sstevel@tonic-gate if (argp->syncaddr) 20737c478bd9Sstevel@tonic-gate netbuf_free(argp->syncaddr); 20747c478bd9Sstevel@tonic-gate if (argp->netname) 20757c478bd9Sstevel@tonic-gate free(argp->netname); 207639d3e169Sevanl if (argp->hostname) 207739d3e169Sevanl free(argp->hostname); 20787c478bd9Sstevel@tonic-gate free_knconf(argp->knconf); 20797c478bd9Sstevel@tonic-gate netbuf_free(argp->addr); 20807c478bd9Sstevel@tonic-gate freenetconfigent(nconf); 20817c478bd9Sstevel@tonic-gate free(argp->fh); 20827c478bd9Sstevel@tonic-gate free(argp); 20837c478bd9Sstevel@tonic-gate head = prevhead; 20847c478bd9Sstevel@tonic-gate tail = prevtail; 20857c478bd9Sstevel@tonic-gate if (tail) 20867c478bd9Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 20877c478bd9Sstevel@tonic-gate last_error = NFSERR_IO; 20887c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 20897c478bd9Sstevel@tonic-gate skipentry = 1; 20907c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 20917c478bd9Sstevel@tonic-gate continue; 20927c478bd9Sstevel@tonic-gate } 20937c478bd9Sstevel@tonic-gate NFS_ARGS_EXTB_secdata(*argp, secdata); 20947c478bd9Sstevel@tonic-gate /* end of security stuff */ 20957c478bd9Sstevel@tonic-gate 20967c478bd9Sstevel@tonic-gate if (trace > 4) 20977c478bd9Sstevel@tonic-gate trace_prt(1, 20987c478bd9Sstevel@tonic-gate " nfsmount: have secure info for %s\n", remname); 20997c478bd9Sstevel@tonic-gate 21007c478bd9Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_GRPID) != NULL) { 21017c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_GRPID; 21027c478bd9Sstevel@tonic-gate } 21037c478bd9Sstevel@tonic-gate if (nopt(&m, MNTOPT_RSIZE, &argp->rsize)) { 21047c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_RSIZE; 21057c478bd9Sstevel@tonic-gate } 21067c478bd9Sstevel@tonic-gate if (nopt(&m, MNTOPT_WSIZE, &argp->wsize)) { 21077c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_WSIZE; 21087c478bd9Sstevel@tonic-gate } 21097c478bd9Sstevel@tonic-gate if (nopt(&m, MNTOPT_TIMEO, &argp->timeo)) { 21107c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_TIMEO; 21117c478bd9Sstevel@tonic-gate } 21127c478bd9Sstevel@tonic-gate if (nopt(&m, MNTOPT_RETRANS, &argp->retrans)) { 21137c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_RETRANS; 21147c478bd9Sstevel@tonic-gate } 21157c478bd9Sstevel@tonic-gate if (nopt(&m, MNTOPT_ACTIMEO, &argp->acregmax)) { 21167c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_ACREGMAX; 21177c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_ACDIRMAX; 21187c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_ACDIRMIN; 21197c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_ACREGMIN; 21207c478bd9Sstevel@tonic-gate argp->acdirmin = argp->acregmin = argp->acdirmax 21217c478bd9Sstevel@tonic-gate = argp->acregmax; 21227c478bd9Sstevel@tonic-gate } else { 21237c478bd9Sstevel@tonic-gate if (nopt(&m, MNTOPT_ACREGMIN, &argp->acregmin)) { 21247c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_ACREGMIN; 21257c478bd9Sstevel@tonic-gate } 21267c478bd9Sstevel@tonic-gate if (nopt(&m, MNTOPT_ACREGMAX, &argp->acregmax)) { 21277c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_ACREGMAX; 21287c478bd9Sstevel@tonic-gate } 21297c478bd9Sstevel@tonic-gate if (nopt(&m, MNTOPT_ACDIRMIN, &argp->acdirmin)) { 21307c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_ACDIRMIN; 21317c478bd9Sstevel@tonic-gate } 21327c478bd9Sstevel@tonic-gate if (nopt(&m, MNTOPT_ACDIRMAX, &argp->acdirmax)) { 21337c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_ACDIRMAX; 21347c478bd9Sstevel@tonic-gate } 21357c478bd9Sstevel@tonic-gate } 21367c478bd9Sstevel@tonic-gate 21377c478bd9Sstevel@tonic-gate if (posix) { 21387c478bd9Sstevel@tonic-gate argp->pathconf = NULL; 21397c478bd9Sstevel@tonic-gate if (error = get_pathconf(cl, dir, remname, 21407c478bd9Sstevel@tonic-gate &argp->pathconf, retries)) { 21417c478bd9Sstevel@tonic-gate if (secflags & AUTH_F_RPCTIMESYNC) 21427c478bd9Sstevel@tonic-gate netbuf_free(syncaddr); 21437c478bd9Sstevel@tonic-gate else if (retaddrs) 21447c478bd9Sstevel@tonic-gate netdir_free(retaddrs, ND_ADDRLIST); 21457c478bd9Sstevel@tonic-gate free_knconf(argp->knconf); 21467c478bd9Sstevel@tonic-gate netbuf_free(argp->addr); 21477c478bd9Sstevel@tonic-gate freenetconfigent(nconf); 21487c478bd9Sstevel@tonic-gate nfs_free_secdata( 21497c478bd9Sstevel@tonic-gate argp->nfs_ext_u.nfs_extB.secdata); 21507c478bd9Sstevel@tonic-gate if (argp->syncaddr) 21517c478bd9Sstevel@tonic-gate netbuf_free(argp->syncaddr); 21527c478bd9Sstevel@tonic-gate if (argp->netname) 21537c478bd9Sstevel@tonic-gate free(argp->netname); 215439d3e169Sevanl if (argp->hostname) 215539d3e169Sevanl free(argp->hostname); 21567c478bd9Sstevel@tonic-gate free(argp->fh); 21577c478bd9Sstevel@tonic-gate free(argp); 21587c478bd9Sstevel@tonic-gate head = prevhead; 21597c478bd9Sstevel@tonic-gate tail = prevtail; 21607c478bd9Sstevel@tonic-gate if (tail) 21617c478bd9Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 21627c478bd9Sstevel@tonic-gate last_error = NFSERR_IO; 21637c478bd9Sstevel@tonic-gate 21647c478bd9Sstevel@tonic-gate if (error == RET_RETRY && retries-- > 0) { 21657c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 21667c478bd9Sstevel@tonic-gate DELAY(delay); 21677c478bd9Sstevel@tonic-gate goto retry; 21687c478bd9Sstevel@tonic-gate } 21697c478bd9Sstevel@tonic-gate 21707c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 21717c478bd9Sstevel@tonic-gate skipentry = 1; 21727c478bd9Sstevel@tonic-gate mfs->mfs_ignore = 1; 21737c478bd9Sstevel@tonic-gate continue; 21747c478bd9Sstevel@tonic-gate } 21757c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_POSIX; 21767c478bd9Sstevel@tonic-gate if (trace > 4) 21777c478bd9Sstevel@tonic-gate trace_prt(1, 21787c478bd9Sstevel@tonic-gate " nfsmount: have pathconf for %s\n", 21797c478bd9Sstevel@tonic-gate remname); 21807c478bd9Sstevel@tonic-gate } 21817c478bd9Sstevel@tonic-gate 21827c478bd9Sstevel@tonic-gate /* 21837c478bd9Sstevel@tonic-gate * free loop-specific data structures 21847c478bd9Sstevel@tonic-gate */ 21857c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 21867c478bd9Sstevel@tonic-gate freenetconfigent(nconf); 21877c478bd9Sstevel@tonic-gate if (secflags & AUTH_F_RPCTIMESYNC) 21887c478bd9Sstevel@tonic-gate netbuf_free(syncaddr); 21897c478bd9Sstevel@tonic-gate else if (retaddrs) 21907c478bd9Sstevel@tonic-gate netdir_free(retaddrs, ND_ADDRLIST); 21917c478bd9Sstevel@tonic-gate 21927c478bd9Sstevel@tonic-gate /* 21937c478bd9Sstevel@tonic-gate * Decide whether to use remote host's lockd or local locking. 21947c478bd9Sstevel@tonic-gate * If we are using the public fh, we've already turned 21957c478bd9Sstevel@tonic-gate * LLOCK on. 21967c478bd9Sstevel@tonic-gate */ 21977c478bd9Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_LLOCK)) 21987c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_LLOCK; 21997c478bd9Sstevel@tonic-gate if (!(argp->flags & NFSMNT_LLOCK) && nfsvers == NFS_VERSION && 22007c478bd9Sstevel@tonic-gate remote_lock(host, argp->fh)) { 22017c478bd9Sstevel@tonic-gate syslog(loglevel, "No network locking on %s : " 22027c478bd9Sstevel@tonic-gate "contact admin to install server change", host); 22037c478bd9Sstevel@tonic-gate argp->flags |= NFSMNT_LLOCK; 22047c478bd9Sstevel@tonic-gate } 22057c478bd9Sstevel@tonic-gate 22067c478bd9Sstevel@tonic-gate /* 22077c478bd9Sstevel@tonic-gate * Build a string for /etc/mnttab. 22087c478bd9Sstevel@tonic-gate * If possible, coalesce strings with same 'dir' info. 22097c478bd9Sstevel@tonic-gate */ 22107c478bd9Sstevel@tonic-gate if ((mfs->mfs_flags & MFS_URL) == 0) { 22117c478bd9Sstevel@tonic-gate char *tmp; 22127c478bd9Sstevel@tonic-gate 22137c478bd9Sstevel@tonic-gate if (mnttabcnt) { 22147c478bd9Sstevel@tonic-gate p = strrchr(mnttabtext, (int)':'); 22157c478bd9Sstevel@tonic-gate if (!p || strcmp(p+1, dir) != 0) { 22167c478bd9Sstevel@tonic-gate mnttabcnt += strlen(remname) + 2; 22177c478bd9Sstevel@tonic-gate } else { 22187c478bd9Sstevel@tonic-gate *p = '\0'; 22196a6d3e5eSjs195444 mnttabcnt += strlen(rhost) + 2; 22207c478bd9Sstevel@tonic-gate } 22217c478bd9Sstevel@tonic-gate if ((tmp = realloc(mnttabtext, 22227c478bd9Sstevel@tonic-gate mnttabcnt)) != NULL) { 22237c478bd9Sstevel@tonic-gate mnttabtext = tmp; 22247c478bd9Sstevel@tonic-gate strcat(mnttabtext, ","); 22257c478bd9Sstevel@tonic-gate } else { 22267c478bd9Sstevel@tonic-gate free(mnttabtext); 22277c478bd9Sstevel@tonic-gate mnttabtext = NULL; 22287c478bd9Sstevel@tonic-gate } 22297c478bd9Sstevel@tonic-gate } else { 22307c478bd9Sstevel@tonic-gate mnttabcnt = strlen(remname) + 1; 22317c478bd9Sstevel@tonic-gate if ((mnttabtext = malloc(mnttabcnt)) != NULL) 22327c478bd9Sstevel@tonic-gate mnttabtext[0] = '\0'; 22337c478bd9Sstevel@tonic-gate } 22347c478bd9Sstevel@tonic-gate 22357c478bd9Sstevel@tonic-gate if (mnttabtext != NULL) 22367c478bd9Sstevel@tonic-gate strcat(mnttabtext, remname); 22377c478bd9Sstevel@tonic-gate 22387c478bd9Sstevel@tonic-gate } else { 22397c478bd9Sstevel@tonic-gate char *tmp; 22407c478bd9Sstevel@tonic-gate int more_cnt = 0; 22417c478bd9Sstevel@tonic-gate char sport[16]; 22427c478bd9Sstevel@tonic-gate 22437c478bd9Sstevel@tonic-gate more_cnt += strlen("nfs://"); 22447c478bd9Sstevel@tonic-gate more_cnt += strlen(mfs->mfs_host); 22457c478bd9Sstevel@tonic-gate 22467c478bd9Sstevel@tonic-gate if (mfs->mfs_port != 0) { 22477c478bd9Sstevel@tonic-gate (void) sprintf(sport, ":%u", mfs->mfs_port); 22487c478bd9Sstevel@tonic-gate } else 22497c478bd9Sstevel@tonic-gate sport[0] = '\0'; 22507c478bd9Sstevel@tonic-gate 22517c478bd9Sstevel@tonic-gate more_cnt += strlen(sport); 22527c478bd9Sstevel@tonic-gate more_cnt += 1; /* "/" */ 22537c478bd9Sstevel@tonic-gate more_cnt += strlen(mfs->mfs_dir); 22547c478bd9Sstevel@tonic-gate 22557c478bd9Sstevel@tonic-gate if (mnttabcnt) { 22567c478bd9Sstevel@tonic-gate more_cnt += 1; /* "," */ 22577c478bd9Sstevel@tonic-gate mnttabcnt += more_cnt; 22587c478bd9Sstevel@tonic-gate 22597c478bd9Sstevel@tonic-gate if ((tmp = realloc(mnttabtext, 22607c478bd9Sstevel@tonic-gate mnttabcnt)) != NULL) { 22617c478bd9Sstevel@tonic-gate mnttabtext = tmp; 22627c478bd9Sstevel@tonic-gate strcat(mnttabtext, ","); 22637c478bd9Sstevel@tonic-gate } else { 22647c478bd9Sstevel@tonic-gate free(mnttabtext); 22657c478bd9Sstevel@tonic-gate mnttabtext = NULL; 22667c478bd9Sstevel@tonic-gate } 22677c478bd9Sstevel@tonic-gate } else { 22687c478bd9Sstevel@tonic-gate mnttabcnt = more_cnt + 1; 22697c478bd9Sstevel@tonic-gate if ((mnttabtext = malloc(mnttabcnt)) != NULL) 22707c478bd9Sstevel@tonic-gate mnttabtext[0] = '\0'; 22717c478bd9Sstevel@tonic-gate } 22727c478bd9Sstevel@tonic-gate 22737c478bd9Sstevel@tonic-gate if (mnttabtext != NULL) { 22747c478bd9Sstevel@tonic-gate strcat(mnttabtext, "nfs://"); 22757c478bd9Sstevel@tonic-gate strcat(mnttabtext, mfs->mfs_host); 22767c478bd9Sstevel@tonic-gate strcat(mnttabtext, sport); 22777c478bd9Sstevel@tonic-gate strcat(mnttabtext, "/"); 22787c478bd9Sstevel@tonic-gate strcat(mnttabtext, mfs->mfs_dir); 22797c478bd9Sstevel@tonic-gate } 22807c478bd9Sstevel@tonic-gate } 22817c478bd9Sstevel@tonic-gate 22827c478bd9Sstevel@tonic-gate if (!mnttabtext) { 22837c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 22847c478bd9Sstevel@tonic-gate last_error = NFSERR_IO; 22857c478bd9Sstevel@tonic-gate goto out; 22867c478bd9Sstevel@tonic-gate } 22877c478bd9Sstevel@tonic-gate 22887c478bd9Sstevel@tonic-gate /* 22897c478bd9Sstevel@tonic-gate * At least one entry, can call mount(2). 22907c478bd9Sstevel@tonic-gate */ 22917c478bd9Sstevel@tonic-gate entries++; 22927c478bd9Sstevel@tonic-gate 22937c478bd9Sstevel@tonic-gate /* 22947c478bd9Sstevel@tonic-gate * If replication was defeated, don't do more work 22957c478bd9Sstevel@tonic-gate */ 22967c478bd9Sstevel@tonic-gate if (!replicated) 22977c478bd9Sstevel@tonic-gate break; 22987c478bd9Sstevel@tonic-gate } 22997c478bd9Sstevel@tonic-gate 23007c478bd9Sstevel@tonic-gate 23017c478bd9Sstevel@tonic-gate /* 23027c478bd9Sstevel@tonic-gate * Did we get through all possibilities without success? 23037c478bd9Sstevel@tonic-gate */ 23047c478bd9Sstevel@tonic-gate if (!entries) 23057c478bd9Sstevel@tonic-gate goto out; 23067c478bd9Sstevel@tonic-gate 23077c478bd9Sstevel@tonic-gate /* Make "xattr" the default if "noxattr" is not specified. */ 23087c478bd9Sstevel@tonic-gate strcpy(mopts, opts); 23097c478bd9Sstevel@tonic-gate if (!hasmntopt(&m, MNTOPT_NOXATTR) && !hasmntopt(&m, MNTOPT_XATTR)) { 23107c478bd9Sstevel@tonic-gate if (strlen(mopts) > 0) 23117c478bd9Sstevel@tonic-gate strcat(mopts, ","); 23127c478bd9Sstevel@tonic-gate strcat(mopts, "xattr"); 23137c478bd9Sstevel@tonic-gate } 23147c478bd9Sstevel@tonic-gate 23157c478bd9Sstevel@tonic-gate /* 23167c478bd9Sstevel@tonic-gate * enable services as needed. 23177c478bd9Sstevel@tonic-gate */ 23187c478bd9Sstevel@tonic-gate { 23197c478bd9Sstevel@tonic-gate char **sl; 23207c478bd9Sstevel@tonic-gate 23217c478bd9Sstevel@tonic-gate if (strcmp(fstype, MNTTYPE_NFS4) == 0) 23227c478bd9Sstevel@tonic-gate sl = service_list_v4; 23237c478bd9Sstevel@tonic-gate else 23247c478bd9Sstevel@tonic-gate sl = service_list; 23257c478bd9Sstevel@tonic-gate 232645916cd2Sjpk (void) _check_services(sl); 23277c478bd9Sstevel@tonic-gate } 23287c478bd9Sstevel@tonic-gate 23297c478bd9Sstevel@tonic-gate /* 23307c478bd9Sstevel@tonic-gate * Whew; do the mount, at last. 23317c478bd9Sstevel@tonic-gate */ 23327c478bd9Sstevel@tonic-gate if (trace > 1) { 23337c478bd9Sstevel@tonic-gate trace_prt(1, " mount %s %s (%s)\n", mnttabtext, mntpnt, mopts); 23347c478bd9Sstevel@tonic-gate } 23357c478bd9Sstevel@tonic-gate 233639d3e169Sevanl /* 2337b9238976Sth199096 * About to do a nfs mount, make sure the mount_to is set for 2338b9238976Sth199096 * potential ephemeral mounts with NFSv4. 2339b9238976Sth199096 */ 2340b9238976Sth199096 set_nfsv4_ephemeral_mount_to(); 2341b9238976Sth199096 2342b9238976Sth199096 /* 234339d3e169Sevanl * If no action list pointer then do the mount, otherwise 234439d3e169Sevanl * build the actions list pointer with the mount information. 234539d3e169Sevanl * so the mount can be done in the kernel. 234639d3e169Sevanl */ 234739d3e169Sevanl if (alp == NULL) { 23487c478bd9Sstevel@tonic-gate if (mount(mnttabtext, mntpnt, flags | MS_DATA, fstype, 23497c478bd9Sstevel@tonic-gate head, sizeof (*head), mopts, MAX_MNTOPT_STR) < 0) { 23507c478bd9Sstevel@tonic-gate if (trace > 1) 23517c478bd9Sstevel@tonic-gate trace_prt(1, " Mount of %s on %s: %d\n", 23527c478bd9Sstevel@tonic-gate mnttabtext, mntpnt, errno); 23537c478bd9Sstevel@tonic-gate if (errno != EBUSY || verbose) 23547c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 23557c478bd9Sstevel@tonic-gate "Mount of %s on %s: %m", mnttabtext, mntpnt); 23567c478bd9Sstevel@tonic-gate last_error = NFSERR_IO; 23577c478bd9Sstevel@tonic-gate goto out; 23587c478bd9Sstevel@tonic-gate } 23597c478bd9Sstevel@tonic-gate 23607c478bd9Sstevel@tonic-gate last_error = NFS_OK; 23617c478bd9Sstevel@tonic-gate if (stat(mntpnt, &stbuf) == 0) { 23627c478bd9Sstevel@tonic-gate if (trace > 1) { 23637c478bd9Sstevel@tonic-gate trace_prt(1, " mount %s dev=%x rdev=%x OK\n", 23647c478bd9Sstevel@tonic-gate mnttabtext, stbuf.st_dev, stbuf.st_rdev); 23657c478bd9Sstevel@tonic-gate } 23667c478bd9Sstevel@tonic-gate } else { 23677c478bd9Sstevel@tonic-gate if (trace > 1) { 23687c478bd9Sstevel@tonic-gate trace_prt(1, " mount %s OK\n", mnttabtext); 23697c478bd9Sstevel@tonic-gate trace_prt(1, " stat of %s failed\n", mntpnt); 23707c478bd9Sstevel@tonic-gate } 237139d3e169Sevanl 237239d3e169Sevanl } 237339d3e169Sevanl } else { 237439d3e169Sevanl alp->action.action = AUTOFS_MOUNT_RQ; 237539d3e169Sevanl alp->action.action_list_entry_u.mounta.spec = 237639d3e169Sevanl strdup(mnttabtext); 237739d3e169Sevanl alp->action.action_list_entry_u.mounta.dir = strdup(mntpnt); 237839d3e169Sevanl alp->action.action_list_entry_u.mounta.flags = 237939d3e169Sevanl flags | MS_DATA; 238039d3e169Sevanl alp->action.action_list_entry_u.mounta.fstype = 238139d3e169Sevanl strdup(fstype); 238239d3e169Sevanl alp->action.action_list_entry_u.mounta.dataptr = (char *)head; 238339d3e169Sevanl alp->action.action_list_entry_u.mounta.datalen = 238439d3e169Sevanl sizeof (*head); 238539d3e169Sevanl mntopts = malloc(strlen(mopts) + 1); 238639d3e169Sevanl strcpy(mntopts, mopts); 238739d3e169Sevanl mntopts[strlen(mopts)] = '\0'; 238839d3e169Sevanl alp->action.action_list_entry_u.mounta.optptr = mntopts; 238939d3e169Sevanl alp->action.action_list_entry_u.mounta.optlen = 239039d3e169Sevanl strlen(mntopts) + 1; 239139d3e169Sevanl last_error = NFS_OK; 239239d3e169Sevanl goto ret; 23937c478bd9Sstevel@tonic-gate } 23947c478bd9Sstevel@tonic-gate 23957c478bd9Sstevel@tonic-gate out: 23967c478bd9Sstevel@tonic-gate argp = head; 23977c478bd9Sstevel@tonic-gate while (argp) { 23987c478bd9Sstevel@tonic-gate if (argp->pathconf) 23997c478bd9Sstevel@tonic-gate free(argp->pathconf); 24007c478bd9Sstevel@tonic-gate free_knconf(argp->knconf); 24017c478bd9Sstevel@tonic-gate netbuf_free(argp->addr); 24027c478bd9Sstevel@tonic-gate if (argp->syncaddr) 24037c478bd9Sstevel@tonic-gate netbuf_free(argp->syncaddr); 24047c478bd9Sstevel@tonic-gate if (argp->netname) { 24057c478bd9Sstevel@tonic-gate free(argp->netname); 24067c478bd9Sstevel@tonic-gate } 240739d3e169Sevanl if (argp->hostname) 240839d3e169Sevanl free(argp->hostname); 24097c478bd9Sstevel@tonic-gate nfs_free_secdata(argp->nfs_ext_u.nfs_extB.secdata); 24107c478bd9Sstevel@tonic-gate free(argp->fh); 24117c478bd9Sstevel@tonic-gate head = argp; 24127c478bd9Sstevel@tonic-gate argp = argp->nfs_ext_u.nfs_extB.next; 24137c478bd9Sstevel@tonic-gate free(head); 24147c478bd9Sstevel@tonic-gate } 24157c478bd9Sstevel@tonic-gate ret: 24167c478bd9Sstevel@tonic-gate if (nfs_proto) 24177c478bd9Sstevel@tonic-gate free(nfs_proto); 24187c478bd9Sstevel@tonic-gate if (mnttabtext) 24197c478bd9Sstevel@tonic-gate free(mnttabtext); 24207c478bd9Sstevel@tonic-gate 24217c478bd9Sstevel@tonic-gate for (mfs = mfs_in; mfs; mfs = mfs->mfs_next) { 24227c478bd9Sstevel@tonic-gate 24237c478bd9Sstevel@tonic-gate if (mfs->mfs_flags & MFS_ALLOC_DIR) { 24247c478bd9Sstevel@tonic-gate free(mfs->mfs_dir); 24257c478bd9Sstevel@tonic-gate mfs->mfs_dir = NULL; 24267c478bd9Sstevel@tonic-gate mfs->mfs_flags &= ~MFS_ALLOC_DIR; 24277c478bd9Sstevel@tonic-gate } 24287c478bd9Sstevel@tonic-gate 242939d3e169Sevanl if (mfs->mfs_args != NULL && alp == NULL) { 24307c478bd9Sstevel@tonic-gate free(mfs->mfs_args); 24317c478bd9Sstevel@tonic-gate mfs->mfs_args = NULL; 24327c478bd9Sstevel@tonic-gate } 24337c478bd9Sstevel@tonic-gate 24347c478bd9Sstevel@tonic-gate if (mfs->mfs_nconf != NULL) { 24357c478bd9Sstevel@tonic-gate freenetconfigent(mfs->mfs_nconf); 24367c478bd9Sstevel@tonic-gate mfs->mfs_nconf = NULL; 24377c478bd9Sstevel@tonic-gate } 24387c478bd9Sstevel@tonic-gate } 24397c478bd9Sstevel@tonic-gate 24407c478bd9Sstevel@tonic-gate return (last_error); 24417c478bd9Sstevel@tonic-gate } 24427c478bd9Sstevel@tonic-gate 24437c478bd9Sstevel@tonic-gate /* 24447c478bd9Sstevel@tonic-gate * get_pathconf(cl, path, fsname, pcnf, cretries) 24457c478bd9Sstevel@tonic-gate * ugliness that requires that ppathcnf and pathcnf stay consistent 24467c478bd9Sstevel@tonic-gate * cretries is a copy of retries used to determine when to syslog 24477c478bd9Sstevel@tonic-gate * on retry situations. 24487c478bd9Sstevel@tonic-gate */ 24497c478bd9Sstevel@tonic-gate static int 24507c478bd9Sstevel@tonic-gate get_pathconf(CLIENT *cl, char *path, char *fsname, struct pathcnf **pcnf, 24517c478bd9Sstevel@tonic-gate int cretries) 24527c478bd9Sstevel@tonic-gate { 24537c478bd9Sstevel@tonic-gate struct ppathcnf *p = NULL; 24547c478bd9Sstevel@tonic-gate enum clnt_stat rpc_stat; 24557c478bd9Sstevel@tonic-gate struct timeval timeout; 24567c478bd9Sstevel@tonic-gate 24577c478bd9Sstevel@tonic-gate p = (struct ppathcnf *)malloc(sizeof (struct ppathcnf)); 24587c478bd9Sstevel@tonic-gate if (p == NULL) { 24597c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "get_pathconf: Out of memory"); 24607c478bd9Sstevel@tonic-gate return (RET_ERR); 24617c478bd9Sstevel@tonic-gate } 24627c478bd9Sstevel@tonic-gate memset((caddr_t)p, 0, sizeof (struct ppathcnf)); 24637c478bd9Sstevel@tonic-gate 24647c478bd9Sstevel@tonic-gate timeout.tv_sec = 10; 24657c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 24667c478bd9Sstevel@tonic-gate rpc_stat = clnt_call(cl, MOUNTPROC_PATHCONF, 24677c478bd9Sstevel@tonic-gate xdr_dirpath, (caddr_t)&path, xdr_ppathcnf, (caddr_t)p, timeout); 24687c478bd9Sstevel@tonic-gate if (rpc_stat != RPC_SUCCESS) { 24697c478bd9Sstevel@tonic-gate if (cretries-- <= 0) { 24707c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 24717c478bd9Sstevel@tonic-gate "get_pathconf: %s: server not responding: %s", 24727c478bd9Sstevel@tonic-gate fsname, clnt_sperror(cl, "")); 24737c478bd9Sstevel@tonic-gate } 24747c478bd9Sstevel@tonic-gate free(p); 24757c478bd9Sstevel@tonic-gate return (RET_RETRY); 24767c478bd9Sstevel@tonic-gate } 24777c478bd9Sstevel@tonic-gate if (_PC_ISSET(_PC_ERROR, p->pc_mask)) { 24787c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "get_pathconf: no info for %s", fsname); 24797c478bd9Sstevel@tonic-gate free(p); 24807c478bd9Sstevel@tonic-gate return (RET_ERR); 24817c478bd9Sstevel@tonic-gate } 24827c478bd9Sstevel@tonic-gate *pcnf = (struct pathcnf *)p; 24837c478bd9Sstevel@tonic-gate return (RET_OK); 24847c478bd9Sstevel@tonic-gate } 24857c478bd9Sstevel@tonic-gate 248639d3e169Sevanl void 24877c478bd9Sstevel@tonic-gate netbuf_free(nb) 24887c478bd9Sstevel@tonic-gate struct netbuf *nb; 24897c478bd9Sstevel@tonic-gate { 24907c478bd9Sstevel@tonic-gate if (nb == NULL) 24917c478bd9Sstevel@tonic-gate return; 24927c478bd9Sstevel@tonic-gate if (nb->buf) 24937c478bd9Sstevel@tonic-gate free(nb->buf); 24947c478bd9Sstevel@tonic-gate free(nb); 24957c478bd9Sstevel@tonic-gate } 24967c478bd9Sstevel@tonic-gate 24977c478bd9Sstevel@tonic-gate #define SMALL_HOSTNAME 20 24987c478bd9Sstevel@tonic-gate #define SMALL_PROTONAME 10 24997c478bd9Sstevel@tonic-gate #define SMALL_PROTOFMLYNAME 10 25007c478bd9Sstevel@tonic-gate 25017c478bd9Sstevel@tonic-gate struct portmap_cache { 25027c478bd9Sstevel@tonic-gate int cache_prog; 25037c478bd9Sstevel@tonic-gate int cache_vers; 25047c478bd9Sstevel@tonic-gate time_t cache_time; 25057c478bd9Sstevel@tonic-gate char cache_small_hosts[SMALL_HOSTNAME + 1]; 25067c478bd9Sstevel@tonic-gate char *cache_hostname; 25077c478bd9Sstevel@tonic-gate char *cache_proto; 25087c478bd9Sstevel@tonic-gate char *cache_protofmly; 25097c478bd9Sstevel@tonic-gate char cache_small_protofmly[SMALL_PROTOFMLYNAME + 1]; 25107c478bd9Sstevel@tonic-gate char cache_small_proto[SMALL_PROTONAME + 1]; 25117c478bd9Sstevel@tonic-gate struct netbuf cache_srv_addr; 25127c478bd9Sstevel@tonic-gate struct portmap_cache *cache_prev, *cache_next; 25137c478bd9Sstevel@tonic-gate }; 25147c478bd9Sstevel@tonic-gate 25157c478bd9Sstevel@tonic-gate rwlock_t portmap_cache_lock; 25167c478bd9Sstevel@tonic-gate static int portmap_cache_valid_time = 30; 25177c478bd9Sstevel@tonic-gate struct portmap_cache *portmap_cache_head, *portmap_cache_tail; 25187c478bd9Sstevel@tonic-gate 25197c478bd9Sstevel@tonic-gate #ifdef MALLOC_DEBUG 25207c478bd9Sstevel@tonic-gate void 25217c478bd9Sstevel@tonic-gate portmap_cache_flush() 25227c478bd9Sstevel@tonic-gate { 25237c478bd9Sstevel@tonic-gate struct portmap_cache *next = NULL, *cp; 25247c478bd9Sstevel@tonic-gate 25257c478bd9Sstevel@tonic-gate (void) rw_wrlock(&portmap_cache_lock); 25267c478bd9Sstevel@tonic-gate for (cp = portmap_cache_head; cp; cp = cp->cache_next) { 25277c478bd9Sstevel@tonic-gate if (cp->cache_hostname != NULL && 25287c478bd9Sstevel@tonic-gate cp->cache_hostname != 25297c478bd9Sstevel@tonic-gate cp->cache_small_hosts) 25307c478bd9Sstevel@tonic-gate free(cp->cache_hostname); 25317c478bd9Sstevel@tonic-gate if (cp->cache_proto != NULL && 25327c478bd9Sstevel@tonic-gate cp->cache_proto != 25337c478bd9Sstevel@tonic-gate cp->cache_small_proto) 25347c478bd9Sstevel@tonic-gate free(cp->cache_proto); 25357c478bd9Sstevel@tonic-gate if (cp->cache_srv_addr.buf != NULL) 25367c478bd9Sstevel@tonic-gate free(cp->cache_srv_addr.buf); 25377c478bd9Sstevel@tonic-gate next = cp->cache_next; 25387c478bd9Sstevel@tonic-gate free(cp); 25397c478bd9Sstevel@tonic-gate } 25407c478bd9Sstevel@tonic-gate portmap_cache_head = NULL; 25417c478bd9Sstevel@tonic-gate portmap_cache_tail = NULL; 25427c478bd9Sstevel@tonic-gate (void) rw_unlock(&portmap_cache_lock); 25437c478bd9Sstevel@tonic-gate } 25447c478bd9Sstevel@tonic-gate #endif 25457c478bd9Sstevel@tonic-gate 25467c478bd9Sstevel@tonic-gate /* 25477c478bd9Sstevel@tonic-gate * Returns 1 if the entry is found in the cache, 0 otherwise. 25487c478bd9Sstevel@tonic-gate */ 25497c478bd9Sstevel@tonic-gate static int 25507c478bd9Sstevel@tonic-gate portmap_cache_lookup(hostname, prog, vers, nconf, addrp) 25517c478bd9Sstevel@tonic-gate char *hostname; 25527c478bd9Sstevel@tonic-gate rpcprog_t prog; 25537c478bd9Sstevel@tonic-gate rpcvers_t vers; 25547c478bd9Sstevel@tonic-gate struct netconfig *nconf; 25557c478bd9Sstevel@tonic-gate struct netbuf *addrp; 25567c478bd9Sstevel@tonic-gate { 25577c478bd9Sstevel@tonic-gate struct portmap_cache *cachep, *prev, *next = NULL, *cp; 25587c478bd9Sstevel@tonic-gate int retval = 0; 25597c478bd9Sstevel@tonic-gate 25607c478bd9Sstevel@tonic-gate timenow = time(NULL); 25617c478bd9Sstevel@tonic-gate 25627c478bd9Sstevel@tonic-gate (void) rw_rdlock(&portmap_cache_lock); 25637c478bd9Sstevel@tonic-gate 25647c478bd9Sstevel@tonic-gate /* 25657c478bd9Sstevel@tonic-gate * Increment the portmap cache counters for # accesses and lookups 25667c478bd9Sstevel@tonic-gate * Use a smaller factor (100 vs 1000 for the host cache) since 25677c478bd9Sstevel@tonic-gate * initial analysis shows this cache is looked up 10% that of the 25687c478bd9Sstevel@tonic-gate * host cache. 25697c478bd9Sstevel@tonic-gate */ 25707c478bd9Sstevel@tonic-gate #ifdef CACHE_DEBUG 25717c478bd9Sstevel@tonic-gate portmap_cache_accesses++; 25727c478bd9Sstevel@tonic-gate portmap_cache_lookups++; 25737c478bd9Sstevel@tonic-gate if ((portmap_cache_lookups%100) == 0) 25747c478bd9Sstevel@tonic-gate trace_portmap_cache(); 25757c478bd9Sstevel@tonic-gate #endif /* CACHE_DEBUG */ 25767c478bd9Sstevel@tonic-gate 25777c478bd9Sstevel@tonic-gate for (cachep = portmap_cache_head; cachep; 25787c478bd9Sstevel@tonic-gate cachep = cachep->cache_next) { 25797c478bd9Sstevel@tonic-gate if (timenow > cachep->cache_time) { 25807c478bd9Sstevel@tonic-gate /* 25817c478bd9Sstevel@tonic-gate * We stumbled across an entry in the cache which 25827c478bd9Sstevel@tonic-gate * has timed out. Free up all the entries that 25837c478bd9Sstevel@tonic-gate * were added before it, which will positionally 25847c478bd9Sstevel@tonic-gate * be after this entry. And adjust neighboring 25857c478bd9Sstevel@tonic-gate * pointers. 25867c478bd9Sstevel@tonic-gate * When we drop the lock and re-acquire it, we 25877c478bd9Sstevel@tonic-gate * need to start from the beginning. 25887c478bd9Sstevel@tonic-gate */ 25897c478bd9Sstevel@tonic-gate (void) rw_unlock(&portmap_cache_lock); 25907c478bd9Sstevel@tonic-gate (void) rw_wrlock(&portmap_cache_lock); 25917c478bd9Sstevel@tonic-gate for (cp = portmap_cache_head; 25927c478bd9Sstevel@tonic-gate cp && (cp->cache_time >= timenow); 25937c478bd9Sstevel@tonic-gate cp = cp->cache_next) 25947c478bd9Sstevel@tonic-gate ; 25957c478bd9Sstevel@tonic-gate if (cp == NULL) 25967c478bd9Sstevel@tonic-gate goto done; 25977c478bd9Sstevel@tonic-gate /* 25987c478bd9Sstevel@tonic-gate * Adjust the link of the predecessor. 25997c478bd9Sstevel@tonic-gate * Make the tail point to the new last entry. 26007c478bd9Sstevel@tonic-gate */ 26017c478bd9Sstevel@tonic-gate prev = cp->cache_prev; 26027c478bd9Sstevel@tonic-gate if (prev == NULL) { 26037c478bd9Sstevel@tonic-gate portmap_cache_head = NULL; 26047c478bd9Sstevel@tonic-gate portmap_cache_tail = NULL; 26057c478bd9Sstevel@tonic-gate } else { 26067c478bd9Sstevel@tonic-gate prev->cache_next = NULL; 26077c478bd9Sstevel@tonic-gate portmap_cache_tail = prev; 26087c478bd9Sstevel@tonic-gate } 26097c478bd9Sstevel@tonic-gate for (; cp; cp = next) { 26107c478bd9Sstevel@tonic-gate if (cp->cache_hostname != NULL && 26117c478bd9Sstevel@tonic-gate cp->cache_hostname != 26127c478bd9Sstevel@tonic-gate cp->cache_small_hosts) 26137c478bd9Sstevel@tonic-gate free(cp->cache_hostname); 26147c478bd9Sstevel@tonic-gate if (cp->cache_proto != NULL && 26157c478bd9Sstevel@tonic-gate cp->cache_proto != 26167c478bd9Sstevel@tonic-gate cp->cache_small_proto) 26177c478bd9Sstevel@tonic-gate free(cp->cache_proto); 26187c478bd9Sstevel@tonic-gate if (cp->cache_srv_addr.buf != NULL) 26197c478bd9Sstevel@tonic-gate free(cp->cache_srv_addr.buf); 26207c478bd9Sstevel@tonic-gate next = cp->cache_next; 26217c478bd9Sstevel@tonic-gate free(cp); 26227c478bd9Sstevel@tonic-gate } 26237c478bd9Sstevel@tonic-gate goto done; 26247c478bd9Sstevel@tonic-gate } 26257c478bd9Sstevel@tonic-gate if (cachep->cache_hostname == NULL || 26267c478bd9Sstevel@tonic-gate prog != cachep->cache_prog || vers != cachep->cache_vers || 26277c478bd9Sstevel@tonic-gate strcmp(nconf->nc_proto, cachep->cache_proto) != 0 || 26287c478bd9Sstevel@tonic-gate strcmp(nconf->nc_protofmly, cachep->cache_protofmly) != 0 || 26297c478bd9Sstevel@tonic-gate strcmp(hostname, cachep->cache_hostname) != 0) 26307c478bd9Sstevel@tonic-gate continue; 26317c478bd9Sstevel@tonic-gate /* 26327c478bd9Sstevel@tonic-gate * Cache Hit. 26337c478bd9Sstevel@tonic-gate */ 26347c478bd9Sstevel@tonic-gate #ifdef CACHE_DEBUG 26357c478bd9Sstevel@tonic-gate portmap_cache_hits++; /* up portmap cache hit counter */ 26367c478bd9Sstevel@tonic-gate #endif /* CACHE_DEBUG */ 26377c478bd9Sstevel@tonic-gate addrp->len = cachep->cache_srv_addr.len; 26387c478bd9Sstevel@tonic-gate memcpy(addrp->buf, cachep->cache_srv_addr.buf, addrp->len); 26397c478bd9Sstevel@tonic-gate retval = 1; 26407c478bd9Sstevel@tonic-gate break; 26417c478bd9Sstevel@tonic-gate } 26427c478bd9Sstevel@tonic-gate done: 26437c478bd9Sstevel@tonic-gate (void) rw_unlock(&portmap_cache_lock); 26447c478bd9Sstevel@tonic-gate return (retval); 26457c478bd9Sstevel@tonic-gate } 26467c478bd9Sstevel@tonic-gate 26477c478bd9Sstevel@tonic-gate static void 26487c478bd9Sstevel@tonic-gate portmap_cache_enter(hostname, prog, vers, nconf, addrp) 26497c478bd9Sstevel@tonic-gate char *hostname; 26507c478bd9Sstevel@tonic-gate rpcprog_t prog; 26517c478bd9Sstevel@tonic-gate rpcvers_t vers; 26527c478bd9Sstevel@tonic-gate struct netconfig *nconf; 26537c478bd9Sstevel@tonic-gate struct netbuf *addrp; 26547c478bd9Sstevel@tonic-gate { 26557c478bd9Sstevel@tonic-gate struct portmap_cache *cachep; 26567c478bd9Sstevel@tonic-gate int protofmlylen; 26577c478bd9Sstevel@tonic-gate int protolen, hostnamelen; 26587c478bd9Sstevel@tonic-gate 26597c478bd9Sstevel@tonic-gate timenow = time(NULL); 26607c478bd9Sstevel@tonic-gate 26617c478bd9Sstevel@tonic-gate cachep = malloc(sizeof (struct portmap_cache)); 26627c478bd9Sstevel@tonic-gate if (cachep == NULL) 26637c478bd9Sstevel@tonic-gate return; 26647c478bd9Sstevel@tonic-gate memset((char *)cachep, 0, sizeof (*cachep)); 26657c478bd9Sstevel@tonic-gate 26667c478bd9Sstevel@tonic-gate hostnamelen = strlen(hostname); 26677c478bd9Sstevel@tonic-gate if (hostnamelen <= SMALL_HOSTNAME) 26687c478bd9Sstevel@tonic-gate cachep->cache_hostname = cachep->cache_small_hosts; 26697c478bd9Sstevel@tonic-gate else { 26707c478bd9Sstevel@tonic-gate cachep->cache_hostname = malloc(hostnamelen + 1); 26717c478bd9Sstevel@tonic-gate if (cachep->cache_hostname == NULL) 26727c478bd9Sstevel@tonic-gate goto nomem; 26737c478bd9Sstevel@tonic-gate } 26747c478bd9Sstevel@tonic-gate strcpy(cachep->cache_hostname, hostname); 26757c478bd9Sstevel@tonic-gate protolen = strlen(nconf->nc_proto); 26767c478bd9Sstevel@tonic-gate if (protolen <= SMALL_PROTONAME) 26777c478bd9Sstevel@tonic-gate cachep->cache_proto = cachep->cache_small_proto; 26787c478bd9Sstevel@tonic-gate else { 26797c478bd9Sstevel@tonic-gate cachep->cache_proto = malloc(protolen + 1); 26807c478bd9Sstevel@tonic-gate if (cachep->cache_proto == NULL) 26817c478bd9Sstevel@tonic-gate goto nomem; 26827c478bd9Sstevel@tonic-gate } 26837c478bd9Sstevel@tonic-gate protofmlylen = strlen(nconf->nc_protofmly); 26847c478bd9Sstevel@tonic-gate if (protofmlylen <= SMALL_PROTOFMLYNAME) 26857c478bd9Sstevel@tonic-gate cachep->cache_protofmly = cachep->cache_small_protofmly; 26867c478bd9Sstevel@tonic-gate else { 26877c478bd9Sstevel@tonic-gate cachep->cache_protofmly = malloc(protofmlylen + 1); 26887c478bd9Sstevel@tonic-gate if (cachep->cache_protofmly == NULL) 26897c478bd9Sstevel@tonic-gate goto nomem; 26907c478bd9Sstevel@tonic-gate } 26917c478bd9Sstevel@tonic-gate 26927c478bd9Sstevel@tonic-gate strcpy(cachep->cache_proto, nconf->nc_proto); 26937c478bd9Sstevel@tonic-gate cachep->cache_prog = prog; 26947c478bd9Sstevel@tonic-gate cachep->cache_vers = vers; 26957c478bd9Sstevel@tonic-gate cachep->cache_time = timenow + portmap_cache_valid_time; 26967c478bd9Sstevel@tonic-gate cachep->cache_srv_addr.len = addrp->len; 26977c478bd9Sstevel@tonic-gate cachep->cache_srv_addr.buf = malloc(addrp->len); 26987c478bd9Sstevel@tonic-gate if (cachep->cache_srv_addr.buf == NULL) 26997c478bd9Sstevel@tonic-gate goto nomem; 27007c478bd9Sstevel@tonic-gate memcpy(cachep->cache_srv_addr.buf, addrp->buf, addrp->maxlen); 27017c478bd9Sstevel@tonic-gate cachep->cache_prev = NULL; 27027c478bd9Sstevel@tonic-gate (void) rw_wrlock(&portmap_cache_lock); 27037c478bd9Sstevel@tonic-gate /* 27047c478bd9Sstevel@tonic-gate * There's a window in which we could have multiple threads making 27057c478bd9Sstevel@tonic-gate * the same cache entry. This can be avoided by walking the cache 27067c478bd9Sstevel@tonic-gate * once again here to check and see if there are duplicate entries 27077c478bd9Sstevel@tonic-gate * (after grabbing the write lock). This isn't fatal and I'm not 27087c478bd9Sstevel@tonic-gate * going to bother with this. 27097c478bd9Sstevel@tonic-gate */ 27107c478bd9Sstevel@tonic-gate #ifdef CACHE_DEBUG 27117c478bd9Sstevel@tonic-gate portmap_cache_accesses++; /* up portmap cache access counter */ 27127c478bd9Sstevel@tonic-gate #endif /* CACHE_DEBUG */ 27137c478bd9Sstevel@tonic-gate cachep->cache_next = portmap_cache_head; 27147c478bd9Sstevel@tonic-gate if (portmap_cache_head != NULL) 27157c478bd9Sstevel@tonic-gate portmap_cache_head->cache_prev = cachep; 27167c478bd9Sstevel@tonic-gate portmap_cache_head = cachep; 27177c478bd9Sstevel@tonic-gate (void) rw_unlock(&portmap_cache_lock); 27187c478bd9Sstevel@tonic-gate return; 27197c478bd9Sstevel@tonic-gate 27207c478bd9Sstevel@tonic-gate nomem: 27217c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "portmap_cache_enter: Memory allocation failed"); 27227c478bd9Sstevel@tonic-gate if (cachep->cache_srv_addr.buf) 27237c478bd9Sstevel@tonic-gate free(cachep->cache_srv_addr.buf); 27247c478bd9Sstevel@tonic-gate if (cachep->cache_proto && protolen > SMALL_PROTONAME) 27257c478bd9Sstevel@tonic-gate free(cachep->cache_proto); 27267c478bd9Sstevel@tonic-gate if (cachep->cache_hostname && hostnamelen > SMALL_HOSTNAME) 27277c478bd9Sstevel@tonic-gate free(cachep->cache_hostname); 27287c478bd9Sstevel@tonic-gate if (cachep->cache_protofmly && protofmlylen > SMALL_PROTOFMLYNAME) 27297c478bd9Sstevel@tonic-gate free(cachep->cache_protofmly); 27307c478bd9Sstevel@tonic-gate if (cachep) 27317c478bd9Sstevel@tonic-gate free(cachep); 27327c478bd9Sstevel@tonic-gate cachep = NULL; 27337c478bd9Sstevel@tonic-gate } 27347c478bd9Sstevel@tonic-gate 27357c478bd9Sstevel@tonic-gate static int 27367c478bd9Sstevel@tonic-gate get_cached_srv_addr(char *hostname, rpcprog_t prog, rpcvers_t vers, 27377c478bd9Sstevel@tonic-gate struct netconfig *nconf, struct netbuf *addrp) 27387c478bd9Sstevel@tonic-gate { 27397c478bd9Sstevel@tonic-gate if (portmap_cache_lookup(hostname, prog, vers, nconf, addrp)) 27407c478bd9Sstevel@tonic-gate return (1); 27417c478bd9Sstevel@tonic-gate if (rpcb_getaddr(prog, vers, nconf, addrp, hostname) == 0) 27427c478bd9Sstevel@tonic-gate return (0); 27437c478bd9Sstevel@tonic-gate portmap_cache_enter(hostname, prog, vers, nconf, addrp); 27447c478bd9Sstevel@tonic-gate return (1); 27457c478bd9Sstevel@tonic-gate } 27467c478bd9Sstevel@tonic-gate 27477c478bd9Sstevel@tonic-gate /* 27482f172c55SRobert Thurlow * Get a network address on "hostname" for program "prog" 27492f172c55SRobert Thurlow * with version "vers". If the port number is specified (non zero) 27502f172c55SRobert Thurlow * then try for a TCP/UDP transport and set the port number of the 27512f172c55SRobert Thurlow * resulting IP address. 27527c478bd9Sstevel@tonic-gate * 27532f172c55SRobert Thurlow * If the address of a netconfig pointer was passed and 27542f172c55SRobert Thurlow * if it's not null, use it as the netconfig otherwise 27552f172c55SRobert Thurlow * assign the address of the netconfig that was used to 27562f172c55SRobert Thurlow * establish contact with the service. 27577c478bd9Sstevel@tonic-gate * 27582f172c55SRobert Thurlow * tinfo argument is for matching the get_addr() defined in 27597c478bd9Sstevel@tonic-gate * ../nfs/mount/mount.c 27607c478bd9Sstevel@tonic-gate */ 27612f172c55SRobert Thurlow 27622f172c55SRobert Thurlow static struct netbuf * 27632f172c55SRobert Thurlow get_addr(char *hostname, rpcprog_t prog, rpcvers_t vers, 27642f172c55SRobert Thurlow struct netconfig **nconfp, char *proto, ushort_t port, 27652f172c55SRobert Thurlow struct t_info *tinfo) 27662f172c55SRobert Thurlow 27672f172c55SRobert Thurlow { 27682f172c55SRobert Thurlow enum clnt_stat cstat; 27692f172c55SRobert Thurlow 27702f172c55SRobert Thurlow return (get_server_netinfo(SERVER_ADDR, hostname, prog, vers, NULL, 27712f172c55SRobert Thurlow nconfp, proto, port, tinfo, NULL, FALSE, NULL, &cstat)); 27722f172c55SRobert Thurlow } 27732f172c55SRobert Thurlow 27742f172c55SRobert Thurlow static struct netbuf * 27752f172c55SRobert Thurlow get_pubfh(char *hostname, rpcvers_t vers, mfs_snego_t *mfssnego, 27762f172c55SRobert Thurlow struct netconfig **nconfp, char *proto, ushort_t port, 27772f172c55SRobert Thurlow struct t_info *tinfo, caddr_t *fhp, bool_t get_pubfh, char *fspath) 27782f172c55SRobert Thurlow { 27792f172c55SRobert Thurlow enum clnt_stat cstat; 27802f172c55SRobert Thurlow 27812f172c55SRobert Thurlow return (get_server_netinfo(SERVER_FH, hostname, NFS_PROGRAM, vers, 27822f172c55SRobert Thurlow mfssnego, nconfp, proto, port, tinfo, fhp, get_pubfh, fspath, 27832f172c55SRobert Thurlow &cstat)); 27842f172c55SRobert Thurlow } 27852f172c55SRobert Thurlow 27862f172c55SRobert Thurlow static enum clnt_stat 27872f172c55SRobert Thurlow get_ping(char *hostname, rpcprog_t prog, rpcvers_t vers, 27882f172c55SRobert Thurlow struct netconfig **nconfp, ushort_t port, bool_t direct_to_server) 27892f172c55SRobert Thurlow { 27902f172c55SRobert Thurlow enum clnt_stat cstat; 27912f172c55SRobert Thurlow 27922f172c55SRobert Thurlow (void) get_server_netinfo(SERVER_PING, hostname, prog, 27932f172c55SRobert Thurlow vers, NULL, nconfp, NULL, port, NULL, NULL, 27942f172c55SRobert Thurlow direct_to_server, NULL, &cstat); 27952f172c55SRobert Thurlow 27962f172c55SRobert Thurlow return (cstat); 27972f172c55SRobert Thurlow } 27982f172c55SRobert Thurlow 279939d3e169Sevanl void * 28002f172c55SRobert Thurlow get_server_netinfo( 28017c478bd9Sstevel@tonic-gate enum type_of_stuff type_of_stuff, 28027c478bd9Sstevel@tonic-gate char *hostname, 28037c478bd9Sstevel@tonic-gate rpcprog_t prog, 28042f172c55SRobert Thurlow rpcvers_t vers, 28057c478bd9Sstevel@tonic-gate mfs_snego_t *mfssnego, 28062f172c55SRobert Thurlow struct netconfig **nconfp, 28072f172c55SRobert Thurlow char *proto, 28082f172c55SRobert Thurlow ushort_t port, /* may be zero */ 28097c478bd9Sstevel@tonic-gate struct t_info *tinfo, 28107c478bd9Sstevel@tonic-gate caddr_t *fhp, 28117c478bd9Sstevel@tonic-gate bool_t direct_to_server, 28127c478bd9Sstevel@tonic-gate char *fspath, 28132f172c55SRobert Thurlow enum clnt_stat *cstatp) 28147c478bd9Sstevel@tonic-gate { 28157c478bd9Sstevel@tonic-gate struct netbuf *nb = NULL; 28162f172c55SRobert Thurlow struct netconfig *nconf = NULL; 28172f172c55SRobert Thurlow NCONF_HANDLE *nc = NULL; 28182f172c55SRobert Thurlow int error = 0; 28192f172c55SRobert Thurlow int fd = 0; 28207c478bd9Sstevel@tonic-gate struct t_bind *tbind = NULL; 28212f172c55SRobert Thurlow int nthtry = FIRST_TRY; 28222f172c55SRobert Thurlow 28232f172c55SRobert Thurlow if (nconfp && *nconfp) { 28242f172c55SRobert Thurlow return (get_netconfig_info(type_of_stuff, hostname, 28252f172c55SRobert Thurlow prog, vers, nconf, port, tinfo, tbind, fhp, 28262f172c55SRobert Thurlow direct_to_server, fspath, cstatp, mfssnego)); 28272f172c55SRobert Thurlow } 28282f172c55SRobert Thurlow 28292f172c55SRobert Thurlow /* 28302f172c55SRobert Thurlow * No nconf passed in. 28312f172c55SRobert Thurlow * 28322f172c55SRobert Thurlow * Try to get a nconf from /etc/netconfig. 28332f172c55SRobert Thurlow * First choice is COTS, second is CLTS unless proto 28342f172c55SRobert Thurlow * is specified. When we retry, we reset the 28352f172c55SRobert Thurlow * netconfig list, so that we search the whole list 28362f172c55SRobert Thurlow * for the next choice. 28372f172c55SRobert Thurlow */ 28382f172c55SRobert Thurlow if ((nc = setnetpath()) == NULL) 28392f172c55SRobert Thurlow goto done; 28402f172c55SRobert Thurlow 28412f172c55SRobert Thurlow /* 28422f172c55SRobert Thurlow * If proto is specified, then only search for the match, 28432f172c55SRobert Thurlow * otherwise try COTS first, if failed, then try CLTS. 28442f172c55SRobert Thurlow */ 28452f172c55SRobert Thurlow if (proto) { 28462f172c55SRobert Thurlow while ((nconf = getnetpath(nc)) != NULL) { 28472f172c55SRobert Thurlow if (strcmp(nconf->nc_proto, proto)) 28482f172c55SRobert Thurlow continue; 28492f172c55SRobert Thurlow /* 28502f172c55SRobert Thurlow * If the port number is specified then TCP/UDP 28512f172c55SRobert Thurlow * is needed. Otherwise any cots/clts will do. 28522f172c55SRobert Thurlow */ 28532f172c55SRobert Thurlow if (port) { 28542f172c55SRobert Thurlow if ((strcmp(nconf->nc_protofmly, NC_INET) && 28552f172c55SRobert Thurlow strcmp(nconf->nc_protofmly, NC_INET6)) || 28562f172c55SRobert Thurlow (strcmp(nconf->nc_proto, NC_TCP) && 28572f172c55SRobert Thurlow strcmp(nconf->nc_proto, NC_UDP))) 28582f172c55SRobert Thurlow continue; 28592f172c55SRobert Thurlow } 28602f172c55SRobert Thurlow nb = get_netconfig_info(type_of_stuff, hostname, 28612f172c55SRobert Thurlow prog, vers, nconf, port, tinfo, tbind, fhp, 28622f172c55SRobert Thurlow direct_to_server, fspath, cstatp, mfssnego); 28632f172c55SRobert Thurlow if (*cstatp == RPC_SUCCESS) 28642f172c55SRobert Thurlow break; 28652f172c55SRobert Thurlow 28662f172c55SRobert Thurlow assert(nb == NULL); 28672f172c55SRobert Thurlow 28682f172c55SRobert Thurlow } 28692f172c55SRobert Thurlow if (nconf == NULL) 28702f172c55SRobert Thurlow goto done; 28712f172c55SRobert Thurlow } else { 28722f172c55SRobert Thurlow retry: 28732f172c55SRobert Thurlow while ((nconf = getnetpath(nc)) != NULL) { 28742f172c55SRobert Thurlow if (nconf->nc_flag & NC_VISIBLE) { 28752f172c55SRobert Thurlow if (nthtry == FIRST_TRY) { 28762f172c55SRobert Thurlow if ((nconf->nc_semantics == 28772f172c55SRobert Thurlow NC_TPI_COTS_ORD) || 28782f172c55SRobert Thurlow (nconf->nc_semantics == 28792f172c55SRobert Thurlow NC_TPI_COTS)) { 28802f172c55SRobert Thurlow if (port == 0) 28812f172c55SRobert Thurlow break; 28822f172c55SRobert Thurlow if ((strcmp(nconf->nc_protofmly, 28832f172c55SRobert Thurlow NC_INET) == 0 || 28842f172c55SRobert Thurlow strcmp(nconf->nc_protofmly, 28852f172c55SRobert Thurlow NC_INET6) == 0) && 28862f172c55SRobert Thurlow (strcmp(nconf->nc_proto, 28872f172c55SRobert Thurlow NC_TCP) == 0)) 28882f172c55SRobert Thurlow break; 28892f172c55SRobert Thurlow } 28902f172c55SRobert Thurlow } 28912f172c55SRobert Thurlow if (nthtry == SECOND_TRY) { 28922f172c55SRobert Thurlow if (nconf->nc_semantics == 28932f172c55SRobert Thurlow NC_TPI_CLTS) { 28942f172c55SRobert Thurlow if (port == 0) 28952f172c55SRobert Thurlow break; 28962f172c55SRobert Thurlow if ((strcmp(nconf->nc_protofmly, 28972f172c55SRobert Thurlow NC_INET) == 0 || 28982f172c55SRobert Thurlow strcmp(nconf->nc_protofmly, 28992f172c55SRobert Thurlow NC_INET6) == 0) && 29002f172c55SRobert Thurlow (strcmp(nconf->nc_proto, 29012f172c55SRobert Thurlow NC_UDP) == 0)) 29022f172c55SRobert Thurlow break; 29032f172c55SRobert Thurlow } 29042f172c55SRobert Thurlow } 29052f172c55SRobert Thurlow } 29062f172c55SRobert Thurlow } 29072f172c55SRobert Thurlow 29082f172c55SRobert Thurlow if (nconf == NULL) { 29092f172c55SRobert Thurlow if (++nthtry <= MNT_PREF_LISTLEN) { 29102f172c55SRobert Thurlow endnetpath(nc); 29112f172c55SRobert Thurlow if ((nc = setnetpath()) == NULL) 29122f172c55SRobert Thurlow goto done; 29132f172c55SRobert Thurlow goto retry; 29142f172c55SRobert Thurlow } else 29152f172c55SRobert Thurlow goto done; 29162f172c55SRobert Thurlow } else { 29172f172c55SRobert Thurlow nb = get_netconfig_info(type_of_stuff, hostname, 29182f172c55SRobert Thurlow prog, vers, nconf, port, tinfo, tbind, fhp, 29192f172c55SRobert Thurlow direct_to_server, fspath, cstatp, mfssnego); 29202f172c55SRobert Thurlow if (*cstatp != RPC_SUCCESS) 29212f172c55SRobert Thurlow /* 29222f172c55SRobert Thurlow * Continue the same search path in the 29232f172c55SRobert Thurlow * netconfig db until no more matched nconf 29242f172c55SRobert Thurlow * (nconf == NULL). 29252f172c55SRobert Thurlow */ 29262f172c55SRobert Thurlow goto retry; 29272f172c55SRobert Thurlow } 29282f172c55SRobert Thurlow } 29292f172c55SRobert Thurlow 29302f172c55SRobert Thurlow /* 29312f172c55SRobert Thurlow * Got nconf and nb. Now dup the netconfig structure (nconf) 29322f172c55SRobert Thurlow * and return it thru nconfp. 29332f172c55SRobert Thurlow */ 29342f172c55SRobert Thurlow if (nconf != NULL) { 29352f172c55SRobert Thurlow if ((*nconfp = getnetconfigent(nconf->nc_netid)) == NULL) { 29362f172c55SRobert Thurlow syslog(LOG_ERR, "no memory\n"); 29372f172c55SRobert Thurlow free(nb); 29382f172c55SRobert Thurlow nb = NULL; 29392f172c55SRobert Thurlow } 29402f172c55SRobert Thurlow } else { 29412f172c55SRobert Thurlow *nconfp = NULL; 29422f172c55SRobert Thurlow } 29432f172c55SRobert Thurlow done: 29442f172c55SRobert Thurlow if (nc) 29452f172c55SRobert Thurlow endnetpath(nc); 29462f172c55SRobert Thurlow return (nb); 29472f172c55SRobert Thurlow } 29482f172c55SRobert Thurlow 29492f172c55SRobert Thurlow void * 29502f172c55SRobert Thurlow get_server_fh(char *hostname, rpcprog_t prog, rpcvers_t vers, 29512f172c55SRobert Thurlow mfs_snego_t *mfssnego, struct netconfig *nconf, ushort_t port, 29522f172c55SRobert Thurlow struct t_info *tinfo, struct t_bind *tbind, caddr_t *fhp, 29532f172c55SRobert Thurlow bool_t direct_to_server, char *fspath, enum clnt_stat *cstat) 29542f172c55SRobert Thurlow { 29557c478bd9Sstevel@tonic-gate AUTH *ah = NULL; 29567c478bd9Sstevel@tonic-gate AUTH *new_ah = NULL; 29577c478bd9Sstevel@tonic-gate struct snego_t snego; 29582f172c55SRobert Thurlow enum clnt_stat cs = RPC_TIMEDOUT; 29592f172c55SRobert Thurlow struct timeval tv; 29602f172c55SRobert Thurlow bool_t file_handle = 1; 29612f172c55SRobert Thurlow enum snego_stat sec; 29622f172c55SRobert Thurlow CLIENT *cl = NULL; 29632f172c55SRobert Thurlow int fd = -1; 29642f172c55SRobert Thurlow struct netbuf *nb = NULL; 29657c478bd9Sstevel@tonic-gate 29662f172c55SRobert Thurlow if (direct_to_server != TRUE) 29672f172c55SRobert Thurlow return (NULL); 29687c478bd9Sstevel@tonic-gate 29697c478bd9Sstevel@tonic-gate if (prog == NFS_PROGRAM && vers == NFS_V4) 29707c478bd9Sstevel@tonic-gate if (strncasecmp(nconf->nc_proto, NC_UDP, strlen(NC_UDP)) == 0) 29717c478bd9Sstevel@tonic-gate goto done; 29727c478bd9Sstevel@tonic-gate 29732f172c55SRobert Thurlow if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) < 0) 29747c478bd9Sstevel@tonic-gate goto done; 29757c478bd9Sstevel@tonic-gate 29767c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 29772f172c55SRobert Thurlow if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR)) == NULL) 29782f172c55SRobert Thurlow goto done; 29792f172c55SRobert Thurlow 29802f172c55SRobert Thurlow if (setup_nb_parms(nconf, tbind, tinfo, hostname, fd, 29812f172c55SRobert Thurlow direct_to_server, port, prog, vers, file_handle) < 0) { 29827c478bd9Sstevel@tonic-gate goto done; 29837c478bd9Sstevel@tonic-gate } 29847c478bd9Sstevel@tonic-gate 29852f172c55SRobert Thurlow cl = clnt_tli_create(fd, nconf, &tbind->addr, prog, vers, 0, 0); 29867c478bd9Sstevel@tonic-gate if (cl == NULL) 29877c478bd9Sstevel@tonic-gate goto done; 29887c478bd9Sstevel@tonic-gate 29897c478bd9Sstevel@tonic-gate ah = authsys_create_default(); 29907c478bd9Sstevel@tonic-gate if (ah != NULL) { 29917c478bd9Sstevel@tonic-gate #ifdef MALLOC_DEBUG 29927c478bd9Sstevel@tonic-gate drop_alloc("AUTH_HANDLE", cl->cl_auth, 29937c478bd9Sstevel@tonic-gate __FILE__, __LINE__); 29947c478bd9Sstevel@tonic-gate #endif 29957c478bd9Sstevel@tonic-gate AUTH_DESTROY(cl->cl_auth); 29967c478bd9Sstevel@tonic-gate cl->cl_auth = ah; 29977c478bd9Sstevel@tonic-gate #ifdef MALLOC_DEBUG 29987c478bd9Sstevel@tonic-gate add_alloc("AUTH_HANDLE", cl->cl_auth, 0, 29997c478bd9Sstevel@tonic-gate __FILE__, __LINE__); 30007c478bd9Sstevel@tonic-gate #endif 30017c478bd9Sstevel@tonic-gate } 30027c478bd9Sstevel@tonic-gate 30037c478bd9Sstevel@tonic-gate if (!mfssnego->snego_done && vers != NFS_V4) { 30047c478bd9Sstevel@tonic-gate /* 30057c478bd9Sstevel@tonic-gate * negotiate sec flavor. 30067c478bd9Sstevel@tonic-gate */ 30077c478bd9Sstevel@tonic-gate snego.cnt = 0; 30087c478bd9Sstevel@tonic-gate if ((sec = nfs_sec_nego(vers, cl, fspath, &snego)) == 30097c478bd9Sstevel@tonic-gate SNEGO_SUCCESS) { 30107c478bd9Sstevel@tonic-gate int jj; 30117c478bd9Sstevel@tonic-gate 30127c478bd9Sstevel@tonic-gate /* 30137c478bd9Sstevel@tonic-gate * check if server supports the one 30147c478bd9Sstevel@tonic-gate * specified in the sec= option. 30157c478bd9Sstevel@tonic-gate */ 30167c478bd9Sstevel@tonic-gate if (mfssnego->sec_opt) { 30177c478bd9Sstevel@tonic-gate for (jj = 0; jj < snego.cnt; jj++) { 30187c478bd9Sstevel@tonic-gate if (snego.array[jj] == 30197c478bd9Sstevel@tonic-gate mfssnego->nfs_sec.sc_nfsnum) { 30207c478bd9Sstevel@tonic-gate mfssnego->snego_done = TRUE; 30217c478bd9Sstevel@tonic-gate break; 30227c478bd9Sstevel@tonic-gate } 30237c478bd9Sstevel@tonic-gate } 30247c478bd9Sstevel@tonic-gate } 30257c478bd9Sstevel@tonic-gate 30267c478bd9Sstevel@tonic-gate /* 30277c478bd9Sstevel@tonic-gate * find a common sec flavor 30287c478bd9Sstevel@tonic-gate */ 30297c478bd9Sstevel@tonic-gate if (!mfssnego->snego_done) { 30307c478bd9Sstevel@tonic-gate for (jj = 0; jj < snego.cnt; jj++) { 30317c478bd9Sstevel@tonic-gate if (!nfs_getseconfig_bynumber( 30322f172c55SRobert Thurlow snego.array[jj], 30332f172c55SRobert Thurlow &mfssnego->nfs_sec)) { 30347c478bd9Sstevel@tonic-gate mfssnego->snego_done = TRUE; 30357c478bd9Sstevel@tonic-gate break; 30367c478bd9Sstevel@tonic-gate } 30377c478bd9Sstevel@tonic-gate } 30387c478bd9Sstevel@tonic-gate } 30397c478bd9Sstevel@tonic-gate if (!mfssnego->snego_done) 30402f172c55SRobert Thurlow goto done; 30417c478bd9Sstevel@tonic-gate /* 30427c478bd9Sstevel@tonic-gate * Now that the flavor has been 30437c478bd9Sstevel@tonic-gate * negotiated, get the fh. 30447c478bd9Sstevel@tonic-gate * 30457c478bd9Sstevel@tonic-gate * First, create an auth handle using the negotiated 30467c478bd9Sstevel@tonic-gate * sec flavor in the next lookup to 30477c478bd9Sstevel@tonic-gate * fetch the filehandle. 30487c478bd9Sstevel@tonic-gate */ 30497c478bd9Sstevel@tonic-gate new_ah = nfs_create_ah(cl, hostname, 30507c478bd9Sstevel@tonic-gate &mfssnego->nfs_sec); 30517c478bd9Sstevel@tonic-gate if (new_ah == NULL) 30527c478bd9Sstevel@tonic-gate goto done; 30537c478bd9Sstevel@tonic-gate #ifdef MALLOC_DEBUG 30547c478bd9Sstevel@tonic-gate drop_alloc("AUTH_HANDLE", cl->cl_auth, 30557c478bd9Sstevel@tonic-gate __FILE__, __LINE__); 30567c478bd9Sstevel@tonic-gate #endif 30577c478bd9Sstevel@tonic-gate AUTH_DESTROY(cl->cl_auth); 30587c478bd9Sstevel@tonic-gate cl->cl_auth = new_ah; 30597c478bd9Sstevel@tonic-gate #ifdef MALLOC_DEBUG 30607c478bd9Sstevel@tonic-gate add_alloc("AUTH_HANDLE", cl->cl_auth, 0, 30617c478bd9Sstevel@tonic-gate __FILE__, __LINE__); 30627c478bd9Sstevel@tonic-gate #endif 30637c478bd9Sstevel@tonic-gate } else if (sec == SNEGO_ARRAY_TOO_SMALL || 30647c478bd9Sstevel@tonic-gate sec == SNEGO_FAILURE) { 30657c478bd9Sstevel@tonic-gate goto done; 30667c478bd9Sstevel@tonic-gate } 30677c478bd9Sstevel@tonic-gate } 30687c478bd9Sstevel@tonic-gate 30697c478bd9Sstevel@tonic-gate switch (vers) { 30707c478bd9Sstevel@tonic-gate case NFS_VERSION: 30717c478bd9Sstevel@tonic-gate { 30727c478bd9Sstevel@tonic-gate wnl_diropargs arg; 3073bfa62c28SVallish Vaidyeshwara wnl_diropres res; 30747c478bd9Sstevel@tonic-gate 30757c478bd9Sstevel@tonic-gate memset((char *)&arg.dir, 0, sizeof (wnl_fh)); 3076bfa62c28SVallish Vaidyeshwara memset((char *)&res, 0, sizeof (wnl_diropres)); 30777c478bd9Sstevel@tonic-gate arg.name = fspath; 3078bfa62c28SVallish Vaidyeshwara if (wnlproc_lookup_2(&arg, &res, cl) != 30792c2d21e9SRichard Lowe RPC_SUCCESS || res.status != WNL_OK) 30807c478bd9Sstevel@tonic-gate goto done; 30817c478bd9Sstevel@tonic-gate *fhp = malloc(sizeof (wnl_fh)); 30827c478bd9Sstevel@tonic-gate 30837c478bd9Sstevel@tonic-gate if (*fhp == NULL) { 30847c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "no memory\n"); 30857c478bd9Sstevel@tonic-gate goto done; 30867c478bd9Sstevel@tonic-gate } 30877c478bd9Sstevel@tonic-gate 30887c478bd9Sstevel@tonic-gate memcpy((char *)*fhp, 3089bfa62c28SVallish Vaidyeshwara (char *)&res.wnl_diropres_u.wnl_diropres.file, 30907c478bd9Sstevel@tonic-gate sizeof (wnl_fh)); 30917c478bd9Sstevel@tonic-gate cs = RPC_SUCCESS; 30927c478bd9Sstevel@tonic-gate } 30937c478bd9Sstevel@tonic-gate break; 30947c478bd9Sstevel@tonic-gate case NFS_V3: 30957c478bd9Sstevel@tonic-gate { 30967c478bd9Sstevel@tonic-gate WNL_LOOKUP3args arg; 3097bfa62c28SVallish Vaidyeshwara WNL_LOOKUP3res res; 30987c478bd9Sstevel@tonic-gate nfs_fh3 *fh3p; 30997c478bd9Sstevel@tonic-gate 31007c478bd9Sstevel@tonic-gate memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3)); 3101bfa62c28SVallish Vaidyeshwara memset((char *)&res, 0, sizeof (WNL_LOOKUP3res)); 31027c478bd9Sstevel@tonic-gate arg.what.name = fspath; 3103bfa62c28SVallish Vaidyeshwara if (wnlproc3_lookup_3(&arg, &res, cl) != 31042c2d21e9SRichard Lowe RPC_SUCCESS || res.status != WNL3_OK) 31057c478bd9Sstevel@tonic-gate goto done; 31067c478bd9Sstevel@tonic-gate 31077c478bd9Sstevel@tonic-gate fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p)); 31087c478bd9Sstevel@tonic-gate 31097c478bd9Sstevel@tonic-gate if (fh3p == NULL) { 31107c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "no memory\n"); 31117c478bd9Sstevel@tonic-gate goto done; 31127c478bd9Sstevel@tonic-gate } 31137c478bd9Sstevel@tonic-gate 31142f172c55SRobert Thurlow fh3p->fh3_length = 31152f172c55SRobert Thurlow res.WNL_LOOKUP3res_u.res_ok.object.data.data_len; 31162f172c55SRobert Thurlow memcpy(fh3p->fh3_u.data, 31172f172c55SRobert Thurlow res.WNL_LOOKUP3res_u.res_ok.object.data.data_val, 31187c478bd9Sstevel@tonic-gate fh3p->fh3_length); 31197c478bd9Sstevel@tonic-gate 31207c478bd9Sstevel@tonic-gate *fhp = (caddr_t)fh3p; 31217c478bd9Sstevel@tonic-gate 31227c478bd9Sstevel@tonic-gate cs = RPC_SUCCESS; 31237c478bd9Sstevel@tonic-gate } 31247c478bd9Sstevel@tonic-gate break; 31257c478bd9Sstevel@tonic-gate case NFS_V4: 31261bbc88acSrm15945 tv.tv_sec = 10; 31271bbc88acSrm15945 tv.tv_usec = 0; 31281bbc88acSrm15945 cs = clnt_call(cl, NULLPROC, xdr_void, 0, 31291bbc88acSrm15945 xdr_void, 0, tv); 31301bbc88acSrm15945 if (cs != RPC_SUCCESS) 31311bbc88acSrm15945 goto done; 31322f172c55SRobert Thurlow 31337c478bd9Sstevel@tonic-gate *fhp = strdup(fspath); 31342f172c55SRobert Thurlow if (fhp == NULL) { 31357c478bd9Sstevel@tonic-gate cs = RPC_SYSTEMERROR; 31362f172c55SRobert Thurlow goto done; 31372f172c55SRobert Thurlow } 31382f172c55SRobert Thurlow break; 31392f172c55SRobert Thurlow } 31407c478bd9Sstevel@tonic-gate nb = (struct netbuf *)malloc(sizeof (struct netbuf)); 31417c478bd9Sstevel@tonic-gate if (nb == NULL) { 31427c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "no memory\n"); 31432f172c55SRobert Thurlow cs = RPC_SYSTEMERROR; 31447c478bd9Sstevel@tonic-gate goto done; 31457c478bd9Sstevel@tonic-gate } 31462f172c55SRobert Thurlow nb->buf = (char *)malloc(tbind->addr.maxlen); 31477c478bd9Sstevel@tonic-gate if (nb->buf == NULL) { 31487c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "no memory\n"); 31497c478bd9Sstevel@tonic-gate free(nb); 31507c478bd9Sstevel@tonic-gate nb = NULL; 31512f172c55SRobert Thurlow cs = RPC_SYSTEMERROR; 31527c478bd9Sstevel@tonic-gate goto done; 31537c478bd9Sstevel@tonic-gate } 31547c478bd9Sstevel@tonic-gate (void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len); 31552f172c55SRobert Thurlow nb->len = tbind->addr.len; 31562f172c55SRobert Thurlow nb->maxlen = tbind->addr.maxlen; 31577c478bd9Sstevel@tonic-gate done: 31587c478bd9Sstevel@tonic-gate if (cstat != NULL) 31597c478bd9Sstevel@tonic-gate *cstat = cs; 31602f172c55SRobert Thurlow destroy_auth_client_handle(cl); 31612f172c55SRobert Thurlow cleanup_tli_parms(tbind, fd); 31627c478bd9Sstevel@tonic-gate return (nb); 31637c478bd9Sstevel@tonic-gate } 31647c478bd9Sstevel@tonic-gate 31657c478bd9Sstevel@tonic-gate /* 31667c478bd9Sstevel@tonic-gate * Sends a null call to the remote host's (NFS program, versp). versp 31677c478bd9Sstevel@tonic-gate * may be "NULL" in which case the default maximum version is used. 31687c478bd9Sstevel@tonic-gate * Upon return, versp contains the maximum version supported iff versp!= NULL. 31697c478bd9Sstevel@tonic-gate */ 31707c478bd9Sstevel@tonic-gate enum clnt_stat 31717c478bd9Sstevel@tonic-gate pingnfs( 31727c478bd9Sstevel@tonic-gate char *hostpart, 31737c478bd9Sstevel@tonic-gate int attempts, 31747c478bd9Sstevel@tonic-gate rpcvers_t *versp, 31757c478bd9Sstevel@tonic-gate rpcvers_t versmin, 31766a6d3e5eSjs195444 ushort_t port, /* may be zero */ 31777c478bd9Sstevel@tonic-gate bool_t usepub, 31787c478bd9Sstevel@tonic-gate char *path, 31797c478bd9Sstevel@tonic-gate char *proto) 31807c478bd9Sstevel@tonic-gate { 31817c478bd9Sstevel@tonic-gate CLIENT *cl = NULL; 31827c478bd9Sstevel@tonic-gate struct timeval rpc_to_new = {15, 0}; 31837c478bd9Sstevel@tonic-gate static struct timeval rpc_rtrans_new = {-1, -1}; 31847c478bd9Sstevel@tonic-gate enum clnt_stat clnt_stat; 31857c478bd9Sstevel@tonic-gate int i, j; 31867c478bd9Sstevel@tonic-gate rpcvers_t versmax; /* maximum version to try against server */ 31877c478bd9Sstevel@tonic-gate rpcvers_t outvers; /* version supported by host on last call */ 31887c478bd9Sstevel@tonic-gate rpcvers_t vers_to_try; /* to try different versions against host */ 31896a6d3e5eSjs195444 char *hostname; 31907c478bd9Sstevel@tonic-gate struct netconfig *nconf; 31917c478bd9Sstevel@tonic-gate 31926a6d3e5eSjs195444 hostname = strdup(hostpart); 31936a6d3e5eSjs195444 if (hostname == NULL) { 31946a6d3e5eSjs195444 return (RPC_SYSTEMERROR); 31956a6d3e5eSjs195444 } 31966a6d3e5eSjs195444 unbracket(&hostname); 31976a6d3e5eSjs195444 31987c478bd9Sstevel@tonic-gate if (path != NULL && strcmp(hostname, "nfs") == 0 && 31997c478bd9Sstevel@tonic-gate strncmp(path, "//", 2) == 0) { 32007c478bd9Sstevel@tonic-gate char *sport; 32017c478bd9Sstevel@tonic-gate 32027c478bd9Sstevel@tonic-gate hostname = strdup(path+2); 32037c478bd9Sstevel@tonic-gate 32047c478bd9Sstevel@tonic-gate if (hostname == NULL) 32057c478bd9Sstevel@tonic-gate return (RPC_SYSTEMERROR); 32067c478bd9Sstevel@tonic-gate 32077c478bd9Sstevel@tonic-gate path = strchr(hostname, '/'); 32087c478bd9Sstevel@tonic-gate 32097c478bd9Sstevel@tonic-gate /* 32107c478bd9Sstevel@tonic-gate * This cannot happen. If it does, give up 32117c478bd9Sstevel@tonic-gate * on the ping as this is obviously a corrupt 32127c478bd9Sstevel@tonic-gate * entry. 32137c478bd9Sstevel@tonic-gate */ 32147c478bd9Sstevel@tonic-gate if (path == NULL) { 32157c478bd9Sstevel@tonic-gate free(hostname); 32167c478bd9Sstevel@tonic-gate return (RPC_SUCCESS); 32177c478bd9Sstevel@tonic-gate } 32187c478bd9Sstevel@tonic-gate 32197c478bd9Sstevel@tonic-gate /* 32207c478bd9Sstevel@tonic-gate * Probable end point of host string. 32217c478bd9Sstevel@tonic-gate */ 32227c478bd9Sstevel@tonic-gate *path = '\0'; 32237c478bd9Sstevel@tonic-gate 32247c478bd9Sstevel@tonic-gate sport = strchr(hostname, ':'); 32257c478bd9Sstevel@tonic-gate 32267c478bd9Sstevel@tonic-gate if (sport != NULL && sport < path) { 32277c478bd9Sstevel@tonic-gate 32287c478bd9Sstevel@tonic-gate /* 32297c478bd9Sstevel@tonic-gate * Actual end point of host string. 32307c478bd9Sstevel@tonic-gate */ 32317c478bd9Sstevel@tonic-gate *sport = '\0'; 32327c478bd9Sstevel@tonic-gate port = htons((ushort_t)atoi(sport+1)); 32337c478bd9Sstevel@tonic-gate } 32347c478bd9Sstevel@tonic-gate 32357c478bd9Sstevel@tonic-gate usepub = TRUE; 32367c478bd9Sstevel@tonic-gate } 32377c478bd9Sstevel@tonic-gate 32387c478bd9Sstevel@tonic-gate /* Pick up the default versions and then set them appropriately */ 32397c478bd9Sstevel@tonic-gate if (versp) { 32407c478bd9Sstevel@tonic-gate versmax = *versp; 32417c478bd9Sstevel@tonic-gate /* use versmin passed in */ 32427c478bd9Sstevel@tonic-gate } else { 32437c478bd9Sstevel@tonic-gate read_default_nfs(); 32447c478bd9Sstevel@tonic-gate set_versrange(0, &versmax, &versmin); 32457c478bd9Sstevel@tonic-gate } 32467c478bd9Sstevel@tonic-gate 32477c478bd9Sstevel@tonic-gate if (proto && 32487c478bd9Sstevel@tonic-gate strncasecmp(proto, NC_UDP, strlen(NC_UDP)) == 0 && 32497c478bd9Sstevel@tonic-gate versmax == NFS_V4) { 32507c478bd9Sstevel@tonic-gate if (versmin == NFS_V4) { 32517c478bd9Sstevel@tonic-gate if (versp) { 32527c478bd9Sstevel@tonic-gate *versp = versmax - 1; 32537c478bd9Sstevel@tonic-gate return (RPC_SUCCESS); 32547c478bd9Sstevel@tonic-gate } 32557c478bd9Sstevel@tonic-gate return (RPC_PROGUNAVAIL); 32567c478bd9Sstevel@tonic-gate } else { 32577c478bd9Sstevel@tonic-gate versmax--; 32587c478bd9Sstevel@tonic-gate } 32597c478bd9Sstevel@tonic-gate } 32607c478bd9Sstevel@tonic-gate 32617c478bd9Sstevel@tonic-gate if (versp) 32627c478bd9Sstevel@tonic-gate *versp = versmax; 32637c478bd9Sstevel@tonic-gate 32647c478bd9Sstevel@tonic-gate switch (cache_check(hostname, versp, proto)) { 32657c478bd9Sstevel@tonic-gate case GOODHOST: 32667c478bd9Sstevel@tonic-gate if (hostname != hostpart) 32677c478bd9Sstevel@tonic-gate free(hostname); 32687c478bd9Sstevel@tonic-gate return (RPC_SUCCESS); 32697c478bd9Sstevel@tonic-gate case DEADHOST: 32707c478bd9Sstevel@tonic-gate if (hostname != hostpart) 32717c478bd9Sstevel@tonic-gate free(hostname); 32727c478bd9Sstevel@tonic-gate return (RPC_TIMEDOUT); 32737c478bd9Sstevel@tonic-gate case NOHOST: 32747c478bd9Sstevel@tonic-gate default: 32757c478bd9Sstevel@tonic-gate break; 32767c478bd9Sstevel@tonic-gate } 32777c478bd9Sstevel@tonic-gate 32787c478bd9Sstevel@tonic-gate /* 32797c478bd9Sstevel@tonic-gate * XXX The retransmission time rpcbrmttime is a global defined 32807c478bd9Sstevel@tonic-gate * in the rpc library (rpcb_clnt.c). We use (and like) the default 32817c478bd9Sstevel@tonic-gate * value of 15 sec in the rpc library. The code below is to protect 32827c478bd9Sstevel@tonic-gate * us in case it changes. This need not be done under a lock since 32837c478bd9Sstevel@tonic-gate * any # of threads entering this function will get the same 32847c478bd9Sstevel@tonic-gate * retransmission value. 32857c478bd9Sstevel@tonic-gate */ 32867c478bd9Sstevel@tonic-gate if (rpc_rtrans_new.tv_sec == -1 && rpc_rtrans_new.tv_usec == -1) { 32877c478bd9Sstevel@tonic-gate __rpc_control(CLCR_GET_RPCB_RMTTIME, (char *)&rpc_rtrans_new); 32887c478bd9Sstevel@tonic-gate if (rpc_rtrans_new.tv_sec != 15 && rpc_rtrans_new.tv_sec != 0) 32897c478bd9Sstevel@tonic-gate if (trace > 1) 32907c478bd9Sstevel@tonic-gate trace_prt(1, "RPC library rttimer changed\n"); 32917c478bd9Sstevel@tonic-gate } 32927c478bd9Sstevel@tonic-gate 32937c478bd9Sstevel@tonic-gate /* 32947c478bd9Sstevel@tonic-gate * XXX Manipulate the total timeout to get the number of 32957c478bd9Sstevel@tonic-gate * desired retransmissions. This code is heavily dependant on 32967c478bd9Sstevel@tonic-gate * the RPC backoff mechanism in clnt_dg_call (clnt_dg.c). 32977c478bd9Sstevel@tonic-gate */ 32987c478bd9Sstevel@tonic-gate for (i = 0, j = rpc_rtrans_new.tv_sec; i < attempts-1; i++) { 32997c478bd9Sstevel@tonic-gate if (j < RPC_MAX_BACKOFF) 33007c478bd9Sstevel@tonic-gate j *= 2; 33017c478bd9Sstevel@tonic-gate else 33027c478bd9Sstevel@tonic-gate j = RPC_MAX_BACKOFF; 33037c478bd9Sstevel@tonic-gate rpc_to_new.tv_sec += j; 33047c478bd9Sstevel@tonic-gate } 33057c478bd9Sstevel@tonic-gate 33067c478bd9Sstevel@tonic-gate vers_to_try = versmax; 33077c478bd9Sstevel@tonic-gate 33087c478bd9Sstevel@tonic-gate /* 33097c478bd9Sstevel@tonic-gate * check the host's version within the timeout 33107c478bd9Sstevel@tonic-gate */ 33117c478bd9Sstevel@tonic-gate if (trace > 1) 33127c478bd9Sstevel@tonic-gate trace_prt(1, " ping: %s timeout=%ld request vers=%d min=%d\n", 33137c478bd9Sstevel@tonic-gate hostname, rpc_to_new.tv_sec, versmax, versmin); 33147c478bd9Sstevel@tonic-gate 33157c478bd9Sstevel@tonic-gate if (usepub == FALSE) { 33167c478bd9Sstevel@tonic-gate do { 33177c478bd9Sstevel@tonic-gate /* 33187c478bd9Sstevel@tonic-gate * If NFSv4, then we do the same thing as is used 33197c478bd9Sstevel@tonic-gate * for public filehandles so that we avoid rpcbind 33207c478bd9Sstevel@tonic-gate */ 33217c478bd9Sstevel@tonic-gate if (vers_to_try == NFS_V4) { 33227c478bd9Sstevel@tonic-gate if (trace > 4) { 33237c478bd9Sstevel@tonic-gate trace_prt(1, " pingnfs: Trying ping via " 33247c478bd9Sstevel@tonic-gate "\"circuit_v\"\n"); 33257c478bd9Sstevel@tonic-gate } 33267c478bd9Sstevel@tonic-gate 33271bbc88acSrm15945 cl = clnt_create_service_timed(hostname, "nfs", 33281bbc88acSrm15945 NFS_PROGRAM, vers_to_try, 33291bbc88acSrm15945 port, "circuit_v", &rpc_to_new); 33301bbc88acSrm15945 if (cl != NULL) { 33317c478bd9Sstevel@tonic-gate outvers = vers_to_try; 33327c478bd9Sstevel@tonic-gate break; 33337c478bd9Sstevel@tonic-gate } 33347c478bd9Sstevel@tonic-gate if (trace > 4) { 33351bbc88acSrm15945 trace_prt(1, 33361bbc88acSrm15945 " pingnfs: Can't ping via " 33377c478bd9Sstevel@tonic-gate "\"circuit_v\" %s: RPC error=%d\n", 33387c478bd9Sstevel@tonic-gate hostname, rpc_createerr.cf_stat); 33397c478bd9Sstevel@tonic-gate } 33407c478bd9Sstevel@tonic-gate 33417c478bd9Sstevel@tonic-gate } else { 33421bbc88acSrm15945 cl = clnt_create_vers_timed(hostname, 33431bbc88acSrm15945 NFS_PROGRAM, &outvers, versmin, vers_to_try, 33441bbc88acSrm15945 "datagram_v", &rpc_to_new); 33451bbc88acSrm15945 if (cl != NULL) 33467c478bd9Sstevel@tonic-gate break; 33477c478bd9Sstevel@tonic-gate if (trace > 4) { 33481bbc88acSrm15945 trace_prt(1, 33491bbc88acSrm15945 " pingnfs: Can't ping via " 33507c478bd9Sstevel@tonic-gate "\"datagram_v\"%s: RPC error=%d\n", 33517c478bd9Sstevel@tonic-gate hostname, rpc_createerr.cf_stat); 33527c478bd9Sstevel@tonic-gate } 33537c478bd9Sstevel@tonic-gate if (rpc_createerr.cf_stat == RPC_UNKNOWNHOST || 33547c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat == RPC_TIMEDOUT) 33557c478bd9Sstevel@tonic-gate break; 33561bbc88acSrm15945 if (rpc_createerr.cf_stat == 33571bbc88acSrm15945 RPC_PROGNOTREGISTERED) { 33587c478bd9Sstevel@tonic-gate if (trace > 4) { 33591bbc88acSrm15945 trace_prt(1, 33601bbc88acSrm15945 " pingnfs: Trying ping " 33617c478bd9Sstevel@tonic-gate "via \"circuit_v\"\n"); 33627c478bd9Sstevel@tonic-gate } 33631bbc88acSrm15945 cl = clnt_create_vers_timed(hostname, 33647c478bd9Sstevel@tonic-gate NFS_PROGRAM, &outvers, 33657c478bd9Sstevel@tonic-gate versmin, vers_to_try, 33661bbc88acSrm15945 "circuit_v", &rpc_to_new); 33671bbc88acSrm15945 if (cl != NULL) 33687c478bd9Sstevel@tonic-gate break; 33697c478bd9Sstevel@tonic-gate if (trace > 4) { 33701bbc88acSrm15945 trace_prt(1, 33711bbc88acSrm15945 " pingnfs: Can't ping " 33727c478bd9Sstevel@tonic-gate "via \"circuit_v\" %s: " 33737c478bd9Sstevel@tonic-gate "RPC error=%d\n", 33747c478bd9Sstevel@tonic-gate hostname, 33757c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat); 33767c478bd9Sstevel@tonic-gate } 33777c478bd9Sstevel@tonic-gate } 33787c478bd9Sstevel@tonic-gate } 33797c478bd9Sstevel@tonic-gate 33807c478bd9Sstevel@tonic-gate /* 33817c478bd9Sstevel@tonic-gate * backoff and return lower version to retry the ping. 33827c478bd9Sstevel@tonic-gate * XXX we should be more careful and handle 33837c478bd9Sstevel@tonic-gate * RPC_PROGVERSMISMATCH here, because that error is handled 33847c478bd9Sstevel@tonic-gate * in clnt_create_vers(). It's not done to stay in sync 33857c478bd9Sstevel@tonic-gate * with the nfs mount command. 33867c478bd9Sstevel@tonic-gate */ 33877c478bd9Sstevel@tonic-gate vers_to_try--; 33887c478bd9Sstevel@tonic-gate if (vers_to_try < versmin) 33897c478bd9Sstevel@tonic-gate break; 33907c478bd9Sstevel@tonic-gate if (versp != NULL) { /* recheck the cache */ 33917c478bd9Sstevel@tonic-gate *versp = vers_to_try; 33927c478bd9Sstevel@tonic-gate if (trace > 4) { 33937c478bd9Sstevel@tonic-gate trace_prt(1, 33947c478bd9Sstevel@tonic-gate " pingnfs: check cache: vers=%d\n", 33957c478bd9Sstevel@tonic-gate *versp); 33967c478bd9Sstevel@tonic-gate } 33977c478bd9Sstevel@tonic-gate switch (cache_check(hostname, versp, proto)) { 33987c478bd9Sstevel@tonic-gate case GOODHOST: 33997c478bd9Sstevel@tonic-gate if (hostname != hostpart) 34007c478bd9Sstevel@tonic-gate free(hostname); 34017c478bd9Sstevel@tonic-gate return (RPC_SUCCESS); 34027c478bd9Sstevel@tonic-gate case DEADHOST: 34037c478bd9Sstevel@tonic-gate if (hostname != hostpart) 34047c478bd9Sstevel@tonic-gate free(hostname); 34057c478bd9Sstevel@tonic-gate return (RPC_TIMEDOUT); 34067c478bd9Sstevel@tonic-gate case NOHOST: 34077c478bd9Sstevel@tonic-gate default: 34087c478bd9Sstevel@tonic-gate break; 34097c478bd9Sstevel@tonic-gate } 34107c478bd9Sstevel@tonic-gate } 34117c478bd9Sstevel@tonic-gate if (trace > 4) { 34127c478bd9Sstevel@tonic-gate trace_prt(1, " pingnfs: Try version=%d\n", 34137c478bd9Sstevel@tonic-gate vers_to_try); 34147c478bd9Sstevel@tonic-gate } 34157c478bd9Sstevel@tonic-gate } while (cl == NULL); 34167c478bd9Sstevel@tonic-gate 34177c478bd9Sstevel@tonic-gate 34187c478bd9Sstevel@tonic-gate if (cl == NULL) { 34197c478bd9Sstevel@tonic-gate if (verbose) 34207c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "pingnfs: %s%s", 34217c478bd9Sstevel@tonic-gate hostname, clnt_spcreateerror("")); 34227c478bd9Sstevel@tonic-gate clnt_stat = rpc_createerr.cf_stat; 34237c478bd9Sstevel@tonic-gate } else { 34247c478bd9Sstevel@tonic-gate clnt_destroy(cl); 34257c478bd9Sstevel@tonic-gate clnt_stat = RPC_SUCCESS; 34267c478bd9Sstevel@tonic-gate } 34277c478bd9Sstevel@tonic-gate 34287c478bd9Sstevel@tonic-gate } else { 34297c478bd9Sstevel@tonic-gate for (vers_to_try = versmax; vers_to_try >= versmin; 34307c478bd9Sstevel@tonic-gate vers_to_try--) { 34317c478bd9Sstevel@tonic-gate 34327c478bd9Sstevel@tonic-gate nconf = NULL; 34337c478bd9Sstevel@tonic-gate 34347c478bd9Sstevel@tonic-gate if (trace > 4) { 34357c478bd9Sstevel@tonic-gate trace_prt(1, " pingnfs: Try version=%d " 34367c478bd9Sstevel@tonic-gate "using get_ping()\n", vers_to_try); 34377c478bd9Sstevel@tonic-gate } 34387c478bd9Sstevel@tonic-gate 34397c478bd9Sstevel@tonic-gate clnt_stat = get_ping(hostname, NFS_PROGRAM, 34407c478bd9Sstevel@tonic-gate vers_to_try, &nconf, port, TRUE); 34417c478bd9Sstevel@tonic-gate 34427c478bd9Sstevel@tonic-gate if (nconf != NULL) 34437c478bd9Sstevel@tonic-gate freenetconfigent(nconf); 34447c478bd9Sstevel@tonic-gate 34457c478bd9Sstevel@tonic-gate if (clnt_stat == RPC_SUCCESS) { 34467c478bd9Sstevel@tonic-gate outvers = vers_to_try; 34477c478bd9Sstevel@tonic-gate break; 34487c478bd9Sstevel@tonic-gate } 34497c478bd9Sstevel@tonic-gate } 34507c478bd9Sstevel@tonic-gate } 34517c478bd9Sstevel@tonic-gate 34527c478bd9Sstevel@tonic-gate if (trace > 1) 34537c478bd9Sstevel@tonic-gate clnt_stat == RPC_SUCCESS ? 34547c478bd9Sstevel@tonic-gate trace_prt(1, " pingnfs OK: nfs version=%d\n", outvers): 34557c478bd9Sstevel@tonic-gate trace_prt(1, " pingnfs FAIL: can't get nfs version\n"); 34567c478bd9Sstevel@tonic-gate 34577c478bd9Sstevel@tonic-gate if (clnt_stat == RPC_SUCCESS) { 34587c478bd9Sstevel@tonic-gate cache_enter(hostname, versmax, outvers, proto, GOODHOST); 34597c478bd9Sstevel@tonic-gate if (versp != NULL) 34607c478bd9Sstevel@tonic-gate *versp = outvers; 34617c478bd9Sstevel@tonic-gate } else 34627c478bd9Sstevel@tonic-gate cache_enter(hostname, versmax, versmax, proto, DEADHOST); 34637c478bd9Sstevel@tonic-gate 34647c478bd9Sstevel@tonic-gate if (hostpart != hostname) 34657c478bd9Sstevel@tonic-gate free(hostname); 34667c478bd9Sstevel@tonic-gate 34677c478bd9Sstevel@tonic-gate return (clnt_stat); 34687c478bd9Sstevel@tonic-gate } 34697c478bd9Sstevel@tonic-gate 34707c478bd9Sstevel@tonic-gate #define MNTTYPE_LOFS "lofs" 34717c478bd9Sstevel@tonic-gate 34727c478bd9Sstevel@tonic-gate int 34737c478bd9Sstevel@tonic-gate loopbackmount(fsname, dir, mntopts, overlay) 34747c478bd9Sstevel@tonic-gate char *fsname; /* Directory being mounted */ 34757c478bd9Sstevel@tonic-gate char *dir; /* Directory being mounted on */ 34767c478bd9Sstevel@tonic-gate char *mntopts; 34777c478bd9Sstevel@tonic-gate int overlay; 34787c478bd9Sstevel@tonic-gate { 34797c478bd9Sstevel@tonic-gate struct mnttab mnt; 34807c478bd9Sstevel@tonic-gate int flags = 0; 34817c478bd9Sstevel@tonic-gate char fstype[] = MNTTYPE_LOFS; 34827c478bd9Sstevel@tonic-gate int dirlen; 34837c478bd9Sstevel@tonic-gate struct stat st; 34847c478bd9Sstevel@tonic-gate char optbuf[MAX_MNTOPT_STR]; 34857c478bd9Sstevel@tonic-gate 34867c478bd9Sstevel@tonic-gate dirlen = strlen(dir); 34877c478bd9Sstevel@tonic-gate if (dir[dirlen-1] == ' ') 34887c478bd9Sstevel@tonic-gate dirlen--; 34897c478bd9Sstevel@tonic-gate 34907c478bd9Sstevel@tonic-gate if (dirlen == strlen(fsname) && 34917c478bd9Sstevel@tonic-gate strncmp(fsname, dir, dirlen) == 0) { 34927c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 34937c478bd9Sstevel@tonic-gate "Mount of %s on %s would result in deadlock, aborted\n", 34947c478bd9Sstevel@tonic-gate fsname, dir); 34957c478bd9Sstevel@tonic-gate return (RET_ERR); 34967c478bd9Sstevel@tonic-gate } 34977c478bd9Sstevel@tonic-gate mnt.mnt_mntopts = mntopts; 34987c478bd9Sstevel@tonic-gate if (hasmntopt(&mnt, MNTOPT_RO) != NULL) 34997c478bd9Sstevel@tonic-gate flags |= MS_RDONLY; 35007c478bd9Sstevel@tonic-gate 35017c478bd9Sstevel@tonic-gate (void) strlcpy(optbuf, mntopts, sizeof (optbuf)); 35027c478bd9Sstevel@tonic-gate 35037c478bd9Sstevel@tonic-gate if (overlay) 35047c478bd9Sstevel@tonic-gate flags |= MS_OVERLAY; 35057c478bd9Sstevel@tonic-gate 35067c478bd9Sstevel@tonic-gate if (trace > 1) 35077c478bd9Sstevel@tonic-gate trace_prt(1, 35087c478bd9Sstevel@tonic-gate " loopbackmount: fsname=%s, dir=%s, flags=%d\n", 35097c478bd9Sstevel@tonic-gate fsname, dir, flags); 35107c478bd9Sstevel@tonic-gate 351145916cd2Sjpk if (is_system_labeled()) { 351245916cd2Sjpk if (create_homedir((const char *)fsname, 351345916cd2Sjpk (const char *)dir) == 0) { 351445916cd2Sjpk return (NFSERR_NOENT); 351545916cd2Sjpk } 351645916cd2Sjpk } 351745916cd2Sjpk 35187c478bd9Sstevel@tonic-gate if (mount(fsname, dir, flags | MS_DATA | MS_OPTIONSTR, fstype, 35197c478bd9Sstevel@tonic-gate NULL, 0, optbuf, sizeof (optbuf)) < 0) { 35207c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Mount of %s on %s: %m", fsname, dir); 35217c478bd9Sstevel@tonic-gate return (RET_ERR); 35227c478bd9Sstevel@tonic-gate } 35237c478bd9Sstevel@tonic-gate 35247c478bd9Sstevel@tonic-gate if (stat(dir, &st) == 0) { 35257c478bd9Sstevel@tonic-gate if (trace > 1) { 35267c478bd9Sstevel@tonic-gate trace_prt(1, 35277c478bd9Sstevel@tonic-gate " loopbackmount of %s on %s dev=%x rdev=%x OK\n", 35287c478bd9Sstevel@tonic-gate fsname, dir, st.st_dev, st.st_rdev); 35297c478bd9Sstevel@tonic-gate } 35307c478bd9Sstevel@tonic-gate } else { 35317c478bd9Sstevel@tonic-gate if (trace > 1) { 35327c478bd9Sstevel@tonic-gate trace_prt(1, 35337c478bd9Sstevel@tonic-gate " loopbackmount of %s on %s OK\n", fsname, dir); 35347c478bd9Sstevel@tonic-gate trace_prt(1, " stat of %s failed\n", dir); 35357c478bd9Sstevel@tonic-gate } 35367c478bd9Sstevel@tonic-gate } 35377c478bd9Sstevel@tonic-gate 35387c478bd9Sstevel@tonic-gate return (0); 35397c478bd9Sstevel@tonic-gate } 35407c478bd9Sstevel@tonic-gate 35417c478bd9Sstevel@tonic-gate /* 35427c478bd9Sstevel@tonic-gate * Look for the value of a numeric option of the form foo=x. If found, set 35437c478bd9Sstevel@tonic-gate * *valp to the value and return non-zero. If not found or the option is 35447c478bd9Sstevel@tonic-gate * malformed, return zero. 35457c478bd9Sstevel@tonic-gate */ 35467c478bd9Sstevel@tonic-gate 35477c478bd9Sstevel@tonic-gate int 35487c478bd9Sstevel@tonic-gate nopt(mnt, opt, valp) 35497c478bd9Sstevel@tonic-gate struct mnttab *mnt; 35507c478bd9Sstevel@tonic-gate char *opt; 35517c478bd9Sstevel@tonic-gate int *valp; /* OUT */ 35527c478bd9Sstevel@tonic-gate { 35537c478bd9Sstevel@tonic-gate char *equal; 35547c478bd9Sstevel@tonic-gate char *str; 35557c478bd9Sstevel@tonic-gate 35567c478bd9Sstevel@tonic-gate /* 35577c478bd9Sstevel@tonic-gate * We should never get a null pointer, but if we do, it's better to 35587c478bd9Sstevel@tonic-gate * ignore the option than to dump core. 35597c478bd9Sstevel@tonic-gate */ 35607c478bd9Sstevel@tonic-gate 35617c478bd9Sstevel@tonic-gate if (valp == NULL) { 35627c478bd9Sstevel@tonic-gate syslog(LOG_DEBUG, "null pointer for %s option", opt); 35637c478bd9Sstevel@tonic-gate return (0); 35647c478bd9Sstevel@tonic-gate } 35657c478bd9Sstevel@tonic-gate 35667c478bd9Sstevel@tonic-gate if (str = hasmntopt(mnt, opt)) { 35677c478bd9Sstevel@tonic-gate if (equal = strchr(str, '=')) { 35687c478bd9Sstevel@tonic-gate *valp = atoi(&equal[1]); 35697c478bd9Sstevel@tonic-gate return (1); 35707c478bd9Sstevel@tonic-gate } else { 35717c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Bad numeric option '%s'", str); 35727c478bd9Sstevel@tonic-gate } 35737c478bd9Sstevel@tonic-gate } 35747c478bd9Sstevel@tonic-gate return (0); 35757c478bd9Sstevel@tonic-gate } 35767c478bd9Sstevel@tonic-gate 357711606941Sjwahlig int 35787c478bd9Sstevel@tonic-gate nfsunmount(mnt) 35797c478bd9Sstevel@tonic-gate struct mnttab *mnt; 35807c478bd9Sstevel@tonic-gate { 35817c478bd9Sstevel@tonic-gate struct timeval timeout; 35827c478bd9Sstevel@tonic-gate CLIENT *cl; 35837c478bd9Sstevel@tonic-gate enum clnt_stat rpc_stat; 35847c478bd9Sstevel@tonic-gate char *host, *path; 35857c478bd9Sstevel@tonic-gate struct replica *list; 35867c478bd9Sstevel@tonic-gate int i, count = 0; 35877c478bd9Sstevel@tonic-gate int isv4mount = is_v4_mount(mnt->mnt_mountp); 35887c478bd9Sstevel@tonic-gate 35897c478bd9Sstevel@tonic-gate if (trace > 1) 35907c478bd9Sstevel@tonic-gate trace_prt(1, " nfsunmount: umount %s\n", mnt->mnt_mountp); 35917c478bd9Sstevel@tonic-gate 35927c478bd9Sstevel@tonic-gate if (umount(mnt->mnt_mountp) < 0) { 35937c478bd9Sstevel@tonic-gate if (trace > 1) 35947c478bd9Sstevel@tonic-gate trace_prt(1, " nfsunmount: umount %s FAILED\n", 35957c478bd9Sstevel@tonic-gate mnt->mnt_mountp); 35967c478bd9Sstevel@tonic-gate if (errno) 35977c478bd9Sstevel@tonic-gate return (errno); 35987c478bd9Sstevel@tonic-gate } 35997c478bd9Sstevel@tonic-gate 36007c478bd9Sstevel@tonic-gate /* 36017c478bd9Sstevel@tonic-gate * If this is a NFSv4 mount, the mount protocol was not used 36027c478bd9Sstevel@tonic-gate * so we just return. 36037c478bd9Sstevel@tonic-gate */ 36047c478bd9Sstevel@tonic-gate if (isv4mount) { 36057c478bd9Sstevel@tonic-gate if (trace > 1) 36067c478bd9Sstevel@tonic-gate trace_prt(1, " nfsunmount: umount %s OK\n", 36077c478bd9Sstevel@tonic-gate mnt->mnt_mountp); 36087c478bd9Sstevel@tonic-gate return (0); 36097c478bd9Sstevel@tonic-gate } 36107c478bd9Sstevel@tonic-gate 36117c478bd9Sstevel@tonic-gate /* 36127c478bd9Sstevel@tonic-gate * If mounted with -o public, then no need to contact server 36137c478bd9Sstevel@tonic-gate * because mount protocol was not used. 36147c478bd9Sstevel@tonic-gate */ 36157c478bd9Sstevel@tonic-gate if (hasmntopt(mnt, MNTOPT_PUBLIC) != NULL) { 36167c478bd9Sstevel@tonic-gate return (0); 36177c478bd9Sstevel@tonic-gate } 36187c478bd9Sstevel@tonic-gate 36197c478bd9Sstevel@tonic-gate /* 36207c478bd9Sstevel@tonic-gate * The rest of this code is advisory to the server. 36217c478bd9Sstevel@tonic-gate * If it fails return success anyway. 36227c478bd9Sstevel@tonic-gate */ 36237c478bd9Sstevel@tonic-gate 36247c478bd9Sstevel@tonic-gate list = parse_replica(mnt->mnt_special, &count); 36257c478bd9Sstevel@tonic-gate if (!list) { 36267c478bd9Sstevel@tonic-gate if (count >= 0) 36277c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 36287c478bd9Sstevel@tonic-gate "Memory allocation failed: %m"); 36297c478bd9Sstevel@tonic-gate return (ENOMEM); 36307c478bd9Sstevel@tonic-gate } 36317c478bd9Sstevel@tonic-gate 36327c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) { 36337c478bd9Sstevel@tonic-gate 36347c478bd9Sstevel@tonic-gate host = list[i].host; 36357c478bd9Sstevel@tonic-gate path = list[i].path; 36367c478bd9Sstevel@tonic-gate 36377c478bd9Sstevel@tonic-gate /* 36387c478bd9Sstevel@tonic-gate * Skip file systems mounted using WebNFS, because mount 36397c478bd9Sstevel@tonic-gate * protocol was not used. 36407c478bd9Sstevel@tonic-gate */ 36417c478bd9Sstevel@tonic-gate if (strcmp(host, "nfs") == 0 && strncmp(path, "//", 2) == 0) 36427c478bd9Sstevel@tonic-gate continue; 36437c478bd9Sstevel@tonic-gate 36447c478bd9Sstevel@tonic-gate cl = clnt_create(host, MOUNTPROG, MOUNTVERS, "datagram_v"); 36457c478bd9Sstevel@tonic-gate if (cl == NULL) 36467c478bd9Sstevel@tonic-gate break; 36477c478bd9Sstevel@tonic-gate #ifdef MALLOC_DEBUG 36487c478bd9Sstevel@tonic-gate add_alloc("CLNT_HANDLE", cl, 0, __FILE__, __LINE__); 36497c478bd9Sstevel@tonic-gate add_alloc("AUTH_HANDLE", cl->cl_auth, 0, 36507c478bd9Sstevel@tonic-gate __FILE__, __LINE__); 36517c478bd9Sstevel@tonic-gate #endif 36527c478bd9Sstevel@tonic-gate if (__clnt_bindresvport(cl) < 0) { 36537c478bd9Sstevel@tonic-gate if (verbose) 36547c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "umount %s:%s: %s", 36557c478bd9Sstevel@tonic-gate host, path, 36567c478bd9Sstevel@tonic-gate "Couldn't bind to reserved port"); 36577c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 36587c478bd9Sstevel@tonic-gate continue; 36597c478bd9Sstevel@tonic-gate } 36607c478bd9Sstevel@tonic-gate #ifdef MALLOC_DEBUG 36617c478bd9Sstevel@tonic-gate drop_alloc("AUTH_HANDLE", cl->cl_auth, __FILE__, __LINE__); 36627c478bd9Sstevel@tonic-gate #endif 36637c478bd9Sstevel@tonic-gate AUTH_DESTROY(cl->cl_auth); 36647c478bd9Sstevel@tonic-gate if ((cl->cl_auth = authsys_create_default()) == NULL) { 36657c478bd9Sstevel@tonic-gate if (verbose) 36667c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "umount %s:%s: %s", 36677c478bd9Sstevel@tonic-gate host, path, 36687c478bd9Sstevel@tonic-gate "Failed creating default auth handle"); 36697c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 36707c478bd9Sstevel@tonic-gate continue; 36717c478bd9Sstevel@tonic-gate } 36727c478bd9Sstevel@tonic-gate #ifdef MALLOC_DEBUG 36737c478bd9Sstevel@tonic-gate add_alloc("AUTH_HANDLE", cl->cl_auth, 0, __FILE__, __LINE__); 36747c478bd9Sstevel@tonic-gate #endif 36757c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 36767c478bd9Sstevel@tonic-gate timeout.tv_sec = 5; 36777c478bd9Sstevel@tonic-gate rpc_stat = clnt_call(cl, MOUNTPROC_UMNT, xdr_dirpath, 36787c478bd9Sstevel@tonic-gate (caddr_t)&path, xdr_void, (char *)NULL, timeout); 36797c478bd9Sstevel@tonic-gate if (verbose && rpc_stat != RPC_SUCCESS) 36807c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s: %s", 36817c478bd9Sstevel@tonic-gate host, clnt_sperror(cl, "unmount")); 36827c478bd9Sstevel@tonic-gate destroy_auth_client_handle(cl); 36837c478bd9Sstevel@tonic-gate } 36847c478bd9Sstevel@tonic-gate 36857c478bd9Sstevel@tonic-gate free_replica(list, count); 36867c478bd9Sstevel@tonic-gate 36877c478bd9Sstevel@tonic-gate if (trace > 1) 36887c478bd9Sstevel@tonic-gate trace_prt(1, " nfsunmount: umount %s OK\n", mnt->mnt_mountp); 36897c478bd9Sstevel@tonic-gate 36907c478bd9Sstevel@tonic-gate done: 36917c478bd9Sstevel@tonic-gate return (0); 36927c478bd9Sstevel@tonic-gate } 36937c478bd9Sstevel@tonic-gate 36947c478bd9Sstevel@tonic-gate /* 36957c478bd9Sstevel@tonic-gate * Put a new entry in the cache chain by prepending it to the front. 36967c478bd9Sstevel@tonic-gate * If there isn't enough memory then just give up. 36977c478bd9Sstevel@tonic-gate */ 36987c478bd9Sstevel@tonic-gate static void 36997c478bd9Sstevel@tonic-gate cache_enter(host, reqvers, outvers, proto, state) 37007c478bd9Sstevel@tonic-gate char *host; 37017c478bd9Sstevel@tonic-gate rpcvers_t reqvers; 37027c478bd9Sstevel@tonic-gate rpcvers_t outvers; 37037c478bd9Sstevel@tonic-gate char *proto; 37047c478bd9Sstevel@tonic-gate int state; 37057c478bd9Sstevel@tonic-gate { 37067c478bd9Sstevel@tonic-gate struct cache_entry *entry; 37077c478bd9Sstevel@tonic-gate int cache_time = 30; /* sec */ 37087c478bd9Sstevel@tonic-gate 37097c478bd9Sstevel@tonic-gate timenow = time(NULL); 37107c478bd9Sstevel@tonic-gate 37117c478bd9Sstevel@tonic-gate entry = (struct cache_entry *)malloc(sizeof (struct cache_entry)); 37127c478bd9Sstevel@tonic-gate if (entry == NULL) 37137c478bd9Sstevel@tonic-gate return; 37147c478bd9Sstevel@tonic-gate (void) memset((caddr_t)entry, 0, sizeof (struct cache_entry)); 37157c478bd9Sstevel@tonic-gate entry->cache_host = strdup(host); 37167c478bd9Sstevel@tonic-gate if (entry->cache_host == NULL) { 37177c478bd9Sstevel@tonic-gate cache_free(entry); 37187c478bd9Sstevel@tonic-gate return; 37197c478bd9Sstevel@tonic-gate } 37207c478bd9Sstevel@tonic-gate entry->cache_reqvers = reqvers; 37217c478bd9Sstevel@tonic-gate entry->cache_outvers = outvers; 37227c478bd9Sstevel@tonic-gate entry->cache_proto = (proto == NULL ? NULL : strdup(proto)); 37237c478bd9Sstevel@tonic-gate entry->cache_state = state; 37247c478bd9Sstevel@tonic-gate entry->cache_time = timenow + cache_time; 37257c478bd9Sstevel@tonic-gate (void) rw_wrlock(&cache_lock); 37267c478bd9Sstevel@tonic-gate #ifdef CACHE_DEBUG 37277c478bd9Sstevel@tonic-gate host_cache_accesses++; /* up host cache access counter */ 37287c478bd9Sstevel@tonic-gate #endif /* CACHE DEBUG */ 37297c478bd9Sstevel@tonic-gate entry->cache_next = cache_head; 37307c478bd9Sstevel@tonic-gate cache_head = entry; 37317c478bd9Sstevel@tonic-gate (void) rw_unlock(&cache_lock); 37327c478bd9Sstevel@tonic-gate } 37337c478bd9Sstevel@tonic-gate 37347c478bd9Sstevel@tonic-gate static int 37357c478bd9Sstevel@tonic-gate cache_check(host, versp, proto) 37367c478bd9Sstevel@tonic-gate char *host; 37377c478bd9Sstevel@tonic-gate rpcvers_t *versp; 37387c478bd9Sstevel@tonic-gate char *proto; 37397c478bd9Sstevel@tonic-gate { 37407c478bd9Sstevel@tonic-gate int state = NOHOST; 37417c478bd9Sstevel@tonic-gate struct cache_entry *ce, *prev; 37427c478bd9Sstevel@tonic-gate 37437c478bd9Sstevel@tonic-gate timenow = time(NULL); 37447c478bd9Sstevel@tonic-gate 37457c478bd9Sstevel@tonic-gate (void) rw_rdlock(&cache_lock); 37467c478bd9Sstevel@tonic-gate 37477c478bd9Sstevel@tonic-gate #ifdef CACHE_DEBUG 37487c478bd9Sstevel@tonic-gate /* Increment the lookup and access counters for the host cache */ 37497c478bd9Sstevel@tonic-gate host_cache_accesses++; 37507c478bd9Sstevel@tonic-gate host_cache_lookups++; 37517c478bd9Sstevel@tonic-gate if ((host_cache_lookups%1000) == 0) 37527c478bd9Sstevel@tonic-gate trace_host_cache(); 37537c478bd9Sstevel@tonic-gate #endif /* CACHE DEBUG */ 37547c478bd9Sstevel@tonic-gate 37557c478bd9Sstevel@tonic-gate for (ce = cache_head; ce; ce = ce->cache_next) { 37567c478bd9Sstevel@tonic-gate if (timenow > ce->cache_time) { 37577c478bd9Sstevel@tonic-gate (void) rw_unlock(&cache_lock); 37587c478bd9Sstevel@tonic-gate (void) rw_wrlock(&cache_lock); 37597c478bd9Sstevel@tonic-gate for (prev = NULL, ce = cache_head; ce; 37607c478bd9Sstevel@tonic-gate prev = ce, ce = ce->cache_next) { 37617c478bd9Sstevel@tonic-gate if (timenow > ce->cache_time) { 37627c478bd9Sstevel@tonic-gate cache_free(ce); 37637c478bd9Sstevel@tonic-gate if (prev) 37647c478bd9Sstevel@tonic-gate prev->cache_next = NULL; 37657c478bd9Sstevel@tonic-gate else 37667c478bd9Sstevel@tonic-gate cache_head = NULL; 37677c478bd9Sstevel@tonic-gate break; 37687c478bd9Sstevel@tonic-gate } 37697c478bd9Sstevel@tonic-gate } 37707c478bd9Sstevel@tonic-gate (void) rw_unlock(&cache_lock); 37717c478bd9Sstevel@tonic-gate return (state); 37727c478bd9Sstevel@tonic-gate } 37737c478bd9Sstevel@tonic-gate if (strcmp(host, ce->cache_host) != 0) 37747c478bd9Sstevel@tonic-gate continue; 37757c478bd9Sstevel@tonic-gate if ((proto == NULL && ce->cache_proto != NULL) || 37767c478bd9Sstevel@tonic-gate (proto != NULL && ce->cache_proto == NULL)) 37777c478bd9Sstevel@tonic-gate continue; 37787c478bd9Sstevel@tonic-gate if (proto != NULL && 37797c478bd9Sstevel@tonic-gate strcmp(proto, ce->cache_proto) != 0) 37807c478bd9Sstevel@tonic-gate continue; 37817c478bd9Sstevel@tonic-gate 37827c478bd9Sstevel@tonic-gate if (versp == NULL || 37837c478bd9Sstevel@tonic-gate (versp != NULL && *versp == ce->cache_reqvers) || 37847c478bd9Sstevel@tonic-gate (versp != NULL && *versp == ce->cache_outvers)) { 37857c478bd9Sstevel@tonic-gate if (versp != NULL) 37867c478bd9Sstevel@tonic-gate *versp = ce->cache_outvers; 37877c478bd9Sstevel@tonic-gate state = ce->cache_state; 37887c478bd9Sstevel@tonic-gate 37897c478bd9Sstevel@tonic-gate /* increment the host cache hit counters */ 37907c478bd9Sstevel@tonic-gate #ifdef CACHE_DEBUG 37917c478bd9Sstevel@tonic-gate if (state == GOODHOST) 37927c478bd9Sstevel@tonic-gate goodhost_cache_hits++; 37937c478bd9Sstevel@tonic-gate if (state == DEADHOST) 37947c478bd9Sstevel@tonic-gate deadhost_cache_hits++; 37957c478bd9Sstevel@tonic-gate #endif /* CACHE_DEBUG */ 37967c478bd9Sstevel@tonic-gate (void) rw_unlock(&cache_lock); 37977c478bd9Sstevel@tonic-gate return (state); 37987c478bd9Sstevel@tonic-gate } 37997c478bd9Sstevel@tonic-gate } 38007c478bd9Sstevel@tonic-gate (void) rw_unlock(&cache_lock); 38017c478bd9Sstevel@tonic-gate return (state); 38027c478bd9Sstevel@tonic-gate } 38037c478bd9Sstevel@tonic-gate 38047c478bd9Sstevel@tonic-gate /* 38057c478bd9Sstevel@tonic-gate * Free a cache entry and all entries 38067c478bd9Sstevel@tonic-gate * further down the chain since they 38077c478bd9Sstevel@tonic-gate * will also be expired. 38087c478bd9Sstevel@tonic-gate */ 38097c478bd9Sstevel@tonic-gate static void 38107c478bd9Sstevel@tonic-gate cache_free(entry) 38117c478bd9Sstevel@tonic-gate struct cache_entry *entry; 38127c478bd9Sstevel@tonic-gate { 38137c478bd9Sstevel@tonic-gate struct cache_entry *ce, *next = NULL; 38147c478bd9Sstevel@tonic-gate 38157c478bd9Sstevel@tonic-gate for (ce = entry; ce; ce = next) { 38167c478bd9Sstevel@tonic-gate if (ce->cache_host) 38177c478bd9Sstevel@tonic-gate free(ce->cache_host); 38187c478bd9Sstevel@tonic-gate if (ce->cache_proto) 38197c478bd9Sstevel@tonic-gate free(ce->cache_proto); 38207c478bd9Sstevel@tonic-gate next = ce->cache_next; 38217c478bd9Sstevel@tonic-gate free(ce); 38227c478bd9Sstevel@tonic-gate } 38237c478bd9Sstevel@tonic-gate } 38247c478bd9Sstevel@tonic-gate 38257c478bd9Sstevel@tonic-gate #ifdef MALLOC_DEBUG 38267c478bd9Sstevel@tonic-gate void 38277c478bd9Sstevel@tonic-gate cache_flush() 38287c478bd9Sstevel@tonic-gate { 38297c478bd9Sstevel@tonic-gate (void) rw_wrlock(&cache_lock); 38307c478bd9Sstevel@tonic-gate cache_free(cache_head); 38317c478bd9Sstevel@tonic-gate cache_head = NULL; 38327c478bd9Sstevel@tonic-gate (void) rw_unlock(&cache_lock); 38337c478bd9Sstevel@tonic-gate } 38347c478bd9Sstevel@tonic-gate 38357c478bd9Sstevel@tonic-gate void 38367c478bd9Sstevel@tonic-gate flush_caches() 38377c478bd9Sstevel@tonic-gate { 38387c478bd9Sstevel@tonic-gate mutex_lock(&cleanup_lock); 38397c478bd9Sstevel@tonic-gate cond_signal(&cleanup_start_cv); 38407c478bd9Sstevel@tonic-gate (void) cond_wait(&cleanup_done_cv, &cleanup_lock); 38417c478bd9Sstevel@tonic-gate mutex_unlock(&cleanup_lock); 38427c478bd9Sstevel@tonic-gate cache_flush(); 38437c478bd9Sstevel@tonic-gate portmap_cache_flush(); 38447c478bd9Sstevel@tonic-gate } 38457c478bd9Sstevel@tonic-gate #endif 38467c478bd9Sstevel@tonic-gate 38477c478bd9Sstevel@tonic-gate /* 38487c478bd9Sstevel@tonic-gate * Returns 1, if port option is NFS_PORT or 38497c478bd9Sstevel@tonic-gate * nfsd is running on the port given 38507c478bd9Sstevel@tonic-gate * Returns 0, if both port is not NFS_PORT and nfsd is not 38517c478bd9Sstevel@tonic-gate * running on the port. 38527c478bd9Sstevel@tonic-gate */ 38537c478bd9Sstevel@tonic-gate 38547c478bd9Sstevel@tonic-gate static int 38557c478bd9Sstevel@tonic-gate is_nfs_port(char *opts) 38567c478bd9Sstevel@tonic-gate { 38577c478bd9Sstevel@tonic-gate struct mnttab m; 38587c478bd9Sstevel@tonic-gate uint_t nfs_port = 0; 38597c478bd9Sstevel@tonic-gate struct servent sv; 38607c478bd9Sstevel@tonic-gate char buf[256]; 38617c478bd9Sstevel@tonic-gate int got_port; 38627c478bd9Sstevel@tonic-gate 38637c478bd9Sstevel@tonic-gate m.mnt_mntopts = opts; 38647c478bd9Sstevel@tonic-gate 38657c478bd9Sstevel@tonic-gate /* 38667c478bd9Sstevel@tonic-gate * Get port specified in options list, if any. 38677c478bd9Sstevel@tonic-gate */ 38687c478bd9Sstevel@tonic-gate got_port = nopt(&m, MNTOPT_PORT, (int *)&nfs_port); 38697c478bd9Sstevel@tonic-gate 38707c478bd9Sstevel@tonic-gate /* 38717c478bd9Sstevel@tonic-gate * if no port specified or it is same as NFS_PORT return nfs 38727c478bd9Sstevel@tonic-gate * To use any other daemon the port number should be different 38737c478bd9Sstevel@tonic-gate */ 38747c478bd9Sstevel@tonic-gate if (!got_port || nfs_port == NFS_PORT) 38757c478bd9Sstevel@tonic-gate return (1); 38767c478bd9Sstevel@tonic-gate /* 38777c478bd9Sstevel@tonic-gate * If daemon is nfsd, return nfs 38787c478bd9Sstevel@tonic-gate */ 38797c478bd9Sstevel@tonic-gate if (getservbyport_r(nfs_port, NULL, &sv, buf, 256) == &sv && 38807c478bd9Sstevel@tonic-gate strcmp(sv.s_name, "nfsd") == 0) 38817c478bd9Sstevel@tonic-gate return (1); 38827c478bd9Sstevel@tonic-gate 38837c478bd9Sstevel@tonic-gate /* 38847c478bd9Sstevel@tonic-gate * daemon is not nfs 38857c478bd9Sstevel@tonic-gate */ 38867c478bd9Sstevel@tonic-gate return (0); 38877c478bd9Sstevel@tonic-gate } 38887c478bd9Sstevel@tonic-gate 38897c478bd9Sstevel@tonic-gate 38907c478bd9Sstevel@tonic-gate /* 38917c478bd9Sstevel@tonic-gate * destroy_auth_client_handle(cl) 38927c478bd9Sstevel@tonic-gate * destroys the created client handle 38937c478bd9Sstevel@tonic-gate */ 389439d3e169Sevanl void 38957c478bd9Sstevel@tonic-gate destroy_auth_client_handle(CLIENT *cl) 38967c478bd9Sstevel@tonic-gate { 38977c478bd9Sstevel@tonic-gate if (cl) { 38987c478bd9Sstevel@tonic-gate if (cl->cl_auth) { 38997c478bd9Sstevel@tonic-gate #ifdef MALLOC_DEBUG 39007c478bd9Sstevel@tonic-gate drop_alloc("AUTH_HANDLE", cl->cl_auth, 39017c478bd9Sstevel@tonic-gate __FILE__, __LINE__); 39027c478bd9Sstevel@tonic-gate #endif 39037c478bd9Sstevel@tonic-gate AUTH_DESTROY(cl->cl_auth); 39047c478bd9Sstevel@tonic-gate cl->cl_auth = NULL; 39057c478bd9Sstevel@tonic-gate } 39067c478bd9Sstevel@tonic-gate #ifdef MALLOC_DEBUG 39077c478bd9Sstevel@tonic-gate drop_alloc("CLNT_HANDLE", cl, 39087c478bd9Sstevel@tonic-gate __FILE__, __LINE__); 39097c478bd9Sstevel@tonic-gate #endif 39107c478bd9Sstevel@tonic-gate clnt_destroy(cl); 39117c478bd9Sstevel@tonic-gate } 39127c478bd9Sstevel@tonic-gate } 39137c478bd9Sstevel@tonic-gate 39147c478bd9Sstevel@tonic-gate 39157c478bd9Sstevel@tonic-gate /* 39167c478bd9Sstevel@tonic-gate * Attempt to figure out which version of NFS to use in pingnfs(). If 39177c478bd9Sstevel@tonic-gate * the version number was specified (i.e., non-zero), then use it. 39187c478bd9Sstevel@tonic-gate * Otherwise, default to the compiled-in default or the default as set 39197c478bd9Sstevel@tonic-gate * by the /etc/default/nfs configuration (as read by read_default(). 39207c478bd9Sstevel@tonic-gate */ 39217c478bd9Sstevel@tonic-gate int 39227c478bd9Sstevel@tonic-gate set_versrange(rpcvers_t nfsvers, rpcvers_t *vers, rpcvers_t *versmin) 39237c478bd9Sstevel@tonic-gate { 39247c478bd9Sstevel@tonic-gate switch (nfsvers) { 39257c478bd9Sstevel@tonic-gate case 0: 39267c478bd9Sstevel@tonic-gate *vers = vers_max_default; 39277c478bd9Sstevel@tonic-gate *versmin = vers_min_default; 39287c478bd9Sstevel@tonic-gate break; 39297c478bd9Sstevel@tonic-gate case NFS_V4: 39307c478bd9Sstevel@tonic-gate *vers = NFS_V4; 39317c478bd9Sstevel@tonic-gate *versmin = NFS_V4; 39327c478bd9Sstevel@tonic-gate break; 39337c478bd9Sstevel@tonic-gate case NFS_V3: 39347c478bd9Sstevel@tonic-gate *vers = NFS_V3; 39357c478bd9Sstevel@tonic-gate *versmin = NFS_V3; 39367c478bd9Sstevel@tonic-gate break; 39377c478bd9Sstevel@tonic-gate case NFS_VERSION: 39387c478bd9Sstevel@tonic-gate *vers = NFS_VERSION; /* version 2 */ 39397c478bd9Sstevel@tonic-gate *versmin = NFS_VERSMIN; /* version 2 */ 39407c478bd9Sstevel@tonic-gate break; 39417c478bd9Sstevel@tonic-gate default: 39427c478bd9Sstevel@tonic-gate return (-1); 39437c478bd9Sstevel@tonic-gate } 39447c478bd9Sstevel@tonic-gate return (0); 39457c478bd9Sstevel@tonic-gate } 39467c478bd9Sstevel@tonic-gate 39477c478bd9Sstevel@tonic-gate #ifdef CACHE_DEBUG 39487c478bd9Sstevel@tonic-gate /* 39497c478bd9Sstevel@tonic-gate * trace_portmap_cache() 39507c478bd9Sstevel@tonic-gate * traces the portmap cache values at desired points 39517c478bd9Sstevel@tonic-gate */ 39527c478bd9Sstevel@tonic-gate static void 39537c478bd9Sstevel@tonic-gate trace_portmap_cache() 39547c478bd9Sstevel@tonic-gate { 39557c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "portmap_cache: accesses=%d lookups=%d hits=%d\n", 39567c478bd9Sstevel@tonic-gate portmap_cache_accesses, portmap_cache_lookups, 39577c478bd9Sstevel@tonic-gate portmap_cache_hits); 39587c478bd9Sstevel@tonic-gate } 39597c478bd9Sstevel@tonic-gate 39607c478bd9Sstevel@tonic-gate /* 39617c478bd9Sstevel@tonic-gate * trace_host_cache() 39627c478bd9Sstevel@tonic-gate * traces the host cache values at desired points 39637c478bd9Sstevel@tonic-gate */ 39647c478bd9Sstevel@tonic-gate static void 39657c478bd9Sstevel@tonic-gate trace_host_cache() 39667c478bd9Sstevel@tonic-gate { 39677c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 39687c478bd9Sstevel@tonic-gate "host_cache: accesses=%d lookups=%d deadhits=%d goodhits=%d\n", 39697c478bd9Sstevel@tonic-gate host_cache_accesses, host_cache_lookups, deadhost_cache_hits, 39707c478bd9Sstevel@tonic-gate goodhost_cache_hits); 39717c478bd9Sstevel@tonic-gate } 39727c478bd9Sstevel@tonic-gate #endif /* CACHE_DEBUG */ 39737c478bd9Sstevel@tonic-gate 39747c478bd9Sstevel@tonic-gate /* 3975dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States * Read the NFS SMF properties to determine if the 39767c478bd9Sstevel@tonic-gate * client has been configured for a new min/max for the NFS version to 39777c478bd9Sstevel@tonic-gate * use. 39787c478bd9Sstevel@tonic-gate */ 39797c478bd9Sstevel@tonic-gate 3980dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #define SVC_NFS_CLIENT "svc:/network/nfs/client" 39817c478bd9Sstevel@tonic-gate 39827c478bd9Sstevel@tonic-gate static void 39837c478bd9Sstevel@tonic-gate read_default_nfs(void) 39847c478bd9Sstevel@tonic-gate { 39857c478bd9Sstevel@tonic-gate static time_t lastread = 0; 39867c478bd9Sstevel@tonic-gate struct stat buf; 3987dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States char defval[4]; 3988dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States int errno, bufsz; 3989dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States int tmp, ret = 0; 39907c478bd9Sstevel@tonic-gate 3991dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States bufsz = 4; 3992dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States ret = nfs_smf_get_prop("client_versmin", defval, DEFAULT_INSTANCE, 3993dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States SCF_TYPE_INTEGER, SVC_NFS_CLIENT, &bufsz); 3994dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if (ret == SA_OK) { 39957c478bd9Sstevel@tonic-gate errno = 0; 39967c478bd9Sstevel@tonic-gate tmp = strtol(defval, (char **)NULL, 10); 39977c478bd9Sstevel@tonic-gate if (errno == 0) { 39987c478bd9Sstevel@tonic-gate vers_min_default = tmp; 39997c478bd9Sstevel@tonic-gate } 40007c478bd9Sstevel@tonic-gate } 4001dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 4002dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States bufsz = 4; 4003dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States ret = nfs_smf_get_prop("client_versmax", defval, DEFAULT_INSTANCE, 4004dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States SCF_TYPE_INTEGER, SVC_NFS_CLIENT, &bufsz); 4005dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if (ret == SA_OK) { 40067c478bd9Sstevel@tonic-gate errno = 0; 40077c478bd9Sstevel@tonic-gate tmp = strtol(defval, (char **)NULL, 10); 40087c478bd9Sstevel@tonic-gate if (errno == 0) { 40097c478bd9Sstevel@tonic-gate vers_max_default = tmp; 40107c478bd9Sstevel@tonic-gate } 40117c478bd9Sstevel@tonic-gate } 40127c478bd9Sstevel@tonic-gate 40137c478bd9Sstevel@tonic-gate lastread = buf.st_mtime; 40147c478bd9Sstevel@tonic-gate 40157c478bd9Sstevel@tonic-gate /* 40167c478bd9Sstevel@tonic-gate * Quick sanity check on the values picked up from the 40177c478bd9Sstevel@tonic-gate * defaults file. Make sure that a mistake wasn't 40187c478bd9Sstevel@tonic-gate * made that will confuse things later on. 40197c478bd9Sstevel@tonic-gate * If so, reset to compiled-in defaults 40207c478bd9Sstevel@tonic-gate */ 40217c478bd9Sstevel@tonic-gate if (vers_min_default > vers_max_default || 40227c478bd9Sstevel@tonic-gate vers_min_default < NFS_VERSMIN || 40237c478bd9Sstevel@tonic-gate vers_max_default > NFS_VERSMAX) { 40247c478bd9Sstevel@tonic-gate if (trace > 1) { 40257c478bd9Sstevel@tonic-gate trace_prt(1, 40267c478bd9Sstevel@tonic-gate " read_default: version minimum/maximum incorrectly configured\n"); 40277c478bd9Sstevel@tonic-gate trace_prt(1, 40287c478bd9Sstevel@tonic-gate " read_default: config is min=%d, max%d. Resetting to min=%d, max%d\n", 40297c478bd9Sstevel@tonic-gate vers_min_default, vers_max_default, 40307c478bd9Sstevel@tonic-gate NFS_VERSMIN_DEFAULT, 40317c478bd9Sstevel@tonic-gate NFS_VERSMAX_DEFAULT); 40327c478bd9Sstevel@tonic-gate } 40337c478bd9Sstevel@tonic-gate vers_min_default = NFS_VERSMIN_DEFAULT; 40347c478bd9Sstevel@tonic-gate vers_max_default = NFS_VERSMAX_DEFAULT; 40357c478bd9Sstevel@tonic-gate } 40367c478bd9Sstevel@tonic-gate } 40377c478bd9Sstevel@tonic-gate 40387c478bd9Sstevel@tonic-gate /* 40397c478bd9Sstevel@tonic-gate * Find the mnttab entry that corresponds to "name". 40407c478bd9Sstevel@tonic-gate * We're not sure what the name represents: either 40417c478bd9Sstevel@tonic-gate * a mountpoint name, or a special name (server:/path). 40427c478bd9Sstevel@tonic-gate * Return the last entry in the file that matches. 40437c478bd9Sstevel@tonic-gate */ 40447c478bd9Sstevel@tonic-gate static struct extmnttab * 40457c478bd9Sstevel@tonic-gate mnttab_find(dirname) 40467c478bd9Sstevel@tonic-gate char *dirname; 40477c478bd9Sstevel@tonic-gate { 40487c478bd9Sstevel@tonic-gate FILE *fp; 40497c478bd9Sstevel@tonic-gate struct extmnttab mnt; 40507c478bd9Sstevel@tonic-gate struct extmnttab *res = NULL; 40517c478bd9Sstevel@tonic-gate 40527c478bd9Sstevel@tonic-gate fp = fopen(MNTTAB, "r"); 40537c478bd9Sstevel@tonic-gate if (fp == NULL) { 40547c478bd9Sstevel@tonic-gate if (trace > 1) 40557c478bd9Sstevel@tonic-gate trace_prt(1, " mnttab_find: unable to open mnttab\n"); 40567c478bd9Sstevel@tonic-gate return (NULL); 40577c478bd9Sstevel@tonic-gate } 40587c478bd9Sstevel@tonic-gate while (getextmntent(fp, &mnt, sizeof (struct extmnttab)) == 0) { 40597c478bd9Sstevel@tonic-gate if (strcmp(mnt.mnt_mountp, dirname) == 0 || 40607c478bd9Sstevel@tonic-gate strcmp(mnt.mnt_special, dirname) == 0) { 40617c478bd9Sstevel@tonic-gate if (res) 40627c478bd9Sstevel@tonic-gate fsfreemnttab(res); 40637c478bd9Sstevel@tonic-gate res = fsdupmnttab(&mnt); 40647c478bd9Sstevel@tonic-gate } 40657c478bd9Sstevel@tonic-gate } 40667c478bd9Sstevel@tonic-gate 40677c478bd9Sstevel@tonic-gate resetmnttab(fp); 40687c478bd9Sstevel@tonic-gate fclose(fp); 40697c478bd9Sstevel@tonic-gate if (res == NULL) { 40707c478bd9Sstevel@tonic-gate if (trace > 1) 40717c478bd9Sstevel@tonic-gate trace_prt(1, " mnttab_find: unable to find %s\n", 40727c478bd9Sstevel@tonic-gate dirname); 40737c478bd9Sstevel@tonic-gate } 40747c478bd9Sstevel@tonic-gate return (res); 40757c478bd9Sstevel@tonic-gate } 40767c478bd9Sstevel@tonic-gate 40777c478bd9Sstevel@tonic-gate /* 40787c478bd9Sstevel@tonic-gate * This function's behavior is taken from nfsstat. 40797c478bd9Sstevel@tonic-gate * Trying to determine what NFS version was used for the mount. 40807c478bd9Sstevel@tonic-gate */ 40817c478bd9Sstevel@tonic-gate static int 40827c478bd9Sstevel@tonic-gate is_v4_mount(char *mntpath) 40837c478bd9Sstevel@tonic-gate { 40847c478bd9Sstevel@tonic-gate kstat_ctl_t *kc = NULL; /* libkstat cookie */ 40857c478bd9Sstevel@tonic-gate kstat_t *ksp; 40867c478bd9Sstevel@tonic-gate ulong_t fsid; 40877c478bd9Sstevel@tonic-gate struct mntinfo_kstat mik; 40887c478bd9Sstevel@tonic-gate struct extmnttab *mntp; 40897c478bd9Sstevel@tonic-gate uint_t mnt_minor; 40907c478bd9Sstevel@tonic-gate 40917c478bd9Sstevel@tonic-gate if ((mntp = mnttab_find(mntpath)) == NULL) 40927c478bd9Sstevel@tonic-gate return (FALSE); 40937c478bd9Sstevel@tonic-gate 40947c478bd9Sstevel@tonic-gate /* save the minor number and free the struct so we don't forget */ 40957c478bd9Sstevel@tonic-gate mnt_minor = mntp->mnt_minor; 40967c478bd9Sstevel@tonic-gate fsfreemnttab(mntp); 40977c478bd9Sstevel@tonic-gate 40987c478bd9Sstevel@tonic-gate if ((kc = kstat_open()) == NULL) 40997c478bd9Sstevel@tonic-gate return (FALSE); 41007c478bd9Sstevel@tonic-gate 41017c478bd9Sstevel@tonic-gate for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 41027c478bd9Sstevel@tonic-gate if (ksp->ks_type != KSTAT_TYPE_RAW) 41037c478bd9Sstevel@tonic-gate continue; 41047c478bd9Sstevel@tonic-gate if (strcmp(ksp->ks_module, "nfs") != 0) 41057c478bd9Sstevel@tonic-gate continue; 41067c478bd9Sstevel@tonic-gate if (strcmp(ksp->ks_name, "mntinfo") != 0) 41077c478bd9Sstevel@tonic-gate continue; 41087c478bd9Sstevel@tonic-gate if (mnt_minor != ksp->ks_instance) 41097c478bd9Sstevel@tonic-gate continue; 41107c478bd9Sstevel@tonic-gate 41117c478bd9Sstevel@tonic-gate if (kstat_read(kc, ksp, &mik) == -1) 41127c478bd9Sstevel@tonic-gate continue; 41137c478bd9Sstevel@tonic-gate 41147c478bd9Sstevel@tonic-gate (void) kstat_close(kc); 41157c478bd9Sstevel@tonic-gate if (mik.mik_vers == 4) 41167c478bd9Sstevel@tonic-gate return (TRUE); 41177c478bd9Sstevel@tonic-gate else 41187c478bd9Sstevel@tonic-gate return (FALSE); 41197c478bd9Sstevel@tonic-gate } 41207c478bd9Sstevel@tonic-gate (void) kstat_close(kc); 41217c478bd9Sstevel@tonic-gate 41227c478bd9Sstevel@tonic-gate return (FALSE); 41237c478bd9Sstevel@tonic-gate } 412445916cd2Sjpk 412545916cd2Sjpk static int 412645916cd2Sjpk create_homedir(const char *src, const char *dst) { 412745916cd2Sjpk 412845916cd2Sjpk struct stat stbuf; 412945916cd2Sjpk char *dst_username; 413045916cd2Sjpk struct passwd *pwd, pwds; 413145916cd2Sjpk char buf_pwd[NSS_BUFLEN_PASSWD]; 413245916cd2Sjpk int homedir_len; 413345916cd2Sjpk int dst_dir_len; 413445916cd2Sjpk int src_dir_len; 413545916cd2Sjpk 413645916cd2Sjpk if (trace > 1) 413745916cd2Sjpk trace_prt(1, "entered create_homedir\n"); 413845916cd2Sjpk 413945916cd2Sjpk if (stat(src, &stbuf) == 0) { 414045916cd2Sjpk if (trace > 1) 414145916cd2Sjpk trace_prt(1, "src exists\n"); 414245916cd2Sjpk return (1); 414345916cd2Sjpk } 414445916cd2Sjpk 414545916cd2Sjpk dst_username = strrchr(dst, '/'); 414645916cd2Sjpk if (dst_username) { 414745916cd2Sjpk dst_username++; /* Skip over slash */ 414845916cd2Sjpk pwd = getpwnam_r(dst_username, &pwds, buf_pwd, 414945916cd2Sjpk sizeof (buf_pwd)); 415045916cd2Sjpk if (pwd == NULL) { 415145916cd2Sjpk return (0); 415245916cd2Sjpk } 415345916cd2Sjpk } else { 415445916cd2Sjpk return (0); 415545916cd2Sjpk } 415645916cd2Sjpk 415745916cd2Sjpk homedir_len = strlen(pwd->pw_dir); 415845916cd2Sjpk dst_dir_len = strlen(dst) - homedir_len; 415945916cd2Sjpk src_dir_len = strlen(src) - homedir_len; 416045916cd2Sjpk 416145916cd2Sjpk /* Check that the paths are in the same zone */ 416245916cd2Sjpk if (src_dir_len < dst_dir_len || 416345916cd2Sjpk (strncmp(dst, src, dst_dir_len) != 0)) { 416445916cd2Sjpk if (trace > 1) 416545916cd2Sjpk trace_prt(1, " paths don't match\n"); 416645916cd2Sjpk return (0); 416745916cd2Sjpk } 416845916cd2Sjpk /* Check that mountpoint is an auto_home entry */ 416945916cd2Sjpk if (dst_dir_len < 0 || 417045916cd2Sjpk (strcmp(pwd->pw_dir, dst + dst_dir_len) != 0)) { 417145916cd2Sjpk return (0); 417245916cd2Sjpk } 417345916cd2Sjpk 417445916cd2Sjpk /* Check that source is an home directory entry */ 417545916cd2Sjpk if (src_dir_len < 0 || 417645916cd2Sjpk (strcmp(pwd->pw_dir, src + src_dir_len) != 0)) { 417745916cd2Sjpk if (trace > 1) 417845916cd2Sjpk trace_prt(1, " homedir (2) doesn't match %s\n", 417945916cd2Sjpk src+src_dir_len); 418045916cd2Sjpk return (0); 418145916cd2Sjpk } 418245916cd2Sjpk 418345916cd2Sjpk if (mkdir(src, 418445916cd2Sjpk S_IRUSR | S_IWUSR | S_IXUSR | S_IXGRP | S_IXOTH) == -1) { 418545916cd2Sjpk if (trace > 1) { 418645916cd2Sjpk trace_prt(1, " Couldn't mkdir %s\n", src); 418745916cd2Sjpk } 418845916cd2Sjpk return (0); 418945916cd2Sjpk } 419045916cd2Sjpk 419145916cd2Sjpk if (chown(src, pwd->pw_uid, pwd->pw_gid) == -1) { 419245916cd2Sjpk unlink(src); 419345916cd2Sjpk return (0); 419445916cd2Sjpk } 419545916cd2Sjpk 419645916cd2Sjpk /* Created new home directory for the user */ 419745916cd2Sjpk return (1); 419845916cd2Sjpk } 419939d3e169Sevanl 420039d3e169Sevanl void 420139d3e169Sevanl free_nfs_args(struct nfs_args *argp) 420239d3e169Sevanl { 420339d3e169Sevanl struct nfs_args *oldp; 420439d3e169Sevanl while (argp) { 420539d3e169Sevanl if (argp->pathconf) 420639d3e169Sevanl free(argp->pathconf); 420739d3e169Sevanl if (argp->knconf) 420839d3e169Sevanl free_knconf(argp->knconf); 420939d3e169Sevanl if (argp->addr) 421039d3e169Sevanl netbuf_free(argp->addr); 421139d3e169Sevanl if (argp->syncaddr) 421239d3e169Sevanl netbuf_free(argp->syncaddr); 421339d3e169Sevanl if (argp->netname) 421439d3e169Sevanl free(argp->netname); 421539d3e169Sevanl if (argp->hostname) 421639d3e169Sevanl free(argp->hostname); 421739d3e169Sevanl if (argp->nfs_ext_u.nfs_extB.secdata) 421839d3e169Sevanl nfs_free_secdata(argp->nfs_ext_u.nfs_extB.secdata); 421939d3e169Sevanl if (argp->fh) 422039d3e169Sevanl free(argp->fh); 422139d3e169Sevanl if (argp->nfs_ext_u.nfs_extA.secdata) { 422239d3e169Sevanl sec_data_t *sd; 422339d3e169Sevanl sd = argp->nfs_ext_u.nfs_extA.secdata; 422439d3e169Sevanl if (sd == NULL) 422539d3e169Sevanl break; 422639d3e169Sevanl switch (sd->rpcflavor) { 422739d3e169Sevanl case AUTH_NONE: 422839d3e169Sevanl case AUTH_UNIX: 422939d3e169Sevanl case AUTH_LOOPBACK: 423039d3e169Sevanl break; 423139d3e169Sevanl case AUTH_DES: 423239d3e169Sevanl { 423339d3e169Sevanl dh_k4_clntdata_t *dhk4; 423439d3e169Sevanl dhk4 = (dh_k4_clntdata_t *)sd->data; 423539d3e169Sevanl if (dhk4 == NULL) 423639d3e169Sevanl break; 423739d3e169Sevanl if (dhk4->syncaddr.buf) 423839d3e169Sevanl free(dhk4->syncaddr.buf); 423939d3e169Sevanl if (dhk4->knconf->knc_protofmly) 424039d3e169Sevanl free(dhk4->knconf->knc_protofmly); 424139d3e169Sevanl if (dhk4->knconf->knc_proto) 424239d3e169Sevanl free(dhk4->knconf->knc_proto); 424339d3e169Sevanl if (dhk4->knconf) 424439d3e169Sevanl free(dhk4->knconf); 424539d3e169Sevanl if (dhk4->netname) 424639d3e169Sevanl free(dhk4->netname); 424739d3e169Sevanl free(dhk4); 424839d3e169Sevanl break; 424939d3e169Sevanl } 425039d3e169Sevanl case RPCSEC_GSS: 425139d3e169Sevanl { 425239d3e169Sevanl gss_clntdata_t *gss; 425339d3e169Sevanl gss = (gss_clntdata_t *)sd->data; 425439d3e169Sevanl if (gss == NULL) 425539d3e169Sevanl break; 425639d3e169Sevanl if (gss->mechanism.elements) 425739d3e169Sevanl free(gss->mechanism.elements); 425839d3e169Sevanl free(gss); 425939d3e169Sevanl break; 426039d3e169Sevanl } 426139d3e169Sevanl } 426239d3e169Sevanl } 426339d3e169Sevanl oldp = argp; 426439d3e169Sevanl if (argp->nfs_args_ext == NFS_ARGS_EXTB) 426539d3e169Sevanl argp = argp->nfs_ext_u.nfs_extB.next; 426639d3e169Sevanl else 426739d3e169Sevanl argp = NULL; 426839d3e169Sevanl free(oldp); 426939d3e169Sevanl } 427039d3e169Sevanl } 42712f172c55SRobert Thurlow 42722f172c55SRobert Thurlow void * 42732f172c55SRobert Thurlow get_netconfig_info(enum type_of_stuff type_of_stuff, char *hostname, 42742f172c55SRobert Thurlow rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf, 42752f172c55SRobert Thurlow ushort_t port, struct t_info *tinfo, struct t_bind *tbind, 42762f172c55SRobert Thurlow caddr_t *fhp, bool_t direct_to_server, char *fspath, 42772f172c55SRobert Thurlow enum clnt_stat *cstat, mfs_snego_t *mfssnego) 42782f172c55SRobert Thurlow { 42792f172c55SRobert Thurlow struct netconfig *nb = NULL; 42802f172c55SRobert Thurlow int ping_server = 0; 42812f172c55SRobert Thurlow 42822f172c55SRobert Thurlow 42832f172c55SRobert Thurlow if (nconf == NULL) 42842f172c55SRobert Thurlow return (NULL); 42852f172c55SRobert Thurlow 42862f172c55SRobert Thurlow switch (type_of_stuff) { 42872f172c55SRobert Thurlow case SERVER_FH: 42882f172c55SRobert Thurlow nb = get_server_fh(hostname, prog, vers, mfssnego, 42892f172c55SRobert Thurlow nconf, port, tinfo, tbind, fhp, direct_to_server, 42902f172c55SRobert Thurlow fspath, cstat); 42912f172c55SRobert Thurlow break; 42922f172c55SRobert Thurlow case SERVER_PING: 42932f172c55SRobert Thurlow ping_server = 1; 42942f172c55SRobert Thurlow case SERVER_ADDR: 42952f172c55SRobert Thurlow nb = get_server_addrorping(hostname, prog, vers, 42962f172c55SRobert Thurlow nconf, port, tinfo, tbind, fhp, direct_to_server, 42972f172c55SRobert Thurlow fspath, cstat, ping_server); 42982f172c55SRobert Thurlow break; 42992f172c55SRobert Thurlow default: 43002f172c55SRobert Thurlow assert(nb != NULL); 43012f172c55SRobert Thurlow } 43022f172c55SRobert Thurlow return (nb); 43032f172c55SRobert Thurlow } 43042f172c55SRobert Thurlow 43052f172c55SRobert Thurlow /* 43062f172c55SRobert Thurlow * Get the server address or can we ping it or not. 43072f172c55SRobert Thurlow * Check the portmap cache first for server address. 43082f172c55SRobert Thurlow * If no entries there, ping the server with a NULLPROC rpc. 43092f172c55SRobert Thurlow */ 43102f172c55SRobert Thurlow void * 43112f172c55SRobert Thurlow get_server_addrorping(char *hostname, rpcprog_t prog, rpcvers_t vers, 43122f172c55SRobert Thurlow struct netconfig *nconf, ushort_t port, struct t_info *tinfo, 43132f172c55SRobert Thurlow struct t_bind *tbind, caddr_t *fhp, bool_t direct_to_server, 43142f172c55SRobert Thurlow char *fspath, enum clnt_stat *cstat, int ping_server) 43152f172c55SRobert Thurlow { 43162f172c55SRobert Thurlow struct timeval tv; 43172f172c55SRobert Thurlow enum clnt_stat cs = RPC_TIMEDOUT; 43182f172c55SRobert Thurlow struct netbuf *nb = NULL; 43192f172c55SRobert Thurlow CLIENT *cl = NULL; 43202f172c55SRobert Thurlow int fd = -1; 43212f172c55SRobert Thurlow 43222f172c55SRobert Thurlow if (prog == NFS_PROGRAM && vers == NFS_V4) 43232f172c55SRobert Thurlow if (strncasecmp(nconf->nc_proto, NC_UDP, strlen(NC_UDP)) == 0) 43242f172c55SRobert Thurlow goto done; 43252f172c55SRobert Thurlow 43262f172c55SRobert Thurlow if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) < 0) { 43272f172c55SRobert Thurlow goto done; 43282f172c55SRobert Thurlow } 43292f172c55SRobert Thurlow 43302f172c55SRobert Thurlow /* LINTED pointer alignment */ 43312f172c55SRobert Thurlow if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR)) 43322f172c55SRobert Thurlow == NULL) { 43332f172c55SRobert Thurlow goto done; 43342f172c55SRobert Thurlow } 43352f172c55SRobert Thurlow 43362f172c55SRobert Thurlow if (direct_to_server != TRUE) { 43372f172c55SRobert Thurlow if (!ping_server) { 43382f172c55SRobert Thurlow if (get_cached_srv_addr(hostname, prog, vers, 43392f172c55SRobert Thurlow nconf, &tbind->addr) == 0) 43402f172c55SRobert Thurlow goto done; 43412f172c55SRobert Thurlow } else { 43422f172c55SRobert Thurlow if (port == 0) 43432f172c55SRobert Thurlow goto done; 43442f172c55SRobert Thurlow } 43452f172c55SRobert Thurlow } 43462f172c55SRobert Thurlow if (setup_nb_parms(nconf, tbind, tinfo, hostname, 43472f172c55SRobert Thurlow fd, direct_to_server, port, prog, vers, 0) < 0) 43482f172c55SRobert Thurlow goto done; 43492f172c55SRobert Thurlow 43502f172c55SRobert Thurlow if (port || (direct_to_server == TRUE)) { 43512f172c55SRobert Thurlow tv.tv_sec = 10; 43522f172c55SRobert Thurlow tv.tv_usec = 0; 43532f172c55SRobert Thurlow cl = clnt_tli_create(fd, nconf, &tbind->addr, 43542f172c55SRobert Thurlow prog, vers, 0, 0); 43552f172c55SRobert Thurlow if (cl == NULL) 43562f172c55SRobert Thurlow goto done; 43572f172c55SRobert Thurlow 43582f172c55SRobert Thurlow cs = clnt_call(cl, NULLPROC, xdr_void, 0, 43592f172c55SRobert Thurlow xdr_void, 0, tv); 43602f172c55SRobert Thurlow if (cs != RPC_SUCCESS) { 43612f172c55SRobert Thurlow syslog(LOG_ERR, "error is %d", cs); 43622f172c55SRobert Thurlow goto done; 43632f172c55SRobert Thurlow } 43642f172c55SRobert Thurlow } 43652f172c55SRobert Thurlow if (!ping_server) { 43662f172c55SRobert Thurlow nb = (struct netbuf *)malloc(sizeof (struct netbuf)); 43672f172c55SRobert Thurlow if (nb == NULL) { 43682f172c55SRobert Thurlow syslog(LOG_ERR, "no memory\n"); 43692f172c55SRobert Thurlow goto done; 43702f172c55SRobert Thurlow } 43712f172c55SRobert Thurlow nb->buf = (char *)malloc(tbind->addr.maxlen); 43722f172c55SRobert Thurlow if (nb->buf == NULL) { 43732f172c55SRobert Thurlow syslog(LOG_ERR, "no memory\n"); 43742f172c55SRobert Thurlow free(nb); 43752f172c55SRobert Thurlow nb = NULL; 43762f172c55SRobert Thurlow goto done; 43772f172c55SRobert Thurlow } 43782f172c55SRobert Thurlow (void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len); 43792f172c55SRobert Thurlow nb->len = tbind->addr.len; 43802f172c55SRobert Thurlow nb->maxlen = tbind->addr.maxlen; 43812f172c55SRobert Thurlow cs = RPC_SUCCESS; 43822f172c55SRobert Thurlow } 43832f172c55SRobert Thurlow done: 43842f172c55SRobert Thurlow destroy_auth_client_handle(cl); 43852f172c55SRobert Thurlow cleanup_tli_parms(tbind, fd); 43862f172c55SRobert Thurlow *cstat = cs; 43872f172c55SRobert Thurlow return (nb); 43882f172c55SRobert Thurlow } 4389