From: Apple Date: Thu, 22 Apr 2004 22:54:50 +0000 (+0000) Subject: network_cmds-176.3.1.tar.gz X-Git-Tag: mac-os-x-1034^0 X-Git-Url: https://git.saurik.com/apple/network_cmds.git/commitdiff_plain/7902cf7ebc800a8fa50568a473e718c925f2af80 network_cmds-176.3.1.tar.gz --- diff --git a/ifconfig.tproj/Makefile b/ifconfig.tproj/Makefile index 2ae172d..0f7f623 100644 --- a/ifconfig.tproj/Makefile +++ b/ifconfig.tproj/Makefile @@ -14,7 +14,7 @@ PROJECT_TYPE = Tool HFILES = ifconfig.h -CFILES = ifconfig.c ifmedia.c +CFILES = ifconfig.c ifmedia.c ifvlan.c OTHERSRCS = Makefile.preamble Makefile Makefile.dist ifconfig.8\ Makefile.postamble @@ -31,6 +31,7 @@ DEBUG_LIBS = $(LIBS) PROF_LIBS = $(LIBS) +HEADER_PATHS = -I$(NEXT_ROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc @@ -49,3 +50,4 @@ include $(MAKEFILEDIR)/$(MAKEFILE) -include Makefile.postamble -include Makefile.dependencies + diff --git a/ifconfig.tproj/Makefile.preamble b/ifconfig.tproj/Makefile.preamble index bf2aff8..7100e37 100644 --- a/ifconfig.tproj/Makefile.preamble +++ b/ifconfig.tproj/Makefile.preamble @@ -1,3 +1,3 @@ OTHER_GENERATED_OFILES = $(VERS_OFILE) -include ../Makefile.include -OTHER_CFLAGS += -DUSE_IF_MEDIA -DINET6 -DNO_IPX +OTHER_CFLAGS += -DUSE_IF_MEDIA -DINET6 -DNO_IPX -DUSE_VLANS diff --git a/ifconfig.tproj/PB.project b/ifconfig.tproj/PB.project index e699c93..e5cc832 100644 --- a/ifconfig.tproj/PB.project +++ b/ifconfig.tproj/PB.project @@ -5,7 +5,7 @@ H_FILES = (ifconfig.h); M_FILES = (); OTHER_LIBS = (); - OTHER_LINKED = (ifconfig.c, ifmedia.c); + OTHER_LINKED = (ifconfig.c, ifmedia.c, ifvlan.c); OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.dist, ifconfig.8, Makefile.postamble); PRECOMPILED_HEADERS = (); PROJECT_HEADERS = (); diff --git a/ifconfig.tproj/ifconfig.8 b/ifconfig.tproj/ifconfig.8 index 5f7828a..d9a3c35 100644 --- a/ifconfig.tproj/ifconfig.8 +++ b/ifconfig.tproj/ifconfig.8 @@ -288,7 +288,7 @@ interfaces previously configured with Create the specified network pseudo-device. If the interface is given without a unit number, try to create a new device with an arbitrary unit number. -If creation of an arbitrary device is sucessful, the new device name is +If creation of an arbitrary device is successful, the new device name is printed to standard output. .It Cm destroy Destroy the specified network pseudo-device. @@ -306,6 +306,54 @@ parameter. Included for .Tn Solaris compatibility. +.It Cm vlan Ar vlan_tag +If the interface is a vlan pseudo interface, set the vlan tag value +to +.Ar vlan_tag . +This value is a 16-bit number which is used to create an 802.1Q +vlan header for packets sent from the vlan interface. +Note that +.Cm vlan +and +.Cm vlandev +must both be set at the same time. +.It Cm vlandev Ar iface +If the interface is a vlan pseudo device, associate physical interface +.Ar iface +with it. +Packets transmitted through the vlan interface will be +diverted to the specified physical interface +.Ar iface +with 802.1Q vlan encapsulation. +Packets with 802.1Q encapsulation received +by the parent interface with the correct vlan tag will be diverted to +the associated vlan pseudo-interface. +The vlan interface is assigned a +copy of the parent interface's flags and the parent's ethernet address. +The +.Cm vlandev +and +.Cm vlan +must both be set at the same time. +If the vlan interface already has +a physical interface associated with it, this command will fail. +To +change the association to another physical interface, the existing +association must be cleared first. +.Pp +Note: if the hardware tagging capability +is set on the vlan interface, the vlan pseudo +interface's behavior changes: +the vlan interface recognizes that the +parent interface supports insertion and extraction of vlan tags on its +own (usually in firmware) and that it should pass packets to and from +the parent unaltered. +.It Fl vlandev Ar iface +If the driver is a vlan pseudo device, disassociate the physical interface +.Ar iface +from it. +This breaks the link between the vlan interface and its parent, +clears its vlan tag, flags and its link address and shuts the interface down. .It Cm metric Ar n Set the routing metric of the interface to .Ar n , diff --git a/ifconfig.tproj/ifconfig.c b/ifconfig.tproj/ifconfig.c index 6444c62..8d71e86 100644 --- a/ifconfig.tproj/ifconfig.c +++ b/ifconfig.tproj/ifconfig.c @@ -42,11 +42,13 @@ static const char copyright[] = static char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94"; #endif static const char rcsid[] = - "$Id: ifconfig.c,v 1.5 2003/07/02 01:22:29 lindak Exp $"; + "$Id: ifconfig.c,v 1.5.28.1 2004/04/14 00:27:17 lindak Exp $"; #endif /* not lint */ #include +#define KERNEL_PRIVATE #include +#undef KERNEL_PRIVATE #include #include #include @@ -86,6 +88,8 @@ static const char rcsid[] = #include #include +struct ether_addr *ether_aton __P((const char *)); + #include "ifconfig.h" /* wrapper for KAME-special getnameinfo() */ @@ -164,8 +168,10 @@ c_func2 setip6lifetime; #endif c_func setifipdst; c_func setifflags, setifmetric, setifmtu, setiflladdr; +c_func clone_destroy; +void clone_create(void); #define NEXTARG 0xffffff #define NEXTARG2 0xfffffe @@ -231,10 +237,8 @@ struct cmd { {"create", 0, clone_create }, {"plumb", 0, clone_create }, #endif -#ifndef __APPLE__ {"destroy", 0, clone_destroy }, {"unplumb", 0, clone_destroy }, -#endif #ifdef USE_IEEE80211 { "ssid", NEXTARG, set80211ssid }, { "nwid", NEXTARG, set80211ssid }, @@ -357,21 +361,21 @@ void usage() { #ifndef INET6 - fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n", - "usage: ifconfig interface address_family [address [dest_address]]", - " [parameters]", - " ifconfig interface create", - " ifconfig -a [-d] [-m] [-u] [address_family]", - " ifconfig -l [-d] [-u] [address_family]", - " ifconfig [-d] [-m] [-u]"); + fprintf(stderr, "%s", + "usage: ifconfig interface address_family [address [dest_address]]\n" + " [parameters]\n" + " ifconfig interface create\n" + " ifconfig -a [-d] [-m] [-u] [address_family]\n" + " ifconfig -l [-d] [-u] [address_family]\n" + " ifconfig [-d] [-m] [-u]\n"); #else - fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n", - "usage: ifconfig [-L] interface address_family [address [dest_address]]", - " [parameters]", - " ifconfig interface create", - " ifconfig -a [-L] [-d] [-m] [-u] [address_family]", - " ifconfig -l [-d] [-u] [address_family]", - " ifconfig [-L] [-d] [-m] [-u]"); + fprintf(stderr, "%s", + "usage: ifconfig [-L] interface address_family [address [dest_address]]\n" + " [parameters]\n" + " ifconfig interface create\n" + " ifconfig -a [-L] [-d] [-m] [-u] [address_family]\n" + " ifconfig -l [-d] [-u] [address_family]\n" + " ifconfig [-L] [-d] [-m] [-u]\n"); #endif exit(1); } @@ -473,9 +477,7 @@ main(argc, argv) */ if (argc > 0 && (strcmp(argv[0], "create") == 0 || strcmp(argv[0], "plumb") == 0)) { -#ifndef __APPLE__ clone_create(); -#endif argc--, argv++; if (argc == 0) exit(0); @@ -694,7 +696,7 @@ ifconfig(argc, argv, afp) } #define RIDADDR 0 #define ADDR 1 -#define MASK 2 +#define NMASK 2 #define DSTADDR 3 /*ARGSUSED*/ @@ -804,7 +806,7 @@ setifnetmask(addr, dummy, s, afp) if (*afp->af_getaddr == NULL) return; setmask++; - (*afp->af_getaddr)(addr, MASK); + (*afp->af_getaddr)(addr, NMASK); } #ifdef INET6 @@ -816,7 +818,7 @@ setifprefixlen(addr, dummy, s, afp) const struct afswtch *afp; { if (*afp->af_getprefix) - (*afp->af_getprefix)(addr, MASK); + (*afp->af_getprefix)(addr, NMASK); explicit_prefix = 1; } @@ -1463,7 +1465,7 @@ in_getaddr(s, which) struct netent *np; sin->sin_len = sizeof(*sin); - if (which != MASK) + if (which != NMASK) sin->sin_family = AF_INET; if (which == ADDR) { @@ -1473,7 +1475,7 @@ in_getaddr(s, which) /* address is `name/masklen' */ int masklen; int ret; - struct sockaddr_in *min = sintab[MASK]; + struct sockaddr_in *min = sintab[NMASK]; *p = '\0'; ret = sscanf(p+1, "%u", &masklen); if(ret != 1 || (masklen < 0 || masklen > 32)) { @@ -1515,14 +1517,14 @@ in6_getaddr(s, which) newaddr &= 1; sin->sin6_len = sizeof(*sin); - if (which != MASK) + if (which != NMASK) sin->sin6_family = AF_INET6; if (which == ADDR) { char *p = NULL; if((p = strrchr(s, '/')) != NULL) { *p = '\0'; - in6_getprefix(p + 1, MASK); + in6_getprefix(p + 1, NMASK); explicit_prefix = 1; } } @@ -1551,7 +1553,7 @@ in6_getprefix(plen, which) if ((len < 0) || (len > 128)) errx(1, "%s: bad value", plen); sin->sin6_len = sizeof(*sin); - if (which != MASK) + if (which != NMASK) sin->sin6_family = AF_INET6; if ((len == 0) || (len == 128)) { memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr)); @@ -1609,7 +1611,7 @@ ether_getaddr(addr, which) ea = ether_aton(addr); if (ea == NULL) errx(1, "malformed ether address"); - if (which == MASK) + if (which == NMASK) errx(1, "Ethernet does not use netmasks"); sea->sa_family = AF_LINK; sea->sa_len = ETHER_ADDR_LEN; @@ -1678,3 +1680,33 @@ sec2str(total) } #endif /*INET6*/ +void +clone_create(void) +{ + int s; + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s == -1) + err(1, "socket"); + + memset(&ifr, 0, sizeof(ifr)); + (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + if (ioctl(s, SIOCIFCREATE, &ifr) < 0) + err(1, "SIOCIFCREATE"); + + if (strcmp(name, ifr.ifr_name) != 0) { + printf("%s\n", ifr.ifr_name); + strlcpy(name, ifr.ifr_name, sizeof(name)); + } + + close(s); +} + +void +clone_destroy(const char *val, int d, int s, const struct afswtch *rafp) +{ + + (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + if (ioctl(s, SIOCIFDESTROY, &ifr) < 0) + err(1, "SIOCIFDESTROY"); +} diff --git a/ifconfig.tproj/ifconfig.h b/ifconfig.tproj/ifconfig.h index a088b7a..cc6a5ea 100644 --- a/ifconfig.tproj/ifconfig.h +++ b/ifconfig.tproj/ifconfig.h @@ -31,7 +31,7 @@ * * so there! * - * $Id: ifconfig.h,v 1.1.1.1 2000/01/11 01:48:49 wsanchez Exp $ + * $Id: ifconfig.h,v 1.1.1.1.140.1 2004/04/14 00:27:17 lindak Exp $ */ extern struct ifreq ifr; @@ -44,3 +44,9 @@ extern void setmedia(const char *, int, int, const struct afswtch *rafp); extern void setmediaopt(const char *, int, int, const struct afswtch *rafp); extern void unsetmediaopt(const char *, int, int, const struct afswtch *rafp); extern void media_status(int s, struct rt_addrinfo *); + +extern void setvlantag(const char *, int, int, const struct afswtch *rafp); +extern void setvlandev(const char *, int, int, const struct afswtch *rafp); +extern void unsetvlandev(const char *, int, int, const struct afswtch *rafp); +extern void vlan_status(int s, struct rt_addrinfo *); + diff --git a/ifconfig.tproj/ifvlan.c b/ifconfig.tproj/ifvlan.c new file mode 100644 index 0000000..1a547df --- /dev/null +++ b/ifconfig.tproj/ifvlan.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 1999 + * Bill Paul . 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 Bill Paul. + * 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 Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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 +#define KERNEL_PRIVATE +#include +#undef KERNEL_PRIVATE +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "ifconfig.h" + +static int __tag = 0; +static int __have_tag = 0; + +void +vlan_status(int s, struct rt_addrinfo *info __unused) +{ + struct vlanreq vreq; + + bzero((char *)&vreq, sizeof(struct vlanreq)); + ifr.ifr_data = (caddr_t)&vreq; + + if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1) + return; + + printf("\tvlan: %d parent interface: %s\n", + vreq.vlr_tag, vreq.vlr_parent[0] == '\0' ? + "" : vreq.vlr_parent); + + return; +} + +void +setvlantag(const char *val, int d, int s, const struct afswtch *afp) +{ + u_int16_t tag; + struct vlanreq vreq; + + __tag = tag = atoi(val); + __have_tag = 1; + + bzero((char *)&vreq, sizeof(struct vlanreq)); + ifr.ifr_data = (caddr_t)&vreq; + + if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1) + err(1, "SIOCGETVLAN"); + + vreq.vlr_tag = tag; + + if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1) + err(1, "SIOCSETVLAN"); + + return; +} + +void +setvlandev(const char *val, int d, int s, const struct afswtch *afp) +{ + struct vlanreq vreq; + + if (!__have_tag) + errx(1, "must specify both vlan tag and device"); + + bzero((char *)&vreq, sizeof(struct vlanreq)); + ifr.ifr_data = (caddr_t)&vreq; + + if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1) + err(1, "SIOCGETVLAN"); + + strncpy(vreq.vlr_parent, val, sizeof(vreq.vlr_parent)); + vreq.vlr_tag = __tag; + + if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1) + err(1, "SIOCSETVLAN"); + + return; +} + +void +unsetvlandev(const char *val, int d, int s, const struct afswtch *afp) +{ + struct vlanreq vreq; + + bzero((char *)&vreq, sizeof(struct vlanreq)); + ifr.ifr_data = (caddr_t)&vreq; + + if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1) + err(1, "SIOCGETVLAN"); + + bzero((char *)&vreq.vlr_parent, sizeof(vreq.vlr_parent)); + vreq.vlr_tag = 0; + + if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1) + err(1, "SIOCSETVLAN"); + + return; +} diff --git a/racoon.tproj/crypto_openssl.c b/racoon.tproj/crypto_openssl.c index b569986..cb4da65 100644 --- a/racoon.tproj/crypto_openssl.c +++ b/racoon.tproj/crypto_openssl.c @@ -686,7 +686,7 @@ eay_check_x509sign(source, sig, cert) { X509 *x509; u_char *bp; - vchar_t pubkey; + EVP_PKEY *evp; bp = cert->v; @@ -698,10 +698,13 @@ eay_check_x509sign(source, sig, cert) return -1; } - pubkey.v = x509->cert_info->key->public_key->data; - pubkey.l = x509->cert_info->key->public_key->length; - - return eay_rsa_verify(source, sig, &pubkey); + evp = X509_get_pubkey(x509); + if (!evp) { + plog(LLV_ERROR, LOCATION, NULL, "X509_get_pubkey: %s\n", eay_strerror()); + return -1; + } + + return eay_rsa_verify(source, sig, evp); } /* @@ -902,22 +905,15 @@ eay_rsa_sign(src, privkey) } int -eay_rsa_verify(src, sig, pubkey) - vchar_t *src, *sig, *pubkey; -{ +eay_rsa_verify(src, sig, evp) + vchar_t *src, *sig; EVP_PKEY *evp; - u_char *bp = pubkey->v; +{ vchar_t *xbuf = NULL; int pad = RSA_PKCS1_PADDING; int len = 0; int error; - evp = d2i_PUBKEY(NULL, &bp, pubkey->l); - if (evp == NULL) -#ifndef EAYDEBUG - return NULL; -#endif - len = RSA_size(evp->pkey.rsa); xbuf = vmalloc(len); diff --git a/racoon.tproj/crypto_openssl.h b/racoon.tproj/crypto_openssl.h index 6b3661e..7e2e20a 100644 --- a/racoon.tproj/crypto_openssl.h +++ b/racoon.tproj/crypto_openssl.h @@ -29,6 +29,10 @@ * SUCH DAMAGE. */ +#ifdef HAVE_OPENSSL_EVP_H +#include +#endif + #ifdef HAVE_SIGNING_C /* X509 Certificate */ #define GENT_OTHERNAME 0 @@ -54,7 +58,7 @@ extern int eay_check_pkcs7sign __P((vchar_t *, vchar_t *, vchar_t *)); /* RSA */ extern vchar_t *eay_rsa_sign __P((vchar_t *, vchar_t *)); -extern int eay_rsa_verify __P((vchar_t *, vchar_t *, vchar_t *)); +extern int eay_rsa_verify __P((vchar_t *, vchar_t *, EVP_PKEY *)); /* ASN.1 */ extern vchar_t *eay_get_pkcs1privkey __P((char *)); diff --git a/racoon.tproj/isakmp.c b/racoon.tproj/isakmp.c index 218f3dd..0f6b38b 100644 --- a/racoon.tproj/isakmp.c +++ b/racoon.tproj/isakmp.c @@ -181,6 +181,18 @@ isakmp_handler(so_isakmp) plog(LLV_ERROR, LOCATION, (struct sockaddr *)&remote, "packet shorter than isakmp header size.\n"); /* dummy receive */ + if ((len = recvfrom(so_isakmp, (char *)&isakmp, sizeof(isakmp), + 0, (struct sockaddr *)&remote, &remote_len)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to receive isakmp packet\n"); + } + goto end; + } + + /* reject if the size is toooo big */ + if (ntohl(isakmp.len) > 0xffff) { + plog(LLV_ERROR, LOCATION, NULL, + "the length of the isakmp header is too big.\n"); if ((len = recvfrom(so_isakmp, (char *)&isakmp, sizeof(isakmp), 0, (struct sockaddr *)&remote, &remote_len)) < 0) { plog(LLV_ERROR, LOCATION, NULL, diff --git a/rpc_lockd.tproj/kern.c b/rpc_lockd.tproj/kern.c index cd4213d..a231b87 100644 --- a/rpc_lockd.tproj/kern.c +++ b/rpc_lockd.tproj/kern.c @@ -58,10 +58,8 @@ #include "lockd.h" #include "lockd_lock.h" -#define DAEMON_USERNAME "daemon" - #define nfslockdans(_v, _ansp) \ - ((_ansp)->la_vers = (_v), \ + ((_ansp)->la_version = (_v), \ nfsclnt(NFSCLNT_LOCKDANS, (_ansp))) @@ -77,15 +75,11 @@ static char hostname[MAXHOSTNAMELEN + 1]; /* Hostname. */ static void client_cleanup(void); static void set_auth(CLIENT *cl, struct xucred *ucred); int lock_request(LOCKD_MSG *); +int cancel_request(LOCKD_MSG *); int test_request(LOCKD_MSG *); void show(LOCKD_MSG *); int unlock_request(LOCKD_MSG *); -/* - * will break because fifo needs to be repopened when EOF'd - */ -#define lockd_seteuid(uid) seteuid(uid) - #define d_calls (debug_level > 1) #define d_args (debug_level > 2) @@ -116,7 +110,6 @@ client_kern_wait(void) void client_cleanup(void) { - (void)lockd_seteuid(0); (void) nfsclnt(NFSCLNT_LOCKDFD, (struct lockd_ans *)-1); exit(-1); } @@ -140,9 +133,7 @@ client_request(void) #endif int fd, nr, ret; pid_t child; - uid_t daemon_uid; mode_t old_umask; - struct passwd *pw; /* Recreate the NLM fifo. */ (void)unlink(_PATH_LCKFIFO); @@ -177,21 +168,13 @@ client_request(void) /* Open the fifo for reading. */ if ((fd = open(_PATH_LCKFIFO, O_RDONLY | O_NONBLOCK)) == -1) { syslog(LOG_ERR, "open: %s: %m", _PATH_LCKFIFO); - goto err; + _exit (1); } (void)unlink(_PATH_LCKFIFO); if (nfsclnt(NFSCLNT_LOCKDFD, (struct lockd_ans *)fd)) { syslog(LOG_ERR, "nfsclnt_fd: %d: %m", fd); - goto err; + _exit (1); } - pw = getpwnam(DAEMON_USERNAME); - if (pw == NULL) { - syslog(LOG_ERR, "getpwnam: %s: %m", DAEMON_USERNAME); - goto err; - } - daemon_uid = pw->pw_uid; - /* drop our root priviledges */ - (void)lockd_seteuid(daemon_uid); for (;;) { #ifndef USE_NFSLOCKDWAIT_INSTEAD_OF_SELECT @@ -220,8 +203,10 @@ client_request(void) switch (msg.lm_fl.l_type) { case F_RDLCK: case F_WRLCK: - if (msg.lm_getlk) + if (msg.lm_flags & LOCKD_MSG_TEST) ret = test_request(&msg); + else if (msg.lm_flags & LOCKD_MSG_CANCEL) + ret = cancel_request(&msg); else ret = lock_request(&msg); break; @@ -237,12 +222,12 @@ client_request(void) if (ret) { struct lockd_ans ans; - ans.la_msg_ident = msg.lm_msg_ident; + ans.la_xid = msg.lm_xid; ans.la_errno = ENOTSUP; if (nfslockdans(LOCKD_ANS_VERSION, &ans)) { syslog(LOG_DEBUG, "process %lu: %m", - (u_long)msg.lm_msg_ident.pid); + (u_long)msg.lm_fl.l_pid); } } } else if (nr == -1) { @@ -266,7 +251,6 @@ client_request(void) /* Reached only on error. */ err: - (void)lockd_seteuid(0); (void) nfsclnt(NFSCLNT_LOCKDFD, (struct lockd_ans *)-1); _exit (1); return 0; @@ -300,22 +284,22 @@ test_request(LOCKD_MSG *msg) if (d_calls) syslog(LOG_DEBUG, "test request: %s: %s to %s", - msg->lm_nfsv3 ? "V4" : "V1/3", + (msg->lm_flags & LOCKD_MSG_NFSV3) ? "V4" : "V1/3", msg->lm_fl.l_type == F_WRLCK ? "write" : "read", from_addr((struct sockaddr *)&msg->lm_addr)); - if (msg->lm_nfsv3) { + if (msg->lm_flags & LOCKD_MSG_NFSV3) { struct nlm4_testargs arg4; - arg4.cookie.n_bytes = (char *)&msg->lm_msg_ident; - arg4.cookie.n_len = sizeof(msg->lm_msg_ident); + arg4.cookie.n_bytes = (char *)&msg->lm_xid; + arg4.cookie.n_len = sizeof(msg->lm_xid); arg4.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0; arg4.alock.caller_name = hostname; arg4.alock.fh.n_bytes = (char *)&msg->lm_fh; arg4.alock.fh.n_len = msg->lm_fh_len; arg4.alock.oh.n_bytes = (char *)&owner; arg4.alock.oh.n_len = sizeof(owner); - arg4.alock.svid = msg->lm_msg_ident.pid; + arg4.alock.svid = msg->lm_fl.l_pid; arg4.alock.l_offset = msg->lm_fl.l_start; arg4.alock.l_len = msg->lm_fl.l_len; @@ -325,20 +309,20 @@ test_request(LOCKD_MSG *msg) return (1); set_auth(cli, &msg->lm_cred); - (void)clnt_call(cli, NLM_TEST_MSG, + (void)clnt_call(cli, NLM4_TEST_MSG, xdr_nlm4_testargs, &arg4, xdr_void, &dummy, timeout); } else { struct nlm_testargs arg; - arg.cookie.n_bytes = (char *)&msg->lm_msg_ident; - arg.cookie.n_len = sizeof(msg->lm_msg_ident); + arg.cookie.n_bytes = (char *)&msg->lm_xid; + arg.cookie.n_len = sizeof(msg->lm_xid); arg.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0; arg.alock.caller_name = hostname; arg.alock.fh.n_bytes = (char *)&msg->lm_fh; arg.alock.fh.n_len = msg->lm_fh_len; arg.alock.oh.n_bytes = (char *)&owner; arg.alock.oh.n_len = sizeof(owner); - arg.alock.svid = msg->lm_msg_ident.pid; + arg.alock.svid = msg->lm_fl.l_pid; arg.alock.l_offset = msg->lm_fl.l_start; arg.alock.l_len = msg->lm_fl.l_len; @@ -369,21 +353,21 @@ lock_request(LOCKD_MSG *msg) if (d_calls) syslog(LOG_DEBUG, "lock request: %s: %s to %s", - msg->lm_nfsv3 ? "V4" : "V1/3", + (msg->lm_flags & LOCKD_MSG_NFSV3) ? "V4" : "V1/3", msg->lm_fl.l_type == F_WRLCK ? "write" : "read", from_addr((struct sockaddr *)&msg->lm_addr)); - if (msg->lm_nfsv3) { - arg4.cookie.n_bytes = (char *)&msg->lm_msg_ident; - arg4.cookie.n_len = sizeof(msg->lm_msg_ident); - arg4.block = msg->lm_wait ? 1 : 0; + if (msg->lm_flags & LOCKD_MSG_NFSV3) { + arg4.cookie.n_bytes = (char *)&msg->lm_xid; + arg4.cookie.n_len = sizeof(msg->lm_xid); + arg4.block = (msg->lm_flags & LOCKD_MSG_BLOCK) ? 1 : 0; arg4.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0; arg4.alock.caller_name = hostname; arg4.alock.fh.n_bytes = (char *)&msg->lm_fh; arg4.alock.fh.n_len = msg->lm_fh_len; arg4.alock.oh.n_bytes = (char *)&owner; arg4.alock.oh.n_len = sizeof(owner); - arg4.alock.svid = msg->lm_msg_ident.pid; + arg4.alock.svid = msg->lm_fl.l_pid; arg4.alock.l_offset = msg->lm_fl.l_start; arg4.alock.l_len = msg->lm_fl.l_len; arg4.reclaim = 0; @@ -395,19 +379,19 @@ lock_request(LOCKD_MSG *msg) return (1); set_auth(cli, &msg->lm_cred); - (void)clnt_call(cli, NLM_LOCK_MSG, + (void)clnt_call(cli, NLM4_LOCK_MSG, xdr_nlm4_lockargs, &arg4, xdr_void, &dummy, timeout); } else { - arg.cookie.n_bytes = (char *)&msg->lm_msg_ident; - arg.cookie.n_len = sizeof(msg->lm_msg_ident); - arg.block = msg->lm_wait ? 1 : 0; + arg.cookie.n_bytes = (char *)&msg->lm_xid; + arg.cookie.n_len = sizeof(msg->lm_xid); + arg.block = (msg->lm_flags & LOCKD_MSG_BLOCK) ? 1 : 0; arg.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0; arg.alock.caller_name = hostname; arg.alock.fh.n_bytes = (char *)&msg->lm_fh; arg.alock.fh.n_len = msg->lm_fh_len; arg.alock.oh.n_bytes = (char *)&owner; arg.alock.oh.n_len = sizeof(owner); - arg.alock.svid = msg->lm_msg_ident.pid; + arg.alock.svid = msg->lm_fl.l_pid; arg.alock.l_offset = msg->lm_fl.l_start; arg.alock.l_len = msg->lm_fl.l_len; arg.reclaim = 0; @@ -425,6 +409,71 @@ lock_request(LOCKD_MSG *msg) return (0); } +/* + * cancel_request -- + * Convert a lock LOCKD_MSG into an NLM request, and send it off. + */ +int +cancel_request(LOCKD_MSG *msg) +{ + CLIENT *cli; + struct nlm4_cancargs arg4; + struct nlm_cancargs arg; + struct timeval timeout = {0, 0}; /* No timeout, no response. */ + char dummy; + + if (d_calls) + syslog(LOG_DEBUG, "cancel request: %s: %s to %s", + (msg->lm_flags & LOCKD_MSG_NFSV3) ? "V4" : "V1/3", + msg->lm_fl.l_type == F_WRLCK ? "write" : "read", + from_addr((struct sockaddr *)&msg->lm_addr)); + + if (msg->lm_flags & LOCKD_MSG_NFSV3) { + arg4.cookie.n_bytes = (char *)&msg->lm_xid; + arg4.cookie.n_len = sizeof(msg->lm_xid); + arg4.block = (msg->lm_flags & LOCKD_MSG_BLOCK) ? 1 : 0; + arg4.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0; + arg4.alock.caller_name = hostname; + arg4.alock.fh.n_bytes = (char *)&msg->lm_fh; + arg4.alock.fh.n_len = msg->lm_fh_len; + arg4.alock.oh.n_bytes = (char *)&owner; + arg4.alock.oh.n_len = sizeof(owner); + arg4.alock.svid = msg->lm_fl.l_pid; + arg4.alock.l_offset = msg->lm_fl.l_start; + arg4.alock.l_len = msg->lm_fl.l_len; + + if ((cli = get_client( + (struct sockaddr *)&msg->lm_addr, NLM_VERS4)) == NULL) + return (1); + + set_auth(cli, &msg->lm_cred); + (void)clnt_call(cli, NLM4_CANCEL_MSG, + xdr_nlm4_cancargs, &arg4, xdr_void, &dummy, timeout); + } else { + arg.cookie.n_bytes = (char *)&msg->lm_xid; + arg.cookie.n_len = sizeof(msg->lm_xid); + arg.block = (msg->lm_flags & LOCKD_MSG_BLOCK) ? 1 : 0; + arg.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0; + arg.alock.caller_name = hostname; + arg.alock.fh.n_bytes = (char *)&msg->lm_fh; + arg.alock.fh.n_len = msg->lm_fh_len; + arg.alock.oh.n_bytes = (char *)&owner; + arg.alock.oh.n_len = sizeof(owner); + arg.alock.svid = msg->lm_fl.l_pid; + arg.alock.l_offset = msg->lm_fl.l_start; + arg.alock.l_len = msg->lm_fl.l_len; + + if ((cli = get_client( + (struct sockaddr *)&msg->lm_addr, NLM_VERS)) == NULL) + return (1); + + set_auth(cli, &msg->lm_cred); + (void)clnt_call(cli, NLM_CANCEL_MSG, + xdr_nlm_cancargs, &arg, xdr_void, &dummy, timeout); + } + return (0); +} + /* * unlock_request -- * Convert an unlock LOCKD_MSG into an NLM request, and send it off. @@ -440,18 +489,18 @@ unlock_request(LOCKD_MSG *msg) if (d_calls) syslog(LOG_DEBUG, "unlock request: %s: to %s", - msg->lm_nfsv3 ? "V4" : "V1/3", + (msg->lm_flags & LOCKD_MSG_NFSV3) ? "V4" : "V1/3", from_addr((struct sockaddr *)&msg->lm_addr)); - if (msg->lm_nfsv3) { - arg4.cookie.n_bytes = (char *)&msg->lm_msg_ident; - arg4.cookie.n_len = sizeof(msg->lm_msg_ident); + if (msg->lm_flags & LOCKD_MSG_NFSV3) { + arg4.cookie.n_bytes = (char *)&msg->lm_xid; + arg4.cookie.n_len = sizeof(msg->lm_xid); arg4.alock.caller_name = hostname; arg4.alock.fh.n_bytes = (char *)&msg->lm_fh; arg4.alock.fh.n_len = msg->lm_fh_len; arg4.alock.oh.n_bytes = (char *)&owner; arg4.alock.oh.n_len = sizeof(owner); - arg4.alock.svid = msg->lm_msg_ident.pid; + arg4.alock.svid = msg->lm_fl.l_pid; arg4.alock.l_offset = msg->lm_fl.l_start; arg4.alock.l_len = msg->lm_fl.l_len; @@ -461,17 +510,17 @@ unlock_request(LOCKD_MSG *msg) return (1); set_auth(cli, &msg->lm_cred); - (void)clnt_call(cli, NLM_UNLOCK_MSG, + (void)clnt_call(cli, NLM4_UNLOCK_MSG, xdr_nlm4_unlockargs, &arg4, xdr_void, &dummy, timeout); } else { - arg.cookie.n_bytes = (char *)&msg->lm_msg_ident; - arg.cookie.n_len = sizeof(msg->lm_msg_ident); + arg.cookie.n_bytes = (char *)&msg->lm_xid; + arg.cookie.n_len = sizeof(msg->lm_xid); arg.alock.caller_name = hostname; arg.alock.fh.n_bytes = (char *)&msg->lm_fh; arg.alock.fh.n_len = msg->lm_fh_len; arg.alock.oh.n_bytes = (char *)&owner; arg.alock.oh.n_len = sizeof(owner); - arg.alock.svid = msg->lm_msg_ident.pid; + arg.alock.svid = msg->lm_fl.l_pid; arg.alock.l_offset = msg->lm_fl.l_start; arg.alock.l_len = msg->lm_fl.l_len; @@ -489,47 +538,80 @@ unlock_request(LOCKD_MSG *msg) } int -lock_answer(int pid, netobj *netcookie, int result, int version, - int *pid_p, off_t l_start, off_t l_len) +lock_answer(int version, netobj *netcookie, nlm4_lock *lock, int flags, int result) { struct lockd_ans ans; - if (netcookie->n_len != sizeof(ans.la_msg_ident)) { - if (pid == -1) { /* we're screwed */ + ans.la_flags = 0; + if (flags & LOCK_ANSWER_GRANTED) + ans.la_flags |= LOCKD_ANS_GRANTED; + + if (netcookie->n_len != sizeof(ans.la_xid)) { + if (lock == NULL) { /* we're screwed */ syslog(LOG_ERR, "inedible nlm cookie"); return -1; } - ans.la_msg_ident.pid = pid; - ans.la_msg_ident.msg_seq = -1; + /* no/bad cookie - need to copy lock info to identify request */ + ans.la_xid = 0; + /* copy lock info */ + ans.la_fh_len = lock->fh.n_len; + if (!lock->fh.n_len || (lock->fh.n_len > NFS_SMALLFH)) { + syslog(LOG_ERR, "bogus filehandle size %d in answer", lock->fh.n_len); + return -1; + } + memcpy(ans.la_fh, lock->fh.n_bytes, ans.la_fh_len); + ans.la_pid = lock->svid; + ans.la_start = lock->l_offset; + ans.la_len = lock->l_len; + ans.la_flags |= LOCKD_ANS_LOCK_INFO; + if (flags & LOCK_ANSWER_LOCK_EXCL) + ans.la_flags |= LOCKD_ANS_LOCK_EXCL; } else { - memcpy(&ans.la_msg_ident, netcookie->n_bytes, - sizeof(ans.la_msg_ident)); + memcpy(&ans.la_xid, netcookie->n_bytes, sizeof(ans.la_xid)); + ans.la_fh_len = 0; } if (d_calls) syslog(LOG_DEBUG, "lock answer: pid %lu: %s %d", - (unsigned long)ans.la_msg_ident.pid, + (unsigned long)ans.la_pid, version == NLM_VERS4 ? "nlmv4" : "nlmv3", result); - ans.la_getlk_set = 0; if (version == NLM_VERS4) switch (result) { case nlm4_granted: ans.la_errno = 0; + if ((flags & LOCK_ANSWER_GRANTED) && lock && + !(ans.la_flags & LOCKD_ANS_LOCK_INFO)) { + /* copy lock info */ + ans.la_fh_len = lock->fh.n_len; + if (!lock->fh.n_len || (lock->fh.n_len > NFS_SMALLFH)) { + syslog(LOG_ERR, "bogus filehandle size %d in answer", lock->fh.n_len); + return -1; + } + memcpy(ans.la_fh, lock->fh.n_bytes, ans.la_fh_len); + ans.la_pid = lock->svid; + ans.la_start = lock->l_offset; + ans.la_len = lock->l_len; + ans.la_flags |= LOCKD_ANS_LOCK_INFO; + if (flags & LOCK_ANSWER_LOCK_EXCL) + ans.la_flags |= LOCKD_ANS_LOCK_EXCL; + } break; default: ans.la_errno = EACCES; break; case nlm4_denied: - if (pid_p == NULL) + if (lock == NULL) ans.la_errno = EACCES; else { /* this is an answer to a nlm_test msg */ - ans.la_getlk_set = 1; - ans.la_getlk_pid = *pid_p; - ans.la_getlk_start = l_start; - ans.la_getlk_len = l_len; + ans.la_pid = lock->svid; + ans.la_start = lock->l_offset; + ans.la_len = lock->l_len; + ans.la_flags |= LOCKD_ANS_LOCK_INFO; + if (flags & LOCK_ANSWER_LOCK_EXCL) + ans.la_flags |= LOCKD_ANS_LOCK_EXCL; ans.la_errno = 0; } break; @@ -537,8 +619,8 @@ lock_answer(int pid, netobj *netcookie, int result, int version, ans.la_errno = ENOLCK; break; case nlm4_blocked: - return -1; - /* NOTREACHED */ + ans.la_errno = EINPROGRESS; + break; case nlm4_denied_grace_period: ans.la_errno = EAGAIN; break; @@ -562,19 +644,37 @@ lock_answer(int pid, netobj *netcookie, int result, int version, switch (result) { case nlm_granted: ans.la_errno = 0; + if ((flags & LOCK_ANSWER_GRANTED) && lock && + !(ans.la_flags & LOCKD_ANS_LOCK_INFO)) { + /* copy lock info */ + ans.la_fh_len = lock->fh.n_len; + if (!lock->fh.n_len || (lock->fh.n_len > NFS_SMALLFH)) { + syslog(LOG_ERR, "bogus filehandle size %d in answer", lock->fh.n_len); + return -1; + } + memcpy(ans.la_fh, lock->fh.n_bytes, ans.la_fh_len); + ans.la_pid = lock->svid; + ans.la_start = lock->l_offset; + ans.la_len = lock->l_len; + ans.la_flags |= LOCKD_ANS_LOCK_INFO; + if (flags & LOCK_ANSWER_LOCK_EXCL) + ans.la_flags |= LOCKD_ANS_LOCK_EXCL; + } break; default: ans.la_errno = EACCES; break; case nlm_denied: - if (pid_p == NULL) + if (lock == NULL) ans.la_errno = EACCES; else { /* this is an answer to a nlm_test msg */ - ans.la_getlk_set = 1; - ans.la_getlk_pid = *pid_p; - ans.la_getlk_start = l_start; - ans.la_getlk_len = l_len; + ans.la_pid = lock->svid; + ans.la_start = lock->l_offset; + ans.la_len = lock->l_len; + ans.la_flags |= LOCKD_ANS_LOCK_INFO; + if (flags & LOCK_ANSWER_LOCK_EXCL) + ans.la_flags |= LOCKD_ANS_LOCK_EXCL; ans.la_errno = 0; } break; @@ -582,8 +682,8 @@ lock_answer(int pid, netobj *netcookie, int result, int version, ans.la_errno = ENOLCK; break; case nlm_blocked: - return -1; - /* NOTREACHED */ + ans.la_errno = EINPROGRESS; + break; case nlm_denied_grace_period: ans.la_errno = EAGAIN; break; @@ -594,7 +694,7 @@ lock_answer(int pid, netobj *netcookie, int result, int version, if (nfslockdans(LOCKD_ANS_VERSION, &ans)) { syslog(LOG_DEBUG, "lock_answer(%d): process %lu: %m", - result, (u_long)ans.la_msg_ident.pid); + result, (u_long)ans.la_pid); return -1; } return 0; @@ -613,7 +713,7 @@ show(LOCKD_MSG *mp) size_t len; u_int8_t *p, *t, buf[NFS_SMALLFH*3+1]; - syslog(LOG_DEBUG, "process ID: %lu\n", (long)mp->lm_msg_ident.pid); + syslog(LOG_DEBUG, "process ID: %lu\n", (long)mp->lm_fl.l_pid); fsidp = (fsid_t *)&mp->lm_fh; fidp = (struct fid *)((u_int8_t *)&mp->lm_fh + sizeof(fsid_t)); @@ -635,5 +735,5 @@ show(LOCKD_MSG *mp) mp->lm_fl.l_type, mp->lm_fl.l_whence); /* Show wait flag. */ - syslog(LOG_DEBUG, "wait was %s\n", mp->lm_wait ? "set" : "not set"); + syslog(LOG_DEBUG, "wait was %s\n", (mp->lm_flags & LOCKD_MSG_BLOCK) ? "set" : "not set"); } diff --git a/rpc_lockd.tproj/lock_proc.c b/rpc_lockd.tproj/lock_proc.c index 9a4ee11..2029deb 100644 --- a/rpc_lockd.tproj/lock_proc.c +++ b/rpc_lockd.tproj/lock_proc.c @@ -194,7 +194,6 @@ get_client(host_addr, vers) struct timeval retry_time, time_now; int i; int sock_no; - char host[NI_MAXHOST]; gettimeofday(&time_now, NULL); @@ -265,7 +264,8 @@ get_client(host_addr, vers) clnt_control(client, CLSET_TIMEOUT, (char *)&retry_time); if (debug_level > 3) - syslog(LOG_DEBUG, "Created CLIENT* for %s", host); + syslog(LOG_DEBUG, "Created CLIENT* for %s", + inet_ntoa(((struct sockaddr_in *)host_addr)->sin_addr)); return client; } @@ -531,9 +531,12 @@ nlm_cancel_1_svc(arg, rqstp) struct svc_req *rqstp; { static nlm_res res; - struct nlm4_lock arg4; + struct nlm4_cancargs arg4; - nlmtonlm4(&arg->alock, &arg4); + arg4.cookie = arg->cookie; + arg4.block = arg->block; + arg4.exclusive = arg->exclusive; + nlmtonlm4(&arg->alock, &arg4.alock); if (debug_level) log_from_addr("nlm_cancel", rqstp); @@ -541,11 +544,7 @@ nlm_cancel_1_svc(arg, 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 = unlock(&arg4, LOCK_CANCEL); + res.stat.stat = cancellock(&arg4, 0); return (&res); } @@ -555,19 +554,18 @@ nlm_cancel_msg_1_svc(arg, rqstp) struct svc_req *rqstp; { static nlm_res res; - struct nlm4_lock arg4; + struct nlm4_cancargs arg4; - nlmtonlm4(&arg->alock, &arg4); + arg4.cookie = arg->cookie; + arg4.block = arg->block; + arg4.exclusive = arg->exclusive; + nlmtonlm4(&arg->alock, &arg4.alock); 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 = unlock(&arg4, LOCK_CANCEL); + res.stat.stat = cancellock(&arg4, 0); transmit_result(NLM_CANCEL_RES, &res, (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)); return (NULL); @@ -645,13 +643,25 @@ nlm_granted_1_svc(arg, rqstp) struct svc_req *rqstp; { static nlm_res res; + nlm4_lock lock4; + int flags; if (debug_level) log_from_addr("nlm_granted", rqstp); - res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie, - nlm_granted, NLM_VERS, NULL, 0, 0) == 0 ? - nlm_granted : nlm_denied; + lock4.fh = arg->alock.fh; + lock4.svid = arg->alock.svid; + lock4.l_offset = arg->alock.l_offset; + lock4.l_len = arg->alock.l_len; + + flags = LOCK_ANSWER_GRANTED; + if (arg->exclusive) + flags |= LOCK_ANSWER_LOCK_EXCL; + + if (lock_answer(NLM_VERS, &arg->cookie, &lock4, flags, nlm_granted)) + res.stat.stat = nlm_denied; + else + res.stat.stat = nlm_granted; /* copy cookie from arg to result. See comment in nlm_test_1() */ res.cookie = arg->cookie; @@ -665,13 +675,25 @@ nlm_granted_msg_1_svc(arg, rqstp) struct svc_req *rqstp; { static nlm_res res; + nlm4_lock lock4; + int flags; if (debug_level) log_from_addr("nlm_granted_msg", rqstp); - res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie, - nlm_granted, NLM_VERS, NULL, 0, 0) == 0 ? - nlm_granted : nlm_denied; + lock4.fh = arg->alock.fh; + lock4.svid = arg->alock.svid; + lock4.l_offset = arg->alock.l_offset; + lock4.l_len = arg->alock.l_len; + + flags = LOCK_ANSWER_GRANTED; + if (arg->exclusive) + flags |= LOCK_ANSWER_LOCK_EXCL; + + if (lock_answer(NLM_VERS, &arg->cookie, &lock4, flags, nlm_granted)) + res.stat.stat = nlm_denied; + else + res.stat.stat = nlm_granted; res.cookie = arg->cookie; @@ -690,12 +712,23 @@ nlm_test_res_1_svc(arg, rqstp) nlm_testres *arg; struct svc_req *rqstp; { + nlm4_lock lock4; + int flags = 0; + if (debug_level) log_from_addr("nlm_test_res", rqstp); - (void)lock_answer(-1, &arg->cookie, arg->stat.stat, NLM_VERS, - &arg->stat.nlm_testrply_u.holder.svid, - arg->stat.nlm_testrply_u.holder.l_offset, - arg->stat.nlm_testrply_u.holder.l_len); + + if (arg->stat.stat == nlm_denied) { + lock4.fh.n_len = 0; + lock4.svid = arg->stat.nlm_testrply_u.holder.svid; + lock4.l_offset = arg->stat.nlm_testrply_u.holder.l_offset; + lock4.l_len = arg->stat.nlm_testrply_u.holder.l_len; + if (arg->stat.nlm_testrply_u.holder.exclusive) + flags |= LOCK_ANSWER_LOCK_EXCL; + lock_answer(NLM_VERS, &arg->cookie, &lock4, flags, arg->stat.stat); + } else + lock_answer(NLM_VERS, &arg->cookie, NULL, 0, arg->stat.stat); + return (NULL); } @@ -712,7 +745,7 @@ nlm_lock_res_1_svc(arg, rqstp) if (debug_level) log_from_addr("nlm_lock_res", rqstp); - (void)lock_answer(-1, &arg->cookie, arg->stat.stat, NLM_VERS, NULL, 0, 0); + lock_answer(NLM_VERS, &arg->cookie, NULL, 0, arg->stat.stat); return (NULL); } @@ -724,11 +757,14 @@ nlm_lock_res_1_svc(arg, rqstp) */ void * nlm_cancel_res_1_svc(arg, rqstp) - nlm_res *arg __unused; + nlm_res *arg; struct svc_req *rqstp; { if (debug_level) log_from_addr("nlm_cancel_res", rqstp); + + lock_answer(NLM_VERS, &arg->cookie, NULL, 0, arg->stat.stat); + return (NULL); } @@ -745,7 +781,7 @@ nlm_unlock_res_1_svc(arg, rqstp) if (debug_level) log_from_addr("nlm_unlock_res", rqstp); - lock_answer(-1, &arg->cookie, arg->stat.stat, NLM_VERS, NULL, 0, 0); + lock_answer(NLM_VERS, &arg->cookie, NULL, 0, arg->stat.stat); return (NULL); } @@ -757,12 +793,18 @@ nlm_unlock_res_1_svc(arg, rqstp) */ void * nlm_granted_res_1_svc(arg, rqstp) - nlm_res *arg __unused; + nlm_res *arg; struct svc_req *rqstp; { if (debug_level) log_from_addr("nlm_granted_res", rqstp); - /* XXX should undo lock if granted msg wasn't accepted! */ + /* need to undo lock if granted msg wasn't accepted! */ + if (arg->stat.stat != nlm_granted) { + nlm4_res arg4; + arg4.cookie = arg->cookie; + arg4.stat.stat = arg->stat.stat; + granted_failed(&arg4); + } return (NULL); } @@ -1061,11 +1103,7 @@ nlm4_cancel_4_svc(arg, 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 = unlock(&arg->alock, LOCK_CANCEL); + res.stat.stat = cancellock(arg, LOCK_V4); return (&res); } @@ -1080,11 +1118,7 @@ nlm4_cancel_msg_4_svc(arg, rqstp) log_from_addr("nlm4_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 = unlock(&arg->alock, LOCK_CANCEL | LOCK_V4); + res.stat.stat = cancellock(arg, LOCK_V4); transmit4_result(NLM4_CANCEL_RES, &res, (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)); return (NULL); @@ -1156,13 +1190,19 @@ nlm4_granted_4_svc(arg, rqstp) struct svc_req *rqstp; { static nlm4_res res; + int flags; if (debug_level) log_from_addr("nlm4_granted", rqstp); - res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie, - nlm4_granted, NLM_VERS4, NULL, 0, 0) == 0 ? - nlm4_granted : nlm4_denied; + flags = LOCK_ANSWER_GRANTED; + if (arg->exclusive) + flags |= LOCK_ANSWER_LOCK_EXCL; + + if (lock_answer(NLM_VERS4, &arg->cookie, &arg->alock, flags, nlm4_granted)) + res.stat.stat = nlm4_denied; + else + res.stat.stat = nlm4_granted; /* copy cookie from arg to result. See comment in nlm_test_1() */ res.cookie = arg->cookie; @@ -1176,13 +1216,19 @@ nlm4_granted_msg_4_svc(arg, rqstp) struct svc_req *rqstp; { static nlm4_res res; + int flags; if (debug_level) log_from_addr("nlm4_granted_msg", rqstp); - res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie, - nlm4_granted, NLM_VERS4, NULL, 0, 0) == 0 ? - nlm4_granted : nlm4_denied; + flags = LOCK_ANSWER_GRANTED; + if (arg->exclusive) + flags |= LOCK_ANSWER_LOCK_EXCL; + + if (lock_answer(NLM_VERS4, &arg->cookie, &arg->alock, flags, nlm4_granted)) + res.stat.stat = nlm4_denied; + else + res.stat.stat = nlm4_granted; res.cookie = arg->cookie; @@ -1201,13 +1247,23 @@ nlm4_test_res_4_svc(arg, rqstp) nlm4_testres *arg; struct svc_req *rqstp; { + nlm4_lock lock4; + int flags = 0; + if (debug_level) log_from_addr("nlm4_test_res", rqstp); - (void)lock_answer(-1, &arg->cookie, arg->stat.stat, NLM_VERS4, - (int *)&arg->stat.nlm4_testrply_u.holder.svid, - arg->stat.nlm4_testrply_u.holder.l_offset, - arg->stat.nlm4_testrply_u.holder.l_len); + if (arg->stat.stat == nlm4_denied) { + lock4.fh.n_len = 0; + lock4.svid = arg->stat.nlm4_testrply_u.holder.svid; + lock4.l_offset = arg->stat.nlm4_testrply_u.holder.l_offset; + lock4.l_len = arg->stat.nlm4_testrply_u.holder.l_len; + if (arg->stat.nlm4_testrply_u.holder.exclusive) + flags |= LOCK_ANSWER_LOCK_EXCL; + lock_answer(NLM_VERS4, &arg->cookie, &lock4, flags, arg->stat.stat); + } else + lock_answer(NLM_VERS4, &arg->cookie, NULL, 0, arg->stat.stat); + return (NULL); } @@ -1224,7 +1280,7 @@ nlm4_lock_res_4_svc(arg, rqstp) if (debug_level) log_from_addr("nlm4_lock_res", rqstp); - (void)lock_answer(-1, &arg->cookie, arg->stat.stat, NLM_VERS4, NULL, 0, 0); + lock_answer(NLM_VERS4, &arg->cookie, NULL, 0, arg->stat.stat); return (NULL); } @@ -1236,11 +1292,14 @@ nlm4_lock_res_4_svc(arg, rqstp) */ void * nlm4_cancel_res_4_svc(arg, rqstp) - nlm4_res *arg __unused; + nlm4_res *arg; struct svc_req *rqstp; { if (debug_level) log_from_addr("nlm4_cancel_res", rqstp); + + lock_answer(NLM_VERS4, &arg->cookie, NULL, 0, arg->stat.stat); + return (NULL); } @@ -1256,6 +1315,9 @@ nlm4_unlock_res_4_svc(arg, rqstp) { if (debug_level) log_from_addr("nlm4_unlock_res", rqstp); + + lock_answer(NLM_VERS4, &arg->cookie, NULL, 0, arg->stat.stat); + return (NULL); } @@ -1271,7 +1333,9 @@ nlm4_granted_res_4_svc(arg, rqstp) { if (debug_level) log_from_addr("nlm4_granted_res", rqstp); - /* XXX should undo lock if granted msg wasn't accepted! */ + /* need to undo lock if granted msg wasn't accepted! */ + if (arg->stat.stat != nlm4_granted) + granted_failed(arg); return (NULL); } diff --git a/rpc_lockd.tproj/lockd.c b/rpc_lockd.tproj/lockd.c index f8e46db..f2d9ef2 100644 --- a/rpc_lockd.tproj/lockd.c +++ b/rpc_lockd.tproj/lockd.c @@ -90,6 +90,7 @@ void cleanup_pid_file(void); void handle_sig_cleanup(int); void sigalarm_handler(void); +void my_svc_run(void); const char *transports[] = { "udp", "tcp", "udp6", "tcp6" }; @@ -103,7 +104,7 @@ main(argc, argv) struct sigaction sigalarm; int grace_period = 30; - while ((ch = getopt(argc, argv, "d:g:w")) != (-1)) { + while ((ch = getopt(argc, argv, "d:g:wx:")) != (-1)) { switch (ch) { case 'd': debug_level = atoi(optarg); @@ -122,6 +123,9 @@ main(argc, argv) case 'w': waitkern = 1; break; + case 'x': + host_expire = atoi(optarg); + break; default: case '?': usage(); @@ -164,7 +168,7 @@ main(argc, argv) nanosleep(&ts, NULL); } - openlog("rpc.lockd", 0, LOG_DAEMON); + openlog("rpc.lockd", debug_level == 99 ? LOG_PERROR : 0, LOG_DAEMON); if (debug_level) syslog(LOG_INFO, "Starting, debug level %d", debug_level); else @@ -211,7 +215,7 @@ main(argc, argv) client_pid = client_request(); - svc_run(); /* Should never return */ + my_svc_run(); /* Should never return */ exit(1); } @@ -225,7 +229,8 @@ sigalarm_handler(void) void usage() { - errx(1, "usage: rpc.lockd [-d ] [-g ] [-w]"); + errx(1, "usage: rpc.lockd [-d ] [-g ] " + " [-x ] [-w]"); } /* @@ -369,3 +374,45 @@ handle_sig_cleanup(int sig __unused) exit(1); } +void +my_svc_run(void) +{ + fd_set readfds; + struct timeval timeout; + struct timeval now; + int error; + int hashosts = 0; + int tsize = 0; + struct timeval *top; + + + for( ;; ) { + timeout.tv_sec = host_expire + 1; + timeout.tv_usec = 0; + + tsize = getdtablesize(); + bcopy(&svc_fdset, &readfds, sizeof(svc_fdset)); + /* + * If there are any expired hosts then sleep with a + * timeout to expire them. + */ + if (hashosts && (timeout.tv_sec >= 0)) + top = &timeout; + else + top = NULL; + error = select(tsize, &readfds, NULL, NULL, top); + if (error == -1) { + if (errno == EINTR) + continue; + perror("rpc.lockd: my_svc_run: select failed"); + return; + } + gettimeofday(&now, NULL); + currsec = now.tv_sec; + if (error > 0) + svc_getreqset(&readfds); + if (debug_level > 3 && error == 0) + fprintf(stderr, "my_svc_run: select timeout\n"); + hashosts = expire_lock_hosts(); + } +} diff --git a/rpc_lockd.tproj/lockd.h b/rpc_lockd.tproj/lockd.h index 2799058..a649c69 100644 --- a/rpc_lockd.tproj/lockd.h +++ b/rpc_lockd.tproj/lockd.h @@ -40,8 +40,12 @@ void client_kern_wait(void); pid_t client_request(void); extern int nsm_state; extern pid_t client_pid; +extern time_t currsec; +extern int host_expire; /* XXX these should be in some system headers */ typedef u_int32_t rpcvers_t; int nfsclnt(int, void *); extern int callrpc(const char *, int, int, int, xdrproc_t, void *, xdrproc_t , void *); +int expire_lock_hosts(void); + diff --git a/rpc_lockd.tproj/lockd_lock.c b/rpc_lockd.tproj/lockd_lock.c index f1fe265..29a77c5 100644 --- a/rpc_lockd.tproj/lockd_lock.c +++ b/rpc_lockd.tproj/lockd_lock.c @@ -82,8 +82,7 @@ struct file_lock { netobj filehandle; /* NFS filehandle */ struct sockaddr *addr; struct nlm4_holder client; /* lock holder */ - /* XXX: client_cookie used *only* in send_granted */ - netobj client_cookie; /* cookie sent by the client */ + u_int64_t granted_cookie; char client_name[SM_MAXSTRLEN]; int nsm_status; /* status from the remote lock manager */ int status; /* lock status, see below */ @@ -129,13 +128,19 @@ struct nfssharefilelist_head nfssharefilelist_head = LIST_HEAD_INITIALIZER(nfssh /* struct describing a monitored host */ struct host { - LIST_ENTRY(host) hostlst; + TAILQ_ENTRY(host) hostlst; char name[SM_MAXSTRLEN]; int refcnt; + time_t lastuse; }; /* list of hosts we monitor */ -LIST_HEAD(hostlst_head, host); -struct hostlst_head hostlst_head = LIST_HEAD_INITIALIZER(hostlst_head); +TAILQ_HEAD(hostlst_head, host); +struct hostlst_head hostlst_head = TAILQ_HEAD_INITIALIZER(hostlst_head); +struct hostlst_head hostlst_unref = TAILQ_HEAD_INITIALIZER(hostlst_unref); + +int host_expire = 60; /* seconds */ +time_t currsec; +u_int64_t send_granted_cookie = 0; /* * File monitoring handlers @@ -178,16 +183,17 @@ enum split_status {SPL_DISJOINT=0, SPL_LOCK1=1, SPL_LOCK2=2, SPL_CONTAINED=4, SP enum partialfilelock_status lock_partialfilelock(struct file_lock *fl); -void send_granted(struct file_lock *fl, int opcode); +int send_granted(struct file_lock *fl, int opcode); void siglock(void); void sigunlock(void); +void destroy_lock_host(struct host *ihp); void monitor_lock_host(const char *hostname); void unmonitor_lock_host(const char *hostname); void copy_nlm4_lock_to_nlm4_holder(const struct nlm4_lock *src, const bool_t exclusive, struct nlm4_holder *dest); struct file_lock * allocate_file_lock(const netobj *lockowner, - const netobj *matchcookie, const netobj *filehandle); + const netobj *filehandle); void deallocate_file_lock(struct file_lock *fl); void fill_file_lock(struct file_lock *fl, struct sockaddr *addr, const bool_t exclusive, const int32_t svid, @@ -226,7 +232,7 @@ enum hwlock_status test_hwlock(const struct file_lock *fl, struct file_lock **conflicting_fl); void remove_blockingfilelock(struct file_lock *fl); void clear_blockingfilelock(const char *hostname); -void retry_blockingfilelocklist(void); +void retry_blockingfilelocklist(netobj *fh); enum partialfilelock_status unlock_partialfilelock( const struct file_lock *fl); void clear_partialfilelock(const char *hostname); @@ -366,9 +372,6 @@ dump_filelock(const struct file_lock *fl) debuglog("Dumping client identity:\n"); dump_netobj(&fl->client.oh); - debuglog("Dumping client cookie:\n"); - dump_netobj(&fl->client_cookie); - debuglog("nsm: %d status: %d flags: %d locker: %d" " fd: %d\n", fl->nsm_status, fl->status, fl->flags, fl->locker, fl->fd); @@ -399,7 +402,7 @@ copy_nlm4_lock_to_nlm4_holder(src, exclusive, dest) */ struct file_lock * -allocate_file_lock(const netobj *lockowner, const netobj *matchcookie, const netobj *filehandle) +allocate_file_lock(const netobj *lockowner, const netobj *filehandle) { struct file_lock *newfl; @@ -417,18 +420,8 @@ allocate_file_lock(const netobj *lockowner, const netobj *matchcookie, const net newfl->client.oh.n_len = lockowner->n_len; bcopy(lockowner->n_bytes, newfl->client.oh.n_bytes, lockowner->n_len); - newfl->client_cookie.n_bytes = malloc(matchcookie->n_len); - if (newfl->client_cookie.n_bytes == NULL) { - free(newfl->client.oh.n_bytes); - free(newfl); - return NULL; - } - newfl->client_cookie.n_len = matchcookie->n_len; - bcopy(matchcookie->n_bytes, newfl->client_cookie.n_bytes, matchcookie->n_len); - newfl->filehandle.n_bytes = malloc(filehandle->n_len); if (newfl->filehandle.n_bytes == NULL) { - free(newfl->client_cookie.n_bytes); free(newfl->client.oh.n_bytes); free(newfl); return NULL; @@ -470,7 +463,6 @@ void deallocate_file_lock(struct file_lock *fl) { free(fl->client.oh.n_bytes); - free(fl->client_cookie.n_bytes); free(fl->filehandle.n_bytes); free(fl); } @@ -726,7 +718,7 @@ same_filelock_identity(fl0, fl1) /* * get_lock_matching_unlock: Return a lock which matches the given unlock lock - * or NULL otehrwise + * or NULL otherwise * XXX: It is a shame that this duplicates so much code from test_nfslock. */ struct file_lock * @@ -956,8 +948,7 @@ split_nfslock(exist_lock, unlock_lock, left_lock, right_lock) &start1, &len1, &start2, &len2); if ((spstatus & SPL_LOCK1) != 0) { - *left_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->client_cookie, - &exist_lock->filehandle); + *left_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->filehandle); if (*left_lock == NULL) { debuglog("Unable to allocate resource for split 1\n"); return SPL_RESERR; @@ -972,8 +963,7 @@ split_nfslock(exist_lock, unlock_lock, left_lock, right_lock) } if ((spstatus & SPL_LOCK2) != 0) { - *right_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->client_cookie, - &exist_lock->filehandle); + *right_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->filehandle); if (*right_lock == NULL) { debuglog("Unable to allocate resource for split 1\n"); if (*left_lock != NULL) { @@ -1225,9 +1215,44 @@ test_hwlock(fl, conflicting_fl) void add_blockingfilelock(struct file_lock *fl) { + struct file_lock *ifl, *nfl; debuglog("Entering add_blockingfilelock\n"); + /* + * Check for a duplicate lock request. + * If found, deallocate the older request. + */ + ifl = LIST_FIRST(&blockedlocklist_head); + for (; ifl != NULL; ifl = nfl) { + debuglog("Pointer to file lock: %p\n",ifl); + debuglog("****Dump of ifl****\n"); + dump_filelock(ifl); + debuglog("*******************\n"); + + nfl = LIST_NEXT(ifl, nfslocklist); + + if (fl->filehandle.n_len != ifl->filehandle.n_len) + continue; + if (bcmp(fl->filehandle.n_bytes, ifl->filehandle.n_bytes, + fl->filehandle.n_len)) + continue; + + /* Filehandles match, check region */ + if ((fl->client.l_offset != ifl->client.l_offset) || + (fl->client.l_len != ifl->client.l_len)) + continue; + + /* Regions match, check the identity */ + if (!same_filelock_identity(fl,ifl)) + continue; + + debuglog("add_blockingfilelock: removing duplicate lock request.\n"); + remove_blockingfilelock(ifl); + deallocate_file_lock(ifl); + break; + } + /* * Clear the blocking flag so that it can be reused without * adding it to the blocking queue a second time @@ -1276,15 +1301,24 @@ clear_blockingfilelock(const char *hostname) } } +int need_retry_blocked_locks = 0; /* need to call retry_blockingfilelocklist() */ + void -retry_blockingfilelocklist(void) +retry_blockingfilelocklist(netobj *fh) { - /* Retry all locks in the blocked list */ + /* + * If fh is given, then retry just the locks with the + * same filehandle in the blocked list. + * Otherwise, simply retry all locks in the blocked list. + */ struct file_lock *ifl, *nfl, *pfl; /* Iterator */ enum partialfilelock_status pflstatus; + int rv; debuglog("Entering retry_blockingfilelocklist\n"); + need_retry_blocked_locks = 0; + pfl = NULL; ifl = LIST_FIRST(&blockedlocklist_head); debuglog("Iterator choice %p\n",ifl); @@ -1299,6 +1333,12 @@ retry_blockingfilelocklist(void) debuglog("Prev iterator choice %p\n",pfl); debuglog("Next iterator choice %p\n",nfl); + /* if given a filehandle, only retry locks for the same filehandle */ + if (fh && !same_netobj(fh, &ifl->filehandle)) { + ifl = nfl; + continue; + } + /* * SUBTLE BUG: The file_lock must be removed from the * old list so that it's list pointers get disconnected @@ -1312,8 +1352,18 @@ retry_blockingfilelocklist(void) if (pflstatus == PFL_GRANTED || pflstatus == PFL_GRANTED_DUPLICATE) { debuglog("Granted blocked lock\n"); /* lock granted and is now being used */ - send_granted(ifl,0); - /* XXX should undo lock if send_granted fails */ + rv = send_granted(ifl, 0); + if (rv) { + /* + * Uh oh... the NLM_GRANTED message failed. + * About the only thing we can do is drop the lock. + * Note: this could be bad if the error was only + * transient. Hopefully, if the client is still + * waiting for the lock, they will resend the request. + */ + do_unlock(ifl); + /* ifl is NO LONGER VALID AT THIS POINT */ + } } else { /* Reinsert lock back into same place in blocked list */ debuglog("Replacing blocked lock\n"); @@ -1324,13 +1374,16 @@ retry_blockingfilelocklist(void) LIST_INSERT_HEAD(&blockedlocklist_head, ifl, nfslocklist); } + if (pflstatus == PFL_GRANTED || pflstatus == PFL_GRANTED_DUPLICATE) { + /* If ifl was permanently removed from the list, (e.g the */ + /* lock was granted), pfl should remain where it's at. */ + } else { + /* If ifl was left in the list, (e.g it was reinserted back */ + /* in place), pfl should simply be moved forward to be ifl */ + pfl = ifl; + } /* Valid increment behavior regardless of state of ifl */ ifl = nfl; - /* if a lock was granted incrementing pfl would make it nfl */ - if (pfl != NULL && (LIST_NEXT(pfl, nfslocklist) != nfl)) - pfl = LIST_NEXT(pfl, nfslocklist); - else - pfl = LIST_FIRST(&blockedlocklist_head); } debuglog("Exiting retry_blockingfilelocklist\n"); @@ -1583,6 +1636,7 @@ unlock_partialfilelock(const struct file_lock *fl) // XXX Workaround is to move this to nlm_prot_svc.c // XXX after the unlock response is sent. // retry_blockingfilelocklist(); + need_retry_blocked_locks = 1; break; case NFS_DENIED_NOLOCK: retval = PFL_GRANTED; @@ -1949,7 +2003,7 @@ getlock(nlm4_lockargs *lckarg, struct svc_req *rqstp, const int flags) nlm4_denied_grace_period : nlm_denied_grace_period; /* allocate new file_lock for this request */ - newfl = allocate_file_lock(&lckarg->alock.oh, &lckarg->cookie, &lckarg->alock.fh); + newfl = allocate_file_lock(&lckarg->alock.oh, &lckarg->alock.fh); if (newfl == NULL) { syslog(LOG_NOTICE, "lock allocate failed: %s", strerror(errno)); /* failed */ @@ -2028,12 +2082,108 @@ unlock(nlm4_lock *lock, const int flags __unused) return err; } +/* cancel a blocked lock request */ +enum nlm_stats +cancellock(nlm4_cancargs *args, const int flags __unused) +{ + struct file_lock *ifl, *nfl; + enum nlm_stats err; + + siglock(); + + debuglog("Entering cancellock...\n"); + + err = nlm_denied; + + /* + * scan blocked lock list for matching request and remove/destroy + */ + ifl = LIST_FIRST(&blockedlocklist_head); + for ( ; ifl != NULL; ifl = nfl) { + nfl = LIST_NEXT(ifl, nfslocklist); + + /* compare lock fh - filehandle */ + if (!same_netobj(&args->alock.fh, &ifl->filehandle)) + continue; + + /* compare lock caller_name - client_name */ + if (strncmp(args->alock.caller_name, ifl->client_name, SM_MAXSTRLEN)) + continue; + + /* Note: done't compare cookie - client_cookie */ + /* The cookie may be specific to the cancel request */ + /* and not be the same as the one in the original lock request. */ + + /* compare lock oh - client.oh */ + if (!same_netobj(&args->alock.oh, &ifl->client.oh)) + continue; + + /* compare lock svid - client.svid */ + if (args->alock.svid != ifl->client.svid) + continue; + + /* compare lock l_offset - client.l_offset */ + if (args->alock.l_offset != ifl->client.l_offset) + continue; + + /* compare lock l_len - client.l_len */ + if (args->alock.l_len != ifl->client.l_len) + continue; + + /* compare exclusive - client.exclusive */ + if (args->exclusive != ifl->client.exclusive) + continue; + + /* got it */ + remove_blockingfilelock(ifl); + deallocate_file_lock(ifl); + err = nlm_granted; + break; + } + + sigunlock(); + + debuglog("Exiting cancellock...\n"); + + return err; +} + + /* * XXX: The following monitor/unmonitor routines * have not been extensively tested (ie. no regression * script exists like for the locking sections */ +/* + * Find a lock host on a queue. If found: + * bump the ref, + * bump the access time, + * dequeue it from the queue it was found on, + * enqueue it at the front of the "in use" queue. + */ +struct host * +get_lock_host(struct hostlst_head *hd, const char *hostname) +{ + struct host *ihp; + + debuglog("get_lock_host %s\n", hostname); + TAILQ_FOREACH(ihp, hd, hostlst) { + if (strncmp(hostname, ihp->name, SM_MAXSTRLEN) == 0) { + TAILQ_REMOVE(hd, ihp, hostlst); + /* Host is already monitored, bump refcount */ + ++ihp->refcnt; + ihp->lastuse = currsec; + /* Host should only be in the monitor list once */ + TAILQ_INSERT_HEAD(&hostlst_head, ihp, hostlst); + break; + } + } + debuglog("get_lock_host %s %s\n", + ihp == NULL ? "did not find" : "found", hostname); + return (ihp); +} + /* * monitor_lock_host: monitor lock hosts locally with a ref count and * inform statd @@ -2045,22 +2195,23 @@ monitor_lock_host(const char *hostname) struct mon smon; struct sm_stat_res sres; int rpcret, statflag; - + rpcret = 0; statflag = 0; - LIST_FOREACH(ihp, &hostlst_head, hostlst) { - if (strncmp(hostname, ihp->name, SM_MAXSTRLEN) == 0) { - /* Host is already monitored, bump refcount */ - ++ihp->refcnt; - /* Host should only be in the monitor list once */ - return; - } + debuglog("monitor_lock_host: %s\n", hostname); + ihp = get_lock_host(&hostlst_head, hostname); + if (ihp == NULL) + ihp = get_lock_host(&hostlst_unref, hostname); + if (ihp != NULL) { + debuglog("Monitor_lock_host: %s (cached)\n", hostname); + return; } + debuglog("Monitor_lock_host: %s (not found, creating)\n", hostname); /* Host is not yet monitored, add it */ nhp = malloc(sizeof(struct host)); - + if (nhp == NULL) { debuglog("Unable to allocate entry for statd mon\n"); return; @@ -2069,22 +2220,23 @@ monitor_lock_host(const char *hostname) /* Allocated new host entry, now fill the fields */ strncpy(nhp->name, hostname, SM_MAXSTRLEN); nhp->refcnt = 1; + nhp->lastuse = currsec; debuglog("Locally Monitoring host %16s\n",hostname); - + debuglog("Attempting to tell statd\n"); - + bzero(&smon,sizeof(smon)); - + smon.mon_id.mon_name = nhp->name; smon.mon_id.my_id.my_name = "localhost\0"; smon.mon_id.my_id.my_prog = NLM_PROG; smon.mon_id.my_id.my_vers = NLM_SM; smon.mon_id.my_id.my_proc = NLM_SM_NOTIFY; - + rpcret = callrpc("localhost", SM_PROG, SM_VERS, SM_MON, xdr_mon, &smon, xdr_sm_stat_res, &sres); - + if (rpcret == 0) { if (sres.res_stat == stat_fail) { debuglog("Statd call failed\n"); @@ -2097,13 +2249,12 @@ monitor_lock_host(const char *hostname) rpcret); statflag = 0; } - + if (statflag == 1) { - LIST_INSERT_HEAD(&hostlst_head, nhp, hostlst); + TAILQ_INSERT_HEAD(&hostlst_head, nhp, hostlst); } else { free(nhp); } - } /* @@ -2113,14 +2264,8 @@ void unmonitor_lock_host(const char *hostname) { struct host *ihp; - struct mon_id smon_id; - struct sm_stat smstat; - int rpcret; - - rpcret = 0; - for( ihp=LIST_FIRST(&hostlst_head); ihp != NULL; - ihp=LIST_NEXT(ihp, hostlst)) { + TAILQ_FOREACH(ihp, &hostlst_head, hostlst) { if (strncmp(hostname, ihp->name, SM_MAXSTRLEN) == 0) { /* Host is monitored, bump refcount */ --ihp->refcnt; @@ -2138,32 +2283,69 @@ unmonitor_lock_host(const char *hostname) return; if (ihp->refcnt < 0) { - debuglog("Negative refcount!: %d\n", - ihp->refcnt); + debuglog("Negative refcount!: %d\n", ihp->refcnt); } - debuglog("Attempting to unmonitor host %16s\n", hostname); + TAILQ_REMOVE(&hostlst_head, ihp, hostlst); + TAILQ_INSERT_HEAD(&hostlst_unref, ihp, hostlst); + if (host_expire <= 0) + destroy_lock_host(ihp); +} + +void +destroy_lock_host(struct host *ihp) +{ + struct mon_id smon_id; + struct sm_stat smstat; + int rpcret; + + debuglog("Attempting to unmonitor host %16s\n", ihp->name); bzero(&smon_id,sizeof(smon_id)); - smon_id.mon_name = (char *)hostname; + smon_id.mon_name = (char *)ihp->name; smon_id.my_id.my_name = "localhost"; smon_id.my_id.my_prog = NLM_PROG; smon_id.my_id.my_vers = NLM_SM; smon_id.my_id.my_proc = NLM_SM_NOTIFY; - rpcret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON, xdr_mon, - &smon_id, xdr_sm_stat_res, &smstat); + rpcret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON, xdr_mon_id, + &smon_id, xdr_sm_stat, &smstat); if (rpcret != 0) { debuglog("Rpc call to unmonitor statd failed with " - " return value: %d\n", rpcret); + " return value: %d: %s", rpcret, clnt_sperrno(rpcret)); + } else { + debuglog("Succeeded unmonitoring %16s\n", ihp->name); } - LIST_REMOVE(ihp, hostlst); + TAILQ_REMOVE(&hostlst_unref, ihp, hostlst); free(ihp); } +/* + * returns 1 if there are hosts to expire or 0 if there are none. + */ +int +expire_lock_hosts(void) +{ + struct host *ihp; + + debuglog("expire_lock_hosts: called\n"); + for ( ;; ) { + ihp = TAILQ_LAST(&hostlst_unref, hostlst_head); + if (ihp == NULL) + break; + if (host_expire > 0 && ihp->lastuse >= currsec - host_expire) + break; + debuglog("expire_lock_hosts: expiring %s %d %d %d\n", + ihp->name, (int)ihp->lastuse, + (int)currsec, (int)currsec - host_expire); + destroy_lock_host(ihp); + } + return (TAILQ_LAST(&hostlst_unref, hostlst_head) != NULL); +} + /* * notify: Clear all locks from a host if statd complains * @@ -2192,7 +2374,7 @@ notify(const char *hostname, const int state) debuglog("Leaving notify\n"); } -void +int send_granted(fl, opcode) struct file_lock *fl; int opcode __unused; @@ -2200,13 +2382,11 @@ send_granted(fl, opcode) CLIENT *cli; static char dummy; struct timeval timeo; - int success; + enum clnt_stat rv; static struct nlm_res retval; static struct nlm4_res retval4; debuglog("About to send granted on blocked lock\n"); - //sleep(1); - debuglog("Blowing off return send\n"); cli = get_client(fl->addr, (fl->flags & LOCK_V4) ? NLM_VERS4 : NLM_VERS); @@ -2218,14 +2398,19 @@ send_granted(fl, opcode) * The client will timeout and retry, the lock will be * granted at this time. */ - return; + return -1; } timeo.tv_sec = 0; timeo.tv_usec = (fl->flags & LOCK_ASYNC) ? 0 : 500000; /* 0.5s */ + fl->granted_cookie = ++send_granted_cookie; + if (!send_granted_cookie) + send_granted_cookie++; + if (fl->flags & LOCK_V4) { static nlm4_testargs res; - res.cookie = fl->client_cookie; + res.cookie.n_len = sizeof(fl->granted_cookie); + res.cookie.n_bytes = (char*)&fl->granted_cookie; res.exclusive = fl->client.exclusive; res.alock.caller_name = fl->client_name; res.alock.fh.n_len = fl->filehandle.n_len; @@ -2237,17 +2422,18 @@ send_granted(fl, opcode) debuglog("sending v4 reply%s", (fl->flags & LOCK_ASYNC) ? " (async)":""); if (fl->flags & LOCK_ASYNC) { - success = clnt_call(cli, NLM4_GRANTED_MSG, + rv = clnt_call(cli, NLM4_GRANTED_MSG, xdr_nlm4_testargs, &res, xdr_void, &dummy, timeo); } else { - success = clnt_call(cli, NLM4_GRANTED, + rv = clnt_call(cli, NLM4_GRANTED, xdr_nlm4_testargs, &res, xdr_nlm4_res, &retval4, timeo); } } else { static nlm_testargs res; - res.cookie = fl->client_cookie; + res.cookie.n_len = sizeof(fl->granted_cookie); + res.cookie.n_bytes = (char*)&fl->granted_cookie; res.exclusive = fl->client.exclusive; res.alock.caller_name = fl->client_name; res.alock.fh.n_len = fl->filehandle.n_len; @@ -2259,18 +2445,65 @@ send_granted(fl, opcode) debuglog("sending v1 reply%s", (fl->flags & LOCK_ASYNC) ? " (async)":""); if (fl->flags & LOCK_ASYNC) { - success = clnt_call(cli, NLM_GRANTED_MSG, + rv = clnt_call(cli, NLM_GRANTED_MSG, xdr_nlm_testargs, &res, xdr_void, &dummy, timeo); } else { - success = clnt_call(cli, NLM_GRANTED, + rv = clnt_call(cli, NLM_GRANTED, xdr_nlm_testargs, &res, xdr_nlm_res, &retval, timeo); } } if (debug_level > 2) debuglog("clnt_call returns %d(%s) for granted", - success, clnt_sperrno(success)); + rv, clnt_sperrno(rv)); + + if ((rv != RPC_SUCCESS) && + !((fl->flags & LOCK_ASYNC) && (rv == RPC_TIMEDOUT))) + return -1; + return 0; +} + +/* + * granted_failed: remove a granted lock that wasn't successfully + * accepted by the client + */ +void +granted_failed(nlm4_res *arg) +{ + u_int64_t cookie; + struct file_lock *ifl; + + debuglog("Entering granted_failed, status %d\n", arg->stat.stat); + + if (arg->cookie.n_len != sizeof(cookie)) { + debuglog("Exiting granted_failed: bogus cookie size %d\n", + arg->cookie.n_len); + return; + } + bcopy(arg->cookie.n_bytes, &cookie, sizeof(cookie)); + debuglog("granted_failed, cookie 0x%llx\n", cookie); + + LIST_FOREACH(ifl, &nfslocklist_head, nfslocklist) { + debuglog("Pointer to file lock: %p\n",ifl); + + debuglog("****Dump of ifl****\n"); + dump_filelock(ifl); + + if (ifl->granted_cookie != cookie) + continue; + + debuglog("granted_failed: cookie found\n"); + break; + } + + if (ifl) { + do_unlock(ifl); + /* ifl is NO LONGER VALID AT THIS POINT */ + } else { + debuglog("granted_failed: cookie NOT FOUND\n"); + } + debuglog("Exiting granted_failed\n"); } /* diff --git a/rpc_lockd.tproj/lockd_lock.h b/rpc_lockd.tproj/lockd_lock.h index fc54f32..4d93c7d 100644 --- a/rpc_lockd.tproj/lockd_lock.h +++ b/rpc_lockd.tproj/lockd_lock.h @@ -3,14 +3,17 @@ /* Headers and function declarations for file-locking utilities */ +#ifndef LOCKD_LOCK_H +#define LOCKD_LOCK_H struct nlm4_holder * testlock(struct nlm4_lock *lock, bool_t exclusive, int flags); enum nlm_stats getlock(nlm4_lockargs *lckarg, struct svc_req *rqstp, const int flags); enum nlm_stats unlock(nlm4_lock *lock, const int flags); -int lock_answer(int pid, netobj *netcookie, int result, int version, - int *pid_p, off_t l_start, off_t l_len); +enum nlm_stats cancellock(nlm4_cancargs *args, const int flags); +int lock_answer(int version, netobj *netcookie, nlm4_lock *lock, int flags, int result); enum nlm_stats getshare(nlm_shareargs *shrarg, struct svc_req *rqstp, const int flags); enum nlm_stats unshare(nlm_shareargs *shrarg, struct svc_req *rqstp); void do_free_all(const char *hostname); +void granted_failed(nlm4_res *arg); void notify(const char *hostname, const int state); @@ -18,9 +21,16 @@ void notify(const char *hostname, const int state); #define LOCK_ASYNC 0x01 /* async version (getlock only) */ #define LOCK_V4 0x02 /* v4 version */ #define LOCK_MON 0x04 /* monitored lock (getlock only) */ -#define LOCK_CANCEL 0x08 /* cancel, not unlock request (unlock only) */ + +/* flags for lock_answer */ +#define LOCK_ANSWER_GRANTED 0x0001 /* NLM_GRANTED request */ +#define LOCK_ANSWER_LOCK_EXCL 0x0004 /* lock is exclusive */ /* callbacks from lock_proc.c */ void transmit_result(int, nlm_res *, struct sockaddr *); void transmit4_result(int, nlm4_res *, struct sockaddr *); CLIENT *get_client(struct sockaddr *, rpcvers_t); + +extern time_t currsec; + +#endif /* !LOCKD_LOCK_H */ diff --git a/rpc_lockd.tproj/nlm_prot_svc.c b/rpc_lockd.tproj/nlm_prot_svc.c index 1e0dd9d..c395643 100644 --- a/rpc_lockd.tproj/nlm_prot_svc.c +++ b/rpc_lockd.tproj/nlm_prot_svc.c @@ -32,13 +32,14 @@ #endif // XXX -void retry_blockingfilelocklist(void); +void retry_blockingfilelocklist(netobj *fh); +extern int need_retry_blocked_locks; /* need to call retry_blockingfilelocklist() */ #define _RPCSVC_CLOSEDOWN 120 #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[] = "$Id: nlm_prot_svc.c,v 1.4 2003/07/24 05:11:22 lindak Exp $"; +static char rcsid[] = "$Id: nlm_prot_svc.c,v 1.4.36.1 2004/04/16 15:50:05 lindak Exp $"; #endif /* not lint */ extern int _rpcpmstart; /* Started by a port monitor ? */ extern int _rpcfdtype; /* Whether Stream or Datagram ? */ @@ -230,18 +231,21 @@ nlm_prog_1(struct svc_req *rqstp, SVCXPRT *transp) if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { svcerr_systemerr(transp); } + if (need_retry_blocked_locks) { + // XXX sending granted messages before unlock response + // XXX causes unlock response to be corrupted? + // XXX so do this after we send any response + netobj *fh = NULL; + if ((local == (char *(*)(char *, struct svc_req *)) nlm_unlock_1_svc) || + (local == (char *(*)(char *, struct svc_req *)) nlm_unlock_msg_1_svc)) + fh = &argument.nlm_unlock_1_arg.alock.fh; + retry_blockingfilelocklist(fh); + } if (!svc_freeargs(transp, xdr_argument, (caddr_t) &argument)) { syslog(LOG_ERR, "unable to free arguments"); exit(1); } _rpcsvcdirty = 0; - if ((local == (char *(*)(char *, struct svc_req *)) nlm_unlock_1_svc) || - (local == (char *(*)(char *, struct svc_req *)) nlm_unlock_msg_1_svc)) { - // XXX sending granted messages before unlock response - // XXX causes unlock response to be corrupted? - // XXX so do this after we send any response - retry_blockingfilelocklist(); - } return; } @@ -411,19 +415,21 @@ nlm_prog_3(struct svc_req *rqstp, SVCXPRT *transp) if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { svcerr_systemerr(transp); } + if (need_retry_blocked_locks) { + // XXX sending granted messages before unlock response + // XXX causes unlock response to be corrupted? + // XXX so do this after we send any response + netobj *fh = NULL; + if ((local == (char *(*)(char *, struct svc_req *)) nlm_unlock_1_svc) || + (local == (char *(*)(char *, struct svc_req *)) nlm_unlock_msg_1_svc)) + fh = &argument.nlm_unlock_3_arg.alock.fh; + retry_blockingfilelocklist(fh); + } if (!svc_freeargs(transp, xdr_argument, (caddr_t) &argument)) { syslog(LOG_ERR, "unable to free arguments"); exit(1); } _rpcsvcdirty = 0; - if ((local == (char *(*)(char *, struct svc_req *)) nlm_unlock_1_svc) || - (local == (char *(*)(char *, struct svc_req *)) nlm_unlock_msg_1_svc) || - (local == (char *(*)(char *, struct svc_req *)) nlm_free_all_3_svc)) { - // XXX sending granted messages before unlock response - // XXX causes unlock response to be corrupted? - // XXX so do this after we send any response - retry_blockingfilelocklist(); - } return; } @@ -593,18 +599,20 @@ nlm_prog_4(struct svc_req *rqstp, SVCXPRT *transp) if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { svcerr_systemerr(transp); } + if (need_retry_blocked_locks) { + // XXX sending granted messages before unlock response + // XXX causes unlock response to be corrupted? + // XXX so do this after we send any response + netobj *fh = NULL; + if ((local == (char *(*)(char *, struct svc_req *)) nlm4_unlock_4_svc) || + (local == (char *(*)(char *, struct svc_req *)) nlm4_unlock_msg_4_svc)) + fh = &argument.nlm4_unlock_4_arg.alock.fh; + retry_blockingfilelocklist(fh); + } if (!svc_freeargs(transp, xdr_argument, (caddr_t) &argument)) { syslog(LOG_ERR, "unable to free arguments"); exit(1); } _rpcsvcdirty = 0; - if ((local == (char *(*)(char *, struct svc_req *)) nlm4_unlock_4_svc) || - (local == (char *(*)(char *, struct svc_req *)) nlm4_unlock_msg_4_svc) || - (local == (char *(*)(char *, struct svc_req *)) nlm4_free_all_4_svc)) { - // XXX sending granted messages before unlock response - // XXX causes unlock response to be corrupted? - // XXX so do this after we send any response - retry_blockingfilelocklist(); - } return; } diff --git a/rpc_lockd.tproj/rpc.lockd.8 b/rpc_lockd.tproj/rpc.lockd.8 index e4172df..191bbec 100644 --- a/rpc_lockd.tproj/rpc.lockd.8 +++ b/rpc_lockd.tproj/rpc.lockd.8 @@ -43,6 +43,7 @@ .Nm .Op Fl d Ar debug_level .Op Fl g Ar grace period +.Op Fl x Ar statd cache period .Sh DESCRIPTION The .Nm @@ -93,6 +94,16 @@ locking daemon(s). This may be used on NFS clients to defer starting the NFS locking daemons until it is known that they will be needed. (Note: .Xr rpc.statd 8 will also be started if it isn't already running) +.It Fl x +The +.Fl x +option tells rpc.lockd how long to cache state records for contacting +client +.Xr rpc.statd 8 +implementations. Setting it to zero will disable the cache which will +make lock and unlock requests from a single client more expensive because +of additional interaction with the client's statd. The default cache time +is 60 seconds. .El .Pp Error conditions are logged to syslog, irrespective of the debug level,