1 /* $NetBSD: lock_proc.c,v 1.1 1997/03/10 06:26:20 scottr Exp $ */ 2 3 /* 4 * Copyright (c) 1995 5 * A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed for the FreeBSD project 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 */ 35 36 #include <stdio.h> 37 #include <netdb.h> 38 #include <string.h> 39 #include <syslog.h> 40 #include <sys/param.h> 41 #include <sys/socket.h> 42 43 #include <netinet/in.h> 44 #include <arpa/inet.h> 45 46 #include <rpc/rpc.h> 47 #include <rpcsvc/sm_inter.h> 48 49 #include "lockd.h" 50 #include "nlm_prot.h" 51 52 53 #define CLIENT_CACHE_SIZE 64 /* No. of client sockets cached */ 54 #define CLIENT_CACHE_LIFETIME 120 /* In seconds */ 55 56 /* log_from_addr ----------------------------------------------------------- */ 57 /* 58 * Purpose: Log name of function called and source address 59 * Returns: Nothing 60 * Notes: Extracts the source address from the transport handle 61 * passed in as part of the called procedure specification 62 */ 63 static void 64 log_from_addr(fun_name, req) 65 char *fun_name; 66 struct svc_req *req; 67 { 68 struct sockaddr_in *addr; 69 struct hostent *host; 70 char hostname_buf[40]; 71 72 addr = svc_getcaller(req->rq_xprt); 73 host = gethostbyaddr((char *)&(addr->sin_addr), addr->sin_len, AF_INET); 74 if (host) { 75 strncpy(hostname_buf, host->h_name, sizeof(hostname_buf)); 76 hostname_buf[sizeof(hostname_buf) - 1] = '\0'; 77 } else /* No hostname available - print raw address */ 78 strcpy(hostname_buf, inet_ntoa(addr->sin_addr)); 79 80 syslog(LOG_DEBUG, "%s from %s", fun_name, hostname_buf); 81 } 82 83 /* get_client -------------------------------------------------------------- */ 84 /* 85 * Purpose: Get a CLIENT* for making RPC calls to lockd on given host 86 * Returns: CLIENT* pointer, from clnt_udp_create, or NULL if error 87 * Notes: Creating a CLIENT* is quite expensive, involving a 88 * conversation with the remote portmapper to get the 89 * port number. Since a given client is quite likely 90 * to make several locking requests in succession, it is 91 * desirable to cache the created CLIENT*. 92 * 93 * Since we are using UDP rather than TCP, there is no cost 94 * to the remote system in keeping these cached indefinitely. 95 * Unfortunately there is a snag: if the remote system 96 * reboots, the cached portmapper results will be invalid, 97 * and we will never detect this since all of the xxx_msg() 98 * calls return no result - we just fire off a udp packet 99 * and hope for the best. 100 * 101 * We solve this by discarding cached values after two 102 * minutes, regardless of whether they have been used 103 * in the meanwhile (since a bad one might have been used 104 * plenty of times, as the host keeps retrying the request 105 * and we keep sending the reply back to the wrong port). 106 * 107 * Given that the entries will always expire in the order 108 * that they were created, there is no point in a LRU 109 * algorithm for when the cache gets full - entries are 110 * always re-used in sequence. 111 */ 112 static CLIENT *clnt_cache_ptr[CLIENT_CACHE_SIZE]; 113 static long clnt_cache_time[CLIENT_CACHE_SIZE]; /* time entry created */ 114 static struct in_addr clnt_cache_addr[CLIENT_CACHE_SIZE]; 115 static int clnt_cache_next_to_use = 0; 116 117 static CLIENT * 118 get_client(host_addr) 119 struct sockaddr_in *host_addr; 120 { 121 CLIENT *client; 122 struct timeval retry_time, time_now; 123 int i, sock_no; 124 125 gettimeofday(&time_now, NULL); 126 127 /* 128 * Search for the given client in the cache, zapping any expired 129 * entries that we happen to notice in passing. 130 */ 131 for (i = 0; i < CLIENT_CACHE_SIZE; i++) { 132 client = clnt_cache_ptr[i]; 133 if (client && ((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME) 134 < time_now.tv_sec)) { 135 /* Cache entry has expired. */ 136 if (debug_level > 3) 137 syslog(LOG_DEBUG, "Expired CLIENT* in cache"); 138 clnt_cache_time[i] = 0L; 139 clnt_destroy(client); 140 clnt_cache_ptr[i] = NULL; 141 client = NULL; 142 } 143 if (client && !memcmp(&clnt_cache_addr[i], 144 &host_addr->sin_addr, sizeof(struct in_addr))) { 145 /* Found it! */ 146 if (debug_level > 3) 147 syslog(LOG_DEBUG, "Found CLIENT* in cache"); 148 return (client); 149 } 150 } 151 152 /* Not found in cache. Free the next entry if it is in use. */ 153 if (clnt_cache_ptr[clnt_cache_next_to_use]) { 154 clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]); 155 clnt_cache_ptr[clnt_cache_next_to_use] = NULL; 156 } 157 158 /* Create the new client handle */ 159 sock_no = RPC_ANYSOCK; 160 retry_time.tv_sec = 5; 161 retry_time.tv_usec = 0; 162 host_addr->sin_port = 0; /* Force consultation with portmapper */ 163 client = clntudp_create(host_addr, NLM_PROG, NLM_VERS, 164 retry_time, &sock_no); 165 if (!client) { 166 syslog(LOG_ERR, clnt_spcreateerror("clntudp_create")); 167 syslog(LOG_ERR, "Unable to return result to %s", 168 inet_ntoa(host_addr->sin_addr)); 169 return NULL; 170 } 171 172 /* Success - update the cache entry */ 173 clnt_cache_ptr[clnt_cache_next_to_use] = client; 174 clnt_cache_addr[clnt_cache_next_to_use] = host_addr->sin_addr; 175 clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec; 176 if (++clnt_cache_next_to_use > CLIENT_CACHE_SIZE) 177 clnt_cache_next_to_use = 0; 178 179 /* 180 * Disable the default timeout, so we can specify our own in calls 181 * to clnt_call(). (Note that the timeout is a different concept 182 * from the retry period set in clnt_udp_create() above.) 183 */ 184 retry_time.tv_sec = -1; 185 retry_time.tv_usec = -1; 186 clnt_control(client, CLSET_TIMEOUT, (char *)&retry_time); 187 188 if (debug_level > 3) 189 syslog(LOG_DEBUG, "Created CLIENT* for %s", 190 inet_ntoa(host_addr->sin_addr)); 191 return client; 192 } 193 194 195 /* transmit_result --------------------------------------------------------- */ 196 /* 197 * Purpose: Transmit result for nlm_xxx_msg pseudo-RPCs 198 * Returns: Nothing - we have no idea if the datagram got there 199 * Notes: clnt_call() will always fail (with timeout) as we are 200 * calling it with timeout 0 as a hack to just issue a datagram 201 * without expecting a result 202 */ 203 static void 204 transmit_result(opcode, result, req) 205 int opcode; 206 nlm_res *result; 207 struct svc_req *req; 208 { 209 static char dummy; 210 struct sockaddr_in *addr; 211 CLIENT *cli; 212 struct timeval timeo; 213 int success; 214 215 addr = svc_getcaller(req->rq_xprt); 216 if (cli = get_client(addr)) { 217 timeo.tv_sec = 0; /* No timeout - not expecting response */ 218 timeo.tv_usec = 0; 219 220 success = clnt_call(cli, opcode, xdr_nlm_res, result, xdr_void, 221 &dummy, timeo); 222 223 if (debug_level > 2) 224 syslog(LOG_DEBUG, "clnt_call returns %d\n", success); 225 } 226 } 227 /* ------------------------------------------------------------------------- */ 228 /* 229 * Functions for Unix<->Unix locking (ie. monitored locking, with rpc.statd 230 * involved to ensure reclaim of locks after a crash of the "stateless" 231 * server. 232 * 233 * These all come in two flavours - nlm_xxx() and nlm_xxx_msg(). 234 * The first are standard RPCs with argument and result. 235 * The nlm_xxx_msg() calls implement exactly the same functions, but 236 * use two pseudo-RPCs (one in each direction). These calls are NOT 237 * standard use of the RPC protocol in that they do not return a result 238 * at all (NB. this is quite different from returning a void result). 239 * The effect of this is to make the nlm_xxx_msg() calls simple unacknowledged 240 * datagrams, requiring higher-level code to perform retries. 241 * 242 * Despite the disadvantages of the nlm_xxx_msg() approach (some of which 243 * are documented in the comments to get_client() above), this is the 244 * interface used by all current commercial NFS implementations 245 * [Solaris, SCO, AIX etc.]. This is presumed to be because these allow 246 * implementations to continue using the standard RPC libraries, while 247 * avoiding the block-until-result nature of the library interface. 248 * 249 * No client implementations have been identified so far that make use 250 * of the true RPC version (early SunOS releases would be a likely candidate 251 * for testing). 252 */ 253 254 /* nlm_test ---------------------------------------------------------------- */ 255 /* 256 * Purpose: Test whether a specified lock would be granted if requested 257 * Returns: nlm_granted (or error code) 258 * Notes: 259 */ 260 nlm_testres * 261 nlm_test_1_svc(arg, rqstp) 262 nlm_testargs *arg; 263 struct svc_req *rqstp; 264 { 265 static nlm_testres res; 266 267 if (debug_level) 268 log_from_addr("nlm_test", rqstp); 269 270 /* 271 * Copy the cookie from the argument into the result. Note that this 272 * is slightly hazardous, as the structure contains a pointer to a 273 * malloc()ed buffer that will get freed by the caller. However, the 274 * main function transmits the result before freeing the argument 275 * so it is in fact safe. 276 */ 277 res.cookie = arg->cookie; 278 res.stat.stat = nlm_granted; 279 return (&res); 280 } 281 282 void * 283 nlm_test_msg_1_svc(arg, rqstp) 284 nlm_testargs *arg; 285 struct svc_req *rqstp; 286 { 287 nlm_testres res; 288 static char dummy; 289 struct sockaddr_in *addr; 290 CLIENT *cli; 291 int success; 292 struct timeval timeo; 293 294 if (debug_level) 295 log_from_addr("nlm_test_msg", rqstp); 296 297 res.cookie = arg->cookie; 298 res.stat.stat = nlm_granted; 299 300 /* 301 * nlm_test has different result type to the other operations, so 302 * can't use transmit_result() in this case 303 */ 304 addr = svc_getcaller(rqstp->rq_xprt); 305 if (cli = get_client(addr)) { 306 timeo.tv_sec = 0; /* No timeout - not expecting response */ 307 timeo.tv_usec = 0; 308 309 success = clnt_call(cli, NLM_TEST_RES, xdr_nlm_testres, 310 &res, xdr_void, &dummy, timeo); 311 312 if (debug_level > 2) 313 syslog(LOG_DEBUG, "clnt_call returns %d\n", success); 314 } 315 return (NULL); 316 } 317 318 /* nlm_lock ---------------------------------------------------------------- */ 319 /* 320 * Purposes: Establish a lock 321 * Returns: granted, denied or blocked 322 * Notes: *** grace period support missing 323 */ 324 nlm_res * 325 nlm_lock_1_svc(arg, rqstp) 326 nlm_lockargs *arg; 327 struct svc_req *rqstp; 328 { 329 static nlm_res res; 330 331 if (debug_level) 332 log_from_addr("nlm_lock", rqstp); 333 334 /* copy cookie from arg to result. See comment in nlm_test_1() */ 335 res.cookie = arg->cookie; 336 337 res.stat.stat = nlm_granted; 338 return (&res); 339 } 340 341 void * 342 nlm_lock_msg_1_svc(arg, rqstp) 343 nlm_lockargs *arg; 344 struct svc_req *rqstp; 345 { 346 static nlm_res res; 347 348 if (debug_level) 349 log_from_addr("nlm_lock_msg", rqstp); 350 351 res.cookie = arg->cookie; 352 res.stat.stat = nlm_granted; 353 transmit_result(NLM_LOCK_RES, &res, rqstp); 354 355 return (NULL); 356 } 357 358 /* nlm_cancel -------------------------------------------------------------- */ 359 /* 360 * Purpose: Cancel a blocked lock request 361 * Returns: granted or denied 362 * Notes: 363 */ 364 nlm_res * 365 nlm_cancel_1_svc(arg, rqstp) 366 nlm_cancargs *arg; 367 struct svc_req *rqstp; 368 { 369 static nlm_res res; 370 371 if (debug_level) 372 log_from_addr("nlm_cancel", rqstp); 373 374 /* copy cookie from arg to result. See comment in nlm_test_1() */ 375 res.cookie = arg->cookie; 376 377 /* 378 * Since at present we never return 'nlm_blocked', there can never be 379 * a lock to cancel, so this call always fails. 380 */ 381 res.stat.stat = nlm_denied; 382 return (&res); 383 } 384 385 void * 386 nlm_cancel_msg_1_svc(arg, rqstp) 387 nlm_cancargs *arg; 388 struct svc_req *rqstp; 389 { 390 static nlm_res res; 391 392 if (debug_level) 393 log_from_addr("nlm_cancel_msg", rqstp); 394 395 res.cookie = arg->cookie; 396 /* 397 * Since at present we never return 'nlm_blocked', there can never be 398 * a lock to cancel, so this call always fails. 399 */ 400 res.stat.stat = nlm_denied; 401 transmit_result(NLM_CANCEL_RES, &res, rqstp); 402 return (NULL); 403 } 404 405 /* nlm_unlock -------------------------------------------------------------- */ 406 /* 407 * Purpose: Release an existing lock 408 * Returns: Always granted, unless during grace period 409 * Notes: "no such lock" error condition is ignored, as the 410 * protocol uses unreliable UDP datagrams, and may well 411 * re-try an unlock that has already succeeded. 412 */ 413 nlm_res * 414 nlm_unlock_1_svc(arg, rqstp) 415 nlm_unlockargs *arg; 416 struct svc_req *rqstp; 417 { 418 static nlm_res res; 419 420 if (debug_level) 421 log_from_addr("nlm_unlock", rqstp); 422 423 res.stat.stat = nlm_granted; 424 res.cookie = arg->cookie; 425 426 return (&res); 427 } 428 429 void * 430 nlm_unlock_msg_1_svc(arg, rqstp) 431 nlm_unlockargs *arg; 432 struct svc_req *rqstp; 433 { 434 static nlm_res res; 435 436 if (debug_level) 437 log_from_addr("nlm_unlock_msg", rqstp); 438 439 res.stat.stat = nlm_granted; 440 res.cookie = arg->cookie; 441 442 transmit_result(NLM_UNLOCK_RES, &res, rqstp); 443 return (NULL); 444 } 445 446 /* ------------------------------------------------------------------------- */ 447 /* 448 * Client-side pseudo-RPCs for results. Note that for the client there 449 * are only nlm_xxx_msg() versions of each call, since the 'real RPC' 450 * version returns the results in the RPC result, and so the client 451 * does not normally receive incoming RPCs. 452 * 453 * The exception to this is nlm_granted(), which is genuinely an RPC 454 * call from the server to the client - a 'call-back' in normal procedure 455 * call terms. 456 */ 457 458 /* nlm_granted ------------------------------------------------------------- */ 459 /* 460 * Purpose: Receive notification that formerly blocked lock now granted 461 * Returns: always success ('granted') 462 * Notes: 463 */ 464 nlm_res * 465 nlm_granted_1_svc(arg, rqstp) 466 nlm_testargs *arg; 467 struct svc_req *rqstp; 468 { 469 static nlm_res res; 470 471 if (debug_level) 472 log_from_addr("nlm_granted", rqstp); 473 474 /* copy cookie from arg to result. See comment in nlm_test_1() */ 475 res.cookie = arg->cookie; 476 477 res.stat.stat = nlm_granted; 478 return (&res); 479 } 480 481 void * 482 nlm_granted_msg_1_svc(arg, rqstp) 483 nlm_testargs *arg; 484 struct svc_req *rqstp; 485 { 486 static nlm_res res; 487 488 if (debug_level) 489 log_from_addr("nlm_granted_msg", rqstp); 490 491 res.cookie = arg->cookie; 492 res.stat.stat = nlm_granted; 493 transmit_result(NLM_GRANTED_RES, &res, rqstp); 494 return (NULL); 495 } 496 497 /* nlm_test_res ------------------------------------------------------------ */ 498 /* 499 * Purpose: Accept result from earlier nlm_test_msg() call 500 * Returns: Nothing 501 */ 502 void * 503 nlm_test_res_1_svc(arg, rqstp) 504 nlm_testres *arg; 505 struct svc_req *rqstp; 506 { 507 if (debug_level) 508 log_from_addr("nlm_test_res", rqstp); 509 return (NULL); 510 } 511 512 /* nlm_lock_res ------------------------------------------------------------ */ 513 /* 514 * Purpose: Accept result from earlier nlm_lock_msg() call 515 * Returns: Nothing 516 */ 517 void * 518 nlm_lock_res_1_svc(arg, rqstp) 519 nlm_res *arg; 520 struct svc_req *rqstp; 521 { 522 if (debug_level) 523 log_from_addr("nlm_lock_res", rqstp); 524 525 return (NULL); 526 } 527 528 /* nlm_cancel_res ---------------------------------------------------------- */ 529 /* 530 * Purpose: Accept result from earlier nlm_cancel_msg() call 531 * Returns: Nothing 532 */ 533 void * 534 nlm_cancel_res_1_svc(arg, rqstp) 535 nlm_res *arg; 536 struct svc_req *rqstp; 537 { 538 if (debug_level) 539 log_from_addr("nlm_cancel_res", rqstp); 540 return (NULL); 541 } 542 543 /* nlm_unlock_res ---------------------------------------------------------- */ 544 /* 545 * Purpose: Accept result from earlier nlm_unlock_msg() call 546 * Returns: Nothing 547 */ 548 void * 549 nlm_unlock_res_1_svc(arg, rqstp) 550 nlm_res *arg; 551 struct svc_req *rqstp; 552 { 553 if (debug_level) 554 log_from_addr("nlm_unlock_res", rqstp); 555 return (NULL); 556 } 557 558 /* nlm_granted_res --------------------------------------------------------- */ 559 /* 560 * Purpose: Accept result from earlier nlm_granted_msg() call 561 * Returns: Nothing 562 */ 563 void * 564 nlm_granted_res_1_svc(arg, rqstp) 565 nlm_res *arg; 566 struct svc_req *rqstp; 567 { 568 if (debug_level) 569 log_from_addr("nlm_granted_res", rqstp); 570 return (NULL); 571 } 572 573 /* ------------------------------------------------------------------------- */ 574 /* 575 * Calls for PCNFS locking (aka non-monitored locking, no involvement 576 * of rpc.statd). 577 * 578 * These are all genuine RPCs - no nlm_xxx_msg() nonsense here. 579 */ 580 581 /* nlm_share --------------------------------------------------------------- */ 582 /* 583 * Purpose: Establish a DOS-style lock 584 * Returns: success or failure 585 * Notes: Blocking locks are not supported - client is expected 586 * to retry if required. 587 */ 588 nlm_shareres * 589 nlm_share_3_svc(arg, rqstp) 590 nlm_shareargs *arg; 591 struct svc_req *rqstp; 592 { 593 static nlm_shareres res; 594 595 if (debug_level) 596 log_from_addr("nlm_share", rqstp); 597 598 res.cookie = arg->cookie; 599 res.stat = nlm_granted; 600 res.sequence = 1234356; /* X/Open says this field is ignored? */ 601 return (&res); 602 } 603 604 /* nlm_unshare ------------------------------------------------------------ */ 605 /* 606 * Purpose: Release a DOS-style lock 607 * Returns: nlm_granted, unless in grace period 608 * Notes: 609 */ 610 nlm_shareres * 611 nlm_unshare_3_svc(arg, rqstp) 612 nlm_shareargs *arg; 613 struct svc_req *rqstp; 614 { 615 static nlm_shareres res; 616 617 if (debug_level) 618 log_from_addr("nlm_unshare", rqstp); 619 620 res.cookie = arg->cookie; 621 res.stat = nlm_granted; 622 res.sequence = 1234356; /* X/Open says this field is ignored? */ 623 return (&res); 624 } 625 626 /* nlm_nm_lock ------------------------------------------------------------ */ 627 /* 628 * Purpose: non-monitored version of nlm_lock() 629 * Returns: as for nlm_lock() 630 * Notes: These locks are in the same style as the standard nlm_lock, 631 * but the rpc.statd should not be called to establish a 632 * monitor for the client machine, since that machine is 633 * declared not to be running a rpc.statd, and so would not 634 * respond to the statd protocol. 635 */ 636 nlm_res * 637 nlm_nm_lock_3_svc(arg, rqstp) 638 nlm_lockargs *arg; 639 struct svc_req *rqstp; 640 { 641 static nlm_res res; 642 643 if (debug_level) 644 log_from_addr("nlm_nm_lock", rqstp); 645 646 /* copy cookie from arg to result. See comment in nlm_test_1() */ 647 res.cookie = arg->cookie; 648 res.stat.stat = nlm_granted; 649 return (&res); 650 } 651 652 /* nlm_free_all ------------------------------------------------------------ */ 653 /* 654 * Purpose: Release all locks held by a named client 655 * Returns: Nothing 656 * Notes: Potential denial of service security problem here - the 657 * locks to be released are specified by a host name, independent 658 * of the address from which the request has arrived. 659 * Should probably be rejected if the named host has been 660 * using monitored locks. 661 */ 662 void * 663 nlm_free_all_3_svc(arg, rqstp) 664 nlm_notify *arg; 665 struct svc_req *rqstp; 666 { 667 static char dummy; 668 669 if (debug_level) 670 log_from_addr("nlm_free_all", rqstp); 671 return (&dummy); 672 } 673