Import Jan 15 version of Andrew Gordon <andrew.gordon@net-tel.co.uk>'s
stub lockd. This implements just the protocol, but does not interact with the kernel. It says "Yes!" to all requests. This is useful if you have people using tools that do locking for no reason (eg: some PC NFS systems running some Microsoft products) and will happily report they couldn't lock the file and merrily proceed anyway. Running this will not change the reliability of sharing files, it'll just keep it out of everybody's face.
This commit is contained in:
parent
add3bbdaef
commit
503d2aa8a2
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/cvs2svn/branches/A_GORDON/; revision=14123
14
sbin/rpc.lockd/Makefile
Normal file
14
sbin/rpc.lockd/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
# $Id$
|
||||
|
||||
PROG = rpc.lockd
|
||||
SRCS = lockd.c procs.c
|
||||
MAN8 = rpc.lockd.8
|
||||
|
||||
DPADD= ${LIBRPCSVC}
|
||||
LDADD= -lrpcsvc
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
||||
test: test.c
|
||||
cc -o test test.c -lrpcsvc
|
||||
|
58
sbin/rpc.lockd/handles.c
Normal file
58
sbin/rpc.lockd/handles.c
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 1995
|
||||
* A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed for the FreeBSD project
|
||||
* 4. Neither the name of the author nor the names of any co-contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "lockd.h"
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/*
|
||||
|
||||
|
||||
* need to find all fds in use by a host and free them when host crashes
|
||||
(need not be efficient)
|
||||
|
||||
* need to find fd corresponding to <inode, device>
|
||||
|
||||
*/
|
||||
|
||||
typedef struct fdinfo
|
||||
{
|
||||
int fd; /* The file descriptor itself */
|
||||
int ref_count; /* Count of hosts using the fd - fd is */
|
||||
/* closed when this reaches zero */
|
||||
ino_t inode_no; /* The inode number of this file. */
|
||||
dev_t device; /* device on which the file lives. */
|
||||
struct fdinfo *next; /* Chain of FdInfo structures */
|
||||
struct fdinfo *prev;
|
||||
} FdInfo;
|
325
sbin/rpc.lockd/lockd.c
Normal file
325
sbin/rpc.lockd/lockd.c
Normal file
@ -0,0 +1,325 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 1995
|
||||
* A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed for the FreeBSD project
|
||||
* 4. Neither the name of the author nor the names of any co-contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* main() function for NFS lock daemon. Most of the code in this */
|
||||
/* file was generated by running rpcgen /usr/include/rpcsvc/nlm_prot.x */
|
||||
/* The actual program logic is in the file procs.c */
|
||||
|
||||
#include "lockd.h"
|
||||
|
||||
|
||||
int debug_level = 0; /* Zero means no debugging syslog() calls */
|
||||
|
||||
|
||||
static void nlm_prog_1();
|
||||
static void nlm_prog_3();
|
||||
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
SVCXPRT *transp;
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
if (strncmp(argv[1], "-d", 2))
|
||||
{
|
||||
fprintf(stderr, "Usage: rpc.lockd [-d [<debuglevel>]]\n");
|
||||
exit(1);
|
||||
}
|
||||
if (argc > 2) debug_level = atoi(argv[2]);
|
||||
else debug_level = atoi(argv[1] + 2);
|
||||
/* Ensure at least some debug if -d with no specified level */
|
||||
if (!debug_level) debug_level = 1;
|
||||
}
|
||||
|
||||
(void)pmap_unset(NLM_PROG, NLM_VERS);
|
||||
(void)pmap_unset(NLM_PROG, NLM_VERSX);
|
||||
|
||||
transp = svcudp_create(RPC_ANYSOCK);
|
||||
if (transp == NULL)
|
||||
{
|
||||
(void)fprintf(stderr, "cannot create udp service.\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!svc_register(transp, NLM_PROG, NLM_VERS, nlm_prog_1, IPPROTO_UDP))
|
||||
{
|
||||
(void)fprintf(stderr, "unable to register (NLM_PROG, NLM_VERS, udp).\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!svc_register(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, IPPROTO_UDP))
|
||||
{
|
||||
(void)fprintf(stderr, "unable to register (NLM_PROG, NLM_VERSX, udp).\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
transp = svctcp_create(RPC_ANYSOCK, 0, 0);
|
||||
if (transp == NULL)
|
||||
{
|
||||
(void)fprintf(stderr, "cannot create tcp service.\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!svc_register(transp, NLM_PROG, NLM_VERS, nlm_prog_1, IPPROTO_TCP))
|
||||
{
|
||||
(void)fprintf(stderr, "unable to register (NLM_PROG, NLM_VERS, tcp).\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!svc_register(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, IPPROTO_TCP))
|
||||
{
|
||||
(void)fprintf(stderr, "unable to register (NLM_PROG, NLM_VERSX, tcp).\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Note that it is NOT sensible to run this program from inetd - the */
|
||||
/* protocol assumes that it will run immediately at boot time. */
|
||||
daemon(0, 0);
|
||||
|
||||
openlog("rpc.lockd", 0, LOG_DAEMON);
|
||||
if (debug_level) syslog(LOG_INFO, "Starting, debug level %d", debug_level);
|
||||
else syslog(LOG_INFO, "Starting");
|
||||
|
||||
svc_run(); /* Should never return */
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
nlm_prog_1(struct svc_req *rqstp, SVCXPRT *transp)
|
||||
{
|
||||
union
|
||||
{
|
||||
struct nlm_testargs nlm_test_1_arg;
|
||||
struct nlm_lockargs nlm_lock_1_arg;
|
||||
struct nlm_cancargs nlm_cancel_1_arg;
|
||||
struct nlm_unlockargs nlm_unlock_1_arg;
|
||||
struct nlm_testargs nlm_granted_1_arg;
|
||||
struct nlm_testargs nlm_test_msg_1_arg;
|
||||
struct nlm_lockargs nlm_lock_msg_1_arg;
|
||||
struct nlm_cancargs nlm_cancel_msg_1_arg;
|
||||
struct nlm_unlockargs nlm_unlock_msg_1_arg;
|
||||
struct nlm_testargs nlm_granted_msg_1_arg;
|
||||
nlm_testres nlm_test_res_1_arg;
|
||||
nlm_res nlm_lock_res_1_arg;
|
||||
nlm_res nlm_cancel_res_1_arg;
|
||||
nlm_res nlm_unlock_res_1_arg;
|
||||
nlm_res nlm_granted_res_1_arg;
|
||||
} argument;
|
||||
char *result;
|
||||
bool_t (*xdr_argument)(), (*xdr_result)();
|
||||
char *(*local)();
|
||||
|
||||
switch (rqstp->rq_proc)
|
||||
{
|
||||
case NULLPROC:
|
||||
(void)svc_sendreply(transp, xdr_void, (char *)NULL);
|
||||
return;
|
||||
|
||||
case NLM_TEST:
|
||||
xdr_argument = xdr_nlm_testargs;
|
||||
xdr_result = xdr_nlm_testres;
|
||||
local = (char *(*)()) nlm_test_1;
|
||||
break;
|
||||
|
||||
case NLM_LOCK:
|
||||
xdr_argument = xdr_nlm_lockargs;
|
||||
xdr_result = xdr_nlm_res;
|
||||
local = (char *(*)()) nlm_lock_1;
|
||||
break;
|
||||
|
||||
case NLM_CANCEL:
|
||||
xdr_argument = xdr_nlm_cancargs;
|
||||
xdr_result = xdr_nlm_res;
|
||||
local = (char *(*)()) nlm_cancel_1;
|
||||
break;
|
||||
|
||||
case NLM_UNLOCK:
|
||||
xdr_argument = xdr_nlm_unlockargs;
|
||||
xdr_result = xdr_nlm_res;
|
||||
local = (char *(*)()) nlm_unlock_1;
|
||||
break;
|
||||
|
||||
case NLM_GRANTED:
|
||||
xdr_argument = xdr_nlm_testargs;
|
||||
xdr_result = xdr_nlm_res;
|
||||
local = (char *(*)()) nlm_granted_1;
|
||||
break;
|
||||
|
||||
case NLM_TEST_MSG:
|
||||
xdr_argument = xdr_nlm_testargs;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_test_msg_1;
|
||||
break;
|
||||
|
||||
case NLM_LOCK_MSG:
|
||||
xdr_argument = xdr_nlm_lockargs;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_lock_msg_1;
|
||||
break;
|
||||
|
||||
case NLM_CANCEL_MSG:
|
||||
xdr_argument = xdr_nlm_cancargs;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_cancel_msg_1;
|
||||
break;
|
||||
|
||||
case NLM_UNLOCK_MSG:
|
||||
xdr_argument = xdr_nlm_unlockargs;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_unlock_msg_1;
|
||||
break;
|
||||
|
||||
case NLM_GRANTED_MSG:
|
||||
xdr_argument = xdr_nlm_testargs;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_granted_msg_1;
|
||||
break;
|
||||
|
||||
case NLM_TEST_RES:
|
||||
xdr_argument = xdr_nlm_testres;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_test_res_1;
|
||||
break;
|
||||
|
||||
case NLM_LOCK_RES:
|
||||
xdr_argument = xdr_nlm_res;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_lock_res_1;
|
||||
break;
|
||||
|
||||
case NLM_CANCEL_RES:
|
||||
xdr_argument = xdr_nlm_res;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_cancel_res_1;
|
||||
break;
|
||||
|
||||
case NLM_UNLOCK_RES:
|
||||
xdr_argument = xdr_nlm_res;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_unlock_res_1;
|
||||
break;
|
||||
|
||||
case NLM_GRANTED_RES:
|
||||
xdr_argument = xdr_nlm_res;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_granted_res_1;
|
||||
break;
|
||||
|
||||
default:
|
||||
svcerr_noproc(transp);
|
||||
return;
|
||||
}
|
||||
bzero((char *)&argument, sizeof(argument));
|
||||
if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument))
|
||||
{
|
||||
syslog(LOG_ERR, "RPC received with invalid arguments");
|
||||
svcerr_decode(transp);
|
||||
return;
|
||||
}
|
||||
result = (*local)(&argument, rqstp);
|
||||
if (result != NULL && !svc_sendreply(transp, xdr_result, result))
|
||||
{
|
||||
svcerr_systemerr(transp);
|
||||
}
|
||||
if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument))
|
||||
{
|
||||
syslog(LOG_ERR, "unable to free arguments");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
nlm_prog_3(struct svc_req *rqstp, SVCXPRT *transp)
|
||||
{
|
||||
union
|
||||
{
|
||||
nlm_shareargs nlm_share_3_arg;
|
||||
nlm_shareargs nlm_unshare_3_arg;
|
||||
nlm_lockargs nlm_nm_lock_3_arg;
|
||||
nlm_notify nlm_free_all_3_arg;
|
||||
} argument;
|
||||
char *result;
|
||||
bool_t (*xdr_argument)(), (*xdr_result)();
|
||||
char *(*local)();
|
||||
|
||||
switch (rqstp->rq_proc)
|
||||
{
|
||||
case NULLPROC:
|
||||
(void)svc_sendreply(transp, xdr_void, (char *)NULL);
|
||||
return;
|
||||
|
||||
case NLM_SHARE:
|
||||
xdr_argument = xdr_nlm_shareargs;
|
||||
xdr_result = xdr_nlm_shareres;
|
||||
local = (char *(*)()) nlm_share_3;
|
||||
break;
|
||||
|
||||
case NLM_UNSHARE:
|
||||
xdr_argument = xdr_nlm_shareargs;
|
||||
xdr_result = xdr_nlm_shareres;
|
||||
local = (char *(*)()) nlm_unshare_3;
|
||||
break;
|
||||
|
||||
case NLM_NM_LOCK:
|
||||
xdr_argument = xdr_nlm_lockargs;
|
||||
xdr_result = xdr_nlm_res;
|
||||
local = (char *(*)()) nlm_nm_lock_3;
|
||||
break;
|
||||
|
||||
case NLM_FREE_ALL:
|
||||
xdr_argument = xdr_nlm_notify;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_free_all_3;
|
||||
break;
|
||||
|
||||
default:
|
||||
svcerr_noproc(transp);
|
||||
return;
|
||||
}
|
||||
bzero((char *)&argument, sizeof(argument));
|
||||
if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument))
|
||||
{
|
||||
syslog(LOG_ERR, "RPC received with invalid arguments");
|
||||
svcerr_decode(transp);
|
||||
return;
|
||||
}
|
||||
result = (*local)(&argument, rqstp);
|
||||
if (result != NULL && !svc_sendreply(transp, xdr_result, result))
|
||||
{
|
||||
svcerr_systemerr(transp);
|
||||
}
|
||||
if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument))
|
||||
{
|
||||
syslog(LOG_ERR, "unable to free arguments");
|
||||
}
|
||||
}
|
||||
|
44
sbin/rpc.lockd/lockd.h
Normal file
44
sbin/rpc.lockd/lockd.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 1995
|
||||
* A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed for the FreeBSD project
|
||||
* 4. Neither the name of the author nor the names of any co-contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <rpc/rpc.h>
|
||||
#include <syslog.h>
|
||||
#include <rpcsvc/sm_inter.h> /* protocol to talk to rpc.statd */
|
||||
#include <rpcsvc/nlm_prot.h> /* The protocol we are implementing */
|
||||
|
||||
|
||||
/* global variables ------------------------------------------------------- */
|
||||
extern int debug_level;
|
588
sbin/rpc.lockd/procs.c
Normal file
588
sbin/rpc.lockd/procs.c
Normal file
@ -0,0 +1,588 @@
|
||||
/*
|
||||
* Copyright (c) 1995
|
||||
* A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed for the FreeBSD project
|
||||
* 4. Neither the name of the author nor the names of any co-contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "lockd.h"
|
||||
|
||||
#include <sys/param.h> /* for MAXHOSTNAMELEN */
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
|
||||
#define CLIENT_CACHE_SIZE 64 /* No. of client sockets cached */
|
||||
#define CLIENT_CACHE_LIFETIME 120 /* In seconds */
|
||||
|
||||
|
||||
/* log_from_addr ----------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Log name of function called and source address
|
||||
Returns: Nothing
|
||||
Notes: Extracts the source address from the transport handle
|
||||
passed in as part of the called procedure specification
|
||||
*/
|
||||
|
||||
static void log_from_addr(char *fun_name, struct svc_req *req)
|
||||
{
|
||||
struct sockaddr_in *addr;
|
||||
struct hostent *host;
|
||||
char hostname_buf[40];
|
||||
|
||||
addr = svc_getcaller(req->rq_xprt);
|
||||
host = gethostbyaddr((char *)&(addr->sin_addr), addr->sin_len, AF_INET);
|
||||
if (host)
|
||||
{
|
||||
strncpy(hostname_buf, host->h_name, sizeof(hostname_buf));
|
||||
hostname_buf[sizeof(hostname_buf) -1] = '\0';
|
||||
}
|
||||
else /* No hostname available - print raw address */
|
||||
{
|
||||
strcpy(hostname_buf, inet_ntoa(addr->sin_addr));
|
||||
}
|
||||
|
||||
syslog(LOG_DEBUG, "%s from %s", fun_name, hostname_buf);
|
||||
}
|
||||
|
||||
|
||||
/* get_client -------------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Get a CLIENT* for making RPC calls to lockd on given host
|
||||
Returns: CLIENT* pointer, from clnt_udp_create, or NULL if error
|
||||
Notes: Creating a CLIENT* is quite expensive, involving a
|
||||
conversation with the remote portmapper to get the
|
||||
port number. Since a given client is quite likely
|
||||
to make several locking requests in succession, it is
|
||||
desirable to cache the created CLIENT*.
|
||||
|
||||
Since we are using UDP rather than TCP, there is no cost
|
||||
to the remote system in keeping these cached indefinitely.
|
||||
Unfortunately there is a snag: if the remote system
|
||||
reboots, the cached portmapper results will be invalid,
|
||||
and we will never detect this since all of the xxx_msg()
|
||||
calls return no result - we just fire off a udp packet
|
||||
and hope for the best.
|
||||
|
||||
We solve this by discarding cached values after two
|
||||
minutes, regardless of whether they have been used
|
||||
in the meanwhile (since a bad one might have been used
|
||||
plenty of times, as the host keeps retrying the request
|
||||
and we keep sending the reply back to the wrong port).
|
||||
|
||||
Given that the entries will always expire in the order
|
||||
that they were created, there is no point in a LRU
|
||||
algorithm for when the cache gets full - entries are
|
||||
always re-used in sequence.
|
||||
*/
|
||||
|
||||
static CLIENT *clnt_cache_ptr[CLIENT_CACHE_SIZE];
|
||||
static long clnt_cache_time[CLIENT_CACHE_SIZE]; /* time entry created */
|
||||
static struct in_addr clnt_cache_addr[CLIENT_CACHE_SIZE];
|
||||
static int clnt_cache_next_to_use = 0;
|
||||
|
||||
static CLIENT *get_client(struct sockaddr_in *host_addr)
|
||||
{
|
||||
CLIENT *client;
|
||||
int sock_no;
|
||||
struct timeval retry_time, time_now;
|
||||
int i;
|
||||
|
||||
gettimeofday(&time_now, NULL);
|
||||
|
||||
/* Search for the given client in the cache, zapping any expired */
|
||||
/* entries that we happen to notice in passing. */
|
||||
for (i = 0; i < CLIENT_CACHE_SIZE; i++)
|
||||
{
|
||||
client = clnt_cache_ptr[i];
|
||||
if (client &&
|
||||
((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME) < time_now.tv_sec))
|
||||
{
|
||||
/* Cache entry has expired. */
|
||||
if (debug_level > 3) syslog(LOG_DEBUG, "Expired CLIENT* in cache");
|
||||
clnt_cache_time[i] = 0L;
|
||||
clnt_destroy(client);
|
||||
clnt_cache_ptr[i] = NULL;
|
||||
client = NULL;
|
||||
}
|
||||
|
||||
if (client && !memcmp(&clnt_cache_addr[i], &host_addr->sin_addr,
|
||||
sizeof(struct in_addr)))
|
||||
{
|
||||
/* Found it! */
|
||||
if (debug_level > 3) syslog(LOG_DEBUG, "Found CLIENT* in cache");
|
||||
return (client);
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found in cache. Free the next entry if it is in use */
|
||||
if (clnt_cache_ptr[clnt_cache_next_to_use])
|
||||
{
|
||||
clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]);
|
||||
clnt_cache_ptr[clnt_cache_next_to_use] = NULL;
|
||||
}
|
||||
|
||||
/* Create the new client handle */
|
||||
|
||||
sock_no = RPC_ANYSOCK;
|
||||
retry_time.tv_sec = 5;
|
||||
retry_time.tv_usec = 0;
|
||||
host_addr->sin_port = 0; /* Force consultation with portmapper */
|
||||
client = clntudp_create(host_addr, NLM_PROG, NLM_VERS, retry_time, &sock_no);
|
||||
if (!client)
|
||||
{
|
||||
syslog(LOG_ERR, clnt_spcreateerror("clntudp_create"));
|
||||
syslog(LOG_ERR, "Unable to return result to %s",
|
||||
inet_ntoa(host_addr->sin_addr));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Success - update the cache entry */
|
||||
clnt_cache_ptr[clnt_cache_next_to_use] = client;
|
||||
clnt_cache_addr[clnt_cache_next_to_use] = host_addr->sin_addr;
|
||||
clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec;
|
||||
if (++clnt_cache_next_to_use > CLIENT_CACHE_SIZE)
|
||||
clnt_cache_next_to_use = 0;
|
||||
|
||||
/* Disable the default timeout, so we can specify our own in calls */
|
||||
/* to clnt_call(). [note that the timeout is a different concept */
|
||||
/* from the retry period set in clnt_udp_create() above.] */
|
||||
retry_time.tv_sec = -1;
|
||||
retry_time.tv_usec = -1;
|
||||
clnt_control(client, CLSET_TIMEOUT, &retry_time);
|
||||
|
||||
if (debug_level > 3) syslog(LOG_DEBUG, "Created CLIENT* for %s",
|
||||
inet_ntoa(host_addr->sin_addr));
|
||||
return client;
|
||||
}
|
||||
|
||||
|
||||
/* transmit_result --------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Transmit result for nlm_xxx_msg pseudo-RPCs
|
||||
Returns: Nothing - we have no idea if the datagram got there
|
||||
Notes: clnt_call() will always fail (with timeout) as we are
|
||||
calling it with timeout 0 as a hack to just issue a datagram
|
||||
without expecting a result
|
||||
*/
|
||||
|
||||
static void transmit_result(int opcode, nlm_res *result, struct svc_req *req)
|
||||
{
|
||||
static char dummy;
|
||||
struct sockaddr_in *addr;
|
||||
CLIENT *cli;
|
||||
int success;
|
||||
struct timeval timeo;
|
||||
|
||||
addr = svc_getcaller(req->rq_xprt);
|
||||
if (cli = get_client(addr))
|
||||
{
|
||||
timeo.tv_sec = 0; /* No timeout - not expecting response */
|
||||
timeo.tv_usec = 0;
|
||||
|
||||
success = clnt_call(cli, opcode, xdr_nlm_res, result, xdr_void,
|
||||
&dummy, timeo);
|
||||
|
||||
if (debug_level > 2) syslog(LOG_DEBUG, "clnt_call returns %d\n", success);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/*
|
||||
Functions for Unix<->Unix locking (ie. monitored locking, with rpc.statd
|
||||
involved to ensure reclaim of locks after a crash of the "stateless"
|
||||
server.
|
||||
|
||||
These all come in two flavours - nlm_xxx() and nlm_xxx_msg().
|
||||
The first are standard RPCs with argument and result.
|
||||
The nlm_xxx_msg() calls implement exactly the same functions, but
|
||||
use two pseudo-RPCs (one in each direction). These calls are NOT
|
||||
standard use of the RPC protocol in that they do not return a result
|
||||
at all (NB. this is quite different from returning a void result).
|
||||
The effect of this is to make the nlm_xxx_msg() calls simple unacknowledged
|
||||
datagrams, requiring higher-level code to perform retries.
|
||||
|
||||
Despite the disadvantages of the nlm_xxx_msg() approach (some of which
|
||||
are documented in the comments to get_client() above), this is the
|
||||
interface used by all current commercial NFS implementations
|
||||
[Solaris, SCO, AIX etc.]. This is presumed to be because these allow
|
||||
implementations to continue using the standard RPC libraries, while
|
||||
avoiding the block-until-result nature of the library interface.
|
||||
|
||||
No client implementations have been identified so far that make use
|
||||
of the true RPC version (early SunOS releases would be a likely candidate
|
||||
for testing).
|
||||
*/
|
||||
|
||||
|
||||
/* nlm_test ---------------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Test whether a specified lock would be granted if requested
|
||||
Returns: nlm_granted (or error code)
|
||||
Notes:
|
||||
*/
|
||||
|
||||
nlm_testres *nlm_test_1(nlm_testargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_testres res;
|
||||
if (debug_level) log_from_addr("nlm_test", rqstp);
|
||||
|
||||
/* Copy the cookie from the argument into the result. Note that this */
|
||||
/* is slightly hazardous, as the structure contains a pointer to a */
|
||||
/* malloc()ed buffer that will get freed by the caller. However, the */
|
||||
/* main function transmits the result before freeing the argument */
|
||||
/* so it is in fact safe. */
|
||||
res.cookie = arg->cookie;
|
||||
res.stat.stat = nlm_granted;
|
||||
return (&res);
|
||||
}
|
||||
|
||||
void *nlm_test_msg_1(nlm_testargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
nlm_testres res;
|
||||
static char dummy;
|
||||
struct sockaddr_in *addr;
|
||||
CLIENT *cli;
|
||||
int success;
|
||||
struct timeval timeo;
|
||||
|
||||
if (debug_level) log_from_addr("nlm_test_msg", rqstp);
|
||||
|
||||
res.cookie = arg->cookie;
|
||||
res.stat.stat = nlm_granted;
|
||||
|
||||
/* nlm_test has different result type to the other operations, so */
|
||||
/* can't use transmit_result() in this case */
|
||||
addr = svc_getcaller(rqstp->rq_xprt);
|
||||
if (cli = get_client(addr))
|
||||
{
|
||||
timeo.tv_sec = 0; /* No timeout - not expecting response */
|
||||
timeo.tv_usec = 0;
|
||||
|
||||
success = clnt_call(cli, NLM_TEST_RES, xdr_nlm_testres, &res, xdr_void,
|
||||
&dummy, timeo);
|
||||
|
||||
if (debug_level > 2) syslog(LOG_DEBUG, "clnt_call returns %d\n", success);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* nlm_lock ---------------------------------------------------------------- */
|
||||
/*
|
||||
Purposes: Establish a lock
|
||||
Returns: granted, denied or blocked
|
||||
Notes: *** grace period support missing
|
||||
*/
|
||||
|
||||
nlm_res *nlm_lock_1(nlm_lockargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_res res;
|
||||
if (debug_level) log_from_addr("nlm_lock", rqstp);
|
||||
|
||||
/* copy cookie from arg to result. See comment in nlm_test_1() */
|
||||
res.cookie = arg->cookie;
|
||||
|
||||
res.stat.stat = nlm_granted;
|
||||
return (&res);
|
||||
}
|
||||
|
||||
void *nlm_lock_msg_1(nlm_lockargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_res res;
|
||||
|
||||
if (debug_level) log_from_addr("nlm_lock_msg", rqstp);
|
||||
|
||||
res.cookie = arg->cookie;
|
||||
res.stat.stat = nlm_granted;
|
||||
transmit_result(NLM_LOCK_RES, &res, rqstp);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* nlm_cancel -------------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Cancel a blocked lock request
|
||||
Returns: granted or denied
|
||||
Notes:
|
||||
*/
|
||||
|
||||
nlm_res *nlm_cancel_1(nlm_cancargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_res res;
|
||||
if (debug_level) log_from_addr("nlm_cancel", rqstp);
|
||||
|
||||
/* copy cookie from arg to result. See comment in nlm_test_1() */
|
||||
res.cookie = arg->cookie;
|
||||
|
||||
/* Since at present we never return 'nlm_blocked', there can never be */
|
||||
/* a lock to cancel, so this call always fails. */
|
||||
res.stat.stat = nlm_denied;
|
||||
return (&res);
|
||||
}
|
||||
|
||||
void *nlm_cancel_msg_1(nlm_cancargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_res res;
|
||||
if (debug_level) log_from_addr("nlm_cancel_msg", rqstp);
|
||||
|
||||
res.cookie = arg->cookie;
|
||||
/* Since at present we never return 'nlm_blocked', there can never be */
|
||||
/* a lock to cancel, so this call always fails. */
|
||||
res.stat.stat = nlm_denied;
|
||||
transmit_result(NLM_CANCEL_RES, &res, rqstp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* nlm_unlock -------------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Release an existing lock
|
||||
Returns: Always granted, unless during grace period
|
||||
Notes: "no such lock" error condition is ignored, as the
|
||||
protocol uses unreliable UDP datagrams, and may well
|
||||
re-try an unlock that has already succeeded.
|
||||
*/
|
||||
|
||||
nlm_res *nlm_unlock_1(nlm_unlockargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_res res;
|
||||
if (debug_level) log_from_addr("nlm_unlock", rqstp);
|
||||
|
||||
res.stat.stat= nlm_granted;
|
||||
res.cookie = arg->cookie;
|
||||
|
||||
return (&res);
|
||||
}
|
||||
|
||||
void *nlm_unlock_msg_1(nlm_unlockargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_res res;
|
||||
if (debug_level) log_from_addr("nlm_unlock_msg", rqstp);
|
||||
|
||||
res.stat.stat = nlm_granted;
|
||||
res.cookie = arg->cookie;
|
||||
|
||||
transmit_result(NLM_UNLOCK_RES, &res, rqstp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/*
|
||||
Client-side pseudo-RPCs for results. Note that for the client there
|
||||
are only nlm_xxx_msg() versions of each call, since the 'real RPC'
|
||||
version returns the results in the RPC result, and so the client
|
||||
does not normally receive incoming RPCs.
|
||||
|
||||
The exception to this is nlm_granted(), which is genuinely an RPC
|
||||
call from the server to the client - a 'call-back' in normal procedure
|
||||
call terms.
|
||||
*/
|
||||
|
||||
/* nlm_granted ------------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Receive notification that formerly blocked lock now granted
|
||||
Returns: always success ('granted')
|
||||
Notes:
|
||||
*/
|
||||
|
||||
nlm_res *nlm_granted_1(nlm_testargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_res res;
|
||||
if (debug_level) log_from_addr("nlm_granted", rqstp);
|
||||
|
||||
/* copy cookie from arg to result. See comment in nlm_test_1() */
|
||||
res.cookie = arg->cookie;
|
||||
|
||||
res.stat.stat = nlm_granted;
|
||||
return (&res);
|
||||
}
|
||||
|
||||
void *nlm_granted_msg_1(nlm_testargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
nlm_res res;
|
||||
if (debug_level) log_from_addr("nlm_granted_msg", rqstp);
|
||||
|
||||
res.cookie = arg->cookie;
|
||||
res.stat.stat = nlm_granted;
|
||||
transmit_result(NLM_GRANTED_RES, &res, rqstp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* nlm_test_res ------------------------------------------------------------ */
|
||||
/*
|
||||
Purpose: Accept result from earlier nlm_test_msg() call
|
||||
Returns: Nothing
|
||||
*/
|
||||
|
||||
void *nlm_test_res_1(nlm_testres *arg, struct svc_req *rqstp)
|
||||
{
|
||||
if (debug_level) log_from_addr("nlm_test_res", rqstp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* nlm_lock_res ------------------------------------------------------------ */
|
||||
/*
|
||||
Purpose: Accept result from earlier nlm_lock_msg() call
|
||||
Returns: Nothing
|
||||
*/
|
||||
|
||||
void *nlm_lock_res_1(nlm_res *arg, struct svc_req *rqstp)
|
||||
{
|
||||
if (debug_level) log_from_addr("nlm_lock_res", rqstp);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* nlm_cancel_res ---------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Accept result from earlier nlm_cancel_msg() call
|
||||
Returns: Nothing
|
||||
*/
|
||||
|
||||
void *nlm_cancel_res_1(nlm_res *arg, struct svc_req *rqstp)
|
||||
{
|
||||
if (debug_level) log_from_addr("nlm_cancel_res", rqstp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* nlm_unlock_res ---------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Accept result from earlier nlm_unlock_msg() call
|
||||
Returns: Nothing
|
||||
*/
|
||||
|
||||
void *nlm_unlock_res_1(nlm_res *arg, struct svc_req *rqstp)
|
||||
{
|
||||
if (debug_level) log_from_addr("nlm_unlock_res", rqstp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* nlm_granted_res --------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Accept result from earlier nlm_granted_msg() call
|
||||
Returns: Nothing
|
||||
*/
|
||||
|
||||
void *nlm_granted_res_1(nlm_res *arg, struct svc_req *rqstp)
|
||||
{
|
||||
if (debug_level) log_from_addr("nlm_granted_res", rqstp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/*
|
||||
Calls for PCNFS locking (aka non-monitored locking, no involvement
|
||||
of rpc.statd).
|
||||
|
||||
These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
|
||||
*/
|
||||
|
||||
|
||||
/* nlm_share --------------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Establish a DOS-style lock
|
||||
Returns: success or failure
|
||||
Notes: Blocking locks are not supported - client is expected
|
||||
to retry if required.
|
||||
*/
|
||||
|
||||
nlm_shareres *nlm_share_3(nlm_shareargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_shareres res;
|
||||
if (debug_level) log_from_addr("nlm_share", rqstp);
|
||||
|
||||
res.cookie = arg->cookie;
|
||||
res.stat = nlm_granted;
|
||||
res.sequence = 1234356; /* X/Open says this field is ignored? */
|
||||
return (&res);
|
||||
}
|
||||
|
||||
/* nlm_unshare ------------------------------------------------------------ */
|
||||
/*
|
||||
Purpose: Release a DOS-style lock
|
||||
Returns: nlm_granted, unless in grace period
|
||||
Notes:
|
||||
*/
|
||||
|
||||
nlm_shareres *nlm_unshare_3(nlm_shareargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_shareres res;
|
||||
if (debug_level) log_from_addr("nlm_unshare", rqstp);
|
||||
|
||||
res.cookie = arg->cookie;
|
||||
res.stat = nlm_granted;
|
||||
res.sequence = 1234356; /* X/Open says this field is ignored? */
|
||||
return (&res);
|
||||
}
|
||||
|
||||
/* nlm_nm_lock ------------------------------------------------------------ */
|
||||
/*
|
||||
Purpose: non-monitored version of nlm_lock()
|
||||
Returns: as for nlm_lock()
|
||||
Notes: These locks are in the same style as the standard nlm_lock,
|
||||
but the rpc.statd should not be called to establish a
|
||||
monitor for the client machine, since that machine is
|
||||
declared not to be running a rpc.statd, and so would not
|
||||
respond to the statd protocol.
|
||||
*/
|
||||
|
||||
nlm_res *nlm_nm_lock_3(nlm_lockargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_res res;
|
||||
if (debug_level) log_from_addr("nlm_nm_lock", rqstp);
|
||||
|
||||
/* copy cookie from arg to result. See comment in nlm_test_1() */
|
||||
res.cookie = arg->cookie;
|
||||
res.stat.stat = nlm_granted;
|
||||
return (&res);
|
||||
}
|
||||
|
||||
/* nlm_free_all ------------------------------------------------------------ */
|
||||
/*
|
||||
Purpose: Release all locks held by a named client
|
||||
Returns: Nothing
|
||||
Notes: Potential denial of service security problem here - the
|
||||
locks to be released are specified by a host name, independent
|
||||
of the address from which the request has arrived.
|
||||
Should probably be rejected if the named host has been
|
||||
using monitored locks.
|
||||
*/
|
||||
|
||||
void *nlm_free_all_3(nlm_notify *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static char dummy;
|
||||
|
||||
if (debug_level) log_from_addr("nlm_free_all", rqstp);
|
||||
return (&dummy);
|
||||
}
|
||||
|
||||
|
94
sbin/rpc.lockd/rpc.lockd.8
Normal file
94
sbin/rpc.lockd/rpc.lockd.8
Normal file
@ -0,0 +1,94 @@
|
||||
.\" -*- nroff -*-
|
||||
.\"
|
||||
.\" Copyright (c) 1995 A.R.Gordon, andrew.gordon@net-tel.co.uk
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\"
|
||||
.Dd September 24, 1995
|
||||
.Dt RPC.LOCK 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm rpc.lock
|
||||
.Nd NFS file locking daemon
|
||||
.Sh SYNOPSIS
|
||||
.Nm /sbin/rpc.lockd
|
||||
.Op Fl d Op Ar debug_level
|
||||
.Sh DESCRIPTION
|
||||
.Nm rpc.rstatd
|
||||
is a daemon which provides file- and record-locking services in an NFS
|
||||
environment.
|
||||
.Pp
|
||||
Options and operands available for
|
||||
.Nm rpc.lockd :
|
||||
.Bl -tag -width Ds
|
||||
.It Fl d
|
||||
The
|
||||
.Fl d
|
||||
option causes debugging information to be written to syslog, recording
|
||||
all RPC transations to the daemon. These messages are logged with level
|
||||
LOG_DEBUG and facility LOG_DAEMON. If debug_level is not specified,
|
||||
level 1 is assumed, giving one log line per protocol operation. Higher
|
||||
debug levels can be specified, causing display of operation arguments
|
||||
and internal operations of the daemon.
|
||||
.El
|
||||
.Pp
|
||||
Error conditions are logged to syslog, irrespecive of the debug level,
|
||||
using log level LOG_ERR and facility LOG_DAEMON.
|
||||
.Pp
|
||||
The
|
||||
.Nm rpc.lockd
|
||||
daemon must NOT be invoked by
|
||||
.Xr inetd 8
|
||||
because the protocol assumes that the daemon will run from system start time.
|
||||
Instead, it should be run from
|
||||
.Xr rc 8
|
||||
after the network has been started.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /usr/include/rpcsvc/nlm_prot.x -compact
|
||||
.It Pa /usr/include/rpcsvc/nlm_prot.x
|
||||
RPC protocol specification for the network lock manager protocol.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr rpc.statd 8 ,
|
||||
.Xr rc 8 ,
|
||||
.Xr syslog 3
|
||||
.Sh BUGS
|
||||
The current implementation provides only the server side of the protocol
|
||||
(ie. clients running other OS types can establish locks on a FreeBSD fileserver,
|
||||
but there is currently no means for a FreeBSD client to establish locks).
|
||||
.Pp
|
||||
Versions 1, 2 and 3 of the protocol are supported. However, only versions
|
||||
2 (Unix systems) and 3 (PC-NFS clients) seem to be in common use - the version
|
||||
1 support has not been tested due to the lack of version 1 clients against
|
||||
which to test.
|
||||
.Sh STANDARDS
|
||||
The implementation is based on the specification in X/Open CAE Specification
|
||||
C218, "Protocols for X/Open PC Interworking: XNFS, Issue 4", ISBN 1 872630 66 9
|
358
sbin/rpc.lockd/test.c
Normal file
358
sbin/rpc.lockd/test.c
Normal file
@ -0,0 +1,358 @@
|
||||
#include <rpc/rpc.h>
|
||||
#include <rpcsvc/nlm_prot.h>
|
||||
#ifndef lint
|
||||
/*static char sccsid[] = "from: @(#)nlm_prot.x 1.8 87/09/21 Copyr 1987 Sun Micro";*/
|
||||
/*static char sccsid[] = "from: * @(#)nlm_prot.x 2.1 88/08/01 4.0 RPCSRC";*/
|
||||
static char rcsid[] = "nlm_prot.x,v 1.1 1994/08/04 19:01:48 wollman Exp";
|
||||
#endif /* not lint */
|
||||
|
||||
/* Default timeout can be changed using clnt_control() */
|
||||
static struct timeval TIMEOUT = { 0, 0 };
|
||||
|
||||
nlm_testres *
|
||||
nlm_test_1(argp, clnt)
|
||||
struct nlm_testargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static nlm_testres res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_TEST, xdr_nlm_testargs, argp, xdr_nlm_testres, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return (&res);
|
||||
}
|
||||
|
||||
|
||||
nlm_res *
|
||||
nlm_lock_1(argp, clnt)
|
||||
struct nlm_lockargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
enum clnt_stat st;
|
||||
static nlm_res res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (st = clnt_call(clnt, NLM_LOCK, xdr_nlm_lockargs, argp, xdr_nlm_res, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
printf("clnt_call returns %d\n", st);
|
||||
clnt_perror(clnt, "humbug");
|
||||
return (NULL);
|
||||
}
|
||||
return (&res);
|
||||
}
|
||||
|
||||
|
||||
nlm_res *
|
||||
nlm_cancel_1(argp, clnt)
|
||||
struct nlm_cancargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static nlm_res res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_CANCEL, xdr_nlm_cancargs, argp, xdr_nlm_res, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return (&res);
|
||||
}
|
||||
|
||||
|
||||
nlm_res *
|
||||
nlm_unlock_1(argp, clnt)
|
||||
struct nlm_unlockargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static nlm_res res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_UNLOCK, xdr_nlm_unlockargs, argp, xdr_nlm_res, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return (&res);
|
||||
}
|
||||
|
||||
|
||||
nlm_res *
|
||||
nlm_granted_1(argp, clnt)
|
||||
struct nlm_testargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static nlm_res res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_GRANTED, xdr_nlm_testargs, argp, xdr_nlm_res, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return (&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_test_msg_1(argp, clnt)
|
||||
struct nlm_testargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_TEST_MSG, xdr_nlm_testargs, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_lock_msg_1(argp, clnt)
|
||||
struct nlm_lockargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_LOCK_MSG, xdr_nlm_lockargs, argp, xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
|
||||
clnt_perror(clnt, "nlm_lock_msg_1");
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_cancel_msg_1(argp, clnt)
|
||||
struct nlm_cancargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_CANCEL_MSG, xdr_nlm_cancargs, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_unlock_msg_1(argp, clnt)
|
||||
struct nlm_unlockargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_UNLOCK_MSG, xdr_nlm_unlockargs, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_granted_msg_1(argp, clnt)
|
||||
struct nlm_testargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_GRANTED_MSG, xdr_nlm_testargs, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_test_res_1(argp, clnt)
|
||||
nlm_testres *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_TEST_RES, xdr_nlm_testres, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_lock_res_1(argp, clnt)
|
||||
nlm_res *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_LOCK_RES, xdr_nlm_res, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_cancel_res_1(argp, clnt)
|
||||
nlm_res *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_CANCEL_RES, xdr_nlm_res, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_unlock_res_1(argp, clnt)
|
||||
nlm_res *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_UNLOCK_RES, xdr_nlm_res, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_granted_res_1(argp, clnt)
|
||||
nlm_res *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_GRANTED_RES, xdr_nlm_res, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
nlm_shareres *
|
||||
nlm_share_3(argp, clnt)
|
||||
nlm_shareargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static nlm_shareres res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_SHARE, xdr_nlm_shareargs, argp, xdr_nlm_shareres, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return (&res);
|
||||
}
|
||||
|
||||
|
||||
nlm_shareres *
|
||||
nlm_unshare_3(argp, clnt)
|
||||
nlm_shareargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static nlm_shareres res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_UNSHARE, xdr_nlm_shareargs, argp, xdr_nlm_shareres, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return (&res);
|
||||
}
|
||||
|
||||
|
||||
nlm_res *
|
||||
nlm_nm_lock_3(argp, clnt)
|
||||
nlm_lockargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static nlm_res res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_NM_LOCK, xdr_nlm_lockargs, argp, xdr_nlm_res, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return (&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_free_all_3(argp, clnt)
|
||||
nlm_notify *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_FREE_ALL, xdr_nlm_notify, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CLIENT *cli;
|
||||
nlm_res res_block;
|
||||
nlm_res *out;
|
||||
nlm_lockargs arg;
|
||||
struct timeval tim;
|
||||
|
||||
printf("Creating client for host %s\n", argv[1]);
|
||||
cli = clnt_create(argv[1], NLM_PROG, NLM_VERS, "udp");
|
||||
if (!cli)
|
||||
{
|
||||
printf("Failed to create client\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
clnt_control(cli, CLGET_TIMEOUT, &tim);
|
||||
printf("Default timeout was %d.%d\n", tim.tv_sec, tim.tv_usec);
|
||||
tim.tv_usec = -1;
|
||||
tim.tv_sec = -1;
|
||||
clnt_control(cli, CLSET_TIMEOUT, &tim);
|
||||
|
||||
arg.cookie.n_len = 4;
|
||||
arg.cookie.n_bytes = "hello";
|
||||
arg.block = 0;
|
||||
arg.exclusive = 0;
|
||||
arg.reclaim = 0;
|
||||
arg.state = 0x1234;
|
||||
arg.alock.caller_name = "localhost";
|
||||
arg.alock.fh.n_len = 32;
|
||||
arg.alock.fh.n_bytes = "\x04\x04\x02\x00\x01\x00\x00\x00\x0c\x00\x00\x00\xff\xff\xff\xd0\x16\x00\x00\x5b\x7c\xff\xff\xff\xec\x2f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\x54\xef\xbf\xd7\x94";
|
||||
arg.alock.oh.n_len = 8;
|
||||
arg.alock.oh.n_bytes = "\x00\x00\x02\xff\xff\xff\xd3";
|
||||
arg.alock.svid = 0x5678;
|
||||
arg.alock.l_offset = 0;
|
||||
arg.alock.l_len = 100;
|
||||
|
||||
res_block.stat.stat = nlm_granted;
|
||||
res_block.cookie.n_bytes = "hello";
|
||||
res_block.cookie.n_len = 5;
|
||||
|
||||
#if 0
|
||||
if (nlm_lock_res_1(&res_block, cli)) printf("Success!\n");
|
||||
else printf("Fail\n");
|
||||
#else
|
||||
if (out = nlm_lock_msg_1(&arg, cli))
|
||||
{
|
||||
printf("Success!\n");
|
||||
printf("out->stat = %d", out->stat);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Fail\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
14
usr.sbin/rpc.lockd/Makefile
Normal file
14
usr.sbin/rpc.lockd/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
# $Id$
|
||||
|
||||
PROG = rpc.lockd
|
||||
SRCS = lockd.c procs.c
|
||||
MAN8 = rpc.lockd.8
|
||||
|
||||
DPADD= ${LIBRPCSVC}
|
||||
LDADD= -lrpcsvc
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
||||
test: test.c
|
||||
cc -o test test.c -lrpcsvc
|
||||
|
58
usr.sbin/rpc.lockd/handles.c
Normal file
58
usr.sbin/rpc.lockd/handles.c
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 1995
|
||||
* A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed for the FreeBSD project
|
||||
* 4. Neither the name of the author nor the names of any co-contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "lockd.h"
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/*
|
||||
|
||||
|
||||
* need to find all fds in use by a host and free them when host crashes
|
||||
(need not be efficient)
|
||||
|
||||
* need to find fd corresponding to <inode, device>
|
||||
|
||||
*/
|
||||
|
||||
typedef struct fdinfo
|
||||
{
|
||||
int fd; /* The file descriptor itself */
|
||||
int ref_count; /* Count of hosts using the fd - fd is */
|
||||
/* closed when this reaches zero */
|
||||
ino_t inode_no; /* The inode number of this file. */
|
||||
dev_t device; /* device on which the file lives. */
|
||||
struct fdinfo *next; /* Chain of FdInfo structures */
|
||||
struct fdinfo *prev;
|
||||
} FdInfo;
|
325
usr.sbin/rpc.lockd/lockd.c
Normal file
325
usr.sbin/rpc.lockd/lockd.c
Normal file
@ -0,0 +1,325 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 1995
|
||||
* A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed for the FreeBSD project
|
||||
* 4. Neither the name of the author nor the names of any co-contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* main() function for NFS lock daemon. Most of the code in this */
|
||||
/* file was generated by running rpcgen /usr/include/rpcsvc/nlm_prot.x */
|
||||
/* The actual program logic is in the file procs.c */
|
||||
|
||||
#include "lockd.h"
|
||||
|
||||
|
||||
int debug_level = 0; /* Zero means no debugging syslog() calls */
|
||||
|
||||
|
||||
static void nlm_prog_1();
|
||||
static void nlm_prog_3();
|
||||
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
SVCXPRT *transp;
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
if (strncmp(argv[1], "-d", 2))
|
||||
{
|
||||
fprintf(stderr, "Usage: rpc.lockd [-d [<debuglevel>]]\n");
|
||||
exit(1);
|
||||
}
|
||||
if (argc > 2) debug_level = atoi(argv[2]);
|
||||
else debug_level = atoi(argv[1] + 2);
|
||||
/* Ensure at least some debug if -d with no specified level */
|
||||
if (!debug_level) debug_level = 1;
|
||||
}
|
||||
|
||||
(void)pmap_unset(NLM_PROG, NLM_VERS);
|
||||
(void)pmap_unset(NLM_PROG, NLM_VERSX);
|
||||
|
||||
transp = svcudp_create(RPC_ANYSOCK);
|
||||
if (transp == NULL)
|
||||
{
|
||||
(void)fprintf(stderr, "cannot create udp service.\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!svc_register(transp, NLM_PROG, NLM_VERS, nlm_prog_1, IPPROTO_UDP))
|
||||
{
|
||||
(void)fprintf(stderr, "unable to register (NLM_PROG, NLM_VERS, udp).\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!svc_register(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, IPPROTO_UDP))
|
||||
{
|
||||
(void)fprintf(stderr, "unable to register (NLM_PROG, NLM_VERSX, udp).\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
transp = svctcp_create(RPC_ANYSOCK, 0, 0);
|
||||
if (transp == NULL)
|
||||
{
|
||||
(void)fprintf(stderr, "cannot create tcp service.\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!svc_register(transp, NLM_PROG, NLM_VERS, nlm_prog_1, IPPROTO_TCP))
|
||||
{
|
||||
(void)fprintf(stderr, "unable to register (NLM_PROG, NLM_VERS, tcp).\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!svc_register(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, IPPROTO_TCP))
|
||||
{
|
||||
(void)fprintf(stderr, "unable to register (NLM_PROG, NLM_VERSX, tcp).\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Note that it is NOT sensible to run this program from inetd - the */
|
||||
/* protocol assumes that it will run immediately at boot time. */
|
||||
daemon(0, 0);
|
||||
|
||||
openlog("rpc.lockd", 0, LOG_DAEMON);
|
||||
if (debug_level) syslog(LOG_INFO, "Starting, debug level %d", debug_level);
|
||||
else syslog(LOG_INFO, "Starting");
|
||||
|
||||
svc_run(); /* Should never return */
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
nlm_prog_1(struct svc_req *rqstp, SVCXPRT *transp)
|
||||
{
|
||||
union
|
||||
{
|
||||
struct nlm_testargs nlm_test_1_arg;
|
||||
struct nlm_lockargs nlm_lock_1_arg;
|
||||
struct nlm_cancargs nlm_cancel_1_arg;
|
||||
struct nlm_unlockargs nlm_unlock_1_arg;
|
||||
struct nlm_testargs nlm_granted_1_arg;
|
||||
struct nlm_testargs nlm_test_msg_1_arg;
|
||||
struct nlm_lockargs nlm_lock_msg_1_arg;
|
||||
struct nlm_cancargs nlm_cancel_msg_1_arg;
|
||||
struct nlm_unlockargs nlm_unlock_msg_1_arg;
|
||||
struct nlm_testargs nlm_granted_msg_1_arg;
|
||||
nlm_testres nlm_test_res_1_arg;
|
||||
nlm_res nlm_lock_res_1_arg;
|
||||
nlm_res nlm_cancel_res_1_arg;
|
||||
nlm_res nlm_unlock_res_1_arg;
|
||||
nlm_res nlm_granted_res_1_arg;
|
||||
} argument;
|
||||
char *result;
|
||||
bool_t (*xdr_argument)(), (*xdr_result)();
|
||||
char *(*local)();
|
||||
|
||||
switch (rqstp->rq_proc)
|
||||
{
|
||||
case NULLPROC:
|
||||
(void)svc_sendreply(transp, xdr_void, (char *)NULL);
|
||||
return;
|
||||
|
||||
case NLM_TEST:
|
||||
xdr_argument = xdr_nlm_testargs;
|
||||
xdr_result = xdr_nlm_testres;
|
||||
local = (char *(*)()) nlm_test_1;
|
||||
break;
|
||||
|
||||
case NLM_LOCK:
|
||||
xdr_argument = xdr_nlm_lockargs;
|
||||
xdr_result = xdr_nlm_res;
|
||||
local = (char *(*)()) nlm_lock_1;
|
||||
break;
|
||||
|
||||
case NLM_CANCEL:
|
||||
xdr_argument = xdr_nlm_cancargs;
|
||||
xdr_result = xdr_nlm_res;
|
||||
local = (char *(*)()) nlm_cancel_1;
|
||||
break;
|
||||
|
||||
case NLM_UNLOCK:
|
||||
xdr_argument = xdr_nlm_unlockargs;
|
||||
xdr_result = xdr_nlm_res;
|
||||
local = (char *(*)()) nlm_unlock_1;
|
||||
break;
|
||||
|
||||
case NLM_GRANTED:
|
||||
xdr_argument = xdr_nlm_testargs;
|
||||
xdr_result = xdr_nlm_res;
|
||||
local = (char *(*)()) nlm_granted_1;
|
||||
break;
|
||||
|
||||
case NLM_TEST_MSG:
|
||||
xdr_argument = xdr_nlm_testargs;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_test_msg_1;
|
||||
break;
|
||||
|
||||
case NLM_LOCK_MSG:
|
||||
xdr_argument = xdr_nlm_lockargs;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_lock_msg_1;
|
||||
break;
|
||||
|
||||
case NLM_CANCEL_MSG:
|
||||
xdr_argument = xdr_nlm_cancargs;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_cancel_msg_1;
|
||||
break;
|
||||
|
||||
case NLM_UNLOCK_MSG:
|
||||
xdr_argument = xdr_nlm_unlockargs;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_unlock_msg_1;
|
||||
break;
|
||||
|
||||
case NLM_GRANTED_MSG:
|
||||
xdr_argument = xdr_nlm_testargs;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_granted_msg_1;
|
||||
break;
|
||||
|
||||
case NLM_TEST_RES:
|
||||
xdr_argument = xdr_nlm_testres;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_test_res_1;
|
||||
break;
|
||||
|
||||
case NLM_LOCK_RES:
|
||||
xdr_argument = xdr_nlm_res;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_lock_res_1;
|
||||
break;
|
||||
|
||||
case NLM_CANCEL_RES:
|
||||
xdr_argument = xdr_nlm_res;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_cancel_res_1;
|
||||
break;
|
||||
|
||||
case NLM_UNLOCK_RES:
|
||||
xdr_argument = xdr_nlm_res;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_unlock_res_1;
|
||||
break;
|
||||
|
||||
case NLM_GRANTED_RES:
|
||||
xdr_argument = xdr_nlm_res;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_granted_res_1;
|
||||
break;
|
||||
|
||||
default:
|
||||
svcerr_noproc(transp);
|
||||
return;
|
||||
}
|
||||
bzero((char *)&argument, sizeof(argument));
|
||||
if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument))
|
||||
{
|
||||
syslog(LOG_ERR, "RPC received with invalid arguments");
|
||||
svcerr_decode(transp);
|
||||
return;
|
||||
}
|
||||
result = (*local)(&argument, rqstp);
|
||||
if (result != NULL && !svc_sendreply(transp, xdr_result, result))
|
||||
{
|
||||
svcerr_systemerr(transp);
|
||||
}
|
||||
if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument))
|
||||
{
|
||||
syslog(LOG_ERR, "unable to free arguments");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
nlm_prog_3(struct svc_req *rqstp, SVCXPRT *transp)
|
||||
{
|
||||
union
|
||||
{
|
||||
nlm_shareargs nlm_share_3_arg;
|
||||
nlm_shareargs nlm_unshare_3_arg;
|
||||
nlm_lockargs nlm_nm_lock_3_arg;
|
||||
nlm_notify nlm_free_all_3_arg;
|
||||
} argument;
|
||||
char *result;
|
||||
bool_t (*xdr_argument)(), (*xdr_result)();
|
||||
char *(*local)();
|
||||
|
||||
switch (rqstp->rq_proc)
|
||||
{
|
||||
case NULLPROC:
|
||||
(void)svc_sendreply(transp, xdr_void, (char *)NULL);
|
||||
return;
|
||||
|
||||
case NLM_SHARE:
|
||||
xdr_argument = xdr_nlm_shareargs;
|
||||
xdr_result = xdr_nlm_shareres;
|
||||
local = (char *(*)()) nlm_share_3;
|
||||
break;
|
||||
|
||||
case NLM_UNSHARE:
|
||||
xdr_argument = xdr_nlm_shareargs;
|
||||
xdr_result = xdr_nlm_shareres;
|
||||
local = (char *(*)()) nlm_unshare_3;
|
||||
break;
|
||||
|
||||
case NLM_NM_LOCK:
|
||||
xdr_argument = xdr_nlm_lockargs;
|
||||
xdr_result = xdr_nlm_res;
|
||||
local = (char *(*)()) nlm_nm_lock_3;
|
||||
break;
|
||||
|
||||
case NLM_FREE_ALL:
|
||||
xdr_argument = xdr_nlm_notify;
|
||||
xdr_result = xdr_void;
|
||||
local = (char *(*)()) nlm_free_all_3;
|
||||
break;
|
||||
|
||||
default:
|
||||
svcerr_noproc(transp);
|
||||
return;
|
||||
}
|
||||
bzero((char *)&argument, sizeof(argument));
|
||||
if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument))
|
||||
{
|
||||
syslog(LOG_ERR, "RPC received with invalid arguments");
|
||||
svcerr_decode(transp);
|
||||
return;
|
||||
}
|
||||
result = (*local)(&argument, rqstp);
|
||||
if (result != NULL && !svc_sendreply(transp, xdr_result, result))
|
||||
{
|
||||
svcerr_systemerr(transp);
|
||||
}
|
||||
if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument))
|
||||
{
|
||||
syslog(LOG_ERR, "unable to free arguments");
|
||||
}
|
||||
}
|
||||
|
44
usr.sbin/rpc.lockd/lockd.h
Normal file
44
usr.sbin/rpc.lockd/lockd.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 1995
|
||||
* A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed for the FreeBSD project
|
||||
* 4. Neither the name of the author nor the names of any co-contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <rpc/rpc.h>
|
||||
#include <syslog.h>
|
||||
#include <rpcsvc/sm_inter.h> /* protocol to talk to rpc.statd */
|
||||
#include <rpcsvc/nlm_prot.h> /* The protocol we are implementing */
|
||||
|
||||
|
||||
/* global variables ------------------------------------------------------- */
|
||||
extern int debug_level;
|
588
usr.sbin/rpc.lockd/procs.c
Normal file
588
usr.sbin/rpc.lockd/procs.c
Normal file
@ -0,0 +1,588 @@
|
||||
/*
|
||||
* Copyright (c) 1995
|
||||
* A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed for the FreeBSD project
|
||||
* 4. Neither the name of the author nor the names of any co-contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "lockd.h"
|
||||
|
||||
#include <sys/param.h> /* for MAXHOSTNAMELEN */
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
|
||||
#define CLIENT_CACHE_SIZE 64 /* No. of client sockets cached */
|
||||
#define CLIENT_CACHE_LIFETIME 120 /* In seconds */
|
||||
|
||||
|
||||
/* log_from_addr ----------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Log name of function called and source address
|
||||
Returns: Nothing
|
||||
Notes: Extracts the source address from the transport handle
|
||||
passed in as part of the called procedure specification
|
||||
*/
|
||||
|
||||
static void log_from_addr(char *fun_name, struct svc_req *req)
|
||||
{
|
||||
struct sockaddr_in *addr;
|
||||
struct hostent *host;
|
||||
char hostname_buf[40];
|
||||
|
||||
addr = svc_getcaller(req->rq_xprt);
|
||||
host = gethostbyaddr((char *)&(addr->sin_addr), addr->sin_len, AF_INET);
|
||||
if (host)
|
||||
{
|
||||
strncpy(hostname_buf, host->h_name, sizeof(hostname_buf));
|
||||
hostname_buf[sizeof(hostname_buf) -1] = '\0';
|
||||
}
|
||||
else /* No hostname available - print raw address */
|
||||
{
|
||||
strcpy(hostname_buf, inet_ntoa(addr->sin_addr));
|
||||
}
|
||||
|
||||
syslog(LOG_DEBUG, "%s from %s", fun_name, hostname_buf);
|
||||
}
|
||||
|
||||
|
||||
/* get_client -------------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Get a CLIENT* for making RPC calls to lockd on given host
|
||||
Returns: CLIENT* pointer, from clnt_udp_create, or NULL if error
|
||||
Notes: Creating a CLIENT* is quite expensive, involving a
|
||||
conversation with the remote portmapper to get the
|
||||
port number. Since a given client is quite likely
|
||||
to make several locking requests in succession, it is
|
||||
desirable to cache the created CLIENT*.
|
||||
|
||||
Since we are using UDP rather than TCP, there is no cost
|
||||
to the remote system in keeping these cached indefinitely.
|
||||
Unfortunately there is a snag: if the remote system
|
||||
reboots, the cached portmapper results will be invalid,
|
||||
and we will never detect this since all of the xxx_msg()
|
||||
calls return no result - we just fire off a udp packet
|
||||
and hope for the best.
|
||||
|
||||
We solve this by discarding cached values after two
|
||||
minutes, regardless of whether they have been used
|
||||
in the meanwhile (since a bad one might have been used
|
||||
plenty of times, as the host keeps retrying the request
|
||||
and we keep sending the reply back to the wrong port).
|
||||
|
||||
Given that the entries will always expire in the order
|
||||
that they were created, there is no point in a LRU
|
||||
algorithm for when the cache gets full - entries are
|
||||
always re-used in sequence.
|
||||
*/
|
||||
|
||||
static CLIENT *clnt_cache_ptr[CLIENT_CACHE_SIZE];
|
||||
static long clnt_cache_time[CLIENT_CACHE_SIZE]; /* time entry created */
|
||||
static struct in_addr clnt_cache_addr[CLIENT_CACHE_SIZE];
|
||||
static int clnt_cache_next_to_use = 0;
|
||||
|
||||
static CLIENT *get_client(struct sockaddr_in *host_addr)
|
||||
{
|
||||
CLIENT *client;
|
||||
int sock_no;
|
||||
struct timeval retry_time, time_now;
|
||||
int i;
|
||||
|
||||
gettimeofday(&time_now, NULL);
|
||||
|
||||
/* Search for the given client in the cache, zapping any expired */
|
||||
/* entries that we happen to notice in passing. */
|
||||
for (i = 0; i < CLIENT_CACHE_SIZE; i++)
|
||||
{
|
||||
client = clnt_cache_ptr[i];
|
||||
if (client &&
|
||||
((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME) < time_now.tv_sec))
|
||||
{
|
||||
/* Cache entry has expired. */
|
||||
if (debug_level > 3) syslog(LOG_DEBUG, "Expired CLIENT* in cache");
|
||||
clnt_cache_time[i] = 0L;
|
||||
clnt_destroy(client);
|
||||
clnt_cache_ptr[i] = NULL;
|
||||
client = NULL;
|
||||
}
|
||||
|
||||
if (client && !memcmp(&clnt_cache_addr[i], &host_addr->sin_addr,
|
||||
sizeof(struct in_addr)))
|
||||
{
|
||||
/* Found it! */
|
||||
if (debug_level > 3) syslog(LOG_DEBUG, "Found CLIENT* in cache");
|
||||
return (client);
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found in cache. Free the next entry if it is in use */
|
||||
if (clnt_cache_ptr[clnt_cache_next_to_use])
|
||||
{
|
||||
clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]);
|
||||
clnt_cache_ptr[clnt_cache_next_to_use] = NULL;
|
||||
}
|
||||
|
||||
/* Create the new client handle */
|
||||
|
||||
sock_no = RPC_ANYSOCK;
|
||||
retry_time.tv_sec = 5;
|
||||
retry_time.tv_usec = 0;
|
||||
host_addr->sin_port = 0; /* Force consultation with portmapper */
|
||||
client = clntudp_create(host_addr, NLM_PROG, NLM_VERS, retry_time, &sock_no);
|
||||
if (!client)
|
||||
{
|
||||
syslog(LOG_ERR, clnt_spcreateerror("clntudp_create"));
|
||||
syslog(LOG_ERR, "Unable to return result to %s",
|
||||
inet_ntoa(host_addr->sin_addr));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Success - update the cache entry */
|
||||
clnt_cache_ptr[clnt_cache_next_to_use] = client;
|
||||
clnt_cache_addr[clnt_cache_next_to_use] = host_addr->sin_addr;
|
||||
clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec;
|
||||
if (++clnt_cache_next_to_use > CLIENT_CACHE_SIZE)
|
||||
clnt_cache_next_to_use = 0;
|
||||
|
||||
/* Disable the default timeout, so we can specify our own in calls */
|
||||
/* to clnt_call(). [note that the timeout is a different concept */
|
||||
/* from the retry period set in clnt_udp_create() above.] */
|
||||
retry_time.tv_sec = -1;
|
||||
retry_time.tv_usec = -1;
|
||||
clnt_control(client, CLSET_TIMEOUT, &retry_time);
|
||||
|
||||
if (debug_level > 3) syslog(LOG_DEBUG, "Created CLIENT* for %s",
|
||||
inet_ntoa(host_addr->sin_addr));
|
||||
return client;
|
||||
}
|
||||
|
||||
|
||||
/* transmit_result --------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Transmit result for nlm_xxx_msg pseudo-RPCs
|
||||
Returns: Nothing - we have no idea if the datagram got there
|
||||
Notes: clnt_call() will always fail (with timeout) as we are
|
||||
calling it with timeout 0 as a hack to just issue a datagram
|
||||
without expecting a result
|
||||
*/
|
||||
|
||||
static void transmit_result(int opcode, nlm_res *result, struct svc_req *req)
|
||||
{
|
||||
static char dummy;
|
||||
struct sockaddr_in *addr;
|
||||
CLIENT *cli;
|
||||
int success;
|
||||
struct timeval timeo;
|
||||
|
||||
addr = svc_getcaller(req->rq_xprt);
|
||||
if (cli = get_client(addr))
|
||||
{
|
||||
timeo.tv_sec = 0; /* No timeout - not expecting response */
|
||||
timeo.tv_usec = 0;
|
||||
|
||||
success = clnt_call(cli, opcode, xdr_nlm_res, result, xdr_void,
|
||||
&dummy, timeo);
|
||||
|
||||
if (debug_level > 2) syslog(LOG_DEBUG, "clnt_call returns %d\n", success);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/*
|
||||
Functions for Unix<->Unix locking (ie. monitored locking, with rpc.statd
|
||||
involved to ensure reclaim of locks after a crash of the "stateless"
|
||||
server.
|
||||
|
||||
These all come in two flavours - nlm_xxx() and nlm_xxx_msg().
|
||||
The first are standard RPCs with argument and result.
|
||||
The nlm_xxx_msg() calls implement exactly the same functions, but
|
||||
use two pseudo-RPCs (one in each direction). These calls are NOT
|
||||
standard use of the RPC protocol in that they do not return a result
|
||||
at all (NB. this is quite different from returning a void result).
|
||||
The effect of this is to make the nlm_xxx_msg() calls simple unacknowledged
|
||||
datagrams, requiring higher-level code to perform retries.
|
||||
|
||||
Despite the disadvantages of the nlm_xxx_msg() approach (some of which
|
||||
are documented in the comments to get_client() above), this is the
|
||||
interface used by all current commercial NFS implementations
|
||||
[Solaris, SCO, AIX etc.]. This is presumed to be because these allow
|
||||
implementations to continue using the standard RPC libraries, while
|
||||
avoiding the block-until-result nature of the library interface.
|
||||
|
||||
No client implementations have been identified so far that make use
|
||||
of the true RPC version (early SunOS releases would be a likely candidate
|
||||
for testing).
|
||||
*/
|
||||
|
||||
|
||||
/* nlm_test ---------------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Test whether a specified lock would be granted if requested
|
||||
Returns: nlm_granted (or error code)
|
||||
Notes:
|
||||
*/
|
||||
|
||||
nlm_testres *nlm_test_1(nlm_testargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_testres res;
|
||||
if (debug_level) log_from_addr("nlm_test", rqstp);
|
||||
|
||||
/* Copy the cookie from the argument into the result. Note that this */
|
||||
/* is slightly hazardous, as the structure contains a pointer to a */
|
||||
/* malloc()ed buffer that will get freed by the caller. However, the */
|
||||
/* main function transmits the result before freeing the argument */
|
||||
/* so it is in fact safe. */
|
||||
res.cookie = arg->cookie;
|
||||
res.stat.stat = nlm_granted;
|
||||
return (&res);
|
||||
}
|
||||
|
||||
void *nlm_test_msg_1(nlm_testargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
nlm_testres res;
|
||||
static char dummy;
|
||||
struct sockaddr_in *addr;
|
||||
CLIENT *cli;
|
||||
int success;
|
||||
struct timeval timeo;
|
||||
|
||||
if (debug_level) log_from_addr("nlm_test_msg", rqstp);
|
||||
|
||||
res.cookie = arg->cookie;
|
||||
res.stat.stat = nlm_granted;
|
||||
|
||||
/* nlm_test has different result type to the other operations, so */
|
||||
/* can't use transmit_result() in this case */
|
||||
addr = svc_getcaller(rqstp->rq_xprt);
|
||||
if (cli = get_client(addr))
|
||||
{
|
||||
timeo.tv_sec = 0; /* No timeout - not expecting response */
|
||||
timeo.tv_usec = 0;
|
||||
|
||||
success = clnt_call(cli, NLM_TEST_RES, xdr_nlm_testres, &res, xdr_void,
|
||||
&dummy, timeo);
|
||||
|
||||
if (debug_level > 2) syslog(LOG_DEBUG, "clnt_call returns %d\n", success);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* nlm_lock ---------------------------------------------------------------- */
|
||||
/*
|
||||
Purposes: Establish a lock
|
||||
Returns: granted, denied or blocked
|
||||
Notes: *** grace period support missing
|
||||
*/
|
||||
|
||||
nlm_res *nlm_lock_1(nlm_lockargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_res res;
|
||||
if (debug_level) log_from_addr("nlm_lock", rqstp);
|
||||
|
||||
/* copy cookie from arg to result. See comment in nlm_test_1() */
|
||||
res.cookie = arg->cookie;
|
||||
|
||||
res.stat.stat = nlm_granted;
|
||||
return (&res);
|
||||
}
|
||||
|
||||
void *nlm_lock_msg_1(nlm_lockargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_res res;
|
||||
|
||||
if (debug_level) log_from_addr("nlm_lock_msg", rqstp);
|
||||
|
||||
res.cookie = arg->cookie;
|
||||
res.stat.stat = nlm_granted;
|
||||
transmit_result(NLM_LOCK_RES, &res, rqstp);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* nlm_cancel -------------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Cancel a blocked lock request
|
||||
Returns: granted or denied
|
||||
Notes:
|
||||
*/
|
||||
|
||||
nlm_res *nlm_cancel_1(nlm_cancargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_res res;
|
||||
if (debug_level) log_from_addr("nlm_cancel", rqstp);
|
||||
|
||||
/* copy cookie from arg to result. See comment in nlm_test_1() */
|
||||
res.cookie = arg->cookie;
|
||||
|
||||
/* Since at present we never return 'nlm_blocked', there can never be */
|
||||
/* a lock to cancel, so this call always fails. */
|
||||
res.stat.stat = nlm_denied;
|
||||
return (&res);
|
||||
}
|
||||
|
||||
void *nlm_cancel_msg_1(nlm_cancargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_res res;
|
||||
if (debug_level) log_from_addr("nlm_cancel_msg", rqstp);
|
||||
|
||||
res.cookie = arg->cookie;
|
||||
/* Since at present we never return 'nlm_blocked', there can never be */
|
||||
/* a lock to cancel, so this call always fails. */
|
||||
res.stat.stat = nlm_denied;
|
||||
transmit_result(NLM_CANCEL_RES, &res, rqstp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* nlm_unlock -------------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Release an existing lock
|
||||
Returns: Always granted, unless during grace period
|
||||
Notes: "no such lock" error condition is ignored, as the
|
||||
protocol uses unreliable UDP datagrams, and may well
|
||||
re-try an unlock that has already succeeded.
|
||||
*/
|
||||
|
||||
nlm_res *nlm_unlock_1(nlm_unlockargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_res res;
|
||||
if (debug_level) log_from_addr("nlm_unlock", rqstp);
|
||||
|
||||
res.stat.stat= nlm_granted;
|
||||
res.cookie = arg->cookie;
|
||||
|
||||
return (&res);
|
||||
}
|
||||
|
||||
void *nlm_unlock_msg_1(nlm_unlockargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_res res;
|
||||
if (debug_level) log_from_addr("nlm_unlock_msg", rqstp);
|
||||
|
||||
res.stat.stat = nlm_granted;
|
||||
res.cookie = arg->cookie;
|
||||
|
||||
transmit_result(NLM_UNLOCK_RES, &res, rqstp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/*
|
||||
Client-side pseudo-RPCs for results. Note that for the client there
|
||||
are only nlm_xxx_msg() versions of each call, since the 'real RPC'
|
||||
version returns the results in the RPC result, and so the client
|
||||
does not normally receive incoming RPCs.
|
||||
|
||||
The exception to this is nlm_granted(), which is genuinely an RPC
|
||||
call from the server to the client - a 'call-back' in normal procedure
|
||||
call terms.
|
||||
*/
|
||||
|
||||
/* nlm_granted ------------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Receive notification that formerly blocked lock now granted
|
||||
Returns: always success ('granted')
|
||||
Notes:
|
||||
*/
|
||||
|
||||
nlm_res *nlm_granted_1(nlm_testargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_res res;
|
||||
if (debug_level) log_from_addr("nlm_granted", rqstp);
|
||||
|
||||
/* copy cookie from arg to result. See comment in nlm_test_1() */
|
||||
res.cookie = arg->cookie;
|
||||
|
||||
res.stat.stat = nlm_granted;
|
||||
return (&res);
|
||||
}
|
||||
|
||||
void *nlm_granted_msg_1(nlm_testargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
nlm_res res;
|
||||
if (debug_level) log_from_addr("nlm_granted_msg", rqstp);
|
||||
|
||||
res.cookie = arg->cookie;
|
||||
res.stat.stat = nlm_granted;
|
||||
transmit_result(NLM_GRANTED_RES, &res, rqstp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* nlm_test_res ------------------------------------------------------------ */
|
||||
/*
|
||||
Purpose: Accept result from earlier nlm_test_msg() call
|
||||
Returns: Nothing
|
||||
*/
|
||||
|
||||
void *nlm_test_res_1(nlm_testres *arg, struct svc_req *rqstp)
|
||||
{
|
||||
if (debug_level) log_from_addr("nlm_test_res", rqstp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* nlm_lock_res ------------------------------------------------------------ */
|
||||
/*
|
||||
Purpose: Accept result from earlier nlm_lock_msg() call
|
||||
Returns: Nothing
|
||||
*/
|
||||
|
||||
void *nlm_lock_res_1(nlm_res *arg, struct svc_req *rqstp)
|
||||
{
|
||||
if (debug_level) log_from_addr("nlm_lock_res", rqstp);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* nlm_cancel_res ---------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Accept result from earlier nlm_cancel_msg() call
|
||||
Returns: Nothing
|
||||
*/
|
||||
|
||||
void *nlm_cancel_res_1(nlm_res *arg, struct svc_req *rqstp)
|
||||
{
|
||||
if (debug_level) log_from_addr("nlm_cancel_res", rqstp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* nlm_unlock_res ---------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Accept result from earlier nlm_unlock_msg() call
|
||||
Returns: Nothing
|
||||
*/
|
||||
|
||||
void *nlm_unlock_res_1(nlm_res *arg, struct svc_req *rqstp)
|
||||
{
|
||||
if (debug_level) log_from_addr("nlm_unlock_res", rqstp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* nlm_granted_res --------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Accept result from earlier nlm_granted_msg() call
|
||||
Returns: Nothing
|
||||
*/
|
||||
|
||||
void *nlm_granted_res_1(nlm_res *arg, struct svc_req *rqstp)
|
||||
{
|
||||
if (debug_level) log_from_addr("nlm_granted_res", rqstp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/*
|
||||
Calls for PCNFS locking (aka non-monitored locking, no involvement
|
||||
of rpc.statd).
|
||||
|
||||
These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
|
||||
*/
|
||||
|
||||
|
||||
/* nlm_share --------------------------------------------------------------- */
|
||||
/*
|
||||
Purpose: Establish a DOS-style lock
|
||||
Returns: success or failure
|
||||
Notes: Blocking locks are not supported - client is expected
|
||||
to retry if required.
|
||||
*/
|
||||
|
||||
nlm_shareres *nlm_share_3(nlm_shareargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_shareres res;
|
||||
if (debug_level) log_from_addr("nlm_share", rqstp);
|
||||
|
||||
res.cookie = arg->cookie;
|
||||
res.stat = nlm_granted;
|
||||
res.sequence = 1234356; /* X/Open says this field is ignored? */
|
||||
return (&res);
|
||||
}
|
||||
|
||||
/* nlm_unshare ------------------------------------------------------------ */
|
||||
/*
|
||||
Purpose: Release a DOS-style lock
|
||||
Returns: nlm_granted, unless in grace period
|
||||
Notes:
|
||||
*/
|
||||
|
||||
nlm_shareres *nlm_unshare_3(nlm_shareargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_shareres res;
|
||||
if (debug_level) log_from_addr("nlm_unshare", rqstp);
|
||||
|
||||
res.cookie = arg->cookie;
|
||||
res.stat = nlm_granted;
|
||||
res.sequence = 1234356; /* X/Open says this field is ignored? */
|
||||
return (&res);
|
||||
}
|
||||
|
||||
/* nlm_nm_lock ------------------------------------------------------------ */
|
||||
/*
|
||||
Purpose: non-monitored version of nlm_lock()
|
||||
Returns: as for nlm_lock()
|
||||
Notes: These locks are in the same style as the standard nlm_lock,
|
||||
but the rpc.statd should not be called to establish a
|
||||
monitor for the client machine, since that machine is
|
||||
declared not to be running a rpc.statd, and so would not
|
||||
respond to the statd protocol.
|
||||
*/
|
||||
|
||||
nlm_res *nlm_nm_lock_3(nlm_lockargs *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static nlm_res res;
|
||||
if (debug_level) log_from_addr("nlm_nm_lock", rqstp);
|
||||
|
||||
/* copy cookie from arg to result. See comment in nlm_test_1() */
|
||||
res.cookie = arg->cookie;
|
||||
res.stat.stat = nlm_granted;
|
||||
return (&res);
|
||||
}
|
||||
|
||||
/* nlm_free_all ------------------------------------------------------------ */
|
||||
/*
|
||||
Purpose: Release all locks held by a named client
|
||||
Returns: Nothing
|
||||
Notes: Potential denial of service security problem here - the
|
||||
locks to be released are specified by a host name, independent
|
||||
of the address from which the request has arrived.
|
||||
Should probably be rejected if the named host has been
|
||||
using monitored locks.
|
||||
*/
|
||||
|
||||
void *nlm_free_all_3(nlm_notify *arg, struct svc_req *rqstp)
|
||||
{
|
||||
static char dummy;
|
||||
|
||||
if (debug_level) log_from_addr("nlm_free_all", rqstp);
|
||||
return (&dummy);
|
||||
}
|
||||
|
||||
|
94
usr.sbin/rpc.lockd/rpc.lockd.8
Normal file
94
usr.sbin/rpc.lockd/rpc.lockd.8
Normal file
@ -0,0 +1,94 @@
|
||||
.\" -*- nroff -*-
|
||||
.\"
|
||||
.\" Copyright (c) 1995 A.R.Gordon, andrew.gordon@net-tel.co.uk
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the University of
|
||||
.\" California, Berkeley and its contributors.
|
||||
.\" 4. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\"
|
||||
.Dd September 24, 1995
|
||||
.Dt RPC.LOCK 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm rpc.lock
|
||||
.Nd NFS file locking daemon
|
||||
.Sh SYNOPSIS
|
||||
.Nm /sbin/rpc.lockd
|
||||
.Op Fl d Op Ar debug_level
|
||||
.Sh DESCRIPTION
|
||||
.Nm rpc.rstatd
|
||||
is a daemon which provides file- and record-locking services in an NFS
|
||||
environment.
|
||||
.Pp
|
||||
Options and operands available for
|
||||
.Nm rpc.lockd :
|
||||
.Bl -tag -width Ds
|
||||
.It Fl d
|
||||
The
|
||||
.Fl d
|
||||
option causes debugging information to be written to syslog, recording
|
||||
all RPC transations to the daemon. These messages are logged with level
|
||||
LOG_DEBUG and facility LOG_DAEMON. If debug_level is not specified,
|
||||
level 1 is assumed, giving one log line per protocol operation. Higher
|
||||
debug levels can be specified, causing display of operation arguments
|
||||
and internal operations of the daemon.
|
||||
.El
|
||||
.Pp
|
||||
Error conditions are logged to syslog, irrespecive of the debug level,
|
||||
using log level LOG_ERR and facility LOG_DAEMON.
|
||||
.Pp
|
||||
The
|
||||
.Nm rpc.lockd
|
||||
daemon must NOT be invoked by
|
||||
.Xr inetd 8
|
||||
because the protocol assumes that the daemon will run from system start time.
|
||||
Instead, it should be run from
|
||||
.Xr rc 8
|
||||
after the network has been started.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /usr/include/rpcsvc/nlm_prot.x -compact
|
||||
.It Pa /usr/include/rpcsvc/nlm_prot.x
|
||||
RPC protocol specification for the network lock manager protocol.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr rpc.statd 8 ,
|
||||
.Xr rc 8 ,
|
||||
.Xr syslog 3
|
||||
.Sh BUGS
|
||||
The current implementation provides only the server side of the protocol
|
||||
(ie. clients running other OS types can establish locks on a FreeBSD fileserver,
|
||||
but there is currently no means for a FreeBSD client to establish locks).
|
||||
.Pp
|
||||
Versions 1, 2 and 3 of the protocol are supported. However, only versions
|
||||
2 (Unix systems) and 3 (PC-NFS clients) seem to be in common use - the version
|
||||
1 support has not been tested due to the lack of version 1 clients against
|
||||
which to test.
|
||||
.Sh STANDARDS
|
||||
The implementation is based on the specification in X/Open CAE Specification
|
||||
C218, "Protocols for X/Open PC Interworking: XNFS, Issue 4", ISBN 1 872630 66 9
|
358
usr.sbin/rpc.lockd/test.c
Normal file
358
usr.sbin/rpc.lockd/test.c
Normal file
@ -0,0 +1,358 @@
|
||||
#include <rpc/rpc.h>
|
||||
#include <rpcsvc/nlm_prot.h>
|
||||
#ifndef lint
|
||||
/*static char sccsid[] = "from: @(#)nlm_prot.x 1.8 87/09/21 Copyr 1987 Sun Micro";*/
|
||||
/*static char sccsid[] = "from: * @(#)nlm_prot.x 2.1 88/08/01 4.0 RPCSRC";*/
|
||||
static char rcsid[] = "nlm_prot.x,v 1.1 1994/08/04 19:01:48 wollman Exp";
|
||||
#endif /* not lint */
|
||||
|
||||
/* Default timeout can be changed using clnt_control() */
|
||||
static struct timeval TIMEOUT = { 0, 0 };
|
||||
|
||||
nlm_testres *
|
||||
nlm_test_1(argp, clnt)
|
||||
struct nlm_testargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static nlm_testres res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_TEST, xdr_nlm_testargs, argp, xdr_nlm_testres, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return (&res);
|
||||
}
|
||||
|
||||
|
||||
nlm_res *
|
||||
nlm_lock_1(argp, clnt)
|
||||
struct nlm_lockargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
enum clnt_stat st;
|
||||
static nlm_res res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (st = clnt_call(clnt, NLM_LOCK, xdr_nlm_lockargs, argp, xdr_nlm_res, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
printf("clnt_call returns %d\n", st);
|
||||
clnt_perror(clnt, "humbug");
|
||||
return (NULL);
|
||||
}
|
||||
return (&res);
|
||||
}
|
||||
|
||||
|
||||
nlm_res *
|
||||
nlm_cancel_1(argp, clnt)
|
||||
struct nlm_cancargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static nlm_res res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_CANCEL, xdr_nlm_cancargs, argp, xdr_nlm_res, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return (&res);
|
||||
}
|
||||
|
||||
|
||||
nlm_res *
|
||||
nlm_unlock_1(argp, clnt)
|
||||
struct nlm_unlockargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static nlm_res res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_UNLOCK, xdr_nlm_unlockargs, argp, xdr_nlm_res, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return (&res);
|
||||
}
|
||||
|
||||
|
||||
nlm_res *
|
||||
nlm_granted_1(argp, clnt)
|
||||
struct nlm_testargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static nlm_res res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_GRANTED, xdr_nlm_testargs, argp, xdr_nlm_res, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return (&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_test_msg_1(argp, clnt)
|
||||
struct nlm_testargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_TEST_MSG, xdr_nlm_testargs, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_lock_msg_1(argp, clnt)
|
||||
struct nlm_lockargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_LOCK_MSG, xdr_nlm_lockargs, argp, xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
|
||||
clnt_perror(clnt, "nlm_lock_msg_1");
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_cancel_msg_1(argp, clnt)
|
||||
struct nlm_cancargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_CANCEL_MSG, xdr_nlm_cancargs, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_unlock_msg_1(argp, clnt)
|
||||
struct nlm_unlockargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_UNLOCK_MSG, xdr_nlm_unlockargs, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_granted_msg_1(argp, clnt)
|
||||
struct nlm_testargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_GRANTED_MSG, xdr_nlm_testargs, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_test_res_1(argp, clnt)
|
||||
nlm_testres *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_TEST_RES, xdr_nlm_testres, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_lock_res_1(argp, clnt)
|
||||
nlm_res *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_LOCK_RES, xdr_nlm_res, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_cancel_res_1(argp, clnt)
|
||||
nlm_res *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_CANCEL_RES, xdr_nlm_res, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_unlock_res_1(argp, clnt)
|
||||
nlm_res *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_UNLOCK_RES, xdr_nlm_res, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_granted_res_1(argp, clnt)
|
||||
nlm_res *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_GRANTED_RES, xdr_nlm_res, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
nlm_shareres *
|
||||
nlm_share_3(argp, clnt)
|
||||
nlm_shareargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static nlm_shareres res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_SHARE, xdr_nlm_shareargs, argp, xdr_nlm_shareres, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return (&res);
|
||||
}
|
||||
|
||||
|
||||
nlm_shareres *
|
||||
nlm_unshare_3(argp, clnt)
|
||||
nlm_shareargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static nlm_shareres res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_UNSHARE, xdr_nlm_shareargs, argp, xdr_nlm_shareres, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return (&res);
|
||||
}
|
||||
|
||||
|
||||
nlm_res *
|
||||
nlm_nm_lock_3(argp, clnt)
|
||||
nlm_lockargs *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static nlm_res res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_NM_LOCK, xdr_nlm_lockargs, argp, xdr_nlm_res, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return (&res);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
nlm_free_all_3(argp, clnt)
|
||||
nlm_notify *argp;
|
||||
CLIENT *clnt;
|
||||
{
|
||||
static char res;
|
||||
|
||||
bzero((char *)&res, sizeof(res));
|
||||
if (clnt_call(clnt, NLM_FREE_ALL, xdr_nlm_notify, argp, xdr_void, &res, TIMEOUT) != RPC_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
return ((void *)&res);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CLIENT *cli;
|
||||
nlm_res res_block;
|
||||
nlm_res *out;
|
||||
nlm_lockargs arg;
|
||||
struct timeval tim;
|
||||
|
||||
printf("Creating client for host %s\n", argv[1]);
|
||||
cli = clnt_create(argv[1], NLM_PROG, NLM_VERS, "udp");
|
||||
if (!cli)
|
||||
{
|
||||
printf("Failed to create client\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
clnt_control(cli, CLGET_TIMEOUT, &tim);
|
||||
printf("Default timeout was %d.%d\n", tim.tv_sec, tim.tv_usec);
|
||||
tim.tv_usec = -1;
|
||||
tim.tv_sec = -1;
|
||||
clnt_control(cli, CLSET_TIMEOUT, &tim);
|
||||
|
||||
arg.cookie.n_len = 4;
|
||||
arg.cookie.n_bytes = "hello";
|
||||
arg.block = 0;
|
||||
arg.exclusive = 0;
|
||||
arg.reclaim = 0;
|
||||
arg.state = 0x1234;
|
||||
arg.alock.caller_name = "localhost";
|
||||
arg.alock.fh.n_len = 32;
|
||||
arg.alock.fh.n_bytes = "\x04\x04\x02\x00\x01\x00\x00\x00\x0c\x00\x00\x00\xff\xff\xff\xd0\x16\x00\x00\x5b\x7c\xff\xff\xff\xec\x2f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\x54\xef\xbf\xd7\x94";
|
||||
arg.alock.oh.n_len = 8;
|
||||
arg.alock.oh.n_bytes = "\x00\x00\x02\xff\xff\xff\xd3";
|
||||
arg.alock.svid = 0x5678;
|
||||
arg.alock.l_offset = 0;
|
||||
arg.alock.l_len = 100;
|
||||
|
||||
res_block.stat.stat = nlm_granted;
|
||||
res_block.cookie.n_bytes = "hello";
|
||||
res_block.cookie.n_len = 5;
|
||||
|
||||
#if 0
|
||||
if (nlm_lock_res_1(&res_block, cli)) printf("Success!\n");
|
||||
else printf("Fail\n");
|
||||
#else
|
||||
if (out = nlm_lock_msg_1(&arg, cli))
|
||||
{
|
||||
printf("Success!\n");
|
||||
printf("out->stat = %d", out->stat);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Fail\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user