1 1.10 tron /* $NetBSD: lock_proc.c,v 1.10 2012/06/18 20:30:32 tron Exp $ */ 2 1.1 scottr 3 1.1 scottr /* 4 1.1 scottr * Copyright (c) 1995 5 1.1 scottr * A.R. Gordon (andrew.gordon (at) net-tel.co.uk). All rights reserved. 6 1.1 scottr * 7 1.1 scottr * Redistribution and use in source and binary forms, with or without 8 1.1 scottr * modification, are permitted provided that the following conditions 9 1.1 scottr * are met: 10 1.1 scottr * 1. Redistributions of source code must retain the above copyright 11 1.1 scottr * notice, this list of conditions and the following disclaimer. 12 1.1 scottr * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 scottr * notice, this list of conditions and the following disclaimer in the 14 1.1 scottr * documentation and/or other materials provided with the distribution. 15 1.1 scottr * 3. All advertising materials mentioning features or use of this software 16 1.1 scottr * must display the following acknowledgement: 17 1.1 scottr * This product includes software developed for the FreeBSD project 18 1.1 scottr * 4. Neither the name of the author nor the names of any co-contributors 19 1.1 scottr * may be used to endorse or promote products derived from this software 20 1.1 scottr * without specific prior written permission. 21 1.1 scottr * 22 1.1 scottr * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND 23 1.1 scottr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 scottr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 scottr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 1.1 scottr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 scottr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 scottr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 scottr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 scottr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 scottr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 scottr * SUCH DAMAGE. 33 1.1 scottr * 34 1.1 scottr */ 35 1.1 scottr 36 1.2 lukem #include <sys/cdefs.h> 37 1.2 lukem #ifndef lint 38 1.10 tron __RCSID("$NetBSD: lock_proc.c,v 1.10 2012/06/18 20:30:32 tron Exp $"); 39 1.2 lukem #endif 40 1.2 lukem 41 1.1 scottr #include <sys/param.h> 42 1.1 scottr #include <sys/socket.h> 43 1.1 scottr 44 1.1 scottr #include <netinet/in.h> 45 1.1 scottr #include <arpa/inet.h> 46 1.1 scottr 47 1.2 lukem #include <netdb.h> 48 1.2 lukem #include <stdio.h> 49 1.2 lukem #include <string.h> 50 1.2 lukem #include <syslog.h> 51 1.5 fvdl #include <netconfig.h> 52 1.2 lukem 53 1.1 scottr #include <rpc/rpc.h> 54 1.1 scottr #include <rpcsvc/sm_inter.h> 55 1.1 scottr 56 1.1 scottr #include "lockd.h" 57 1.6 thorpej #include <rpcsvc/nlm_prot.h> 58 1.4 bouyer #include "lockd_lock.h" 59 1.1 scottr 60 1.1 scottr 61 1.1 scottr #define CLIENT_CACHE_SIZE 64 /* No. of client sockets cached */ 62 1.1 scottr #define CLIENT_CACHE_LIFETIME 120 /* In seconds */ 63 1.1 scottr 64 1.9 christos static void log_from_addr(const char *, struct svc_req *); 65 1.9 christos static int addrcmp(const struct sockaddr *, const struct sockaddr *); 66 1.9 christos static void nlmtonlm4(struct nlm_lock *, struct nlm4_lock *); 67 1.2 lukem 68 1.1 scottr /* log_from_addr ----------------------------------------------------------- */ 69 1.1 scottr /* 70 1.1 scottr * Purpose: Log name of function called and source address 71 1.1 scottr * Returns: Nothing 72 1.1 scottr * Notes: Extracts the source address from the transport handle 73 1.1 scottr * passed in as part of the called procedure specification 74 1.1 scottr */ 75 1.4 bouyer static void 76 1.9 christos log_from_addr(const char *fun_name, struct svc_req *req) 77 1.1 scottr { 78 1.5 fvdl struct sockaddr *addr; 79 1.5 fvdl char hostname_buf[NI_MAXHOST]; 80 1.5 fvdl 81 1.5 fvdl addr = svc_getrpccaller(req->rq_xprt)->buf; 82 1.9 christos if (getnameinfo(addr, (socklen_t)addr->sa_len, hostname_buf, 83 1.9 christos sizeof(hostname_buf), NULL, 0, 0) != 0) 84 1.5 fvdl return; 85 1.1 scottr 86 1.1 scottr syslog(LOG_DEBUG, "%s from %s", fun_name, hostname_buf); 87 1.1 scottr } 88 1.1 scottr 89 1.1 scottr /* get_client -------------------------------------------------------------- */ 90 1.1 scottr /* 91 1.1 scottr * Purpose: Get a CLIENT* for making RPC calls to lockd on given host 92 1.1 scottr * Returns: CLIENT* pointer, from clnt_udp_create, or NULL if error 93 1.1 scottr * Notes: Creating a CLIENT* is quite expensive, involving a 94 1.1 scottr * conversation with the remote portmapper to get the 95 1.1 scottr * port number. Since a given client is quite likely 96 1.1 scottr * to make several locking requests in succession, it is 97 1.1 scottr * desirable to cache the created CLIENT*. 98 1.1 scottr * 99 1.1 scottr * Since we are using UDP rather than TCP, there is no cost 100 1.1 scottr * to the remote system in keeping these cached indefinitely. 101 1.1 scottr * Unfortunately there is a snag: if the remote system 102 1.1 scottr * reboots, the cached portmapper results will be invalid, 103 1.1 scottr * and we will never detect this since all of the xxx_msg() 104 1.1 scottr * calls return no result - we just fire off a udp packet 105 1.1 scottr * and hope for the best. 106 1.1 scottr * 107 1.1 scottr * We solve this by discarding cached values after two 108 1.1 scottr * minutes, regardless of whether they have been used 109 1.1 scottr * in the meanwhile (since a bad one might have been used 110 1.1 scottr * plenty of times, as the host keeps retrying the request 111 1.1 scottr * and we keep sending the reply back to the wrong port). 112 1.1 scottr * 113 1.1 scottr * Given that the entries will always expire in the order 114 1.1 scottr * that they were created, there is no point in a LRU 115 1.1 scottr * algorithm for when the cache gets full - entries are 116 1.1 scottr * always re-used in sequence. 117 1.1 scottr */ 118 1.1 scottr static CLIENT *clnt_cache_ptr[CLIENT_CACHE_SIZE]; 119 1.1 scottr static long clnt_cache_time[CLIENT_CACHE_SIZE]; /* time entry created */ 120 1.5 fvdl static struct sockaddr_storage clnt_cache_addr[CLIENT_CACHE_SIZE]; 121 1.1 scottr static int clnt_cache_next_to_use = 0; 122 1.1 scottr 123 1.5 fvdl static int 124 1.9 christos addrcmp(const struct sockaddr *sa1, const struct sockaddr *sa2) 125 1.5 fvdl { 126 1.9 christos size_t len; 127 1.9 christos const void *p1, *p2; 128 1.5 fvdl 129 1.5 fvdl if (sa1->sa_family != sa2->sa_family) 130 1.5 fvdl return -1; 131 1.5 fvdl 132 1.5 fvdl switch (sa1->sa_family) { 133 1.5 fvdl case AF_INET: 134 1.9 christos p1 = &((const struct sockaddr_in *)(const void *)sa1)->sin_addr; 135 1.9 christos p2 = &((const struct sockaddr_in *)(const void *)sa2)->sin_addr; 136 1.5 fvdl len = 4; 137 1.5 fvdl break; 138 1.5 fvdl case AF_INET6: 139 1.9 christos p1 = &((const struct sockaddr_in6 *)(const void *)sa1)->sin6_addr; 140 1.9 christos p2 = &((const struct sockaddr_in6 *)(const void *)sa2)->sin6_addr; 141 1.5 fvdl len = 16; 142 1.5 fvdl break; 143 1.5 fvdl default: 144 1.5 fvdl return -1; 145 1.5 fvdl } 146 1.5 fvdl 147 1.5 fvdl return memcmp(p1, p2, len); 148 1.5 fvdl } 149 1.5 fvdl 150 1.4 bouyer CLIENT * 151 1.9 christos get_client(struct sockaddr *host_addr, rpcvers_t vers) 152 1.1 scottr { 153 1.1 scottr CLIENT *client; 154 1.1 scottr struct timeval retry_time, time_now; 155 1.5 fvdl int i; 156 1.9 christos const char *netid; 157 1.5 fvdl struct netconfig *nconf; 158 1.5 fvdl char host[NI_MAXHOST]; 159 1.10 tron int error; 160 1.1 scottr 161 1.9 christos (void)gettimeofday(&time_now, NULL); 162 1.1 scottr 163 1.1 scottr /* 164 1.1 scottr * Search for the given client in the cache, zapping any expired 165 1.1 scottr * entries that we happen to notice in passing. 166 1.1 scottr */ 167 1.1 scottr for (i = 0; i < CLIENT_CACHE_SIZE; i++) { 168 1.1 scottr client = clnt_cache_ptr[i]; 169 1.1 scottr if (client && ((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME) 170 1.1 scottr < time_now.tv_sec)) { 171 1.1 scottr /* Cache entry has expired. */ 172 1.1 scottr if (debug_level > 3) 173 1.1 scottr syslog(LOG_DEBUG, "Expired CLIENT* in cache"); 174 1.1 scottr clnt_cache_time[i] = 0L; 175 1.1 scottr clnt_destroy(client); 176 1.1 scottr clnt_cache_ptr[i] = NULL; 177 1.1 scottr client = NULL; 178 1.1 scottr } 179 1.9 christos if (client && !addrcmp((const struct sockaddr *)(const void *) 180 1.9 christos &clnt_cache_addr[i], host_addr)) { 181 1.1 scottr /* Found it! */ 182 1.1 scottr if (debug_level > 3) 183 1.1 scottr syslog(LOG_DEBUG, "Found CLIENT* in cache"); 184 1.9 christos return client; 185 1.1 scottr } 186 1.1 scottr } 187 1.1 scottr 188 1.1 scottr /* Not found in cache. Free the next entry if it is in use. */ 189 1.1 scottr if (clnt_cache_ptr[clnt_cache_next_to_use]) { 190 1.1 scottr clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]); 191 1.1 scottr clnt_cache_ptr[clnt_cache_next_to_use] = NULL; 192 1.1 scottr } 193 1.1 scottr 194 1.5 fvdl /* 195 1.5 fvdl * Need a host string for clnt_tp_create. Use NI_NUMERICHOST 196 1.5 fvdl * to avoid DNS lookups. 197 1.5 fvdl */ 198 1.10 tron error = getnameinfo(host_addr, (socklen_t)host_addr->sa_len, host, 199 1.10 tron sizeof(host), NULL, 0, NI_NUMERICHOST); 200 1.10 tron if (error != 0) { 201 1.10 tron syslog(LOG_ERR, "unable to get name string for caller: %s", 202 1.10 tron gai_strerror(error)); 203 1.5 fvdl return NULL; 204 1.5 fvdl } 205 1.5 fvdl 206 1.4 bouyer #if 1 207 1.5 fvdl if (host_addr->sa_family == AF_INET6) 208 1.5 fvdl netid = "udp6"; 209 1.5 fvdl else 210 1.5 fvdl netid = "udp"; 211 1.4 bouyer #else 212 1.5 fvdl if (host_addr->sa_family == AF_INET6) 213 1.5 fvdl netid = "tcp6"; 214 1.5 fvdl else 215 1.5 fvdl netid = "tcp"; 216 1.4 bouyer #endif 217 1.5 fvdl nconf = getnetconfigent(netid); 218 1.5 fvdl if (nconf == NULL) { 219 1.5 fvdl syslog(LOG_ERR, "could not get netconfig info for '%s': " 220 1.5 fvdl "no /etc/netconfig file?", netid); 221 1.5 fvdl return NULL; 222 1.5 fvdl } 223 1.5 fvdl 224 1.5 fvdl client = clnt_tp_create(host, NLM_PROG, vers, nconf); 225 1.5 fvdl freenetconfigent(nconf); 226 1.5 fvdl 227 1.1 scottr if (!client) { 228 1.7 is syslog(LOG_ERR, "%s", clnt_spcreateerror("clntudp_create")); 229 1.5 fvdl syslog(LOG_ERR, "Unable to return result to %s", host); 230 1.1 scottr return NULL; 231 1.1 scottr } 232 1.1 scottr 233 1.1 scottr /* Success - update the cache entry */ 234 1.1 scottr clnt_cache_ptr[clnt_cache_next_to_use] = client; 235 1.9 christos (void)memcpy(&clnt_cache_addr[clnt_cache_next_to_use], host_addr, 236 1.9 christos (size_t)host_addr->sa_len); 237 1.1 scottr clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec; 238 1.8 tron if (++clnt_cache_next_to_use >= CLIENT_CACHE_SIZE) 239 1.1 scottr clnt_cache_next_to_use = 0; 240 1.1 scottr 241 1.1 scottr /* 242 1.1 scottr * Disable the default timeout, so we can specify our own in calls 243 1.1 scottr * to clnt_call(). (Note that the timeout is a different concept 244 1.1 scottr * from the retry period set in clnt_udp_create() above.) 245 1.1 scottr */ 246 1.1 scottr retry_time.tv_sec = -1; 247 1.1 scottr retry_time.tv_usec = -1; 248 1.9 christos clnt_control(client, CLSET_TIMEOUT, (char *)(void *)&retry_time); 249 1.1 scottr 250 1.1 scottr if (debug_level > 3) 251 1.5 fvdl syslog(LOG_DEBUG, "Created CLIENT* for %s", host); 252 1.1 scottr return client; 253 1.1 scottr } 254 1.1 scottr 255 1.1 scottr 256 1.1 scottr /* transmit_result --------------------------------------------------------- */ 257 1.1 scottr /* 258 1.1 scottr * Purpose: Transmit result for nlm_xxx_msg pseudo-RPCs 259 1.1 scottr * Returns: Nothing - we have no idea if the datagram got there 260 1.1 scottr * Notes: clnt_call() will always fail (with timeout) as we are 261 1.1 scottr * calling it with timeout 0 as a hack to just issue a datagram 262 1.1 scottr * without expecting a result 263 1.1 scottr */ 264 1.4 bouyer void 265 1.9 christos transmit_result(int opcode, nlm_res *result, struct sockaddr *addr) 266 1.1 scottr { 267 1.1 scottr static char dummy; 268 1.1 scottr CLIENT *cli; 269 1.1 scottr struct timeval timeo; 270 1.1 scottr int success; 271 1.1 scottr 272 1.5 fvdl if ((cli = get_client(addr, NLM_VERS)) != NULL) { 273 1.1 scottr timeo.tv_sec = 0; /* No timeout - not expecting response */ 274 1.1 scottr timeo.tv_usec = 0; 275 1.1 scottr 276 1.9 christos success = clnt_call(cli, (rpcproc_t)opcode, xdr_nlm_res, 277 1.9 christos result, xdr_void, &dummy, timeo); 278 1.1 scottr 279 1.1 scottr if (debug_level > 2) 280 1.4 bouyer syslog(LOG_DEBUG, "clnt_call returns %d(%s)", 281 1.4 bouyer success, clnt_sperrno(success)); 282 1.1 scottr } 283 1.1 scottr } 284 1.3 bouyer /* transmit4_result --------------------------------------------------------- */ 285 1.3 bouyer /* 286 1.3 bouyer * Purpose: Transmit result for nlm4_xxx_msg pseudo-RPCs 287 1.3 bouyer * Returns: Nothing - we have no idea if the datagram got there 288 1.3 bouyer * Notes: clnt_call() will always fail (with timeout) as we are 289 1.3 bouyer * calling it with timeout 0 as a hack to just issue a datagram 290 1.3 bouyer * without expecting a result 291 1.3 bouyer */ 292 1.4 bouyer void 293 1.9 christos transmit4_result(int opcode, nlm4_res *result, struct sockaddr *addr) 294 1.3 bouyer { 295 1.3 bouyer static char dummy; 296 1.3 bouyer CLIENT *cli; 297 1.3 bouyer struct timeval timeo; 298 1.3 bouyer int success; 299 1.3 bouyer 300 1.5 fvdl if ((cli = get_client(addr, NLM_VERS4)) != NULL) { 301 1.3 bouyer timeo.tv_sec = 0; /* No timeout - not expecting response */ 302 1.3 bouyer timeo.tv_usec = 0; 303 1.3 bouyer 304 1.9 christos success = clnt_call(cli, (rpcproc_t)opcode, xdr_nlm4_res, 305 1.9 christos result, xdr_void, &dummy, timeo); 306 1.3 bouyer 307 1.3 bouyer if (debug_level > 2) 308 1.4 bouyer syslog(LOG_DEBUG, "clnt_call returns %d(%s)", 309 1.4 bouyer success, clnt_sperrno(success)); 310 1.3 bouyer } 311 1.3 bouyer } 312 1.4 bouyer 313 1.4 bouyer /* 314 1.4 bouyer * converts a struct nlm_lock to struct nlm4_lock 315 1.4 bouyer */ 316 1.4 bouyer static void 317 1.9 christos nlmtonlm4(struct nlm_lock *arg, struct nlm4_lock *arg4) 318 1.4 bouyer { 319 1.9 christos (void)memcpy(arg4, arg, sizeof(nlm_lock)); 320 1.4 bouyer arg4->l_offset = arg->l_offset; 321 1.4 bouyer arg4->l_len = arg->l_len; 322 1.4 bouyer } 323 1.9 christos 324 1.1 scottr /* ------------------------------------------------------------------------- */ 325 1.1 scottr /* 326 1.1 scottr * Functions for Unix<->Unix locking (ie. monitored locking, with rpc.statd 327 1.1 scottr * involved to ensure reclaim of locks after a crash of the "stateless" 328 1.1 scottr * server. 329 1.1 scottr * 330 1.1 scottr * These all come in two flavours - nlm_xxx() and nlm_xxx_msg(). 331 1.1 scottr * The first are standard RPCs with argument and result. 332 1.1 scottr * The nlm_xxx_msg() calls implement exactly the same functions, but 333 1.1 scottr * use two pseudo-RPCs (one in each direction). These calls are NOT 334 1.1 scottr * standard use of the RPC protocol in that they do not return a result 335 1.1 scottr * at all (NB. this is quite different from returning a void result). 336 1.1 scottr * The effect of this is to make the nlm_xxx_msg() calls simple unacknowledged 337 1.1 scottr * datagrams, requiring higher-level code to perform retries. 338 1.1 scottr * 339 1.1 scottr * Despite the disadvantages of the nlm_xxx_msg() approach (some of which 340 1.1 scottr * are documented in the comments to get_client() above), this is the 341 1.1 scottr * interface used by all current commercial NFS implementations 342 1.1 scottr * [Solaris, SCO, AIX etc.]. This is presumed to be because these allow 343 1.1 scottr * implementations to continue using the standard RPC libraries, while 344 1.1 scottr * avoiding the block-until-result nature of the library interface. 345 1.1 scottr * 346 1.1 scottr * No client implementations have been identified so far that make use 347 1.1 scottr * of the true RPC version (early SunOS releases would be a likely candidate 348 1.1 scottr * for testing). 349 1.1 scottr */ 350 1.1 scottr 351 1.1 scottr /* nlm_test ---------------------------------------------------------------- */ 352 1.1 scottr /* 353 1.1 scottr * Purpose: Test whether a specified lock would be granted if requested 354 1.1 scottr * Returns: nlm_granted (or error code) 355 1.1 scottr * Notes: 356 1.1 scottr */ 357 1.1 scottr nlm_testres * 358 1.9 christos nlm_test_1_svc(nlm_testargs *arg, struct svc_req *rqstp) 359 1.1 scottr { 360 1.9 christos static nlm_testres result; 361 1.4 bouyer struct nlm4_lock arg4; 362 1.4 bouyer struct nlm4_holder *holder; 363 1.4 bouyer nlmtonlm4(&arg->alock, &arg4); 364 1.1 scottr 365 1.1 scottr if (debug_level) 366 1.1 scottr log_from_addr("nlm_test", rqstp); 367 1.1 scottr 368 1.4 bouyer holder = testlock(&arg4, 0); 369 1.1 scottr /* 370 1.1 scottr * Copy the cookie from the argument into the result. Note that this 371 1.1 scottr * is slightly hazardous, as the structure contains a pointer to a 372 1.1 scottr * malloc()ed buffer that will get freed by the caller. However, the 373 1.1 scottr * main function transmits the result before freeing the argument 374 1.1 scottr * so it is in fact safe. 375 1.1 scottr */ 376 1.9 christos result.cookie = arg->cookie; 377 1.4 bouyer if (holder == NULL) { 378 1.9 christos result.stat.stat = nlm_granted; 379 1.4 bouyer } else { 380 1.9 christos result.stat.stat = nlm_denied; 381 1.9 christos (void)memcpy(&result.stat.nlm_testrply_u.holder, holder, 382 1.4 bouyer sizeof(struct nlm_holder)); 383 1.9 christos result.stat.nlm_testrply_u.holder.l_offset = 384 1.9 christos (unsigned int)holder->l_offset; 385 1.9 christos result.stat.nlm_testrply_u.holder.l_len = 386 1.9 christos (unsigned int)holder->l_len; 387 1.4 bouyer } 388 1.9 christos return &result; 389 1.1 scottr } 390 1.1 scottr 391 1.1 scottr void * 392 1.9 christos nlm_test_msg_1_svc(nlm_testargs *arg, struct svc_req *rqstp) 393 1.1 scottr { 394 1.9 christos nlm_testres result; 395 1.1 scottr static char dummy; 396 1.5 fvdl struct sockaddr *addr; 397 1.1 scottr CLIENT *cli; 398 1.1 scottr int success; 399 1.1 scottr struct timeval timeo; 400 1.4 bouyer struct nlm4_lock arg4; 401 1.4 bouyer struct nlm4_holder *holder; 402 1.4 bouyer 403 1.4 bouyer nlmtonlm4(&arg->alock, &arg4); 404 1.1 scottr 405 1.1 scottr if (debug_level) 406 1.1 scottr log_from_addr("nlm_test_msg", rqstp); 407 1.1 scottr 408 1.4 bouyer holder = testlock(&arg4, 0); 409 1.4 bouyer 410 1.9 christos result.cookie = arg->cookie; 411 1.4 bouyer if (holder == NULL) { 412 1.9 christos result.stat.stat = nlm_granted; 413 1.4 bouyer } else { 414 1.9 christos result.stat.stat = nlm_denied; 415 1.9 christos (void)memcpy(&result.stat.nlm_testrply_u.holder, holder, 416 1.4 bouyer sizeof(struct nlm_holder)); 417 1.9 christos result.stat.nlm_testrply_u.holder.l_offset = 418 1.9 christos (unsigned int)holder->l_offset; 419 1.9 christos result.stat.nlm_testrply_u.holder.l_len = 420 1.9 christos (unsigned int)holder->l_len; 421 1.4 bouyer } 422 1.1 scottr 423 1.1 scottr /* 424 1.1 scottr * nlm_test has different result type to the other operations, so 425 1.1 scottr * can't use transmit_result() in this case 426 1.1 scottr */ 427 1.5 fvdl addr = svc_getrpccaller(rqstp->rq_xprt)->buf; 428 1.4 bouyer if ((cli = get_client(addr, NLM_VERS)) != NULL) { 429 1.1 scottr timeo.tv_sec = 0; /* No timeout - not expecting response */ 430 1.1 scottr timeo.tv_usec = 0; 431 1.1 scottr 432 1.1 scottr success = clnt_call(cli, NLM_TEST_RES, xdr_nlm_testres, 433 1.9 christos &result, xdr_void, &dummy, timeo); 434 1.1 scottr 435 1.1 scottr if (debug_level > 2) 436 1.4 bouyer syslog(LOG_DEBUG, "clnt_call returns %d", success); 437 1.1 scottr } 438 1.9 christos return NULL; 439 1.1 scottr } 440 1.1 scottr 441 1.1 scottr /* nlm_lock ---------------------------------------------------------------- */ 442 1.1 scottr /* 443 1.1 scottr * Purposes: Establish a lock 444 1.1 scottr * Returns: granted, denied or blocked 445 1.1 scottr * Notes: *** grace period support missing 446 1.1 scottr */ 447 1.1 scottr nlm_res * 448 1.9 christos nlm_lock_1_svc(nlm_lockargs *arg, struct svc_req *rqstp) 449 1.1 scottr { 450 1.9 christos static nlm_res result; 451 1.4 bouyer struct nlm4_lockargs arg4; 452 1.4 bouyer nlmtonlm4(&arg->alock, &arg4.alock); 453 1.4 bouyer arg4.cookie = arg->cookie; 454 1.4 bouyer arg4.block = arg->block; 455 1.4 bouyer arg4.exclusive = arg->exclusive; 456 1.4 bouyer arg4.reclaim = arg->reclaim; 457 1.4 bouyer arg4.state = arg->state; 458 1.1 scottr 459 1.1 scottr if (debug_level) 460 1.1 scottr log_from_addr("nlm_lock", rqstp); 461 1.1 scottr 462 1.1 scottr /* copy cookie from arg to result. See comment in nlm_test_1() */ 463 1.9 christos result.cookie = arg->cookie; 464 1.1 scottr 465 1.9 christos result.stat.stat = getlock(&arg4, rqstp, LOCK_MON); 466 1.9 christos return &result; 467 1.1 scottr } 468 1.1 scottr 469 1.1 scottr void * 470 1.9 christos nlm_lock_msg_1_svc(nlm_lockargs *arg, struct svc_req *rqstp) 471 1.1 scottr { 472 1.9 christos static nlm_res result; 473 1.4 bouyer struct nlm4_lockargs arg4; 474 1.4 bouyer 475 1.4 bouyer nlmtonlm4(&arg->alock, &arg4.alock); 476 1.4 bouyer arg4.cookie = arg->cookie; 477 1.4 bouyer arg4.block = arg->block; 478 1.4 bouyer arg4.exclusive = arg->exclusive; 479 1.4 bouyer arg4.reclaim = arg->reclaim; 480 1.4 bouyer arg4.state = arg->state; 481 1.1 scottr 482 1.1 scottr if (debug_level) 483 1.1 scottr log_from_addr("nlm_lock_msg", rqstp); 484 1.1 scottr 485 1.9 christos result.cookie = arg->cookie; 486 1.9 christos result.stat.stat = getlock(&arg4, rqstp, LOCK_ASYNC | LOCK_MON); 487 1.9 christos transmit_result(NLM_LOCK_RES, &result, 488 1.10 tron (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf); 489 1.1 scottr 490 1.9 christos return NULL; 491 1.1 scottr } 492 1.1 scottr 493 1.1 scottr /* nlm_cancel -------------------------------------------------------------- */ 494 1.1 scottr /* 495 1.1 scottr * Purpose: Cancel a blocked lock request 496 1.1 scottr * Returns: granted or denied 497 1.1 scottr * Notes: 498 1.1 scottr */ 499 1.1 scottr nlm_res * 500 1.9 christos nlm_cancel_1_svc(nlm_cancargs *arg, struct svc_req *rqstp) 501 1.1 scottr { 502 1.9 christos static nlm_res result; 503 1.4 bouyer struct nlm4_lock arg4; 504 1.4 bouyer 505 1.4 bouyer nlmtonlm4(&arg->alock, &arg4); 506 1.1 scottr 507 1.1 scottr if (debug_level) 508 1.1 scottr log_from_addr("nlm_cancel", rqstp); 509 1.1 scottr 510 1.1 scottr /* copy cookie from arg to result. See comment in nlm_test_1() */ 511 1.9 christos result.cookie = arg->cookie; 512 1.1 scottr 513 1.1 scottr /* 514 1.1 scottr * Since at present we never return 'nlm_blocked', there can never be 515 1.1 scottr * a lock to cancel, so this call always fails. 516 1.1 scottr */ 517 1.9 christos result.stat.stat = unlock(&arg4, LOCK_CANCEL); 518 1.9 christos return &result; 519 1.1 scottr } 520 1.1 scottr 521 1.1 scottr void * 522 1.9 christos nlm_cancel_msg_1_svc(nlm_cancargs *arg, struct svc_req *rqstp) 523 1.1 scottr { 524 1.9 christos static nlm_res result; 525 1.4 bouyer struct nlm4_lock arg4; 526 1.4 bouyer 527 1.4 bouyer nlmtonlm4(&arg->alock, &arg4); 528 1.1 scottr 529 1.1 scottr if (debug_level) 530 1.1 scottr log_from_addr("nlm_cancel_msg", rqstp); 531 1.1 scottr 532 1.9 christos result.cookie = arg->cookie; 533 1.1 scottr /* 534 1.1 scottr * Since at present we never return 'nlm_blocked', there can never be 535 1.1 scottr * a lock to cancel, so this call always fails. 536 1.1 scottr */ 537 1.9 christos result.stat.stat = unlock(&arg4, LOCK_CANCEL); 538 1.9 christos transmit_result(NLM_CANCEL_RES, &result, 539 1.10 tron (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf); 540 1.9 christos return NULL; 541 1.1 scottr } 542 1.1 scottr 543 1.1 scottr /* nlm_unlock -------------------------------------------------------------- */ 544 1.1 scottr /* 545 1.1 scottr * Purpose: Release an existing lock 546 1.1 scottr * Returns: Always granted, unless during grace period 547 1.1 scottr * Notes: "no such lock" error condition is ignored, as the 548 1.1 scottr * protocol uses unreliable UDP datagrams, and may well 549 1.1 scottr * re-try an unlock that has already succeeded. 550 1.1 scottr */ 551 1.1 scottr nlm_res * 552 1.9 christos nlm_unlock_1_svc(nlm_unlockargs *arg, struct svc_req *rqstp) 553 1.1 scottr { 554 1.9 christos static nlm_res result; 555 1.4 bouyer struct nlm4_lock arg4; 556 1.4 bouyer 557 1.4 bouyer nlmtonlm4(&arg->alock, &arg4); 558 1.1 scottr 559 1.1 scottr if (debug_level) 560 1.1 scottr log_from_addr("nlm_unlock", rqstp); 561 1.1 scottr 562 1.9 christos result.stat.stat = unlock(&arg4, 0); 563 1.9 christos result.cookie = arg->cookie; 564 1.1 scottr 565 1.9 christos return &result; 566 1.1 scottr } 567 1.1 scottr 568 1.1 scottr void * 569 1.9 christos nlm_unlock_msg_1_svc(nlm_unlockargs *arg, struct svc_req *rqstp) 570 1.1 scottr { 571 1.9 christos static nlm_res result; 572 1.4 bouyer struct nlm4_lock arg4; 573 1.4 bouyer 574 1.4 bouyer nlmtonlm4(&arg->alock, &arg4); 575 1.1 scottr 576 1.1 scottr if (debug_level) 577 1.1 scottr log_from_addr("nlm_unlock_msg", rqstp); 578 1.1 scottr 579 1.9 christos result.stat.stat = unlock(&arg4, 0); 580 1.9 christos result.cookie = arg->cookie; 581 1.1 scottr 582 1.9 christos transmit_result(NLM_UNLOCK_RES, &result, 583 1.10 tron (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf); 584 1.9 christos return NULL; 585 1.1 scottr } 586 1.1 scottr 587 1.1 scottr /* ------------------------------------------------------------------------- */ 588 1.1 scottr /* 589 1.1 scottr * Client-side pseudo-RPCs for results. Note that for the client there 590 1.1 scottr * are only nlm_xxx_msg() versions of each call, since the 'real RPC' 591 1.1 scottr * version returns the results in the RPC result, and so the client 592 1.1 scottr * does not normally receive incoming RPCs. 593 1.1 scottr * 594 1.1 scottr * The exception to this is nlm_granted(), which is genuinely an RPC 595 1.1 scottr * call from the server to the client - a 'call-back' in normal procedure 596 1.1 scottr * call terms. 597 1.1 scottr */ 598 1.1 scottr 599 1.1 scottr /* nlm_granted ------------------------------------------------------------- */ 600 1.1 scottr /* 601 1.1 scottr * Purpose: Receive notification that formerly blocked lock now granted 602 1.1 scottr * Returns: always success ('granted') 603 1.1 scottr * Notes: 604 1.1 scottr */ 605 1.1 scottr nlm_res * 606 1.9 christos nlm_granted_1_svc(nlm_testargs *arg, struct svc_req *rqstp) 607 1.1 scottr { 608 1.9 christos static nlm_res result; 609 1.1 scottr 610 1.1 scottr if (debug_level) 611 1.1 scottr log_from_addr("nlm_granted", rqstp); 612 1.1 scottr 613 1.1 scottr /* copy cookie from arg to result. See comment in nlm_test_1() */ 614 1.9 christos result.cookie = arg->cookie; 615 1.1 scottr 616 1.9 christos result.stat.stat = nlm_granted; 617 1.9 christos return &result; 618 1.1 scottr } 619 1.1 scottr 620 1.1 scottr void * 621 1.9 christos nlm_granted_msg_1_svc(nlm_testargs *arg, struct svc_req *rqstp) 622 1.1 scottr { 623 1.9 christos static nlm_res result; 624 1.1 scottr 625 1.1 scottr if (debug_level) 626 1.1 scottr log_from_addr("nlm_granted_msg", rqstp); 627 1.1 scottr 628 1.9 christos result.cookie = arg->cookie; 629 1.9 christos result.stat.stat = nlm_granted; 630 1.9 christos transmit_result(NLM_GRANTED_RES, &result, 631 1.10 tron (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf); 632 1.9 christos return NULL; 633 1.1 scottr } 634 1.1 scottr 635 1.1 scottr /* nlm_test_res ------------------------------------------------------------ */ 636 1.1 scottr /* 637 1.1 scottr * Purpose: Accept result from earlier nlm_test_msg() call 638 1.1 scottr * Returns: Nothing 639 1.1 scottr */ 640 1.1 scottr void * 641 1.9 christos /*ARGSUSED*/ 642 1.9 christos nlm_test_res_1_svc(nlm_testres *arg, struct svc_req *rqstp) 643 1.1 scottr { 644 1.1 scottr if (debug_level) 645 1.1 scottr log_from_addr("nlm_test_res", rqstp); 646 1.9 christos return NULL; 647 1.1 scottr } 648 1.1 scottr 649 1.1 scottr /* nlm_lock_res ------------------------------------------------------------ */ 650 1.1 scottr /* 651 1.1 scottr * Purpose: Accept result from earlier nlm_lock_msg() call 652 1.1 scottr * Returns: Nothing 653 1.1 scottr */ 654 1.1 scottr void * 655 1.9 christos /*ARGSUSED*/ 656 1.9 christos nlm_lock_res_1_svc(nlm_res *arg, struct svc_req *rqstp) 657 1.1 scottr { 658 1.1 scottr if (debug_level) 659 1.1 scottr log_from_addr("nlm_lock_res", rqstp); 660 1.1 scottr 661 1.9 christos return NULL; 662 1.1 scottr } 663 1.1 scottr 664 1.1 scottr /* nlm_cancel_res ---------------------------------------------------------- */ 665 1.1 scottr /* 666 1.1 scottr * Purpose: Accept result from earlier nlm_cancel_msg() call 667 1.1 scottr * Returns: Nothing 668 1.1 scottr */ 669 1.1 scottr void * 670 1.9 christos /*ARGSUSED*/ 671 1.9 christos nlm_cancel_res_1_svc(nlm_res *arg, struct svc_req *rqstp) 672 1.1 scottr { 673 1.1 scottr if (debug_level) 674 1.1 scottr log_from_addr("nlm_cancel_res", rqstp); 675 1.9 christos return NULL; 676 1.1 scottr } 677 1.1 scottr 678 1.1 scottr /* nlm_unlock_res ---------------------------------------------------------- */ 679 1.1 scottr /* 680 1.1 scottr * Purpose: Accept result from earlier nlm_unlock_msg() call 681 1.1 scottr * Returns: Nothing 682 1.1 scottr */ 683 1.1 scottr void * 684 1.9 christos /*ARGSUSED*/ 685 1.9 christos nlm_unlock_res_1_svc(nlm_res *arg, struct svc_req *rqstp) 686 1.1 scottr { 687 1.1 scottr if (debug_level) 688 1.1 scottr log_from_addr("nlm_unlock_res", rqstp); 689 1.9 christos return NULL; 690 1.1 scottr } 691 1.1 scottr 692 1.1 scottr /* nlm_granted_res --------------------------------------------------------- */ 693 1.1 scottr /* 694 1.1 scottr * Purpose: Accept result from earlier nlm_granted_msg() call 695 1.1 scottr * Returns: Nothing 696 1.1 scottr */ 697 1.1 scottr void * 698 1.9 christos /*ARGSUSED*/ 699 1.9 christos nlm_granted_res_1_svc(nlm_res *arg, struct svc_req *rqstp) 700 1.1 scottr { 701 1.1 scottr if (debug_level) 702 1.1 scottr log_from_addr("nlm_granted_res", rqstp); 703 1.9 christos return NULL; 704 1.1 scottr } 705 1.1 scottr 706 1.1 scottr /* ------------------------------------------------------------------------- */ 707 1.1 scottr /* 708 1.1 scottr * Calls for PCNFS locking (aka non-monitored locking, no involvement 709 1.1 scottr * of rpc.statd). 710 1.1 scottr * 711 1.1 scottr * These are all genuine RPCs - no nlm_xxx_msg() nonsense here. 712 1.1 scottr */ 713 1.1 scottr 714 1.1 scottr /* nlm_share --------------------------------------------------------------- */ 715 1.1 scottr /* 716 1.1 scottr * Purpose: Establish a DOS-style lock 717 1.1 scottr * Returns: success or failure 718 1.1 scottr * Notes: Blocking locks are not supported - client is expected 719 1.1 scottr * to retry if required. 720 1.1 scottr */ 721 1.1 scottr nlm_shareres * 722 1.9 christos nlm_share_3_svc(nlm_shareargs *arg, struct svc_req *rqstp) 723 1.1 scottr { 724 1.9 christos static nlm_shareres result; 725 1.1 scottr 726 1.1 scottr if (debug_level) 727 1.1 scottr log_from_addr("nlm_share", rqstp); 728 1.1 scottr 729 1.9 christos result.cookie = arg->cookie; 730 1.9 christos result.stat = nlm_granted; 731 1.9 christos result.sequence = 1234356; /* X/Open says this field is ignored? */ 732 1.9 christos return &result; 733 1.1 scottr } 734 1.1 scottr 735 1.1 scottr /* nlm_unshare ------------------------------------------------------------ */ 736 1.1 scottr /* 737 1.1 scottr * Purpose: Release a DOS-style lock 738 1.1 scottr * Returns: nlm_granted, unless in grace period 739 1.1 scottr * Notes: 740 1.1 scottr */ 741 1.1 scottr nlm_shareres * 742 1.9 christos nlm_unshare_3_svc(nlm_shareargs *arg, struct svc_req *rqstp) 743 1.1 scottr { 744 1.9 christos static nlm_shareres result; 745 1.1 scottr 746 1.1 scottr if (debug_level) 747 1.1 scottr log_from_addr("nlm_unshare", rqstp); 748 1.1 scottr 749 1.9 christos result.cookie = arg->cookie; 750 1.9 christos result.stat = nlm_granted; 751 1.9 christos result.sequence = 1234356; /* X/Open says this field is ignored? */ 752 1.9 christos return &result; 753 1.1 scottr } 754 1.1 scottr 755 1.1 scottr /* nlm_nm_lock ------------------------------------------------------------ */ 756 1.1 scottr /* 757 1.1 scottr * Purpose: non-monitored version of nlm_lock() 758 1.1 scottr * Returns: as for nlm_lock() 759 1.1 scottr * Notes: These locks are in the same style as the standard nlm_lock, 760 1.1 scottr * but the rpc.statd should not be called to establish a 761 1.1 scottr * monitor for the client machine, since that machine is 762 1.1 scottr * declared not to be running a rpc.statd, and so would not 763 1.1 scottr * respond to the statd protocol. 764 1.1 scottr */ 765 1.1 scottr nlm_res * 766 1.9 christos nlm_nm_lock_3_svc(nlm_lockargs *arg, struct svc_req *rqstp) 767 1.1 scottr { 768 1.9 christos static nlm_res result; 769 1.1 scottr 770 1.1 scottr if (debug_level) 771 1.1 scottr log_from_addr("nlm_nm_lock", rqstp); 772 1.1 scottr 773 1.1 scottr /* copy cookie from arg to result. See comment in nlm_test_1() */ 774 1.9 christos result.cookie = arg->cookie; 775 1.9 christos result.stat.stat = nlm_granted; 776 1.9 christos return &result; 777 1.1 scottr } 778 1.1 scottr 779 1.1 scottr /* nlm_free_all ------------------------------------------------------------ */ 780 1.1 scottr /* 781 1.1 scottr * Purpose: Release all locks held by a named client 782 1.1 scottr * Returns: Nothing 783 1.1 scottr * Notes: Potential denial of service security problem here - the 784 1.1 scottr * locks to be released are specified by a host name, independent 785 1.1 scottr * of the address from which the request has arrived. 786 1.1 scottr * Should probably be rejected if the named host has been 787 1.1 scottr * using monitored locks. 788 1.1 scottr */ 789 1.1 scottr void * 790 1.9 christos /*ARGSUSED*/ 791 1.9 christos nlm_free_all_3_svc(nlm_notify *arg, struct svc_req *rqstp) 792 1.1 scottr { 793 1.1 scottr static char dummy; 794 1.1 scottr 795 1.1 scottr if (debug_level) 796 1.1 scottr log_from_addr("nlm_free_all", rqstp); 797 1.9 christos return &dummy; 798 1.1 scottr } 799 1.3 bouyer 800 1.3 bouyer /* calls for nlm version 4 (NFSv3) */ 801 1.3 bouyer /* nlm_test ---------------------------------------------------------------- */ 802 1.3 bouyer /* 803 1.3 bouyer * Purpose: Test whether a specified lock would be granted if requested 804 1.3 bouyer * Returns: nlm_granted (or error code) 805 1.3 bouyer * Notes: 806 1.3 bouyer */ 807 1.3 bouyer nlm4_testres * 808 1.9 christos nlm4_test_4_svc(nlm4_testargs *arg, struct svc_req *rqstp) 809 1.3 bouyer { 810 1.9 christos static nlm4_testres result; 811 1.4 bouyer struct nlm4_holder *holder; 812 1.3 bouyer 813 1.3 bouyer if (debug_level) 814 1.3 bouyer log_from_addr("nlm4_test", rqstp); 815 1.3 bouyer 816 1.4 bouyer holder = testlock(&arg->alock, LOCK_V4); 817 1.4 bouyer 818 1.3 bouyer /* 819 1.3 bouyer * Copy the cookie from the argument into the result. Note that this 820 1.3 bouyer * is slightly hazardous, as the structure contains a pointer to a 821 1.3 bouyer * malloc()ed buffer that will get freed by the caller. However, the 822 1.3 bouyer * main function transmits the result before freeing the argument 823 1.3 bouyer * so it is in fact safe. 824 1.3 bouyer */ 825 1.9 christos result.cookie = arg->cookie; 826 1.4 bouyer if (holder == NULL) { 827 1.9 christos result.stat.stat = nlm4_granted; 828 1.4 bouyer } else { 829 1.9 christos result.stat.stat = nlm4_denied; 830 1.9 christos (void)memcpy(&result.stat.nlm4_testrply_u.holder, holder, 831 1.4 bouyer sizeof(struct nlm4_holder)); 832 1.4 bouyer } 833 1.9 christos return &result; 834 1.3 bouyer } 835 1.3 bouyer 836 1.3 bouyer void * 837 1.9 christos nlm4_test_msg_4_svc(nlm4_testargs *arg, struct svc_req *rqstp) 838 1.3 bouyer { 839 1.9 christos nlm4_testres result; 840 1.3 bouyer static char dummy; 841 1.5 fvdl struct sockaddr *addr; 842 1.3 bouyer CLIENT *cli; 843 1.3 bouyer int success; 844 1.3 bouyer struct timeval timeo; 845 1.4 bouyer struct nlm4_holder *holder; 846 1.3 bouyer 847 1.3 bouyer if (debug_level) 848 1.3 bouyer log_from_addr("nlm4_test_msg", rqstp); 849 1.3 bouyer 850 1.4 bouyer holder = testlock(&arg->alock, LOCK_V4); 851 1.4 bouyer 852 1.9 christos result.cookie = arg->cookie; 853 1.4 bouyer if (holder == NULL) { 854 1.9 christos result.stat.stat = nlm4_granted; 855 1.4 bouyer } else { 856 1.9 christos result.stat.stat = nlm4_denied; 857 1.9 christos (void)memcpy(&result.stat.nlm4_testrply_u.holder, holder, 858 1.4 bouyer sizeof(struct nlm4_holder)); 859 1.4 bouyer } 860 1.3 bouyer 861 1.3 bouyer /* 862 1.3 bouyer * nlm_test has different result type to the other operations, so 863 1.3 bouyer * can't use transmit4_result() in this case 864 1.3 bouyer */ 865 1.5 fvdl addr = svc_getrpccaller(rqstp->rq_xprt)->buf; 866 1.4 bouyer if ((cli = get_client(addr, NLM_VERS4)) != NULL) { 867 1.3 bouyer timeo.tv_sec = 0; /* No timeout - not expecting response */ 868 1.3 bouyer timeo.tv_usec = 0; 869 1.3 bouyer 870 1.3 bouyer success = clnt_call(cli, NLM4_TEST_RES, xdr_nlm4_testres, 871 1.9 christos &result, xdr_void, &dummy, timeo); 872 1.3 bouyer 873 1.3 bouyer if (debug_level > 2) 874 1.4 bouyer syslog(LOG_DEBUG, "clnt_call returns %d", success); 875 1.3 bouyer } 876 1.9 christos return NULL; 877 1.3 bouyer } 878 1.3 bouyer 879 1.3 bouyer /* nlm_lock ---------------------------------------------------------------- */ 880 1.3 bouyer /* 881 1.3 bouyer * Purposes: Establish a lock 882 1.3 bouyer * Returns: granted, denied or blocked 883 1.3 bouyer * Notes: *** grace period support missing 884 1.3 bouyer */ 885 1.3 bouyer nlm4_res * 886 1.9 christos nlm4_lock_4_svc(nlm4_lockargs *arg, struct svc_req *rqstp) 887 1.3 bouyer { 888 1.9 christos static nlm4_res result; 889 1.3 bouyer 890 1.3 bouyer if (debug_level) 891 1.3 bouyer log_from_addr("nlm4_lock", rqstp); 892 1.3 bouyer 893 1.3 bouyer /* copy cookie from arg to result. See comment in nlm_test_4() */ 894 1.9 christos result.cookie = arg->cookie; 895 1.3 bouyer 896 1.9 christos result.stat.stat = (enum nlm4_stats)getlock(arg, rqstp, 897 1.9 christos LOCK_MON | LOCK_V4); 898 1.9 christos return &result; 899 1.3 bouyer } 900 1.3 bouyer 901 1.3 bouyer void * 902 1.9 christos nlm4_lock_msg_4_svc(nlm4_lockargs *arg, struct svc_req *rqstp) 903 1.3 bouyer { 904 1.9 christos static nlm4_res result; 905 1.3 bouyer 906 1.3 bouyer if (debug_level) 907 1.3 bouyer log_from_addr("nlm4_lock_msg", rqstp); 908 1.3 bouyer 909 1.9 christos result.cookie = arg->cookie; 910 1.9 christos result.stat.stat = (enum nlm4_stats)getlock(arg, rqstp, 911 1.9 christos LOCK_MON | LOCK_ASYNC | LOCK_V4); 912 1.9 christos transmit4_result(NLM4_LOCK_RES, &result, 913 1.10 tron (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf); 914 1.3 bouyer 915 1.9 christos return NULL; 916 1.3 bouyer } 917 1.3 bouyer 918 1.3 bouyer /* nlm_cancel -------------------------------------------------------------- */ 919 1.3 bouyer /* 920 1.3 bouyer * Purpose: Cancel a blocked lock request 921 1.3 bouyer * Returns: granted or denied 922 1.3 bouyer * Notes: 923 1.3 bouyer */ 924 1.3 bouyer nlm4_res * 925 1.9 christos nlm4_cancel_4_svc(nlm4_cancargs *arg, struct svc_req *rqstp) 926 1.3 bouyer { 927 1.9 christos static nlm4_res result; 928 1.3 bouyer 929 1.3 bouyer if (debug_level) 930 1.3 bouyer log_from_addr("nlm4_cancel", rqstp); 931 1.3 bouyer 932 1.3 bouyer /* copy cookie from arg to result. See comment in nlm_test_1() */ 933 1.9 christos result.cookie = arg->cookie; 934 1.3 bouyer 935 1.3 bouyer /* 936 1.3 bouyer * Since at present we never return 'nlm_blocked', there can never be 937 1.3 bouyer * a lock to cancel, so this call always fails. 938 1.3 bouyer */ 939 1.9 christos result.stat.stat = (enum nlm4_stats)unlock(&arg->alock, LOCK_CANCEL); 940 1.9 christos return &result; 941 1.3 bouyer } 942 1.3 bouyer 943 1.3 bouyer void * 944 1.9 christos nlm4_cancel_msg_4_svc(nlm4_cancargs *arg, struct svc_req *rqstp) 945 1.3 bouyer { 946 1.9 christos static nlm4_res result; 947 1.3 bouyer 948 1.3 bouyer if (debug_level) 949 1.3 bouyer log_from_addr("nlm4_cancel_msg", rqstp); 950 1.3 bouyer 951 1.9 christos result.cookie = arg->cookie; 952 1.3 bouyer /* 953 1.3 bouyer * Since at present we never return 'nlm_blocked', there can never be 954 1.3 bouyer * a lock to cancel, so this call always fails. 955 1.3 bouyer */ 956 1.9 christos result.stat.stat = (enum nlm4_stats)unlock(&arg->alock, 957 1.9 christos LOCK_CANCEL | LOCK_V4); 958 1.9 christos transmit4_result(NLM4_CANCEL_RES, &result, 959 1.10 tron (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf); 960 1.9 christos return NULL; 961 1.3 bouyer } 962 1.3 bouyer 963 1.3 bouyer /* nlm_unlock -------------------------------------------------------------- */ 964 1.3 bouyer /* 965 1.3 bouyer * Purpose: Release an existing lock 966 1.3 bouyer * Returns: Always granted, unless during grace period 967 1.3 bouyer * Notes: "no such lock" error condition is ignored, as the 968 1.3 bouyer * protocol uses unreliable UDP datagrams, and may well 969 1.3 bouyer * re-try an unlock that has already succeeded. 970 1.3 bouyer */ 971 1.3 bouyer nlm4_res * 972 1.9 christos nlm4_unlock_4_svc(nlm4_unlockargs *arg, struct svc_req *rqstp) 973 1.3 bouyer { 974 1.9 christos static nlm4_res result; 975 1.3 bouyer 976 1.3 bouyer if (debug_level) 977 1.3 bouyer log_from_addr("nlm4_unlock", rqstp); 978 1.3 bouyer 979 1.9 christos result.stat.stat = (enum nlm4_stats)unlock(&arg->alock, LOCK_V4); 980 1.9 christos result.cookie = arg->cookie; 981 1.3 bouyer 982 1.9 christos return &result; 983 1.3 bouyer } 984 1.3 bouyer 985 1.3 bouyer void * 986 1.9 christos nlm4_unlock_msg_4_svc(nlm4_unlockargs *arg, struct svc_req *rqstp) 987 1.3 bouyer { 988 1.9 christos static nlm4_res result; 989 1.3 bouyer 990 1.3 bouyer if (debug_level) 991 1.3 bouyer log_from_addr("nlm4_unlock_msg", rqstp); 992 1.3 bouyer 993 1.9 christos result.stat.stat = (enum nlm4_stats)unlock(&arg->alock, LOCK_V4); 994 1.9 christos result.cookie = arg->cookie; 995 1.3 bouyer 996 1.9 christos transmit4_result(NLM4_UNLOCK_RES, &result, 997 1.10 tron (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf); 998 1.9 christos return NULL; 999 1.3 bouyer } 1000 1.3 bouyer 1001 1.3 bouyer /* ------------------------------------------------------------------------- */ 1002 1.3 bouyer /* 1003 1.3 bouyer * Client-side pseudo-RPCs for results. Note that for the client there 1004 1.3 bouyer * are only nlm_xxx_msg() versions of each call, since the 'real RPC' 1005 1.3 bouyer * version returns the results in the RPC result, and so the client 1006 1.3 bouyer * does not normally receive incoming RPCs. 1007 1.3 bouyer * 1008 1.3 bouyer * The exception to this is nlm_granted(), which is genuinely an RPC 1009 1.3 bouyer * call from the server to the client - a 'call-back' in normal procedure 1010 1.3 bouyer * call terms. 1011 1.3 bouyer */ 1012 1.3 bouyer 1013 1.3 bouyer /* nlm_granted ------------------------------------------------------------- */ 1014 1.3 bouyer /* 1015 1.3 bouyer * Purpose: Receive notification that formerly blocked lock now granted 1016 1.3 bouyer * Returns: always success ('granted') 1017 1.3 bouyer * Notes: 1018 1.3 bouyer */ 1019 1.3 bouyer nlm4_res * 1020 1.9 christos nlm4_granted_4_svc(nlm4_testargs *arg, struct svc_req *rqstp) 1021 1.3 bouyer { 1022 1.9 christos static nlm4_res result; 1023 1.3 bouyer 1024 1.3 bouyer if (debug_level) 1025 1.3 bouyer log_from_addr("nlm4_granted", rqstp); 1026 1.3 bouyer 1027 1.3 bouyer /* copy cookie from arg to result. See comment in nlm_test_1() */ 1028 1.9 christos result.cookie = arg->cookie; 1029 1.3 bouyer 1030 1.9 christos result.stat.stat = nlm4_granted; 1031 1.9 christos return &result; 1032 1.3 bouyer } 1033 1.3 bouyer 1034 1.3 bouyer void * 1035 1.9 christos nlm4_granted_msg_4_svc(nlm4_testargs *arg, struct svc_req *rqstp) 1036 1.3 bouyer { 1037 1.9 christos static nlm4_res result; 1038 1.3 bouyer 1039 1.3 bouyer if (debug_level) 1040 1.3 bouyer log_from_addr("nlm4_granted_msg", rqstp); 1041 1.3 bouyer 1042 1.9 christos result.cookie = arg->cookie; 1043 1.9 christos result.stat.stat = nlm4_granted; 1044 1.9 christos transmit4_result(NLM4_GRANTED_RES, &result, 1045 1.5 fvdl (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf); 1046 1.9 christos return NULL; 1047 1.3 bouyer } 1048 1.3 bouyer 1049 1.3 bouyer /* nlm_test_res ------------------------------------------------------------ */ 1050 1.3 bouyer /* 1051 1.3 bouyer * Purpose: Accept result from earlier nlm_test_msg() call 1052 1.3 bouyer * Returns: Nothing 1053 1.3 bouyer */ 1054 1.3 bouyer void * 1055 1.9 christos /*ARGSUSED*/ 1056 1.9 christos nlm4_test_res_4_svc(nlm4_testres *arg, struct svc_req *rqstp) 1057 1.3 bouyer { 1058 1.3 bouyer if (debug_level) 1059 1.3 bouyer log_from_addr("nlm4_test_res", rqstp); 1060 1.9 christos return NULL; 1061 1.3 bouyer } 1062 1.3 bouyer 1063 1.3 bouyer /* nlm_lock_res ------------------------------------------------------------ */ 1064 1.3 bouyer /* 1065 1.3 bouyer * Purpose: Accept result from earlier nlm_lock_msg() call 1066 1.3 bouyer * Returns: Nothing 1067 1.3 bouyer */ 1068 1.3 bouyer void * 1069 1.9 christos /*ARGSUSED*/ 1070 1.9 christos nlm4_lock_res_4_svc(nlm4_res *arg, struct svc_req *rqstp) 1071 1.3 bouyer { 1072 1.3 bouyer if (debug_level) 1073 1.3 bouyer log_from_addr("nlm4_lock_res", rqstp); 1074 1.3 bouyer 1075 1.9 christos return NULL; 1076 1.3 bouyer } 1077 1.3 bouyer 1078 1.3 bouyer /* nlm_cancel_res ---------------------------------------------------------- */ 1079 1.3 bouyer /* 1080 1.3 bouyer * Purpose: Accept result from earlier nlm_cancel_msg() call 1081 1.3 bouyer * Returns: Nothing 1082 1.3 bouyer */ 1083 1.3 bouyer void * 1084 1.9 christos /*ARGSUSED*/ 1085 1.9 christos nlm4_cancel_res_4_svc(nlm4_res *arg, struct svc_req *rqstp) 1086 1.3 bouyer { 1087 1.3 bouyer if (debug_level) 1088 1.3 bouyer log_from_addr("nlm4_cancel_res", rqstp); 1089 1.9 christos return NULL; 1090 1.3 bouyer } 1091 1.3 bouyer 1092 1.3 bouyer /* nlm_unlock_res ---------------------------------------------------------- */ 1093 1.3 bouyer /* 1094 1.3 bouyer * Purpose: Accept result from earlier nlm_unlock_msg() call 1095 1.3 bouyer * Returns: Nothing 1096 1.3 bouyer */ 1097 1.3 bouyer void * 1098 1.9 christos /*ARGSUSED*/ 1099 1.9 christos nlm4_unlock_res_4_svc(nlm4_res *arg, struct svc_req *rqstp) 1100 1.3 bouyer { 1101 1.3 bouyer if (debug_level) 1102 1.3 bouyer log_from_addr("nlm4_unlock_res", rqstp); 1103 1.9 christos return NULL; 1104 1.3 bouyer } 1105 1.3 bouyer 1106 1.3 bouyer /* nlm_granted_res --------------------------------------------------------- */ 1107 1.3 bouyer /* 1108 1.3 bouyer * Purpose: Accept result from earlier nlm_granted_msg() call 1109 1.3 bouyer * Returns: Nothing 1110 1.3 bouyer */ 1111 1.3 bouyer void * 1112 1.9 christos /*ARGSUSED*/ 1113 1.9 christos nlm4_granted_res_4_svc(nlm4_res *arg, struct svc_req *rqstp) 1114 1.3 bouyer { 1115 1.3 bouyer if (debug_level) 1116 1.3 bouyer log_from_addr("nlm4_granted_res", rqstp); 1117 1.9 christos return NULL; 1118 1.3 bouyer } 1119 1.3 bouyer 1120 1.3 bouyer /* ------------------------------------------------------------------------- */ 1121 1.3 bouyer /* 1122 1.3 bouyer * Calls for PCNFS locking (aka non-monitored locking, no involvement 1123 1.3 bouyer * of rpc.statd). 1124 1.3 bouyer * 1125 1.3 bouyer * These are all genuine RPCs - no nlm_xxx_msg() nonsense here. 1126 1.3 bouyer */ 1127 1.3 bouyer 1128 1.3 bouyer /* nlm_share --------------------------------------------------------------- */ 1129 1.3 bouyer /* 1130 1.3 bouyer * Purpose: Establish a DOS-style lock 1131 1.3 bouyer * Returns: success or failure 1132 1.3 bouyer * Notes: Blocking locks are not supported - client is expected 1133 1.3 bouyer * to retry if required. 1134 1.3 bouyer */ 1135 1.3 bouyer nlm4_shareres * 1136 1.9 christos nlm4_share_4_svc(nlm4_shareargs *arg, struct svc_req *rqstp) 1137 1.3 bouyer { 1138 1.9 christos static nlm4_shareres result; 1139 1.3 bouyer 1140 1.3 bouyer if (debug_level) 1141 1.3 bouyer log_from_addr("nlm4_share", rqstp); 1142 1.3 bouyer 1143 1.9 christos result.cookie = arg->cookie; 1144 1.9 christos result.stat = nlm4_granted; 1145 1.9 christos result.sequence = 1234356; /* X/Open says this field is ignored? */ 1146 1.9 christos return &result; 1147 1.3 bouyer } 1148 1.3 bouyer 1149 1.3 bouyer /* nlm4_unshare ------------------------------------------------------------ */ 1150 1.3 bouyer /* 1151 1.3 bouyer * Purpose: Release a DOS-style lock 1152 1.3 bouyer * Returns: nlm_granted, unless in grace period 1153 1.3 bouyer * Notes: 1154 1.3 bouyer */ 1155 1.3 bouyer nlm4_shareres * 1156 1.9 christos nlm4_unshare_4_svc(nlm4_shareargs *arg, struct svc_req *rqstp) 1157 1.3 bouyer { 1158 1.9 christos static nlm4_shareres result; 1159 1.3 bouyer 1160 1.3 bouyer if (debug_level) 1161 1.3 bouyer log_from_addr("nlm_unshare", rqstp); 1162 1.3 bouyer 1163 1.9 christos result.cookie = arg->cookie; 1164 1.9 christos result.stat = nlm4_granted; 1165 1.9 christos result.sequence = 1234356; /* X/Open says this field is ignored? */ 1166 1.9 christos return &result; 1167 1.3 bouyer } 1168 1.3 bouyer 1169 1.3 bouyer /* nlm4_nm_lock ------------------------------------------------------------ */ 1170 1.3 bouyer /* 1171 1.3 bouyer * Purpose: non-monitored version of nlm4_lock() 1172 1.3 bouyer * Returns: as for nlm4_lock() 1173 1.3 bouyer * Notes: These locks are in the same style as the standard nlm4_lock, 1174 1.3 bouyer * but the rpc.statd should not be called to establish a 1175 1.3 bouyer * monitor for the client machine, since that machine is 1176 1.3 bouyer * declared not to be running a rpc.statd, and so would not 1177 1.3 bouyer * respond to the statd protocol. 1178 1.3 bouyer */ 1179 1.3 bouyer nlm4_res * 1180 1.9 christos nlm4_nm_lock_4_svc(nlm4_lockargs *arg, struct svc_req *rqstp) 1181 1.3 bouyer { 1182 1.9 christos static nlm4_res result; 1183 1.3 bouyer 1184 1.3 bouyer if (debug_level) 1185 1.3 bouyer log_from_addr("nlm4_nm_lock", rqstp); 1186 1.3 bouyer 1187 1.3 bouyer /* copy cookie from arg to result. See comment in nlm4_test_1() */ 1188 1.9 christos result.cookie = arg->cookie; 1189 1.9 christos result.stat.stat = nlm4_granted; 1190 1.9 christos return &result; 1191 1.3 bouyer } 1192 1.3 bouyer 1193 1.3 bouyer /* nlm4_free_all ------------------------------------------------------------ */ 1194 1.3 bouyer /* 1195 1.3 bouyer * Purpose: Release all locks held by a named client 1196 1.3 bouyer * Returns: Nothing 1197 1.3 bouyer * Notes: Potential denial of service security problem here - the 1198 1.3 bouyer * locks to be released are specified by a host name, independent 1199 1.3 bouyer * of the address from which the request has arrived. 1200 1.3 bouyer * Should probably be rejected if the named host has been 1201 1.3 bouyer * using monitored locks. 1202 1.3 bouyer */ 1203 1.3 bouyer void * 1204 1.9 christos /*ARGSUSED*/ 1205 1.9 christos nlm4_free_all_4_svc(nlm_notify *arg, struct svc_req *rqstp) 1206 1.3 bouyer { 1207 1.3 bouyer static char dummy; 1208 1.3 bouyer 1209 1.3 bouyer if (debug_level) 1210 1.3 bouyer log_from_addr("nlm4_free_all", rqstp); 1211 1.9 christos return &dummy; 1212 1.3 bouyer } 1213 1.3 bouyer 1214 1.4 bouyer /* nlm_sm_notify --------------------------------------------------------- */ 1215 1.4 bouyer /* 1216 1.4 bouyer * Purpose: called by rpc.statd when a monitored host state changes. 1217 1.4 bouyer * Returns: Nothing 1218 1.4 bouyer */ 1219 1.4 bouyer void * 1220 1.9 christos /*ARGSUSED*/ 1221 1.9 christos nlm_sm_notify_0_svc(struct nlm_sm_status *arg, struct svc_req *rqstp) 1222 1.4 bouyer { 1223 1.4 bouyer static char dummy; 1224 1.4 bouyer notify(arg->mon_name, arg->state); 1225 1.9 christos return &dummy; 1226 1.4 bouyer } 1227