update for version 3 from Rick Macklem
[unix-history] / usr / src / sbin / mount_nfs / mount_nfs.c
index bdbed8a..a0cfa43 100644 (file)
@@ -1,6 +1,6 @@
 /*
 /*
- * Copyright (c) 1992 The Regents of the University of California.
- * All rights reserved.
+ * 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.
  *
  * This code is derived from software contributed to Berkeley by
  * Rick Macklem at The University of Guelph.
@@ -9,13 +9,13 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1992 The Regents of the University of California.\n\
- All rights reserved.\n";
+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
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)mount_nfs.c        5.9 (Berkeley) %G%";
+static char sccsid[] = "@(#)mount_nfs.c        8.7 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/param.h>
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -33,12 +33,13 @@ static char sccsid[] = "@(#)mount_nfs.c     5.9 (Berkeley) %G%";
 #include <netiso/iso.h>
 #endif
 
 #include <netiso/iso.h>
 #endif
 
-#ifdef KERBEROS
+#ifdef NFSKERB
+#include <kerberosIV/des.h>
 #include <kerberosIV/krb.h>
 #endif
 
 #include <nfs/rpcv2.h>
 #include <kerberosIV/krb.h>
 #endif
 
 #include <nfs/rpcv2.h>
-#include <nfs/nfsv2.h>
+#include <nfs/nfsproto.h>
 #define KERNEL
 #include <nfs/nfs.h>
 #undef KERNEL
 #define KERNEL
 #include <nfs/nfs.h>
 #undef KERNEL
@@ -47,6 +48,7 @@ static char sccsid[] = "@(#)mount_nfs.c       5.9 (Berkeley) %G%";
 #include <arpa/inet.h>
 
 #include <ctype.h>
 #include <arpa/inet.h>
 
 #include <ctype.h>
+#include <err.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <netdb.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <netdb.h>
@@ -56,16 +58,58 @@ static char sccsid[] = "@(#)mount_nfs.c     5.9 (Berkeley) %G%";
 #include <strings.h>
 #include <unistd.h>
 
 #include <strings.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
+
+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 },
+       { NULL }
+};
+
 struct nfs_args nfsdefargs = {
        (struct sockaddr *)0,
        sizeof (struct sockaddr_in),
        SOCK_DGRAM,
        0,
 struct nfs_args nfsdefargs = {
        (struct sockaddr *)0,
        sizeof (struct sockaddr_in),
        SOCK_DGRAM,
        0,
-       (nfsv2fh_t *)0,
+       (u_char *)0,
+       0,
        0,
        NFS_WSIZE,
        NFS_RSIZE,
        0,
        NFS_WSIZE,
        NFS_RSIZE,
-       NFS_TIMEO,
+       NFS_READDIRSIZE,
+       10,
        NFS_RETRANS,
        NFS_MAXGRPS,
        NFS_DEFRAHEAD,
        NFS_RETRANS,
        NFS_MAXGRPS,
        NFS_DEFRAHEAD,
@@ -75,29 +119,41 @@ struct nfs_args nfsdefargs = {
 };
 
 struct nfhret {
 };
 
 struct nfhret {
-       u_long  stat;
-       nfsv2fh_t nfh;
+       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;
 };
 #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;
 
 
-#ifdef KERBEROS
+#ifdef NFSKERB
 char inst[INST_SZ];
 char realm[REALM_SZ];
 char inst[INST_SZ];
 char realm[REALM_SZ];
-KTEXT_ST kt;
+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
 
 #endif
 
-void   err __P((const char *, ...));
 int    getnfsargs __P((char *, struct nfs_args *));
 #ifdef ISO
 struct iso_addr *iso_addr __P((const char *));
 #endif
 void   set_rpc_maxgrouplist __P((int));
 __dead void usage __P((void));
 int    getnfsargs __P((char *, struct nfs_args *));
 #ifdef ISO
 struct iso_addr *iso_addr __P((const char *));
 #endif
 void   set_rpc_maxgrouplist __P((int));
 __dead void usage __P((void));
-void   warn __P((const char *, ...));
 int    xdr_dir __P((XDR *, char *));
 int    xdr_fh __P((XDR *, struct nfhret *));
 
 int    xdr_dir __P((XDR *, char *));
 int    xdr_fh __P((XDR *, struct nfhret *));
 
@@ -110,31 +166,36 @@ main(argc, argv)
        register struct nfs_args *nfsargsp;
        struct nfs_args nfsargs;
        struct nfsd_cargs ncd;
        register struct nfs_args *nfsargsp;
        struct nfs_args nfsargs;
        struct nfsd_cargs ncd;
-       int flags, i, nfssvc_flag, num;
+       int mntflags, altflags, i, nfssvc_flag, num;
        char *name, *p, *spec;
        char *name, *p, *spec;
-#ifdef KERBEROS
+       int error = 0;
+#ifdef NFSKERB
        uid_t last_ruid;
        uid_t last_ruid;
-#endif
 
 
-#ifdef KERBEROS
        last_ruid = -1;
        (void)strcpy(realm, KRB_REALM);
        last_ruid = -1;
        (void)strcpy(realm, KRB_REALM);
-#endif
+       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;
 
        retrycnt = DEF_RETRY;
 
-       if (argc <= 1)
-               usage();
-
-       flags = 0;
+       mntflags = 0;
+       altflags = 0;
        nfsargs = nfsdefargs;
        nfsargsp = &nfsargs;
        while ((c = getopt(argc, argv,
        nfsargs = nfsdefargs;
        nfsargsp = &nfsargs;
        while ((c = getopt(argc, argv,
-           "a:bcdD:F:g:iKklL:Mm:PpqR:r:sTt:w:x:")) != EOF)
+           "3a:bcdD:g:I:iKL:lm:o:PpqR:r:sTt:w:x:U")) != EOF)
                switch (c) {
                switch (c) {
+               case '3':
+                       nfsargsp->flags |= NFSMNT_NFSV3;
+                       break;
                case 'a':
                        num = strtol(optarg, &p, 10);
                        if (*p || num < 0)
                case 'a':
                        num = strtol(optarg, &p, 10);
                        if (*p || num < 0)
-                               err("illegal -a value -- %s", optarg);
+                               errx(1, "illegal -a value -- %s", optarg);
                        nfsargsp->readahead = num;
                        nfsargsp->flags |= NFSMNT_READAHEAD;
                        break;
                        nfsargsp->readahead = num;
                        nfsargsp->flags |= NFSMNT_READAHEAD;
                        break;
@@ -147,58 +208,88 @@ main(argc, argv)
                case 'D':
                        num = strtol(optarg, &p, 10);
                        if (*p || num <= 0)
                case 'D':
                        num = strtol(optarg, &p, 10);
                        if (*p || num <= 0)
-                               err("illegal -D value -- %s", optarg);
+                               errx(1, "illegal -D value -- %s", optarg);
                        nfsargsp->deadthresh = num;
                        nfsargsp->flags |= NFSMNT_DEADTHRESH;
                        break;
                case 'd':
                        nfsargsp->flags |= NFSMNT_DUMBTIMR;
                        break;
                        nfsargsp->deadthresh = num;
                        nfsargsp->flags |= NFSMNT_DEADTHRESH;
                        break;
                case 'd':
                        nfsargsp->flags |= NFSMNT_DUMBTIMR;
                        break;
-               case 'F':
-                       num = strtol(optarg, &p, 10);
-                       if (*p)
-                               err("illegal -F value -- %s", optarg);
-                       if (num != 0)
-                               flags = num;
-                       break;
                case 'g':
                        num = strtol(optarg, &p, 10);
                        if (*p || num <= 0)
                case 'g':
                        num = strtol(optarg, &p, 10);
                        if (*p || num <= 0)
-                               err("illegal -g value -- %s", optarg);
+                               errx(1, "illegal -g value -- %s", optarg);
                        set_rpc_maxgrouplist(num);
                        nfsargsp->maxgrouplist = num;
                        nfsargsp->flags |= NFSMNT_MAXGRPS;
                        break;
                        set_rpc_maxgrouplist(num);
                        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;
                case 'i':
                        nfsargsp->flags |= NFSMNT_INT;
                        break;
-#ifdef KERBEROS
+#ifdef NFSKERB
                case 'K':
                        nfsargsp->flags |= NFSMNT_KERB;
                        break;
 #endif
                case 'K':
                        nfsargsp->flags |= NFSMNT_KERB;
                        break;
 #endif
-               case 'k':
-                       nfsargsp->flags |= NFSMNT_NQLOOKLEASE;
-                       break;
                case 'L':
                        num = strtol(optarg, &p, 10);
                        if (*p || num < 2)
                case 'L':
                        num = strtol(optarg, &p, 10);
                        if (*p || num < 2)
-                               err("illegal -L value -- %s", optarg);
+                               errx(1, "illegal -L value -- %s", optarg);
                        nfsargsp->leaseterm = num;
                        nfsargsp->flags |= NFSMNT_LEASETERM;
                        break;
                case 'l':
                        nfsargsp->leaseterm = num;
                        nfsargsp->flags |= NFSMNT_LEASETERM;
                        break;
                case 'l':
-                       nfsargsp->flags |= NFSMNT_RDIRALOOK;
-                       break;
-               case 'M':
-                       nfsargsp->flags |= NFSMNT_MYWRITE;
+                       nfsargsp->flags |= NFSMNT_RDIRPLUS;
                        break;
                        break;
-#ifdef KERBEROS
+#ifdef NFSKERB
                case 'm':
                        (void)strncpy(realm, optarg, REALM_SZ - 1);
                        realm[REALM_SZ - 1] = '\0';
                        break;
 #endif
                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;
+                       }
+                       altflags = 0;
+                       break;
                case 'P':
                        nfsargsp->flags |= NFSMNT_RESVPORT;
                        break;
                case 'P':
                        nfsargsp->flags |= NFSMNT_RESVPORT;
                        break;
@@ -208,18 +299,18 @@ main(argc, argv)
                        break;
 #endif
                case 'q':
                        break;
 #endif
                case 'q':
-                       nfsargsp->flags |= NFSMNT_NQNFS;
+                       nfsargsp->flags |= (NFSMNT_NQNFS | NFSMNT_NFSV3);
                        break;
                case 'R':
                        num = strtol(optarg, &p, 10);
                        if (*p || num <= 0)
                        break;
                case 'R':
                        num = strtol(optarg, &p, 10);
                        if (*p || num <= 0)
-                               err("illegal -R value -- %s", optarg);
+                               errx(1, "illegal -R value -- %s", optarg);
                        retrycnt = num;
                        break;
                case 'r':
                        num = strtol(optarg, &p, 10);
                        if (*p || num <= 0)
                        retrycnt = num;
                        break;
                case 'r':
                        num = strtol(optarg, &p, 10);
                        if (*p || num <= 0)
-                               err("illegal -r value -- %s", optarg);
+                               errx(1, "illegal -r value -- %s", optarg);
                        nfsargsp->rsize = num;
                        nfsargsp->flags |= NFSMNT_RSIZE;
                        break;
                        nfsargsp->rsize = num;
                        nfsargsp->flags |= NFSMNT_RSIZE;
                        break;
@@ -228,47 +319,55 @@ main(argc, argv)
                        break;
                case 'T':
                        nfsargsp->sotype = SOCK_STREAM;
                        break;
                case 'T':
                        nfsargsp->sotype = SOCK_STREAM;
+                       nfsproto = IPPROTO_TCP;
                        break;
                case 't':
                        num = strtol(optarg, &p, 10);
                        if (*p || num <= 0)
                        break;
                case 't':
                        num = strtol(optarg, &p, 10);
                        if (*p || num <= 0)
-                               err("illegal -t value -- %s", optarg);
+                               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)
                        nfsargsp->timeo = num;
                        nfsargsp->flags |= NFSMNT_TIMEO;
                        break;
                case 'w':
                        num = strtol(optarg, &p, 10);
                        if (*p || num <= 0)
-                               err("illegal -w value -- %s", optarg);
+                               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)
                        nfsargsp->wsize = num;
                        nfsargsp->flags |= NFSMNT_WSIZE;
                        break;
                case 'x':
                        num = strtol(optarg, &p, 10);
                        if (*p || num <= 0)
-                               err("illegal -x value -- %s", optarg);
+                               errx(1, "illegal -x value -- %s", optarg);
                        nfsargsp->retrans = num;
                        nfsargsp->flags |= NFSMNT_RETRANS;
                        break;
                        nfsargsp->retrans = num;
                        nfsargsp->flags |= NFSMNT_RETRANS;
                        break;
+               case 'U':
+                       mnttcp_ok = 0;
+                       break;
                default:
                        usage();
                default:
                        usage();
-               };
+                       break;
+               }
+       argc -= optind;
+       argv += optind;
 
 
-       if ((argc - optind) != 2)
+       if (argc != 2)
                usage();
 
                usage();
 
-       spec = argv[optind];
-       name = argv[optind + 1];
+       spec = *argv++;
+       name = *argv;
 
        if (!getnfsargs(spec, nfsargsp))
                exit(1);
 
        if (!getnfsargs(spec, nfsargsp))
                exit(1);
-       if (mount(MOUNT_NFS, name, flags, nfsargsp))
-               err("mount: %s: %s", name, strerror(errno));
+
+       if (mount("nfs", name, mntflags, nfsargsp))
+               err(1, "%s", name);
        if (nfsargsp->flags & (NFSMNT_NQNFS | NFSMNT_KERB)) {
                if ((opflags & ISBGRND) == 0) {
                        if (i = fork()) {
                                if (i == -1)
        if (nfsargsp->flags & (NFSMNT_NQNFS | NFSMNT_KERB)) {
                if ((opflags & ISBGRND) == 0) {
                        if (i = fork()) {
                                if (i == -1)
-                                       err("nqnfs 1: %s", strerror(errno));
+                                       err(1, "nqnfs 1");
                                exit(0);
                        }
                        (void) setsid();
                                exit(0);
                        }
                        (void) setsid();
@@ -285,36 +384,81 @@ main(argc, argv)
                                syslog(LOG_ERR, "nfssvc err %m");
                                continue;
                        }
                                syslog(LOG_ERR, "nfssvc err %m");
                                continue;
                        }
-syslog(LOG_ERR, "in eacces");
                        nfssvc_flag =
                            NFSSVC_MNTD | NFSSVC_GOTAUTH | NFSSVC_AUTHINFAIL;
                        nfssvc_flag =
                            NFSSVC_MNTD | NFSSVC_GOTAUTH | NFSSVC_AUTHINFAIL;
-#ifdef KERBEROS
-syslog(LOG_ERR,
-    "Calling krb uid=%d inst=%s realm=%s", ncd.ncd_authuid, inst,realm);
+#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.
                        /*
                         * 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) {
                                krb_set_tkt_string("");
                                last_ruid = ncd.ncd_authuid;
                        }
                        setreuid(ncd.ncd_authuid, 0);
                         */
                        if (ncd.ncd_authuid != last_ruid) {
                                krb_set_tkt_string("");
                                last_ruid = ncd.ncd_authuid;
                        }
                        setreuid(ncd.ncd_authuid, 0);
-                       if (krb_mk_req(&kt, "rcmd", inst, realm, 0) ==
-                           KSUCCESS &&
-                           kt.length <= (RPCAUTH_MAXSIZ - 2 * NFSX_UNSIGNED)) {
-syslog(LOG_ERR, "Got it\n");
-                               ncd.ncd_authtype = RPCAUTH_NQNFS;
-                               ncd.ncd_authlen = kt.length;
-                               ncd.ncd_authstr = (char *)kt.dat;
-                               nfssvc_flag = NFSSVC_MNTD | NFSSVC_GOTAUTH;
+                       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);
+                           bcopy((caddr_t)kcr.session, (caddr_t)ncd.ncd_key,
+                               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);
                        }
                        setreuid(0, 0);
-syslog(LOG_ERR, "ktlen=%d\n", kt.length);
-#endif /* KERBEROS */
+#endif /* NFSKERB */
                }
        }
        exit(0);
                }
        }
        exit(0);
@@ -335,9 +479,9 @@ getnfsargs(spec, nfsargsp)
 #endif
        struct timeval pertry, try;
        enum clnt_stat clnt_stat;
 #endif
        struct timeval pertry, try;
        enum clnt_stat clnt_stat;
-       int so = RPC_ANYSOCK, i;
+       int so = RPC_ANYSOCK, i, nfsvers, mntvers;
        char *hostp, *delimp;
        char *hostp, *delimp;
-#ifdef KERBEROS
+#ifdef NFSKERB
        char *cp;
 #endif
        u_short tport;
        char *cp;
 #endif
        u_short tport;
@@ -346,13 +490,13 @@ getnfsargs(spec, nfsargsp)
 
        strncpy(nam, spec, MNAMELEN);
        nam[MNAMELEN] = '\0';
 
        strncpy(nam, spec, MNAMELEN);
        nam[MNAMELEN] = '\0';
-       if ((delimp = index(spec, '@')) != NULL) {
+       if ((delimp = strchr(spec, '@')) != NULL) {
                hostp = delimp + 1;
                hostp = delimp + 1;
-       } else if ((delimp = index(spec, ':')) != NULL) {
+       } else if ((delimp = strchr(spec, ':')) != NULL) {
                hostp = spec;
                spec = delimp + 1;
        } else {
                hostp = spec;
                spec = delimp + 1;
        } else {
-               warn("no <host>:<dirpath> or <dirpath>@<host> spec");
+               warnx("no <host>:<dirpath> or <dirpath>@<host> spec");
                return (0);
        }
        *delimp = '\0';
                return (0);
        }
        *delimp = '\0';
@@ -366,13 +510,13 @@ getnfsargs(spec, nfsargsp)
 
                hostp += 4;
                isoflag++;
 
                hostp += 4;
                isoflag++;
-               if ((delimp = index(hostp, '+')) == NULL) {
-                       warn("no iso+inet address");
+               if ((delimp = strchr(hostp, '+')) == NULL) {
+                       warnx("no iso+inet address");
                        return (0);
                }
                *delimp = '\0';
                if ((isop = iso_addr(hostp)) == NULL) {
                        return (0);
                }
                *delimp = '\0';
                if ((isop = iso_addr(hostp)) == NULL) {
-                       warn("bad ISO address");
+                       warnx("bad ISO address");
                        return (0);
                }
                bzero((caddr_t)&isoaddr, sizeof (isoaddr));
                        return (0);
                }
                bzero((caddr_t)&isoaddr, sizeof (isoaddr));
@@ -393,56 +537,73 @@ getnfsargs(spec, nfsargsp)
         */
        if (isdigit(*hostp)) {
                if ((saddr.sin_addr.s_addr = inet_addr(hostp)) == -1) {
         */
        if (isdigit(*hostp)) {
                if ((saddr.sin_addr.s_addr = inet_addr(hostp)) == -1) {
-                       warn("bad net address %s\n", hostp);
+                       warnx("bad net address %s", hostp);
                        return (0);
                }
                        return (0);
                }
-               if ((nfsargsp->flags & NFSMNT_KERB) &&
-                   (hp = gethostbyaddr((char *)&saddr.sin_addr.s_addr,
+       } else if ((hp = gethostbyname(hostp)) != NULL) {
+               bcopy(hp->h_addr, (caddr_t)&saddr.sin_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) {
                    sizeof (u_long), AF_INET)) == (struct hostent *)0) {
-                       warn("can't reverse resolve net address");
+                       warnx("can't reverse resolve net address");
                        return (0);
                }
                        return (0);
                }
-       } else if ((hp = gethostbyname(hostp)) == NULL) {
-               warn("can't get net id for host");
-               return (0);
-       }
-#ifdef KERBEROS
-       if (nfsargsp->flags & NFSMNT_KERB) {
+               bcopy(hp->h_addr, (caddr_t)&saddr.sin_addr, hp->h_length);
                strncpy(inst, hp->h_name, INST_SZ);
                inst[INST_SZ - 1] = '\0';
                strncpy(inst, hp->h_name, INST_SZ);
                inst[INST_SZ - 1] = '\0';
-               if (cp = index(inst, '.'))
+               if (cp = strchr(inst, '.'))
                        *cp = '\0';
        }
                        *cp = '\0';
        }
-#endif /* KERBEROS */
+#endif /* NFSKERB */
 
 
-       bcopy(hp->h_addr, (caddr_t)&saddr.sin_addr, hp->h_length);
+       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 = pmap_getport(&saddr, RPCPROG_NFS,
        nfhret.stat = EACCES;   /* Mark not yet successful */
        while (retrycnt > 0) {
                saddr.sin_family = AF_INET;
                saddr.sin_port = htons(PMAPPORT);
                if ((tport = pmap_getport(&saddr, RPCPROG_NFS,
-                   NFS_VER2, IPPROTO_UDP)) == 0) {
+                   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 ((opflags & ISBGRND) == 0)
                                clnt_pcreateerror("NFS Portmap");
                } else {
                        saddr.sin_port = 0;
                        pertry.tv_sec = 10;
                        pertry.tv_usec = 0;
-                       if ((clp = clntudp_create(&saddr, RPCPROG_MNT,
-                           RPCMNT_VER1, pertry, &so)) == NULL) {
+                       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 PRC");
                        } else {
                                clp->cl_auth = authunix_create_default();
                                try.tv_sec = 10;
                                try.tv_usec = 0;
                                if ((opflags & ISBGRND) == 0)
                                        clnt_pcreateerror("Cannot MNT PRC");
                        } 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) {
                                clnt_stat = clnt_call(clp, RPCMNT_MOUNT,
                                    xdr_dir, spec, xdr_fh, &nfhret, try);
                                if (clnt_stat != RPC_SUCCESS) {
-                                       if ((opflags & ISBGRND) == 0) {
-                                               warn("%s", clnt_sperror(clp,
+                                       if ((opflags & ISBGRND) == 0)
+                                               warnx("%s", clnt_sperror(clp,
                                                    "bad MNT RPC"));
                                                    "bad MNT RPC"));
-                                       }
                                } else {
                                        auth_destroy(clp->cl_auth);
                                        clnt_destroy(clp);
                                } else {
                                        auth_destroy(clp->cl_auth);
                                        clnt_destroy(clp);
@@ -455,8 +616,7 @@ getnfsargs(spec, nfsargsp)
                                opflags &= ~BGRND;
                                if (i = fork()) {
                                        if (i == -1)
                                opflags &= ~BGRND;
                                if (i = fork()) {
                                        if (i == -1)
-                                               err("nqnfs 2: %s",
-                                                   strerror(errno));
+                                               err(1, "nqnfs 2");
                                        exit(0);
                                }
                                (void) setsid();
                                        exit(0);
                                }
                                (void) setsid();
@@ -472,7 +632,8 @@ getnfsargs(spec, nfsargsp)
        if (nfhret.stat) {
                if (opflags & ISBGRND)
                        exit(1);
        if (nfhret.stat) {
                if (opflags & ISBGRND)
                        exit(1);
-               warn("can't access %s: %s\n", spec, strerror(nfhret.stat));
+               errno = nfhret.stat;
+               warn("can't access %s", spec);
                return (0);
        }
        saddr.sin_port = htons(tport);
                return (0);
        }
        saddr.sin_port = htons(tport);
@@ -486,7 +647,8 @@ getnfsargs(spec, nfsargsp)
                nfsargsp->addr = (struct sockaddr *) &saddr;
                nfsargsp->addrlen = sizeof (saddr);
        }
                nfsargsp->addr = (struct sockaddr *) &saddr;
                nfsargsp->addrlen = sizeof (saddr);
        }
-       nfsargsp->fh = &nfhret.nfh;
+       nfsargsp->fh = nfhret.nfh;
+       nfsargsp->fhsize = nfhret.fhsize;
        nfsargsp->hostname = nam;
        return (1);
 }
        nfsargsp->hostname = nam;
        return (1);
 }
@@ -505,13 +667,39 @@ xdr_dir(xdrsp, dirp)
 int
 xdr_fh(xdrsp, np)
        XDR *xdrsp;
 int
 xdr_fh(xdrsp, np)
        XDR *xdrsp;
-       struct nfhret *np;
+       register struct nfhret *np;
 {
 {
-       if (!xdr_u_long(xdrsp, &(np->stat)))
+       register int i;
+       long auth, authcnt, authfnd = 0;
+
+       if (!xdr_u_long(xdrsp, &np->stat))
                return (0);
        if (np->stat)
                return (1);
                return (0);
        if (np->stat)
                return (1);
-       return (xdr_opaque(xdrsp, (caddr_t)&(np->nfh), NFSX_FH));
+       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++;
+               }
+               if (!authfnd)
+                       np->stat = EAUTH;
+               return (1);
+       };
+       return (0);
 }
 
 __dead void
 }
 
 __dead void
@@ -519,58 +707,8 @@ usage()
 {
        (void)fprintf(stderr, "usage: mount_nfs %s\n%s\n%s\n%s\n",
 "[-bcdiKklMPqsT] [-a maxreadahead] [-D deadthresh]",
 {
        (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] [-R retrycnt]",
+"\t[-g maxgroups] [-L leaseterm] [-m realm] [-o options] [-R retrycnt]",
 "\t[-r readsize] [-t timeout] [-w writesize] [-x retrans]",
 "\trhost:path node");
        exit(1);
 }
 "\t[-r readsize] [-t timeout] [-w writesize] [-x retrans]",
 "\trhost:path node");
        exit(1);
 }
-
-#if __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-
-void
-#if __STDC__
-err(const char *fmt, ...)
-#else
-err(fmt, va_alist)
-       char *fmt;
-        va_dcl
-#endif
-{
-       va_list ap;
-#if __STDC__
-       va_start(ap, fmt);
-#else
-       va_start(ap);
-#endif
-       (void)fprintf(stderr, "mount_nfs: ");
-       (void)vfprintf(stderr, fmt, ap);
-       va_end(ap);
-       (void)fprintf(stderr, "\n");
-       exit(1);
-       /* NOTREACHED */
-}
-
-void
-#if __STDC__
-warn(const char *fmt, ...)
-#else
-warn(fmt, va_alist)
-       char *fmt;
-        va_dcl
-#endif
-{
-       va_list ap;
-#if __STDC__
-       va_start(ap, fmt);
-#else
-       va_start(ap);
-#endif
-       (void)fprintf(stderr, "mount_nfs: ");
-       (void)vfprintf(stderr, fmt, ap);
-       va_end(ap);
-       (void)fprintf(stderr, "\n");
-}