a reserved port, so why not the nfs rpc's themselves? With user allowed mounts, this perhaps needs a closer look, but on the other hand, a user could already specify the flag. If normal users should not be able to use resserved ports, the kernel should check for the flag at mount time.
778 lines
19 KiB
C
778 lines
19 KiB
C
/*
|
|
* Copyright (c) 1992, 1993, 1994
|
|
* The Regents of the University of California. All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to Berkeley by
|
|
* Rick Macklem at The University of Guelph.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the University of
|
|
* California, Berkeley and its contributors.
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char copyright[] =
|
|
"@(#) Copyright (c) 1992, 1993, 1994\n\
|
|
The Regents of the University of California. All rights reserved.\n";
|
|
#endif /* not lint */
|
|
|
|
#ifndef lint
|
|
/*
|
|
static char sccsid[] = "@(#)mount_nfs.c 8.11 (Berkeley) 5/4/95";
|
|
*/
|
|
static const char rcsid[] =
|
|
"$Id: mount_nfs.c,v 1.18 1997/03/29 03:32:39 imp Exp $";
|
|
#endif /* not lint */
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/socketvar.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/syslog.h>
|
|
|
|
#include <rpc/rpc.h>
|
|
#include <rpc/pmap_clnt.h>
|
|
#include <rpc/pmap_prot.h>
|
|
|
|
#ifdef ISO
|
|
#include <netiso/iso.h>
|
|
#endif
|
|
|
|
#ifdef NFSKERB
|
|
#include <kerberosIV/des.h>
|
|
#include <kerberosIV/krb.h>
|
|
#endif
|
|
|
|
#include <nfs/rpcv2.h>
|
|
#include <nfs/nfsproto.h>
|
|
#define KERNEL
|
|
#include <nfs/nfs.h>
|
|
#undef KERNEL
|
|
#include <nfs/nqnfs.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <ctype.h>
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <netdb.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <strings.h>
|
|
#include <sysexits.h>
|
|
#include <unistd.h>
|
|
|
|
#include "mntopts.h"
|
|
|
|
#define ALTF_BG 0x1
|
|
#define ALTF_NOCONN 0x2
|
|
#define ALTF_DUMBTIMR 0x4
|
|
#define ALTF_INTR 0x8
|
|
#define ALTF_KERB 0x10
|
|
#define ALTF_NFSV3 0x20
|
|
#define ALTF_RDIRPLUS 0x40
|
|
#define ALTF_MNTUDP 0x80
|
|
#define ALTF_RESVPORT 0x100
|
|
#define ALTF_SEQPACKET 0x200
|
|
#define ALTF_NQNFS 0x400
|
|
#define ALTF_SOFT 0x800
|
|
#define ALTF_TCP 0x1000
|
|
#define ALTF_PORT 0x2000
|
|
|
|
struct mntopt mopts[] = {
|
|
MOPT_STDOPTS,
|
|
MOPT_FORCE,
|
|
MOPT_UPDATE,
|
|
{ "bg", 0, ALTF_BG, 1 },
|
|
{ "conn", 1, ALTF_NOCONN, 1 },
|
|
{ "dumbtimer", 0, ALTF_DUMBTIMR, 1 },
|
|
{ "intr", 0, ALTF_INTR, 1 },
|
|
#ifdef NFSKERB
|
|
{ "kerb", 0, ALTF_KERB, 1 },
|
|
#endif
|
|
{ "nfsv3", 0, ALTF_NFSV3, 1 },
|
|
{ "rdirplus", 0, ALTF_RDIRPLUS, 1 },
|
|
{ "mntudp", 0, ALTF_MNTUDP, 1 },
|
|
{ "resvport", 0, ALTF_RESVPORT, 1 },
|
|
#ifdef ISO
|
|
{ "seqpacket", 0, ALTF_SEQPACKET, 1 },
|
|
#endif
|
|
{ "nqnfs", 0, ALTF_NQNFS, 1 },
|
|
{ "soft", 0, ALTF_SOFT, 1 },
|
|
{ "tcp", 0, ALTF_TCP, 1 },
|
|
{ "port=", 0, ALTF_PORT, 1 },
|
|
{ NULL }
|
|
};
|
|
|
|
struct nfs_args nfsdefargs = {
|
|
NFS_ARGSVERSION,
|
|
(struct sockaddr *)0,
|
|
sizeof (struct sockaddr_in),
|
|
SOCK_DGRAM,
|
|
0,
|
|
(u_char *)0,
|
|
0,
|
|
NFSMNT_RESVPORT,
|
|
NFS_WSIZE,
|
|
NFS_RSIZE,
|
|
NFS_READDIRSIZE,
|
|
10,
|
|
NFS_RETRANS,
|
|
NFS_MAXGRPS,
|
|
NFS_DEFRAHEAD,
|
|
NQ_DEFLEASE,
|
|
NQ_DEADTHRESH,
|
|
(char *)0,
|
|
};
|
|
|
|
struct nfhret {
|
|
u_long stat;
|
|
long vers;
|
|
long auth;
|
|
long fhsize;
|
|
u_char nfh[NFSX_V3FHMAX];
|
|
};
|
|
#define DEF_RETRY 10000
|
|
#define BGRND 1
|
|
#define ISBGRND 2
|
|
int retrycnt = DEF_RETRY;
|
|
int opflags = 0;
|
|
int nfsproto = IPPROTO_UDP;
|
|
int mnttcp_ok = 1;
|
|
u_short port_no = 0;
|
|
|
|
#ifdef NFSKERB
|
|
char inst[INST_SZ];
|
|
char realm[REALM_SZ];
|
|
struct {
|
|
u_long kind;
|
|
KTEXT_ST kt;
|
|
} ktick;
|
|
struct nfsrpc_nickverf kverf;
|
|
struct nfsrpc_fullblock kin, kout;
|
|
NFSKERBKEY_T kivec;
|
|
CREDENTIALS kcr;
|
|
struct timeval ktv;
|
|
NFSKERBKEYSCHED_T kerb_keysched;
|
|
#endif
|
|
|
|
int getnfsargs __P((char *, struct nfs_args *));
|
|
#ifdef ISO
|
|
struct iso_addr *iso_addr __P((const char *));
|
|
#endif
|
|
void set_rpc_maxgrouplist __P((int));
|
|
void usage __P((void)) __dead2;
|
|
int xdr_dir __P((XDR *, char *));
|
|
int xdr_fh __P((XDR *, struct nfhret *));
|
|
|
|
int
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
register int c;
|
|
register struct nfs_args *nfsargsp;
|
|
struct nfs_args nfsargs;
|
|
struct nfsd_cargs ncd;
|
|
int mntflags, altflags, i, nfssvc_flag, num;
|
|
char *name, *p, *spec;
|
|
struct vfsconf vfc;
|
|
int error = 0;
|
|
#ifdef NFSKERB
|
|
uid_t last_ruid;
|
|
|
|
last_ruid = -1;
|
|
(void)strcpy(realm, KRB_REALM);
|
|
if (sizeof (struct nfsrpc_nickverf) != RPCX_NICKVERF ||
|
|
sizeof (struct nfsrpc_fullblock) != RPCX_FULLBLOCK ||
|
|
((char *)&ktick.kt) - ((char *)&ktick) != NFSX_UNSIGNED ||
|
|
((char *)ktick.kt.dat) - ((char *)&ktick) != 2 * NFSX_UNSIGNED)
|
|
fprintf(stderr, "Yikes! NFSKERB structs not packed!!\n");
|
|
#endif /* NFSKERB */
|
|
retrycnt = DEF_RETRY;
|
|
|
|
mntflags = 0;
|
|
altflags = 0;
|
|
nfsargs = nfsdefargs;
|
|
nfsargsp = &nfsargs;
|
|
while ((c = getopt(argc, argv,
|
|
"3a:bcdD:g:I:iKL:lm:o:PpqR:r:sTt:w:x:U")) != -1)
|
|
switch (c) {
|
|
case '3':
|
|
nfsargsp->flags |= NFSMNT_NFSV3;
|
|
break;
|
|
case 'a':
|
|
num = strtol(optarg, &p, 10);
|
|
if (*p || num < 0)
|
|
errx(1, "illegal -a value -- %s", optarg);
|
|
nfsargsp->readahead = num;
|
|
nfsargsp->flags |= NFSMNT_READAHEAD;
|
|
break;
|
|
case 'b':
|
|
opflags |= BGRND;
|
|
break;
|
|
case 'c':
|
|
nfsargsp->flags |= NFSMNT_NOCONN;
|
|
break;
|
|
case 'D':
|
|
num = strtol(optarg, &p, 10);
|
|
if (*p || num <= 0)
|
|
errx(1, "illegal -D value -- %s", optarg);
|
|
nfsargsp->deadthresh = num;
|
|
nfsargsp->flags |= NFSMNT_DEADTHRESH;
|
|
break;
|
|
case 'd':
|
|
nfsargsp->flags |= NFSMNT_DUMBTIMR;
|
|
break;
|
|
case 'g':
|
|
num = strtol(optarg, &p, 10);
|
|
if (*p || num <= 0)
|
|
errx(1, "illegal -g value -- %s", optarg);
|
|
#ifdef __FreeBSD__
|
|
set_rpc_maxgrouplist(num);
|
|
#endif
|
|
nfsargsp->maxgrouplist = num;
|
|
nfsargsp->flags |= NFSMNT_MAXGRPS;
|
|
break;
|
|
case 'I':
|
|
num = strtol(optarg, &p, 10);
|
|
if (*p || num <= 0)
|
|
errx(1, "illegal -I value -- %s", optarg);
|
|
nfsargsp->readdirsize = num;
|
|
nfsargsp->flags |= NFSMNT_READDIRSIZE;
|
|
break;
|
|
case 'i':
|
|
nfsargsp->flags |= NFSMNT_INT;
|
|
break;
|
|
#ifdef NFSKERB
|
|
case 'K':
|
|
nfsargsp->flags |= NFSMNT_KERB;
|
|
break;
|
|
#endif
|
|
case 'L':
|
|
num = strtol(optarg, &p, 10);
|
|
if (*p || num < 2)
|
|
errx(1, "illegal -L value -- %s", optarg);
|
|
nfsargsp->leaseterm = num;
|
|
nfsargsp->flags |= NFSMNT_LEASETERM;
|
|
break;
|
|
case 'l':
|
|
nfsargsp->flags |= NFSMNT_RDIRPLUS;
|
|
break;
|
|
#ifdef NFSKERB
|
|
case 'm':
|
|
(void)strncpy(realm, optarg, REALM_SZ - 1);
|
|
realm[REALM_SZ - 1] = '\0';
|
|
break;
|
|
#endif
|
|
case 'o':
|
|
getmntopts(optarg, mopts, &mntflags, &altflags);
|
|
if(altflags & ALTF_BG)
|
|
opflags |= BGRND;
|
|
if(altflags & ALTF_NOCONN)
|
|
nfsargsp->flags |= NFSMNT_NOCONN;
|
|
if(altflags & ALTF_DUMBTIMR)
|
|
nfsargsp->flags |= NFSMNT_DUMBTIMR;
|
|
if(altflags & ALTF_INTR)
|
|
nfsargsp->flags |= NFSMNT_INT;
|
|
#ifdef NFSKERB
|
|
if(altflags & ALTF_KERB)
|
|
nfsargsp->flags |= NFSMNT_KERB;
|
|
#endif
|
|
if(altflags & ALTF_NFSV3)
|
|
nfsargsp->flags |= NFSMNT_NFSV3;
|
|
if(altflags & ALTF_RDIRPLUS)
|
|
nfsargsp->flags |= NFSMNT_RDIRPLUS;
|
|
if(altflags & ALTF_MNTUDP)
|
|
mnttcp_ok = 0;
|
|
if(altflags & ALTF_RESVPORT)
|
|
nfsargsp->flags |= NFSMNT_RESVPORT;
|
|
#ifdef ISO
|
|
if(altflags & ALTF_SEQPACKET)
|
|
nfsargsp->sotype = SOCK_SEQPACKET;
|
|
#endif
|
|
if(altflags & ALTF_NQNFS)
|
|
nfsargsp->flags |= (NFSMNT_NQNFS|NFSMNT_NFSV3);
|
|
if(altflags & ALTF_SOFT)
|
|
nfsargsp->flags |= NFSMNT_SOFT;
|
|
if(altflags & ALTF_TCP) {
|
|
nfsargsp->sotype = SOCK_STREAM;
|
|
nfsproto = IPPROTO_TCP;
|
|
}
|
|
if(altflags & ALTF_PORT)
|
|
port_no = atoi(strstr(optarg, "port=") + 5);
|
|
altflags = 0;
|
|
break;
|
|
case 'P':
|
|
nfsargsp->flags |= NFSMNT_RESVPORT;
|
|
break;
|
|
#ifdef ISO
|
|
case 'p':
|
|
nfsargsp->sotype = SOCK_SEQPACKET;
|
|
break;
|
|
#endif
|
|
case 'q':
|
|
nfsargsp->flags |= (NFSMNT_NQNFS | NFSMNT_NFSV3);
|
|
break;
|
|
case 'R':
|
|
num = strtol(optarg, &p, 10);
|
|
if (*p || num <= 0)
|
|
errx(1, "illegal -R value -- %s", optarg);
|
|
retrycnt = num;
|
|
break;
|
|
case 'r':
|
|
num = strtol(optarg, &p, 10);
|
|
if (*p || num <= 0)
|
|
errx(1, "illegal -r value -- %s", optarg);
|
|
nfsargsp->rsize = num;
|
|
nfsargsp->flags |= NFSMNT_RSIZE;
|
|
break;
|
|
case 's':
|
|
nfsargsp->flags |= NFSMNT_SOFT;
|
|
break;
|
|
case 'T':
|
|
nfsargsp->sotype = SOCK_STREAM;
|
|
nfsproto = IPPROTO_TCP;
|
|
break;
|
|
case 't':
|
|
num = strtol(optarg, &p, 10);
|
|
if (*p || num <= 0)
|
|
errx(1, "illegal -t value -- %s", optarg);
|
|
nfsargsp->timeo = num;
|
|
nfsargsp->flags |= NFSMNT_TIMEO;
|
|
break;
|
|
case 'w':
|
|
num = strtol(optarg, &p, 10);
|
|
if (*p || num <= 0)
|
|
errx(1, "illegal -w value -- %s", optarg);
|
|
nfsargsp->wsize = num;
|
|
nfsargsp->flags |= NFSMNT_WSIZE;
|
|
break;
|
|
case 'x':
|
|
num = strtol(optarg, &p, 10);
|
|
if (*p || num <= 0)
|
|
errx(1, "illegal -x value -- %s", optarg);
|
|
nfsargsp->retrans = num;
|
|
nfsargsp->flags |= NFSMNT_RETRANS;
|
|
break;
|
|
case 'U':
|
|
mnttcp_ok = 0;
|
|
break;
|
|
default:
|
|
usage();
|
|
break;
|
|
}
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
if (argc != 2) {
|
|
usage();
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
spec = *argv++;
|
|
name = *argv;
|
|
|
|
if (!getnfsargs(spec, nfsargsp))
|
|
exit(1);
|
|
|
|
#ifdef __FreeBSD__
|
|
error = getvfsbyname("nfs", &vfc);
|
|
if (error && vfsisloadable("nfs")) {
|
|
if(vfsload("nfs"))
|
|
err(EX_OSERR, "vfsload(nfs)");
|
|
endvfsent(); /* clear cache */
|
|
error = getvfsbyname("nfs", &vfc);
|
|
}
|
|
if (error)
|
|
errx(EX_OSERR, "nfs filesystem is not available");
|
|
|
|
if (mount(vfc.vfc_name, name, mntflags, nfsargsp))
|
|
err(1, "%s", name);
|
|
#else
|
|
if (mount("nfs", name, mntflags, nfsargsp))
|
|
err(1, "%s", name);
|
|
#endif
|
|
if (nfsargsp->flags & (NFSMNT_NQNFS | NFSMNT_KERB)) {
|
|
if ((opflags & ISBGRND) == 0) {
|
|
if (i = fork()) {
|
|
if (i == -1)
|
|
err(1, "nqnfs 1");
|
|
exit(0);
|
|
}
|
|
(void) setsid();
|
|
(void) close(STDIN_FILENO);
|
|
(void) close(STDOUT_FILENO);
|
|
(void) close(STDERR_FILENO);
|
|
(void) chdir("/");
|
|
}
|
|
openlog("mount_nfs:", LOG_PID, LOG_DAEMON);
|
|
nfssvc_flag = NFSSVC_MNTD;
|
|
ncd.ncd_dirp = name;
|
|
while (nfssvc(nfssvc_flag, (caddr_t)&ncd) < 0) {
|
|
if (errno != ENEEDAUTH) {
|
|
syslog(LOG_ERR, "nfssvc err %m");
|
|
continue;
|
|
}
|
|
nfssvc_flag =
|
|
NFSSVC_MNTD | NFSSVC_GOTAUTH | NFSSVC_AUTHINFAIL;
|
|
#ifdef NFSKERB
|
|
/*
|
|
* Set up as ncd_authuid for the kerberos call.
|
|
* Must set ruid to ncd_authuid and reset the
|
|
* ticket name iff ncd_authuid is not the same
|
|
* as last time, so that the right ticket file
|
|
* is found.
|
|
* Get the Kerberos credential structure so that
|
|
* we have the seesion key and get a ticket for
|
|
* this uid.
|
|
* For more info see the IETF Draft "Authentication
|
|
* in ONC RPC".
|
|
*/
|
|
if (ncd.ncd_authuid != last_ruid) {
|
|
char buf[512];
|
|
(void)sprintf(buf, "%s%d",
|
|
TKT_ROOT, ncd.ncd_authuid);
|
|
krb_set_tkt_string(buf);
|
|
last_ruid = ncd.ncd_authuid;
|
|
}
|
|
setreuid(ncd.ncd_authuid, 0);
|
|
kret = krb_get_cred(NFS_KERBSRV, inst, realm, &kcr);
|
|
if (kret == RET_NOTKT) {
|
|
kret = get_ad_tkt(NFS_KERBSRV, inst, realm,
|
|
DEFAULT_TKT_LIFE);
|
|
if (kret == KSUCCESS)
|
|
kret = krb_get_cred(NFS_KERBSRV, inst, realm,
|
|
&kcr);
|
|
}
|
|
if (kret == KSUCCESS)
|
|
kret = krb_mk_req(&ktick.kt, NFS_KERBSRV, inst,
|
|
realm, 0);
|
|
|
|
/*
|
|
* Fill in the AKN_FULLNAME authenticator and verfier.
|
|
* Along with the Kerberos ticket, we need to build
|
|
* the timestamp verifier and encrypt it in CBC mode.
|
|
*/
|
|
if (kret == KSUCCESS &&
|
|
ktick.kt.length <= (RPCAUTH_MAXSIZ-3*NFSX_UNSIGNED)
|
|
&& gettimeofday(&ktv, (struct timezone *)0) == 0) {
|
|
ncd.ncd_authtype = RPCAUTH_KERB4;
|
|
ncd.ncd_authstr = (u_char *)&ktick;
|
|
ncd.ncd_authlen = nfsm_rndup(ktick.kt.length) +
|
|
3 * NFSX_UNSIGNED;
|
|
ncd.ncd_verfstr = (u_char *)&kverf;
|
|
ncd.ncd_verflen = sizeof (kverf);
|
|
memmove(ncd.ncd_key, kcr.session,
|
|
sizeof (kcr.session));
|
|
kin.t1 = htonl(ktv.tv_sec);
|
|
kin.t2 = htonl(ktv.tv_usec);
|
|
kin.w1 = htonl(NFS_KERBTTL);
|
|
kin.w2 = htonl(NFS_KERBTTL - 1);
|
|
bzero((caddr_t)kivec, sizeof (kivec));
|
|
|
|
/*
|
|
* Encrypt kin in CBC mode using the session
|
|
* key in kcr.
|
|
*/
|
|
XXX
|
|
|
|
/*
|
|
* Finally, fill the timestamp verifier into the
|
|
* authenticator and verifier.
|
|
*/
|
|
ktick.kind = htonl(RPCAKN_FULLNAME);
|
|
kverf.kind = htonl(RPCAKN_FULLNAME);
|
|
NFS_KERBW1(ktick.kt) = kout.w1;
|
|
ktick.kt.length = htonl(ktick.kt.length);
|
|
kverf.verf.t1 = kout.t1;
|
|
kverf.verf.t2 = kout.t2;
|
|
kverf.verf.w2 = kout.w2;
|
|
nfssvc_flag = NFSSVC_MNTD | NFSSVC_GOTAUTH;
|
|
}
|
|
setreuid(0, 0);
|
|
#endif /* NFSKERB */
|
|
}
|
|
}
|
|
exit(0);
|
|
}
|
|
|
|
int
|
|
getnfsargs(spec, nfsargsp)
|
|
char *spec;
|
|
struct nfs_args *nfsargsp;
|
|
{
|
|
register CLIENT *clp;
|
|
struct hostent *hp;
|
|
static struct sockaddr_in saddr;
|
|
#ifdef ISO
|
|
static struct sockaddr_iso isoaddr;
|
|
struct iso_addr *isop;
|
|
int isoflag = 0;
|
|
#endif
|
|
struct timeval pertry, try;
|
|
enum clnt_stat clnt_stat;
|
|
int so = RPC_ANYSOCK, i, nfsvers, mntvers;
|
|
char *hostp, *delimp;
|
|
#ifdef NFSKERB
|
|
char *cp;
|
|
#endif
|
|
u_short tport;
|
|
static struct nfhret nfhret;
|
|
static char nam[MNAMELEN + 1];
|
|
|
|
strncpy(nam, spec, MNAMELEN);
|
|
nam[MNAMELEN] = '\0';
|
|
if ((delimp = strchr(spec, '@')) != NULL) {
|
|
hostp = delimp + 1;
|
|
} else if ((delimp = strchr(spec, ':')) != NULL) {
|
|
hostp = spec;
|
|
spec = delimp + 1;
|
|
} else {
|
|
warnx("no <host>:<dirpath> or <dirpath>@<host> spec");
|
|
return (0);
|
|
}
|
|
*delimp = '\0';
|
|
/*
|
|
* DUMB!! Until the mount protocol works on iso transport, we must
|
|
* supply both an iso and an inet address for the host.
|
|
*/
|
|
#ifdef ISO
|
|
if (!strncmp(hostp, "iso=", 4)) {
|
|
u_short isoport;
|
|
|
|
hostp += 4;
|
|
isoflag++;
|
|
if ((delimp = strchr(hostp, '+')) == NULL) {
|
|
warnx("no iso+inet address");
|
|
return (0);
|
|
}
|
|
*delimp = '\0';
|
|
if ((isop = iso_addr(hostp)) == NULL) {
|
|
warnx("bad ISO address");
|
|
return (0);
|
|
}
|
|
memset(&isoaddr, 0, sizeof (isoaddr));
|
|
memmove(&isoaddr.siso_addr, isop, sizeof (struct iso_addr));
|
|
isoaddr.siso_len = sizeof (isoaddr);
|
|
isoaddr.siso_family = AF_ISO;
|
|
isoaddr.siso_tlen = 2;
|
|
isoport = htons(NFS_PORT);
|
|
memmove(TSEL(&isoaddr), &isoport, isoaddr.siso_tlen);
|
|
hostp = delimp + 1;
|
|
}
|
|
#endif /* ISO */
|
|
|
|
/*
|
|
* Handle an internet host address and reverse resolve it if
|
|
* doing Kerberos.
|
|
*/
|
|
if (isdigit(*hostp)) {
|
|
if ((saddr.sin_addr.s_addr = inet_addr(hostp)) == -1) {
|
|
warnx("bad net address %s", hostp);
|
|
return (0);
|
|
}
|
|
} else if ((hp = gethostbyname(hostp)) != NULL)
|
|
memmove(&saddr.sin_addr, hp->h_addr, hp->h_length);
|
|
else {
|
|
warnx("can't get net id for host");
|
|
return (0);
|
|
}
|
|
#ifdef NFSKERB
|
|
if ((nfsargsp->flags & NFSMNT_KERB)) {
|
|
if ((hp = gethostbyaddr((char *)&saddr.sin_addr.s_addr,
|
|
sizeof (u_long), AF_INET)) == (struct hostent *)0) {
|
|
warnx("can't reverse resolve net address");
|
|
return (0);
|
|
}
|
|
memmove(&saddr.sin_addr, hp->h_addr, hp->h_length);
|
|
strncpy(inst, hp->h_name, INST_SZ);
|
|
inst[INST_SZ - 1] = '\0';
|
|
if (cp = strchr(inst, '.'))
|
|
*cp = '\0';
|
|
}
|
|
#endif /* NFSKERB */
|
|
|
|
if (nfsargsp->flags & NFSMNT_NFSV3) {
|
|
nfsvers = 3;
|
|
mntvers = 3;
|
|
} else {
|
|
nfsvers = 2;
|
|
mntvers = 1;
|
|
}
|
|
nfhret.stat = EACCES; /* Mark not yet successful */
|
|
while (retrycnt > 0) {
|
|
saddr.sin_family = AF_INET;
|
|
saddr.sin_port = htons(PMAPPORT);
|
|
if ((tport = port_no ? port_no :
|
|
pmap_getport(&saddr, RPCPROG_NFS,
|
|
nfsvers, nfsproto)) == 0) {
|
|
if ((opflags & ISBGRND) == 0)
|
|
clnt_pcreateerror("NFS Portmap");
|
|
} else {
|
|
saddr.sin_port = 0;
|
|
pertry.tv_sec = 10;
|
|
pertry.tv_usec = 0;
|
|
if (mnttcp_ok && nfsargsp->sotype == SOCK_STREAM)
|
|
clp = clnttcp_create(&saddr, RPCPROG_MNT, mntvers,
|
|
&so, 0, 0);
|
|
else
|
|
clp = clntudp_create(&saddr, RPCPROG_MNT, mntvers,
|
|
pertry, &so);
|
|
if (clp == NULL) {
|
|
if ((opflags & ISBGRND) == 0)
|
|
clnt_pcreateerror("Cannot MNT RPC");
|
|
} else {
|
|
clp->cl_auth = authunix_create_default();
|
|
try.tv_sec = 10;
|
|
try.tv_usec = 0;
|
|
if (nfsargsp->flags & NFSMNT_KERB)
|
|
nfhret.auth = RPCAUTH_KERB4;
|
|
else
|
|
nfhret.auth = RPCAUTH_UNIX;
|
|
nfhret.vers = mntvers;
|
|
clnt_stat = clnt_call(clp, RPCMNT_MOUNT,
|
|
xdr_dir, spec, xdr_fh, &nfhret, try);
|
|
if (clnt_stat != RPC_SUCCESS) {
|
|
if ((opflags & ISBGRND) == 0)
|
|
warnx("%s", clnt_sperror(clp,
|
|
"bad MNT RPC"));
|
|
} else {
|
|
auth_destroy(clp->cl_auth);
|
|
clnt_destroy(clp);
|
|
retrycnt = 0;
|
|
}
|
|
}
|
|
}
|
|
if (--retrycnt > 0) {
|
|
if (opflags & BGRND) {
|
|
opflags &= ~BGRND;
|
|
if (i = fork()) {
|
|
if (i == -1)
|
|
err(1, "nqnfs 2");
|
|
exit(0);
|
|
}
|
|
(void) setsid();
|
|
(void) close(STDIN_FILENO);
|
|
(void) close(STDOUT_FILENO);
|
|
(void) close(STDERR_FILENO);
|
|
(void) chdir("/");
|
|
opflags |= ISBGRND;
|
|
}
|
|
sleep(60);
|
|
}
|
|
}
|
|
if (nfhret.stat) {
|
|
if (opflags & ISBGRND)
|
|
exit(1);
|
|
warnx("can't access %s: %s", spec, strerror(nfhret.stat));
|
|
return (0);
|
|
}
|
|
saddr.sin_port = htons(tport);
|
|
#ifdef ISO
|
|
if (isoflag) {
|
|
nfsargsp->addr = (struct sockaddr *) &isoaddr;
|
|
nfsargsp->addrlen = sizeof (isoaddr);
|
|
} else
|
|
#endif /* ISO */
|
|
{
|
|
nfsargsp->addr = (struct sockaddr *) &saddr;
|
|
nfsargsp->addrlen = sizeof (saddr);
|
|
}
|
|
nfsargsp->fh = nfhret.nfh;
|
|
nfsargsp->fhsize = nfhret.fhsize;
|
|
nfsargsp->hostname = nam;
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* xdr routines for mount rpc's
|
|
*/
|
|
int
|
|
xdr_dir(xdrsp, dirp)
|
|
XDR *xdrsp;
|
|
char *dirp;
|
|
{
|
|
return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
|
|
}
|
|
|
|
int
|
|
xdr_fh(xdrsp, np)
|
|
XDR *xdrsp;
|
|
register struct nfhret *np;
|
|
{
|
|
register int i;
|
|
long auth, authcnt, authfnd = 0;
|
|
|
|
if (!xdr_u_long(xdrsp, &np->stat))
|
|
return (0);
|
|
if (np->stat)
|
|
return (1);
|
|
switch (np->vers) {
|
|
case 1:
|
|
np->fhsize = NFSX_V2FH;
|
|
return (xdr_opaque(xdrsp, (caddr_t)np->nfh, NFSX_V2FH));
|
|
case 3:
|
|
if (!xdr_long(xdrsp, &np->fhsize))
|
|
return (0);
|
|
if (np->fhsize <= 0 || np->fhsize > NFSX_V3FHMAX)
|
|
return (0);
|
|
if (!xdr_opaque(xdrsp, (caddr_t)np->nfh, np->fhsize))
|
|
return (0);
|
|
if (!xdr_long(xdrsp, &authcnt))
|
|
return (0);
|
|
for (i = 0; i < authcnt; i++) {
|
|
if (!xdr_long(xdrsp, &auth))
|
|
return (0);
|
|
if (auth == np->auth)
|
|
authfnd++;
|
|
}
|
|
/*
|
|
* Some servers, such as DEC's OSF/1 return a nil authenticator
|
|
* list to indicate RPCAUTH_UNIX.
|
|
*/
|
|
if (!authfnd && (authcnt > 0 || np->auth != RPCAUTH_UNIX))
|
|
np->stat = EAUTH;
|
|
return (1);
|
|
};
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
usage()
|
|
{
|
|
(void)fprintf(stderr, "\
|
|
usage: mount_nfs [-3KPTUbcdilqs] [-D deadthresh] [-I readdirsize]\n\
|
|
[-L leaseterm] [-R retrycnt] [-a maxreadahead] [-g maxgroups]\n\
|
|
[-m realm] [-o options] [-r readsize] [-t timeout] [-w writesize]\n\
|
|
[-x retrans] rhost:path node\n");
|
|
exit(1);
|
|
}
|