* Copyright (c) 1989 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Rick Macklem at The University of Guelph.
* %sccs.include.redist.c%
"@(#) Copyright (c) 1989 Regents of the University of California.\n\
static char sccsid
[] = "@(#)nfsd.c 5.13 (Berkeley) %G%";
#include <sys/socketvar.h>
#include <rpc/pmap_clnt.h>
#include <rpc/pmap_prot.h>
#include <kerberosIV/des.h>
#include <kerberosIV/krb.h>
#define syslog(e, s) fprintf(stderr,(s))
char **Argv
= NULL
; /* pointer to argument vector */
char *LastArg
= NULL
; /* end of argv */
* Nfs server daemon mostly just a user context for nfssvc()
* 1 - do file descriptor and signal cleanup
* 3 - create server socket(s)
* 4 - register socket with portmap
* For connectionless protocols, just pass the socket into the kernel via.
* For connection based sockets, loop doing accepts. When you get a new socket
* from accept, pass the msgsock into the kernel via. nfssvc().
* -u - support udp nfs clients
* -t - support tcp nfs clients
* -c - support iso cltp clients
* -r - reregister with portmapper
* followed by "n" which is the number of nfsds' to fork off
register char *cp
, **cpp
;
register struct ucred
*cr
= &nsd
.nsd_cr
;
int sock
, msgsock
, tcpflag
= 0, udpflag
= 0, ret
, len
;
int cltpflag
= 0, tp4flag
= 0, tpipflag
= 0, connect_type_cnt
= 0;
int maxsock
, tcpsock
, tp4sock
, tpipsock
, nfsdcnt
= 4;
int nfssvc_flag
, opt
, on
= 1, reregister
= 0;
struct sockaddr_in inetaddr
, inetpeer
;
struct sockaddr_iso isoaddr
, isopeer
;
struct nfsd_args nfsdargs
;
* Save start and extent of argv for setproctitle.
if (envp
== 0 || *envp
== 0)
LastArg
= envp
[-1] + strlen(envp
[-1]);
while ((opt
= getopt(argc
, argv
, "utcr")) != EOF
)
nfsdcnt
= atoi(argv
[optind
]);
if (nfsdcnt
< 1 || nfsdcnt
> 20)
signal(SIGQUIT
, SIG_IGN
);
signal(SIGTERM
, SIG_IGN
);
signal(SIGCHLD
, reapchild
);
if (udpflag
&& !pmap_set(RPCPROG_NFS
, NFS_VER2
, IPPROTO_UDP
,
"Can't register with portmap for UDP\n");
if (tcpflag
&& !pmap_set(RPCPROG_NFS
, NFS_VER2
, IPPROTO_TCP
,
"Can't register with portmap for TCP\n");
openlog("nfsd:", LOG_PID
, LOG_DAEMON
);
for (i
= 0; i
< nfsdcnt
; i
++)
setproctitle("nfsd-srv");
nfssvc_flag
= NFSSVC_NFSD
;
nsd
.nsd_nfsd
= (struct nfsd
*)0;
nsd
.nsd_authstr
= (char *)kt
.dat
;
while (nfssvc(nfssvc_flag
, (caddr_t
)&nsd
) < 0) {
if (errno
== ENEEDAUTH
) {
nfssvc_flag
= (NFSSVC_NFSD
| NFSSVC_AUTHINFAIL
);
kt
.length
= nsd
.nsd_authlen
;
if (krb_rd_req(&kt
, "rcmd", inst
, nsd
.nsd_haddr
,
&auth
, "") == RD_AP_OK
&&
krb_kntoln(&auth
, lnam
) == KSUCCESS
&&
(pwd
= getpwnam(lnam
))) {
cr
->cr_uid
= pwd
->pw_uid
;
cr
->cr_groups
[0] = pwd
->pw_gid
;
while (grp
= getgrent()) {
if (grp
->gr_gid
== cr
->cr_groups
[0])
cr
->cr_groups
[cr
->cr_ngroups
++] = grp
->gr_gid
;
if (cr
->cr_ngroups
== NGROUPS
)
nfssvc_flag
= (NFSSVC_NFSD
| NFSSVC_AUTHIN
);
syslog(LOG_ERR
, "Nfsd died %m");
* If we are serving udp, set up the socket.
if ((sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
syslog(LOG_ERR
, "Can't create udp socket");
inetaddr
.sin_family
= AF_INET
;
inetaddr
.sin_addr
.s_addr
= INADDR_ANY
;
inetaddr
.sin_port
= htons(NFS_PORT
);
inetaddr
.sin_len
= sizeof(inetaddr
);
if (bind(sock
, (struct sockaddr
*)&inetaddr
, sizeof(inetaddr
)) < 0) {
syslog(LOG_ERR
, "Can't bind udp addr");
if (!pmap_set(RPCPROG_NFS
, NFS_VER2
, IPPROTO_UDP
, NFS_PORT
)) {
syslog(LOG_ERR
, "Can't register with udp portmap");
nfsdargs
.name
= (caddr_t
)0;
if (nfssvc(NFSSVC_ADDSOCK
, &nfsdargs
) < 0) {
syslog(LOG_ERR
, "Can't Add UDP socket");
* If we are serving cltp, set up the socket.
if ((sock
= socket(AF_ISO
, SOCK_DGRAM
, 0)) < 0) {
syslog(LOG_ERR
, "Can't create cltp socket");
bzero((caddr_t
)&isoaddr
, sizeof (isoaddr
));
isoaddr
.siso_family
= AF_ISO
;
isoaddr
.siso_len
= sizeof(isoaddr
);
if (bind(sock
, (struct sockaddr
*)&isoaddr
, sizeof(isoaddr
)) < 0) {
syslog(LOG_ERR
, "Can't bind cltp addr");
* Someday this should probably use "rpcbind", the son of
if (!pmap_set(RPCPROG_NFS
, NFS_VER2
, IPPROTO_UDP
, NFS_PORT
)) {
syslog(LOG_ERR
, "Can't register with udp portmap");
nfsdargs
.name
= (caddr_t
)0;
if (nfssvc(NFSSVC_ADDSOCK
, &nfsdargs
) < 0) {
syslog(LOG_ERR
, "Can't Add UDP socket");
* Now set up the master server socket waiting for tcp connections.
if ((tcpsock
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
syslog(LOG_ERR
, "Can't create tcp socket");
if (setsockopt(tcpsock
, SOL_SOCKET
, SO_REUSEADDR
,
(char *) &on
, sizeof(on
)) < 0)
syslog(LOG_ERR
, "setsockopt SO_REUSEADDR: %m");
inetaddr
.sin_family
= AF_INET
;
inetaddr
.sin_addr
.s_addr
= INADDR_ANY
;
inetaddr
.sin_port
= htons(NFS_PORT
);
inetaddr
.sin_len
= sizeof (inetaddr
);
if (bind(tcpsock
, (struct sockaddr
*)&inetaddr
, sizeof (inetaddr
)) < 0) {
syslog(LOG_ERR
, "Can't bind tcp addr");
if (listen(tcpsock
, 5) < 0) {
syslog(LOG_ERR
, "Listen failed");
if (!pmap_set(RPCPROG_NFS
, NFS_VER2
, IPPROTO_TCP
, NFS_PORT
)) {
syslog(LOG_ERR
, "Can't register tcp with portmap");
FD_SET(tcpsock
, &sockbits
);
* Now set up the master server socket waiting for tp4 connections.
if ((tp4sock
= socket(AF_ISO
, SOCK_SEQPACKET
, 0)) < 0) {
syslog(LOG_ERR
, "Can't create tp4 socket");
if (setsockopt(tp4sock
, SOL_SOCKET
, SO_REUSEADDR
,
(char *) &on
, sizeof(on
)) < 0)
syslog(LOG_ERR
, "setsockopt SO_REUSEADDR: %m");
bzero((caddr_t
)&isoaddr
, sizeof (isoaddr
));
isoaddr
.siso_family
= AF_ISO
;
isoaddr
.siso_len
= sizeof(isoaddr
);
if (bind(tp4sock
, (struct sockaddr
*)&isoaddr
, sizeof (isoaddr
)) < 0) {
syslog(LOG_ERR
, "Can't bind tp4 addr");
if (listen(tp4sock
, 5) < 0) {
syslog(LOG_ERR
, "Listen failed");
* Someday this should probably use "rpcbind".
if (!pmap_set(RPCPROG_NFS
, NFS_VER2
, IPPROTO_TCP
, NFS_PORT
)) {
syslog(LOG_ERR
, "Can't register tcp with portmap");
FD_SET(tp4sock
, &sockbits
);
* Now set up the master server socket waiting for tpip connections.
if ((tpipsock
= socket(AF_INET
, SOCK_SEQPACKET
, 0)) < 0) {
syslog(LOG_ERR
, "Can't create tpip socket");
if (setsockopt(tpipsock
, SOL_SOCKET
, SO_REUSEADDR
,
(char *) &on
, sizeof(on
)) < 0)
syslog(LOG_ERR
, "setsockopt SO_REUSEADDR: %m");
inetaddr
.sin_family
= AF_INET
;
inetaddr
.sin_addr
.s_addr
= INADDR_ANY
;
inetaddr
.sin_port
= htons(NFS_PORT
);
inetaddr
.sin_len
= sizeof (inetaddr
);
if (bind(tpipsock
, (struct sockaddr
*)&inetaddr
, sizeof (inetaddr
)) < 0) {
syslog(LOG_ERR
, "Can't bind tcp addr");
if (listen(tpipsock
, 5) < 0) {
syslog(LOG_ERR
, "Listen failed");
* Someday this should use "rpcbind"
if (!pmap_set(RPCPROG_NFS
, NFS_VER2
, IPPROTO_TCP
, NFS_PORT
)) {
syslog(LOG_ERR
, "Can't register tcp with portmap");
FD_SET(tpipsock
, &sockbits
);
if (connect_type_cnt
== 0)
setproctitle("nfsd-master");
* Loop forever accepting connections and passing the sockets
* into the kernel for the mounts.
if (connect_type_cnt
> 1) {
if (select(maxsock
+ 1, &ready
, (fd_set
*)0,
(fd_set
*)0, (struct timeval
*)0) < 1) {
syslog(LOG_ERR
, "Select failed");
if (tcpflag
&& FD_ISSET(tcpsock
, &ready
)) {
if ((msgsock
= accept(tcpsock
,
(struct sockaddr
*)&inetpeer
, &len
)) < 0) {
syslog(LOG_ERR
, "Accept failed: %m");
bzero((char *)inetpeer
.sin_zero
,
sizeof(inetpeer
.sin_zero
));
if (setsockopt(msgsock
, SOL_SOCKET
,
SO_KEEPALIVE
, (char *) &on
, sizeof(on
)) < 0)
"setsockopt SO_KEEPALIVE: %m");
nfsdargs
.name
= (caddr_t
)&inetpeer
;
nfsdargs
.namelen
= sizeof(inetpeer
);
nfssvc(NFSSVC_ADDSOCK
, &nfsdargs
);
if (tp4flag
&& FD_ISSET(tp4sock
, &ready
)) {
if ((msgsock
= accept(tp4sock
,
(struct sockaddr
*)&isopeer
, &len
)) < 0) {
syslog(LOG_ERR
, "Accept failed: %m");
if (setsockopt(msgsock
, SOL_SOCKET
,
SO_KEEPALIVE
, (char *) &on
, sizeof(on
)) < 0)
"setsockopt SO_KEEPALIVE: %m");
nfsdargs
.name
= (caddr_t
)&isopeer
;
nfssvc(NFSSVC_ADDSOCK
, &nfsdargs
);
if (tpipflag
&& FD_ISSET(tpipsock
, &ready
)) {
if ((msgsock
= accept(tpipsock
,
(struct sockaddr
*)&inetpeer
, &len
)) < 0) {
syslog(LOG_ERR
, "Accept failed: %m");
if (setsockopt(msgsock
, SOL_SOCKET
,
SO_KEEPALIVE
, (char *) &on
, sizeof(on
)) < 0)
"setsockopt SO_KEEPALIVE: %m");
nfsdargs
.name
= (caddr_t
)&inetpeer
;
nfssvc(NFSSVC_ADDSOCK
, &nfsdargs
);
fprintf(stderr
, "nfsd [-u] [-t] [-c] [-r] [num_nfsds]\n");
while (wait3((int *) NULL
, WNOHANG
, (struct rusage
*) NULL
))
(void) sprintf(buf
, "%s", a
);
(void) strncpy(cp
, buf
, LastArg
- cp
);