* 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
* 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
static char copyright
[] =
"@(#) Copyright (c) 1992, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
static char sccsid
[] = "@(#)mount_nfs.c 8.11 (Berkeley) 5/4/95";
#include <sys/socketvar.h>
#include <rpc/pmap_clnt.h>
#include <rpc/pmap_prot.h>
#include <kerberosIV/des.h>
#include <kerberosIV/krb.h>
#include <nfs/nfsproto.h>
#define ALTF_DUMBTIMR 0x4
#define ALTF_RDIRPLUS 0x40
#define ALTF_RESVPORT 0x100
#define ALTF_SEQPACKET 0x200
struct mntopt mopts
[] = {
{ "conn", 1, ALTF_NOCONN
, 1 },
{ "dumbtimer", 0, ALTF_DUMBTIMR
, 1 },
{ "intr", 0, ALTF_INTR
, 1 },
{ "kerb", 0, ALTF_KERB
, 1 },
{ "nfsv3", 0, ALTF_NFSV3
, 1 },
{ "rdirplus", 0, ALTF_RDIRPLUS
, 1 },
{ "mntudp", 0, ALTF_MNTUDP
, 1 },
{ "resvport", 0, ALTF_RESVPORT
, 1 },
{ "seqpacket", 0, ALTF_SEQPACKET
, 1 },
{ "nqnfs", 0, ALTF_NQNFS
, 1 },
{ "soft", 0, ALTF_SOFT
, 1 },
{ "tcp", 0, ALTF_TCP
, 1 },
struct nfs_args nfsdefargs
= {
sizeof (struct sockaddr_in
),
u_char nfh
[NFSX_V3FHMAX
];
int retrycnt
= DEF_RETRY
;
int nfsproto
= IPPROTO_UDP
;
struct nfsrpc_nickverf kverf
;
struct nfsrpc_fullblock kin
, kout
;
NFSKERBKEYSCHED_T kerb_keysched
;
int getnfsargs
__P((char *, struct nfs_args
*));
struct iso_addr
*iso_addr
__P((const char *));
void set_rpc_maxgrouplist
__P((int));
__dead
void usage
__P((void));
int xdr_dir
__P((XDR
*, char *));
int xdr_fh
__P((XDR
*, struct nfhret
*));
register struct nfs_args
*nfsargsp
;
int mntflags
, altflags
, i
, nfssvc_flag
, num
;
(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");
while ((c
= getopt(argc
, argv
,
"3a:bcdD:g:I:iKL:lm:o:PpqR:r:sTt:w:x:U")) != EOF
)
nfsargsp
->flags
|= NFSMNT_NFSV3
;
num
= strtol(optarg
, &p
, 10);
errx(1, "illegal -a value -- %s", optarg
);
nfsargsp
->readahead
= num
;
nfsargsp
->flags
|= NFSMNT_READAHEAD
;
nfsargsp
->flags
|= NFSMNT_NOCONN
;
num
= strtol(optarg
, &p
, 10);
errx(1, "illegal -D value -- %s", optarg
);
nfsargsp
->deadthresh
= num
;
nfsargsp
->flags
|= NFSMNT_DEADTHRESH
;
nfsargsp
->flags
|= NFSMNT_DUMBTIMR
;
num
= strtol(optarg
, &p
, 10);
errx(1, "illegal -g value -- %s", optarg
);
set_rpc_maxgrouplist(num
);
nfsargsp
->maxgrouplist
= num
;
nfsargsp
->flags
|= NFSMNT_MAXGRPS
;
num
= strtol(optarg
, &p
, 10);
errx(1, "illegal -I value -- %s", optarg
);
nfsargsp
->readdirsize
= num
;
nfsargsp
->flags
|= NFSMNT_READDIRSIZE
;
nfsargsp
->flags
|= NFSMNT_INT
;
nfsargsp
->flags
|= NFSMNT_KERB
;
num
= strtol(optarg
, &p
, 10);
errx(1, "illegal -L value -- %s", optarg
);
nfsargsp
->leaseterm
= num
;
nfsargsp
->flags
|= NFSMNT_LEASETERM
;
nfsargsp
->flags
|= NFSMNT_RDIRPLUS
;
(void)strncpy(realm
, optarg
, REALM_SZ
- 1);
realm
[REALM_SZ
- 1] = '\0';
getmntopts(optarg
, mopts
, &mntflags
, &altflags
);
if(altflags
& ALTF_NOCONN
)
nfsargsp
->flags
|= NFSMNT_NOCONN
;
if(altflags
& ALTF_DUMBTIMR
)
nfsargsp
->flags
|= NFSMNT_DUMBTIMR
;
nfsargsp
->flags
|= NFSMNT_INT
;
nfsargsp
->flags
|= NFSMNT_KERB
;
if(altflags
& ALTF_NFSV3
)
nfsargsp
->flags
|= NFSMNT_NFSV3
;
if(altflags
& ALTF_RDIRPLUS
)
nfsargsp
->flags
|= NFSMNT_RDIRPLUS
;
if(altflags
& ALTF_MNTUDP
)
if(altflags
& ALTF_RESVPORT
)
nfsargsp
->flags
|= NFSMNT_RESVPORT
;
if(altflags
& ALTF_SEQPACKET
)
nfsargsp
->sotype
= SOCK_SEQPACKET
;
if(altflags
& ALTF_NQNFS
)
nfsargsp
->flags
|= (NFSMNT_NQNFS
|NFSMNT_NFSV3
);
nfsargsp
->flags
|= NFSMNT_SOFT
;
if(altflags
& ALTF_TCP
) {
nfsargsp
->sotype
= SOCK_STREAM
;
nfsargsp
->flags
|= NFSMNT_RESVPORT
;
nfsargsp
->sotype
= SOCK_SEQPACKET
;
nfsargsp
->flags
|= (NFSMNT_NQNFS
| NFSMNT_NFSV3
);
num
= strtol(optarg
, &p
, 10);
errx(1, "illegal -R value -- %s", optarg
);
num
= strtol(optarg
, &p
, 10);
errx(1, "illegal -r value -- %s", optarg
);
nfsargsp
->flags
|= NFSMNT_RSIZE
;
nfsargsp
->flags
|= NFSMNT_SOFT
;
nfsargsp
->sotype
= SOCK_STREAM
;
num
= strtol(optarg
, &p
, 10);
errx(1, "illegal -t value -- %s", optarg
);
nfsargsp
->flags
|= NFSMNT_TIMEO
;
num
= strtol(optarg
, &p
, 10);
errx(1, "illegal -w value -- %s", optarg
);
nfsargsp
->flags
|= NFSMNT_WSIZE
;
num
= strtol(optarg
, &p
, 10);
errx(1, "illegal -x value -- %s", optarg
);
nfsargsp
->flags
|= NFSMNT_RETRANS
;
if (!getnfsargs(spec
, nfsargsp
))
if (mount("nfs", name
, mntflags
, nfsargsp
))
if (nfsargsp
->flags
& (NFSMNT_NQNFS
| NFSMNT_KERB
)) {
if ((opflags
& ISBGRND
) == 0) {
(void) close(STDIN_FILENO
);
(void) close(STDOUT_FILENO
);
(void) close(STDERR_FILENO
);
openlog("mount_nfs:", LOG_PID
, LOG_DAEMON
);
nfssvc_flag
= NFSSVC_MNTD
;
while (nfssvc(nfssvc_flag
, (caddr_t
)&ncd
) < 0) {
if (errno
!= ENEEDAUTH
) {
syslog(LOG_ERR
, "nfssvc err %m");
NFSSVC_MNTD
| NFSSVC_GOTAUTH
| NFSSVC_AUTHINFAIL
;
* 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
* Get the Kerberos credential structure so that
* we have the seesion key and get a ticket for
* For more info see the IETF Draft "Authentication
if (ncd
.ncd_authuid
!= last_ruid
) {
last_ruid
= ncd
.ncd_authuid
;
setreuid(ncd
.ncd_authuid
, 0);
kret
= krb_get_cred(NFS_KERBSRV
, inst
, realm
, &kcr
);
kret
= get_ad_tkt(NFS_KERBSRV
, inst
, realm
,
kret
= krb_get_cred(NFS_KERBSRV
, inst
, realm
,
kret
= krb_mk_req(&ktick
.kt
, NFS_KERBSRV
, inst
,
* 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.
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
) +
ncd
.ncd_verfstr
= (u_char
*)&kverf
;
ncd
.ncd_verflen
= sizeof (kverf
);
memmove(ncd
.ncd_key
, 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
* 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
);
nfssvc_flag
= NFSSVC_MNTD
| NFSSVC_GOTAUTH
;
getnfsargs(spec
, nfsargsp
)
struct nfs_args
*nfsargsp
;
static struct sockaddr_in saddr
;
static struct sockaddr_iso isoaddr
;
struct timeval pertry
, try;
enum clnt_stat clnt_stat
;
int so
= RPC_ANYSOCK
, i
, nfsvers
, mntvers
;
static struct nfhret nfhret
;
static char nam
[MNAMELEN
+ 1];
strncpy(nam
, spec
, MNAMELEN
);
if ((delimp
= strchr(spec
, '@')) != NULL
) {
} else if ((delimp
= strchr(spec
, ':')) != NULL
) {
warnx("no <host>:<dirpath> or <dirpath>@<host> spec");
* DUMB!! Until the mount protocol works on iso transport, we must
* supply both an iso and an inet address for the host.
if (!strncmp(hostp
, "iso=", 4)) {
if ((delimp
= strchr(hostp
, '+')) == NULL
) {
warnx("no iso+inet address");
if ((isop
= iso_addr(hostp
)) == NULL
) {
warnx("bad ISO address");
memset(&isoaddr
, 0, sizeof (isoaddr
));
memmove(&isoaddr
.siso_addr
, isop
, sizeof (struct iso_addr
));
isoaddr
.siso_len
= sizeof (isoaddr
);
isoaddr
.siso_family
= AF_ISO
;
isoport
= htons(NFS_PORT
);
memmove(TSEL(&isoaddr
), &isoport
, isoaddr
.siso_tlen
);
* Handle an internet host address and reverse resolve it if
if ((saddr
.sin_addr
.s_addr
= inet_addr(hostp
)) == -1) {
warnx("bad net address %s", hostp
);
} else if ((hp
= gethostbyname(hostp
)) != NULL
)
memmove(&saddr
.sin_addr
, hp
->h_addr
, hp
->h_length
);
warnx("can't get net id for host");
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");
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
, '.'))
if (nfsargsp
->flags
& NFSMNT_NFSV3
) {
nfhret
.stat
= EACCES
; /* Mark not yet successful */
saddr
.sin_family
= AF_INET
;
saddr
.sin_port
= htons(PMAPPORT
);
if ((tport
= pmap_getport(&saddr
, RPCPROG_NFS
,
nfsvers
, nfsproto
)) == 0) {
if ((opflags
& ISBGRND
) == 0)
clnt_pcreateerror("NFS Portmap");
if (mnttcp_ok
&& nfsargsp
->sotype
== SOCK_STREAM
)
clp
= clnttcp_create(&saddr
, RPCPROG_MNT
, mntvers
,
clp
= clntudp_create(&saddr
, RPCPROG_MNT
, mntvers
,
if ((opflags
& ISBGRND
) == 0)
clnt_pcreateerror("Cannot MNT PRC");
clp
->cl_auth
= authunix_create_default();
if (nfsargsp
->flags
& NFSMNT_KERB
)
nfhret
.auth
= RPCAUTH_KERB4
;
nfhret
.auth
= RPCAUTH_UNIX
;
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
,
auth_destroy(clp
->cl_auth
);
(void) close(STDIN_FILENO
);
(void) close(STDOUT_FILENO
);
(void) close(STDERR_FILENO
);
warnx("can't access %s: %s", spec
, strerror(nfhret
.stat
));
saddr
.sin_port
= htons(tport
);
nfsargsp
->addr
= (struct sockaddr
*) &isoaddr
;
nfsargsp
->addrlen
= sizeof (isoaddr
);
nfsargsp
->addr
= (struct sockaddr
*) &saddr
;
nfsargsp
->addrlen
= sizeof (saddr
);
nfsargsp
->fh
= nfhret
.nfh
;
nfsargsp
->fhsize
= nfhret
.fhsize
;
nfsargsp
->hostname
= nam
;
* xdr routines for mount rpc's
return (xdr_string(xdrsp
, &dirp
, RPCMNT_PATHLEN
));
register struct nfhret
*np
;
long auth
, authcnt
, authfnd
= 0;
if (!xdr_u_long(xdrsp
, &np
->stat
))
return (xdr_opaque(xdrsp
, (caddr_t
)np
->nfh
, NFSX_V2FH
));
if (!xdr_long(xdrsp
, &np
->fhsize
))
if (np
->fhsize
<= 0 || np
->fhsize
> NFSX_V3FHMAX
)
if (!xdr_opaque(xdrsp
, (caddr_t
)np
->nfh
, np
->fhsize
))
if (!xdr_long(xdrsp
, &authcnt
))
for (i
= 0; i
< authcnt
; i
++) {
if (!xdr_long(xdrsp
, &auth
))
* 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
))
(void)fprintf(stderr
, "usage: mount_nfs %s\n%s\n%s\n%s\n",
"[-bcdiKklMPqsT] [-a maxreadahead] [-D deadthresh]",
"\t[-g maxgroups] [-L leaseterm] [-m realm] [-o options] [-R retrycnt]",
"\t[-r readsize] [-t timeout] [-w writesize] [-x retrans]",