From 666343f7f055c064375d48bb9a608730d7145beb Mon Sep 17 00:00:00 2001 From: dfr Date: Tue, 27 Jun 1995 11:07:30 +0000 Subject: Changes to support version 3 of the NFS protocol. The version 2 support has been tested (client+server) against FreeBSD-2.0, IRIX 5.3 and FreeBSD-current (using a loopback mount). The version 2 support is stable AFAIK. The version 3 support has been tested with a loopback mount and minimally against an IRIX 5.3 server. It needs more testing and may have problems. I have patched amd to support the new variable length filehandles although it will still only use version 2 of the protocol. Before booting a kernel with these changes, nfs clients will need to at least build and install /usr/sbin/mount_nfs. Servers will need to build and install /usr/sbin/mountd. NFS diskless support is untested. Obtained from: Rick Macklem --- sbin/mount_nfs/mount_nfs.8 | 71 ++++++----- sbin/mount_nfs/mount_nfs.c | 285 ++++++++++++++++++++++++++++++++++----------- sbin/mountd/exports.5 | 10 +- sbin/mountd/mountd.8 | 17 ++- sbin/mountd/mountd.c | 247 ++++++++++++++++++++++++++------------- sbin/nfsd/nfsd.8 | 3 +- sbin/nfsd/nfsd.c | 110 +++++++++++++---- sbin/nfsiod/nfsiod.c | 4 +- 8 files changed, 538 insertions(+), 209 deletions(-) (limited to 'sbin') diff --git a/sbin/mount_nfs/mount_nfs.8 b/sbin/mount_nfs/mount_nfs.8 index 0209b49..8ee10f3 100644 --- a/sbin/mount_nfs/mount_nfs.8 +++ b/sbin/mount_nfs/mount_nfs.8 @@ -39,8 +39,9 @@ .Nd mount nfs file systems .Sh SYNOPSIS .Nm mount_nfs -.Op Fl KMPTbcdiklqs +.Op Fl 3KPTUbcdilqs .Op Fl D Ar deadthresh +.Op Fl I Ar readdirsize .Op Fl L Ar leaseterm .Op Fl R Ar retrycnt .Op Fl a Ar maxreadahead @@ -63,10 +64,14 @@ on to the file system tree at the point .Ar node. This command is normally executed by .Xr mount 8 . -It implements the mount protocol as described in RFC 1094, Appendix A. +It implements the mount protocol as described in RFC 1094, Appendix A and +.%T "NFS: Network File System Version 3 Protocol Specification" , +Appendix I. .Pp The options are: .Bl -tag -width indent +.It Fl 3 +Use the NFS Version 3 protocol (Version 2 is the default). .It Fl D Used with NQNFS to set the .Dq "dead server threshold" @@ -80,23 +85,27 @@ Values may be set in the range of 1 - 9, with 9 referring to an (i.e. never assume cached data still valid). This option is not generally recommended and is really an experimental feature. +.It Fl I +Set the readdir read size to the specified value. The value should normally +be a multiple of DIRBLKSIZ that is <= the read size for the mount. .It Fl K Pass Kerberos authenticators to the server for client-to-server user-credential mapping. -This may only be used over TCP mounts between 4.4BSD clients and servers. +This requires that the kernel be built with the NFSKERB option. +(Refer to the INTERNET-DRAFT titled +.%T "Authentication Mechanisms for ONC RPC" , +for more information.) .It Fl L Used with NQNFS to set the lease term to the specified number of seconds. Only use this argument for mounts with a large round trip delay. Values are normally in the 10-30 second range. -.It Fl M -Assume that other clients are not writing a file concurrently with this client. -This implements a slightly less strict consistency criteria than 4.3BSD-Reno -did, that is more in line with most commercial client implementations. -This is recommended for servers that do not support leasing. .It Fl P Use a reserved socket port number. This is useful for mounting servers that require clients to use a -reserved port number. +reserved port number on the mistaken belief that this makes NFS +more secure. (For the rare case where the client has a trusted root account +but untrusworthy users and the network cables are in secure areas this does +help, but for normal desktop clients this does not apply.) .It Fl R Set the retry count for doing the mount to the specified value. .It Fl T @@ -104,11 +113,15 @@ Use TCP transport instead of UDP. This is recommended for servers that are not on the same LAN cable as the client. (NB: This is NOT supported by most non-BSD servers.) +.It Fl U +Force the mount protocol to use UDP transport, even for TCP NFS mounts. +(Necessary for some old BSD servers.) .It Fl a Set the read-ahead count to the specified value. This may be in the range of 0 - 4, and determines how many blocks will be read ahead when a large file is being read sequentially. -This is recommended for mounts with a large bandwidth * delay product. +Trying a value greater than 1 for this is suggested for +mounts with a large bandwidth * delay product. .It Fl b If an initial attempt to contact the server fails, fork off a child to keep trying the mount in the background. @@ -119,10 +132,12 @@ where the filesystem mount is not critical to multiuser operation. For UDP mount points, do not do a .Xr connect 2 . This must be used for servers that do not reply to requests from the -standard port number. +standard NFS port number 2049. .It Fl d -Do not estimate retransmit timeout dynamically. -This may be useful for UDP mounts that exhibit high retry rates. +Turn off the dynamic retransmit timeout estimator. +This may be useful for UDP mounts that exhibit high retry rates, +since it is possible that the dynamically estimated timeout interval is too +short. .It Fl g Set the maximum size of the group list for the credentials to the specified value. @@ -134,20 +149,15 @@ point. Make the mount interruptible, which implies that file system calls that are delayed due to an unresponsive server will fail with EINTR when a termination signal is posted for the process. -.It Fl k -Used with NQNFS to specify -.Dq get a lease -for the file name being looked up. -This is recommended unless the server is complaining about excessive -lease load. .It Fl l -Used with NQNFS to specify that the \fBReaddir_and_Lookup\fR RPC should +Used with NQNFS and NFSV3 to specify that the \fBReaddirPlus\fR RPC should be used. This option reduces RPC traffic for cases such as .Dq "ls -l" , -but increases the lease load on the server. -This is recommended unless the server is complaining about excessive -lease load. +but tends to flood the attribute and name caches with prefetched entries. +Try this option and see whether performance improves or degrades. Probably +most useful for client to server network interconnects with a large bandwidth +times delay product. .It Fl m Set the Kerberos realm to the string argument. Used with the @@ -167,12 +177,16 @@ Use specified port number for NFS requests. The default is to query the portmapper for the NFS port. .El .It Fl q -Use the leasing extensions to the protocol to maintain cache consistency. -This protocol, referred to as Not Quite Nfs (NQNFS), -is only supported by 4.4BSD servers. +Use the leasing extensions to the NFS Version 3 protocol to maintain cache consistency. +This protocol Version 2, referred to as Not Quite Nfs (NQNFS), +is only supported by this updated release of NFS code. +(It is not backwards compatible with the release of NQNFS that went out on +4.4BSD-Lite. To interoperate with a 4.4BSD-Lite NFS system you will have to +avoid this option until you have had an oppurtunity to upgrade the NFS code +on all your 4.4BSD-Lite based systems.) .It Fl r Set the read data size to the specified value. -It should be a power of 2 greater than or equal to 1024. +It should normally be a power of 2 greater than or equal to 1024. This should be used for UDP mounts when the .Dq "fragments dropped due to timeout" value is getting large while actively using a mount point. @@ -197,6 +211,9 @@ Try increasing the interval if .Xr nfsstat 1 shows high retransmit rates while the file system is active or reducing the value if there is a low retransmit rate but long response delay observed. +(Normally, the -d option should be specified when using this option to manually +tune the timeout +interval.) .It Fl w Set the write data size to the specified value. Ditto the comments w.r.t. the diff --git a/sbin/mount_nfs/mount_nfs.c b/sbin/mount_nfs/mount_nfs.c index 9aa15ce..ddba274 100644 --- a/sbin/mount_nfs/mount_nfs.c +++ b/sbin/mount_nfs/mount_nfs.c @@ -59,16 +59,16 @@ static char sccsid[] = "@(#)mount_nfs.c 8.3 (Berkeley) 3/27/94"; #include #endif -#ifdef KERBEROS +#ifdef NFSKERB #include #include #endif #include -#include -#define KERNEL +#include +#define _KERNEL #include -#undef KERNEL +#undef _KERNEL #include #include @@ -86,14 +86,15 @@ static char sccsid[] = "@(#)mount_nfs.c 8.3 (Berkeley) 3/27/94"; #include "mntopts.h" +#ifdef __FreeBSD__ #define ALTF_BG 0x1 #define ALTF_NOCONN 0x2 #define ALTF_DUMBTIMR 0x4 #define ALTF_INTR 0x8 #define ALTF_KERB 0x10 -#define ALTF_NQLOOKLSE 0x20 -#define ALTF_RDIRALOOK 0x40 -#define ALTF_MYWRITE 0x80 +#define ALTF_NFSV3 0x20 +#define ALTF_RDIRPLUS 0x40 +#define ALTF_MNTUDP 0x80 #define ALTF_RESVPORT 0x100 #define ALTF_SEQPACKET 0x200 #define ALTF_NQNFS 0x400 @@ -109,12 +110,12 @@ struct mntopt mopts[] = { { "conn", 1, ALTF_NOCONN, 1 }, { "dumbtimer", 0, ALTF_DUMBTIMR, 1 }, { "intr", 0, ALTF_INTR, 1 }, -#ifdef KERBEROS +#ifdef NFSKERB { "kerb", 0, ALTF_KERB, 1 }, #endif - { "nqlooklease", 0, ALTF_NQLOOKLSE, 1 }, - { "rdiralook", 0, ALTF_RDIRALOOK, 1 }, - { "mywrite", 0, ALTF_MYWRITE, 1 }, + { "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 }, @@ -125,17 +126,27 @@ struct mntopt mopts[] = { { "port=", 0, ALTF_PORT, 1 }, { NULL } }; +#else +struct mntopt mopts[] = { + MOPT_STDOPTS, + MOPT_FORCE, + MOPT_UPDATE, + { NULL } +}; +#endif 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, - NFS_TIMEO, + NFS_READDIRSIZE, + 10, NFS_RETRANS, NFS_MAXGRPS, NFS_DEFRAHEAD, @@ -145,20 +156,34 @@ struct nfs_args nfsdefargs = { }; 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; +int nfsproto = IPPROTO_UDP; +int mnttcp_ok = 1; u_short port_no = 0; -#ifdef KERBEROS +#ifdef NFSKERB 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 int getnfsargs __P((char *, struct nfs_args *)); @@ -182,14 +207,17 @@ main(argc, argv) int mntflags, altflags, i, nfssvc_flag, num; char *name, *p, *spec; struct vfsconf *vfc; -#ifdef KERBEROS +#ifdef NFSKERB uid_t last_ruid; -#endif -#ifdef KERBEROS 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; mntflags = 0; @@ -197,8 +225,11 @@ main(argc, argv) nfsargs = nfsdefargs; nfsargsp = &nfsargs; while ((c = getopt(argc, argv, - "a:bcdD:g:iKklL:Mm:o:PpqR:r:sTt:w:x:")) != EOF) + "3a:bcdD:g:I:iKL:lm:o:PpqR:r:sTt:w:x:U")) != EOF) switch (c) { + case '3': + nfsargsp->flags |= NFSMNT_NFSV3; + break; case 'a': num = strtol(optarg, &p, 10); if (*p || num < 0) @@ -226,21 +257,27 @@ main(argc, argv) 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 KERBEROS +#ifdef NFSKERB 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) @@ -249,18 +286,16 @@ main(argc, argv) nfsargsp->flags |= NFSMNT_LEASETERM; break; case 'l': - nfsargsp->flags |= NFSMNT_RDIRALOOK; + nfsargsp->flags |= NFSMNT_RDIRPLUS; break; - case 'M': - nfsargsp->flags |= NFSMNT_MYWRITE; - break; -#ifdef KERBEROS +#ifdef NFSKERB case 'm': (void)strncpy(realm, optarg, REALM_SZ - 1); realm[REALM_SZ - 1] = '\0'; break; #endif case 'o': +#ifdef __FreeBSD__ getmntopts(optarg, mopts, &mntflags, &altflags); if(altflags & ALTF_BG) opflags |= BGRND; @@ -270,16 +305,16 @@ main(argc, argv) nfsargsp->flags |= NFSMNT_DUMBTIMR; if(altflags & ALTF_INTR) nfsargsp->flags |= NFSMNT_INT; -#ifdef KERBEROS +#ifdef NFSKERB if(altflags & ALTF_KERB) nfsargsp->flags |= NFSMNT_KERB; #endif - if(altflags & ALTF_NQLOOKLSE) - nfsargsp->flags |= NFSMNT_NQLOOKLEASE; - if(altflags & ALTF_RDIRALOOK) - nfsargsp->flags |= NFSMNT_RDIRALOOK; - if(altflags & ALTF_MYWRITE) - nfsargsp->flags |= NFSMNT_MYWRITE; + 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 @@ -287,14 +322,19 @@ main(argc, argv) nfsargsp->sotype = SOCK_SEQPACKET; #endif if(altflags & ALTF_NQNFS) - nfsargsp->flags |= NFSMNT_NQNFS; + nfsargsp->flags |= (NFSMNT_NQNFS|NFSMNT_NFSV3); if(altflags & ALTF_SOFT) nfsargsp->flags |= NFSMNT_SOFT; - if(altflags & ALTF_TCP) + if(altflags & ALTF_TCP) { nfsargsp->sotype = SOCK_STREAM; + nfsproto = IPPROTO_TCP; + } if(altflags & ALTF_PORT) port_no = atoi(strstr(optarg, "port=") + 5); altflags = 0; +#else + getmntopts(optarg, mopts, &mntflags); +#endif break; case 'P': nfsargsp->flags |= NFSMNT_RESVPORT; @@ -305,7 +345,7 @@ main(argc, argv) break; #endif case 'q': - nfsargsp->flags |= NFSMNT_NQNFS; + nfsargsp->flags |= (NFSMNT_NQNFS | NFSMNT_NFSV3); break; case 'R': num = strtol(optarg, &p, 10); @@ -325,6 +365,7 @@ main(argc, argv) break; case 'T': nfsargsp->sotype = SOCK_STREAM; + nfsproto = IPPROTO_TCP; break; case 't': num = strtol(optarg, &p, 10); @@ -347,6 +388,9 @@ main(argc, argv) nfsargsp->retrans = num; nfsargsp->flags |= NFSMNT_RETRANS; break; + case 'U': + mnttcp_ok = 0; + break; default: usage(); break; @@ -363,6 +407,7 @@ main(argc, argv) if (!getnfsargs(spec, nfsargsp)) exit(1); +#ifdef __FreeBSD__ vfc = getvfsbyname("nfs"); if(!vfc && vfsisloadable("nfs")) { if(vfsload("nfs")) @@ -372,6 +417,9 @@ main(argc, argv) } if (mount(vfc ? vfc->vfc_index : MOUNT_NFS, name, mntflags, nfsargsp)) +#else + if (mount(MOUNT_NFS, name, mntflags, nfsargsp)) +#endif err(1, "%s", name); if (nfsargsp->flags & (NFSMNT_NQNFS | NFSMNT_KERB)) { if ((opflags & ISBGRND) == 0) { @@ -396,13 +444,18 @@ main(argc, argv) } nfssvc_flag = NFSSVC_MNTD | NFSSVC_GOTAUTH | NFSSVC_AUTHINFAIL; -#ifdef KERBEROS +#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]; @@ -411,15 +464,62 @@ main(argc, argv) krb_set_tkt_string(buf); last_ruid = ncd.ncd_authuid; } - if (krb_mk_req(&kt, "rcmd", inst, realm, 0) == - KSUCCESS && - kt.length <= (RPCAUTH_MAXSIZ - 2 * NFSX_UNSIGNED)) { - ncd.ncd_authtype = RPCAUTH_NQNFS; - ncd.ncd_authlen = kt.length; - ncd.ncd_authstr = (char *)kt.dat; - nfssvc_flag = NFSSVC_MNTD | NFSSVC_GOTAUTH; + 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); } -#endif /* KERBEROS */ + 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); +#endif /* NFSKERB */ } } exit(0); @@ -440,9 +540,9 @@ getnfsargs(spec, nfsargsp) #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; -#ifdef KERBEROS +#ifdef NFSKERB char *cp; #endif u_short tport; @@ -507,7 +607,7 @@ getnfsargs(spec, nfsargsp) warnx("can't get net id for host"); return (0); } -#ifdef KERBEROS +#ifdef NFSKERB if ((nfsargsp->flags & NFSMNT_KERB)) { if ((hp = gethostbyaddr((char *)&saddr.sin_addr.s_addr, sizeof (u_long), AF_INET)) == (struct hostent *)0) { @@ -520,33 +620,46 @@ getnfsargs(spec, nfsargsp) if (cp = strchr(inst, '.')) *cp = '\0'; } -#endif /* KERBEROS */ +#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, - NFS_VER2, nfsargsp->sotype == SOCK_STREAM ? IPPROTO_TCP : - 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 ((clp = (nfsargsp->sotype == SOCK_STREAM ? - clnttcp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1, - &so, 0, 0) : - 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 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) { @@ -596,7 +709,8 @@ getnfsargs(spec, nfsargsp) 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); } @@ -615,22 +729,53 @@ xdr_dir(xdrsp, dirp) 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 (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++; + } + + /* + * 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); } __dead void usage() { - (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]", -"\trhost:path node"); + (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); } diff --git a/sbin/mountd/exports.5 b/sbin/mountd/exports.5 index d32527f..fc521f2 100644 --- a/sbin/mountd/exports.5 +++ b/sbin/mountd/exports.5 @@ -49,7 +49,9 @@ file specifies remote mount points for the mount protocol per the .Tn NFS server specification; see -.%T "Network File System Protocol Specification \\*(tNRFC\\*(sP 1094, Appendix A" . +.%T "Network File System Protocol Specification \\*(tNRFC\\*(sP 1094, Appendix A" +and +.%T "NFS: Network File System Version 3 Specification, Appendix I" . .Pp Each line in the file (other than comment lines that begin with a #) @@ -71,7 +73,8 @@ The second is to specify the pathname of the root of the filesystem followed by the .Fl alldirs flag; -this form allows the host(s) to mount any directory within the filesystem. +this form allows the host(s) to mount at any point within the filesystem, +including regular files if the ``-r'' option is used on mountd. The pathnames must not have any symbolic links in them and should not have any "." or ".." components. Mount points for a filesystem may appear on multiple lines each with @@ -140,8 +143,7 @@ The .Fl kerb option specifies that the Kerberos authentication server should be used to authenticate and map client credentials. -(Note that this is NOT Sun NFS compatible and -is supported for TCP transport only.) +This requires that the kernel be built with the NFSKERB option. .Pp The .Fl ro diff --git a/sbin/mountd/mountd.8 b/sbin/mountd/mountd.8 index 78f95b5..7168c17 100644 --- a/sbin/mountd/mountd.8 +++ b/sbin/mountd/mountd.8 @@ -30,7 +30,7 @@ .\" SUCH DAMAGE. .\" .\" From: @(#)mountd.8 8.1 (Berkeley) 6/9/93 -.\" $Id: mountd.8,v 1.2 1994/09/22 22:16:49 wollman Exp $ +.\" $Id: mountd.8,v 1.3 1995/02/22 21:42:48 ats Exp $ .\" .Dd September 22, 1994 .Dt MOUNTD 8 @@ -42,7 +42,7 @@ mount requests .Sh SYNOPSIS .Nm /sbin/mountd -.Op Fl n +.Op Fl nr .Op Ar exportsfile .Sh DESCRIPTION .Xr Mountd @@ -54,7 +54,9 @@ listens for service requests at the port indicated in the .Tn NFS server specification; see .%T "Network File System Protocol Specification" , -RFC1094. +RFC1094, Appendix A and +.%T "NFS: Network File System Version 3 Protocol Specification" , +Appendix I. .Pp Options and operands available for .Nm mountd : @@ -65,6 +67,15 @@ The option allows non-root mount requests to be served. This should only be specified if there are clients such as PC's, that require it. +.It Fl r +The +.Fl r +option allows mount RPCs requests for regular files to be served. +Although this seems to violate the mount protocol specification, some diskless +workstations do mount requests for their swapfiles and expect them to be +regular files. Since a regular file cannot be specified in /etc/exports, the +entire file system that the swapfiles reside in will have to be exported with +the ``-alldirs'' flag. .It Ar exportsfile The .Ar exportsfile diff --git a/sbin/mountd/mountd.c b/sbin/mountd/mountd.c index 4434244..0887c59 100644 --- a/sbin/mountd/mountd.c +++ b/sbin/mountd/mountd.c @@ -43,7 +43,7 @@ static char copyright[] = #ifndef lint /*static char sccsid[] = "From: @(#)mountd.c 8.8 (Berkeley) 2/20/94";*/ static const char rcsid[] = - "$Id: mountd.c,v 1.7.2.1 1995/06/08 04:34:11 davidg Exp $"; + "$Id: mountd.c,v 1.8 1995/06/11 19:30:46 rgrimes Exp $"; #endif /*not lint*/ #include @@ -62,7 +62,7 @@ static const char rcsid[] = #include #endif #include -#include +#include #include @@ -100,6 +100,8 @@ struct dirlist { }; /* dp_flag bits */ #define DP_DEFSET 0x1 +#define DP_HOSTSET 0x2 +#define DP_KERB 0x4 struct exportlist { struct exportlist *ex_next; @@ -139,22 +141,29 @@ struct grouplist { #define GT_IGNORE 0x5 struct hostlist { + int ht_flag; /* Uses DP_xx bits */ struct grouplist *ht_grp; struct hostlist *ht_next; }; +struct fhreturn { + int fhr_flag; + int fhr_vers; + nfsfh_t fhr_fh; +}; + /* Global defs */ char *add_expdir __P((struct dirlist **, char *, int)); void add_dlist __P((struct dirlist **, struct dirlist *, - struct grouplist *)); + struct grouplist *, int)); void add_mlist __P((char *, char *)); int check_dirpath __P((char *)); int check_options __P((struct dirlist *)); -int chk_host __P((struct dirlist *, u_long, int *)); +int chk_host __P((struct dirlist *, u_long, int *, int *)); void del_mlist __P((char *, char *)); struct dirlist *dirp_search __P((struct dirlist *, char *)); int do_mount __P((struct exportlist *, struct grouplist *, int, - struct ucred *, char *, int, struct statfs *)); + struct ucred *, char *, int, struct statfs *)); int do_opt __P((char **, char **, struct exportlist *, struct grouplist *, int *, int *, struct ucred *)); struct exportlist *ex_search __P((fsid_t *)); @@ -165,6 +174,7 @@ void free_grp __P((struct grouplist *)); void free_host __P((struct hostlist *)); void get_exportlist __P((void)); int get_host __P((char *, struct grouplist *, struct grouplist *)); +int get_num __P((char *)); struct hostlist *get_ht __P((void)); int get_line __P((void)); void get_mountlist __P((void)); @@ -183,7 +193,7 @@ void send_umntall __P((void)); int umntall_each __P((caddr_t, struct sockaddr_in *)); int xdr_dir __P((XDR *, char *)); int xdr_explist __P((XDR *, caddr_t)); -int xdr_fhs __P((XDR *, nfsv2fh_t *)); +int xdr_fhs __P((XDR *, caddr_t)); int xdr_mlist __P((XDR *, caddr_t)); /* C library */ @@ -205,7 +215,8 @@ struct ucred def_anon = { 1, { (gid_t) -2 } }; -int root_only = 1; +int resvport_only = 1; +int dir_only = 1; int opt_flags; /* Bits for above */ #define OP_MAPROOT 0x01 @@ -238,6 +249,7 @@ main(argc, argv) { SVCXPRT *udptransp, *tcptransp; int c; +#ifdef __FreeBSD__ struct vfsconf *vfc; vfc = getvfsbyname("nfs"); @@ -250,17 +262,21 @@ main(argc, argv) if(!vfc) { errx(1, "NFS support is not available in the running kernel"); } +#endif /* __FreeBSD__ */ - while ((c = getopt(argc, argv, "dn")) != EOF) + while ((c = getopt(argc, argv, "dnr")) != EOF) switch (c) { + case 'n': + resvport_only = 0; + break; + case 'r': + dir_only = 0; + break; case 'd': debug = debug ? 0 : 1; break; - case 'n': - root_only = 0; - break; default: - fprintf(stderr, "Usage: mountd [-n] [export_file]\n"); + fprintf(stderr, "Usage: mountd [-r] [-n] [export_file]\n"); exit(1); }; argc -= optind; @@ -300,11 +316,12 @@ main(argc, argv) syslog(LOG_ERR, "Can't create socket"); exit(1); } - pmap_unset(RPCPROG_MNT, RPCMNT_VER1); - if (!svc_register(udptransp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, - IPPROTO_UDP) || - !svc_register(tcptransp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, - IPPROTO_TCP)) { + pmap_unset(RPCPROG_MNT, 1); + pmap_unset(RPCPROG_MNT, 3); + if (!svc_register(udptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_UDP) || + !svc_register(udptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_UDP) || + !svc_register(tcptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_TCP) || + !svc_register(tcptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_TCP)) { syslog(LOG_ERR, "Can't register mount"); exit(1); } @@ -323,28 +340,21 @@ mntsrv(rqstp, transp) { struct exportlist *ep; struct dirlist *dp; - nfsv2fh_t nfh; + struct fhreturn fhr; struct authunix_parms *ucr; struct stat stb; struct statfs fsb; struct hostent *hp; u_long saddr; + u_short sport; char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN]; - int bad = ENOENT, omask, defset; - uid_t uid = -2; - - /* Get authorization */ - switch (rqstp->rq_cred.oa_flavor) { - case AUTH_UNIX: - ucr = (struct authunix_parms *)rqstp->rq_clntcred; - uid = ucr->aup_uid; - break; - case AUTH_NULL: - default: - break; - } + int bad = ENOENT, defset, hostset; + sigset_t sighup_mask; + sigemptyset(&sighup_mask); + sigaddset(&sighup_mask, SIGHUP); saddr = transp->xp_raddr.sin_addr.s_addr; + sport = ntohs(transp->xp_raddr.sin_port); hp = (struct hostent *)NULL; switch (rqstp->rq_proc) { case NULLPROC: @@ -352,7 +362,7 @@ mntsrv(rqstp, transp) syslog(LOG_ERR, "Can't send reply"); return; case RPCMNT_MOUNT: - if ((uid != 0 && root_only) || uid == -2) { + if (sport >= IPPORT_RESERVED && resvport_only) { svcerr_weakauth(transp); return; } @@ -363,11 +373,13 @@ mntsrv(rqstp, transp) /* * Get the real pathname and make sure it is a directory - * that exists. + * or a regular file if the -r option was specified + * and it exists. */ if (realpath(rpcpath, dirpath) == 0 || stat(dirpath, &stb) < 0 || - (stb.st_mode & S_IFMT) != S_IFDIR || + (!S_ISDIR(stb.st_mode) && + (dir_only || !S_ISREG(stb.st_mode))) || statfs(dirpath, &fsb) < 0) { chdir("/"); /* Just in case realpath doesn't */ if (debug) @@ -378,26 +390,31 @@ mntsrv(rqstp, transp) } /* Check in the exports list */ - omask = sigblock(sigmask(SIGHUP)); + sigprocmask(SIG_BLOCK, &sighup_mask, NULL); ep = ex_search(&fsb.f_fsid); - defset = 0; - if (ep && (chk_host(ep->ex_defdir, saddr, &defset) || + hostset = defset = 0; + if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || ((dp = dirp_search(ep->ex_dirl, dirpath)) && - chk_host(dp, saddr, &defset)) || + chk_host(dp, saddr, &defset, &hostset)) || (defset && scan_tree(ep->ex_defdir, saddr) == 0 && scan_tree(ep->ex_dirl, saddr) == 0))) { + if (hostset & DP_HOSTSET) + fhr.fhr_flag = hostset; + else + fhr.fhr_flag = defset; + fhr.fhr_vers = rqstp->rq_vers; /* Get the file handle */ - bzero((caddr_t)&nfh, sizeof(nfh)); - if (getfh(dirpath, (fhandle_t *)&nfh) < 0) { + bzero((caddr_t)&fhr.fhr_fh, sizeof(nfsfh_t)); + if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { bad = errno; syslog(LOG_ERR, "Can't get fh for %s", dirpath); if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) syslog(LOG_ERR, "Can't send reply"); - sigsetmask(omask); + sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); return; } - if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh)) + if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&fhr)) syslog(LOG_ERR, "Can't send reply"); if (hp == NULL) hp = gethostbyaddr((caddr_t)&saddr, @@ -414,14 +431,14 @@ mntsrv(rqstp, transp) if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) syslog(LOG_ERR, "Can't send reply"); } - sigsetmask(omask); + sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); return; case RPCMNT_DUMP: if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL)) syslog(LOG_ERR, "Can't send reply"); return; case RPCMNT_UMOUNT: - if ((uid != 0 && root_only) || uid == -2) { + if (sport >= IPPORT_RESERVED && resvport_only) { svcerr_weakauth(transp); return; } @@ -437,7 +454,7 @@ mntsrv(rqstp, transp) del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath); return; case RPCMNT_UMNTALL: - if ((uid != 0 && root_only) || uid == -2) { + if (sport >= IPPORT_RESERVED && resvport_only) { svcerr_weakauth(transp); return; } @@ -470,18 +487,37 @@ xdr_dir(xdrsp, dirp) } /* - * Xdr routine to generate fhstatus + * Xdr routine to generate file handle reply */ int -xdr_fhs(xdrsp, nfh) +xdr_fhs(xdrsp, cp) XDR *xdrsp; - nfsv2fh_t *nfh; + caddr_t cp; { - u_long ok = 0; + register struct fhreturn *fhrp = (struct fhreturn *)cp; + u_long ok = 0, len, auth; if (!xdr_long(xdrsp, &ok)) return (0); - return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH)); + switch (fhrp->fhr_vers) { + case 1: + return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); + case 3: + len = NFSX_V3FH; + if (!xdr_long(xdrsp, &len)) + return (0); + if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) + return (0); + if (fhrp->fhr_flag & DP_KERB) + auth = RPCAUTH_KERB4; + else + auth = RPCAUTH_UNIX; + len = 1; + if (!xdr_long(xdrsp, &len)) + return (0); + return (xdr_long(xdrsp, &auth)); + }; + return (0); } int @@ -521,9 +557,12 @@ xdr_explist(xdrsp, cp) { struct exportlist *ep; int false = 0; - int omask, putdef; + int putdef; + sigset_t sighup_mask; - omask = sigblock(sigmask(SIGHUP)); + sigemptyset(&sighup_mask); + sigaddset(&sighup_mask, SIGHUP); + sigprocmask(SIG_BLOCK, &sighup_mask, NULL); ep = exphead; while (ep) { putdef = 0; @@ -535,12 +574,12 @@ xdr_explist(xdrsp, cp) goto errout; ep = ep->ex_next; } - sigsetmask(omask); + sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); if (!xdr_bool(xdrsp, &false)) return (0); return (1); errout: - sigsetmask(omask); + sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); return (0); } @@ -660,6 +699,18 @@ get_exportlist() struct ufs_args ua; struct iso_args ia; struct mfs_args ma; +#ifdef __NetBSD__ + struct msdosfs_args da; + } targs; + + if (!strcmp(fsp->f_fstypename, MOUNT_MFS) || + !strcmp(fsp->f_fstypename, MOUNT_UFS) || + !strcmp(fsp->f_fstypename, MOUNT_MSDOS) || + !strcmp(fsp->f_fstypename, MOUNT_CD9660)) { + targs.ua.fspec = NULL; + targs.ua.export.ex_flags = MNT_DELEXPORT; + if (mount(fsp->f_fstypename, fsp->f_mntonname, +#else } targs; switch (fsp->f_type) { @@ -670,6 +721,7 @@ get_exportlist() targs.ua.fspec = NULL; targs.ua.export.ex_flags = MNT_DELEXPORT; if (mount(fsp->f_type, fsp->f_mntonname, +#endif fsp->f_flags | MNT_UPDATE, (caddr_t)&targs) < 0) syslog(LOG_ERR, "Can't delete exports for %s", @@ -805,6 +857,7 @@ get_exportlist() if (get_host(hst, grp, tgrp)) { syslog(LOG_ERR, "Bad netgroup %s", cp); getexp_err(ep, tgrp); + endnetgrent(); goto nextline; } } else if (get_host(cp, grp, tgrp)) { @@ -865,12 +918,12 @@ get_exportlist() * Success. Update the data structures. */ if (has_host) { - hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS)); + hang_dirp(dirhead, tgrp, ep, opt_flags); grp->gr_next = grphead; grphead = tgrp; } else { hang_dirp(dirhead, (struct grouplist *)NULL, ep, - (opt_flags & OP_ALLDIRS)); + opt_flags); free_grp(grp); } dirhead = (struct dirlist *)NULL; @@ -994,24 +1047,28 @@ add_expdir(dpp, cp, len) * and update the entry for host. */ void -hang_dirp(dp, grp, ep, alldirs) +hang_dirp(dp, grp, ep, flags) struct dirlist *dp; struct grouplist *grp; struct exportlist *ep; - int alldirs; + int flags; { struct hostlist *hp; struct dirlist *dp2; - if (alldirs) { + if (flags & OP_ALLDIRS) { if (ep->ex_defdir) free((caddr_t)dp); else ep->ex_defdir = dp; - if (grp == (struct grouplist *)NULL) + if (grp == (struct grouplist *)NULL) { ep->ex_defdir->dp_flag |= DP_DEFSET; - else while (grp) { + if (flags & OP_KERB) + ep->ex_defdir->dp_flag |= DP_KERB; + } else while (grp) { hp = get_ht(); + if (flags & OP_KERB) + hp->ht_flag |= DP_KERB; hp->ht_grp = grp; hp->ht_next = ep->ex_defdir->dp_hosts; ep->ex_defdir->dp_hosts = hp; @@ -1024,7 +1081,7 @@ hang_dirp(dp, grp, ep, alldirs) */ while (dp) { dp2 = dp->dp_left; - add_dlist(&ep->ex_dirl, dp, grp); + add_dlist(&ep->ex_dirl, dp, grp, flags); dp = dp2; } } @@ -1035,10 +1092,11 @@ hang_dirp(dp, grp, ep, alldirs) * for the new directory or adding the new node. */ void -add_dlist(dpp, newdp, grp) +add_dlist(dpp, newdp, grp, flags) struct dirlist **dpp; struct dirlist *newdp; struct grouplist *grp; + int flags; { struct dirlist *dp; struct hostlist *hp; @@ -1048,10 +1106,10 @@ add_dlist(dpp, newdp, grp) if (dp) { cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); if (cmp > 0) { - add_dlist(&dp->dp_left, newdp, grp); + add_dlist(&dp->dp_left, newdp, grp, flags); return; } else if (cmp < 0) { - add_dlist(&dp->dp_right, newdp, grp); + add_dlist(&dp->dp_right, newdp, grp, flags); return; } else free((caddr_t)newdp); @@ -1067,13 +1125,18 @@ add_dlist(dpp, newdp, grp) */ do { hp = get_ht(); + if (flags & OP_KERB) + hp->ht_flag |= DP_KERB; hp->ht_grp = grp; hp->ht_next = dp->dp_hosts; dp->dp_hosts = hp; grp = grp->gr_next; } while (grp); - } else + } else { dp->dp_flag |= DP_DEFSET; + if (flags & OP_KERB) + dp->dp_flag |= DP_KERB; + } } /* @@ -1102,10 +1165,11 @@ dirp_search(dp, dirpath) * Scan for a host match in a directory tree. */ int -chk_host(dp, saddr, defsetp) +chk_host(dp, saddr, defsetp, hostsetp) struct dirlist *dp; u_long saddr; int *defsetp; + int *hostsetp; { struct hostlist *hp; struct grouplist *grp; @@ -1113,7 +1177,7 @@ chk_host(dp, saddr, defsetp) if (dp) { if (dp->dp_flag & DP_DEFSET) - *defsetp = 1; + *defsetp = dp->dp_flag; hp = dp->dp_hosts; while (hp) { grp = hp->ht_grp; @@ -1122,15 +1186,19 @@ chk_host(dp, saddr, defsetp) addrp = (u_long **) grp->gr_ptr.gt_hostent->h_addr_list; while (*addrp) { - if (**addrp == saddr) + if (**addrp == saddr) { + *hostsetp = (hp->ht_flag | DP_HOSTSET); return (1); + } addrp++; } break; case GT_NET: if ((saddr & grp->gr_ptr.gt_net.nt_mask) == - grp->gr_ptr.gt_net.nt_net) + grp->gr_ptr.gt_net.nt_net) { + *hostsetp = (hp->ht_flag | DP_HOSTSET); return (1); + } break; }; hp = hp->ht_next; @@ -1147,12 +1215,12 @@ scan_tree(dp, saddr) struct dirlist *dp; u_long saddr; { - int defset; + int defset, hostset; if (dp) { if (scan_tree(dp->dp_left, saddr)) return (1); - if (chk_host(dp, saddr, &defset)) + if (chk_host(dp, saddr, &defset, &hostset)) return (1); if (scan_tree(dp->dp_right, saddr)) return (1); @@ -1312,7 +1380,7 @@ get_host(cp, grp, tgrp) if (isdigit(*cp)) { saddr = inet_addr(cp); if (saddr == -1) { - syslog(LOG_ERR, "Inet_addr failed"); + syslog(LOG_ERR, "Inet_addr failed for %s", cp); return (1); } if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr), @@ -1326,7 +1394,7 @@ get_host(cp, grp, tgrp) aptr[1] = (char *)NULL; } } else { - syslog(LOG_ERR, "Gethostbyname failed"); + syslog(LOG_ERR, "Gethostbyname failed for %s", cp); return (1); } } @@ -1424,6 +1492,7 @@ get_ht() if (hp == (struct hostlist *)NULL) out_of_mem(); hp->ht_next = (struct hostlist *)NULL; + hp->ht_flag = 0; return (hp); } @@ -1494,6 +1563,9 @@ do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) struct ufs_args ua; struct iso_args ia; struct mfs_args ma; +#ifdef __NetBSD__ + struct msdosfs_args da; +#endif } args; u_long net; @@ -1569,7 +1641,11 @@ do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) * Also, needs to know how to export all types of local * exportable file systems and not just MOUNT_UFS. */ +#ifdef __NetBSD__ + while (mount(fsb->f_fstypename, dirp, +#else while (mount(fsb->f_type, dirp, +#endif fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { if (cp) *cp-- = savedc; @@ -2033,15 +2109,30 @@ check_dirpath(dirp) while (*cp && ret) { if (*cp == '/') { *cp = '\0'; - if (lstat(dirp, &sb) < 0 || - (sb.st_mode & S_IFMT) != S_IFDIR) + if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) ret = 0; *cp = '/'; } cp++; } - if (lstat(dirp, &sb) < 0 || - (sb.st_mode & S_IFMT) != S_IFDIR) + if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) ret = 0; return (ret); } + +/* + * Just translate an ascii string to an integer. + */ +int +get_num(cp) + register char *cp; +{ + register int res = 0; + + while (*cp) { + if (*cp < '0' || *cp > '9') + return (-1); + res = res * 10 + (*cp++ - '0'); + } + return (res); +} diff --git a/sbin/nfsd/nfsd.8 b/sbin/nfsd/nfsd.8 index a54a564..24573d9 100644 --- a/sbin/nfsd/nfsd.8 +++ b/sbin/nfsd/nfsd.8 @@ -98,7 +98,8 @@ listens for service requests at the port indicated in the .Tn NFS server specification; see .%T "Network File System Protocol Specification" , -RFC1094. +RFC1094 and +.%T "NFS: Network File System Version 3 Protocol Specification" . .Pp If .Nm nfsd diff --git a/sbin/nfsd/nfsd.c b/sbin/nfsd/nfsd.c index 9d4d226..8c8731d 100644 --- a/sbin/nfsd/nfsd.c +++ b/sbin/nfsd/nfsd.c @@ -63,10 +63,10 @@ static char sccsid[] = "@(#)nfsd.c 8.7 (Berkeley) 2/22/94"; #include #endif #include -#include +#include #include -#ifdef KERBEROS +#ifdef NFSKERB #include #include #endif @@ -94,16 +94,23 @@ struct nfsd_srvargs nsd; char **Argv = NULL; /* pointer to argument vector */ char *LastArg = NULL; /* end of argv */ -#ifdef KERBEROS +#ifdef NFSKERB char lnam[ANAME_SZ]; KTEXT_ST kt; -AUTH_DAT auth; +AUTH_DAT kauth; char inst[INST_SZ]; +struct nfsrpc_fullblock kin, kout; +struct nfsrpc_fullverf kverf; +NFSKERBKEY_T kivec; +struct timeval ktv; +NFSKERBKEYSCHED_T kerb_keysched; #endif void nonfs __P((int)); void reapchild __P((int)); +#ifdef __FreeBSD__ void setproctitle __P((char *)); +#endif void usage __P((void)); /* @@ -139,11 +146,13 @@ main(argc, argv, envp) #ifdef ISO struct sockaddr_iso isoaddr, isopeer; #endif + struct timeval ktv; fd_set ready, sockbits; int ch, cltpflag, connect_type_cnt, i, len, maxsock, msgsock; int nfsdcnt, nfssvc_flag, on, reregister, sock, tcpflag, tcpsock; int tp4cnt, tp4flag, tp4sock, tpipcnt, tpipflag, tpipsock, udpflag; char *cp, **cpp; +#ifdef __FreeBSD__ struct vfsconf *vfc; vfc = getvfsbyname("nfs"); @@ -156,6 +165,7 @@ main(argc, argv, envp) if(!vfc) { errx(1, "NFS is not available in the running kernel"); } +#endif /* Save start and extent of argv for setproctitle. */ Argv = argv; @@ -241,10 +251,12 @@ main(argc, argv, envp) if (reregister) { if (udpflag && - !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) + (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) || + !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT))) err(1, "can't register with portmap for UDP."); if (tcpflag && - !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) + (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) || + !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT))) err(1, "can't register with portmap for TCP."); exit(0); } @@ -261,11 +273,17 @@ main(argc, argv, envp) continue; } - setproctitle("nfsd-srv"); + setproctitle("server"); nfssvc_flag = NFSSVC_NFSD; nsd.nsd_nfsd = NULL; -#ifdef KERBEROS - nsd.nsd_authstr = (char *)kt.dat; +#ifdef NFSKERB + if (sizeof (struct nfsrpc_fullverf) != RPCX_FULLVERF || + sizeof (struct nfsrpc_fullblock) != RPCX_FULLBLOCK) + syslog(LOG_ERR, "Yikes NFSKERB structs not packed!"); + nsd.nsd_authstr = (u_char *)&kt; + nsd.nsd_authlen = sizeof (kt); + nsd.nsd_verfstr = (u_char *)&kverf; + nsd.nsd_verflen = sizeof (kverf); #endif while (nfssvc(nfssvc_flag, &nsd) < 0) { if (errno != ENEEDAUTH) { @@ -273,14 +291,27 @@ main(argc, argv, envp) exit(1); } nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHINFAIL; -#ifdef KERBEROS - kt.length = nsd.nsd_authlen; - kt.mbz = 0; - (void)strcpy(inst, "*"); - if (krb_rd_req(&kt, "rcmd", - inst, nsd.nsd_haddr, &auth, "") == RD_AP_OK && - krb_kntoln(&auth, lnam) == KSUCCESS && - (pwd = getpwnam(lnam)) != NULL) { +#ifdef NFSKERB + /* + * Get the Kerberos ticket out of the authenticator + * verify it and convert the principal name to a user + * name. The user name is then converted to a set of + * user credentials via the password and group file. + * Finally, decrypt the timestamp and validate it. + * For more info see the IETF Draft "Authentication + * in ONC RPC". + */ + kt.length = ntohl(kt.length); + if (gettimeofday(&ktv, (struct timezone *)0) == 0 && + kt.length > 0 && kt.length <= + (RPCAUTH_MAXSIZ - 3 * NFSX_UNSIGNED)) { + kin.w1 = NFS_KERBW1(kt); + kt.mbz = 0; + (void)strcpy(inst, "*"); + if (krb_rd_req(&kt, NFS_KERBSRV, + inst, nsd.nsd_haddr, &kauth, "") == RD_AP_OK && + krb_kntoln(&kauth, lnam) == KSUCCESS && + (pwd = getpwnam(lnam)) != NULL) { cr = &nsd.nsd_cr; cr->cr_uid = pwd->pw_uid; cr->cr_groups[0] = pwd->pw_gid; @@ -301,9 +332,34 @@ main(argc, argv, envp) break; } endgrent(); - nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHIN; + + /* + * Get the timestamp verifier out of the + * authenticator and verifier strings. + */ + kin.t1 = kverf.t1; + kin.t2 = kverf.t2; + kin.w2 = kverf.w2; + bzero((caddr_t)kivec, sizeof (kivec)); + bcopy((caddr_t)kauth.session, + (caddr_t)nsd.nsd_key,sizeof(kauth.session)); + + /* + * Decrypt the timestamp verifier in CBC mode. + */ + XXX + + /* + * Validate the timestamp verifier, to + * check that the session key is ok. + */ + nsd.nsd_timestamp.tv_sec = ntohl(kout.t1); + nsd.nsd_timestamp.tv_usec = ntohl(kout.t2); + nsd.nsd_ttl = ntohl(kout.w1); + if ((nsd.nsd_ttl - 1) == ntohl(kout.w2)) + nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHIN; } -#endif /* KERBEROS */ +#endif /* NFSKERB */ } exit(0); } @@ -323,7 +379,8 @@ main(argc, argv, envp) syslog(LOG_ERR, "can't bind udp addr"); exit(1); } - if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) { + if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) || + !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)) { syslog(LOG_ERR, "can't register with udp portmap"); exit(1); } @@ -403,7 +460,8 @@ main(argc, argv, envp) syslog(LOG_ERR, "listen failed"); exit(1); } - if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) { + if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) || + !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)) { syslog(LOG_ERR, "can't register tcp with portmap"); exit(1); } @@ -492,7 +550,7 @@ main(argc, argv, envp) if (connect_type_cnt == 0) exit(0); - setproctitle("nfsd-master"); + setproctitle("master"); /* * Loop forever accepting connections and passing the sockets @@ -566,7 +624,7 @@ main(argc, argv, envp) void usage() { - (void)fprintf(stderr, "nfsd %s\n", USAGE); + (void)fprintf(stderr, "usage: nfsd %s\n", USAGE); exit(1); } @@ -582,9 +640,10 @@ reapchild(signo) int signo; { - while (wait3(NULL, WNOHANG, NULL)); + while (wait3(NULL, WNOHANG, NULL) > 0); } +#ifdef __FreeBSD__ void setproctitle(a) char *a; @@ -593,9 +652,10 @@ setproctitle(a) char buf[80]; cp = Argv[0]; - (void)snprintf(buf, sizeof(buf), "%s", a); + (void)snprintf(buf, sizeof(buf), "nfsd-%s", a); (void)strncpy(cp, buf, LastArg - cp); cp += strlen(cp); while (cp < LastArg) *cp++ = '\0'; } +#endif /* __FreeBSD__ */ diff --git a/sbin/nfsiod/nfsiod.c b/sbin/nfsiod/nfsiod.c index d066329..0a6985f 100644 --- a/sbin/nfsiod/nfsiod.c +++ b/sbin/nfsiod/nfsiod.c @@ -50,8 +50,10 @@ static char sccsid[] = "@(#)nfsiod.c 8.3 (Berkeley) 2/22/94"; #include #include #include +#include -#include +#include +#include #include #include -- cgit v1.1