1/* 2 * Copyright (c) 2002-2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/*- 24 * Copyright (c) 1997 Berkeley Software Design, Inc. All rights reserved. 25 * 26 * Redistribution and use in source and binary forms, with or without 27 * modification, are permitted provided that the following conditions 28 * are met: 29 * 1. Redistributions of source code must retain the above copyright 30 * notice, this list of conditions and the following disclaimer. 31 * 2. Redistributions in binary form must reproduce the above copyright 32 * notice, this list of conditions and the following disclaimer in the 33 * documentation and/or other materials provided with the distribution. 34 * 3. Berkeley Software Design Inc's name may not be used to endorse or 35 * promote products derived from this software without specific prior 36 * written permission. 37 * 38 * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND 39 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 41 * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE 42 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 43 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 44 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 46 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 47 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48 * SUCH DAMAGE. 49 * 50 * from BSDI kern.c,v 1.2 1998/11/25 22:38:27 don Exp 51 * $FreeBSD: src/usr.sbin/rpc.lockd/kern.c,v 1.11 2002/08/15 21:52:21 alfred Exp $ 52 */ 53 54#include <sys/param.h> 55#include <sys/mount.h> 56#include <sys/queue.h> 57#include <sys/socket.h> 58#include <sys/stat.h> 59#include <sys/sysctl.h> 60 61#include <netinet/in.h> 62#include <arpa/inet.h> 63 64#include <err.h> 65#include <errno.h> 66#include <fcntl.h> 67#include <pwd.h> 68#include <stdio.h> 69#include <stdlib.h> 70#include <string.h> 71#include <syslog.h> 72#include <unistd.h> 73#include <signal.h> 74#include <netdb.h> 75 76#include "nlm_prot.h" 77#include <nfs/rpcv2.h> 78#include <nfs/nfsproto.h> 79#include <nfs/nfs_lock.h> 80#include <nfs/nfs.h> 81 82#include <mach/mach.h> 83#include <mach/mach_error.h> 84#include <servers/bootstrap.h> 85 86#include "lockd_mach.h" 87#include "lockd_machServer.h" 88 89#include "lockd.h" 90#include "lockd_lock.h" 91 92#define nfslockdans(_v, _ansp) \ 93 ((_ansp)->la_version = (_v), \ 94 nfsclnt(NFSCLNT_LOCKDANS, (_ansp))) 95 96static mach_port_t lockd_receive_right; 97 98union MaxMsgSize { 99 union __RequestUnion__lockd_mach_subsystem req; 100 union __ReplyUnion__lockd_mach_subsystem rep; 101}; 102 103#define MAX_LOCKD_MSG_SIZE (sizeof (union MaxMsgSize) + MAX_TRAILER_SIZE) 104 105#define BOOTSTRAP_NAME "com.apple.lockd" 106 107/* Lock request owner. */ 108typedef struct __owner { 109 pid_t pid; /* Process ID. */ 110 time_t tod; /* Time-of-day. */ 111} OWNER; 112static OWNER owner; 113 114static char hostname[MAXHOSTNAMELEN + 1]; /* Hostname. */ 115 116static time_t shutdown_time_client = 0; 117static time_t shutdown_time_server = 0; 118 119static void set_auth(CLIENT *cl, struct xucred *ucred); 120int lock_request(LOCKD_MSG *); 121int cancel_request(LOCKD_MSG *); 122int test_request(LOCKD_MSG *); 123void show(LOCKD_MSG *); 124int unlock_request(LOCKD_MSG *); 125 126#define d_calls (config.verbose > 1) 127#define d_args (config.verbose > 2) 128 129static const char * 130from_addr(saddr) 131 struct sockaddr *saddr; 132{ 133 static char inet_buf[INET6_ADDRSTRLEN]; 134 135 if (getnameinfo(saddr, saddr->sa_len, inet_buf, sizeof(inet_buf), 136 NULL, 0, NI_NUMERICHOST) == 0) 137 return inet_buf; 138 return "???"; 139} 140 141/* 142 * Use sysctl to get NFS client and NFS server state from kernel. 143 */ 144static int 145get_client_and_server_state(int *mounts, int *servers, int *maxservers) 146{ 147 size_t size = sizeof(int); 148 int rv = 0; 149 150 *mounts = *servers = *maxservers = 0; 151 if (sysctlbyname("vfs.generic.nfs.client.lockd_mounts", mounts, &size, NULL, 0)) 152 rv++; 153 if (sysctlbyname("vfs.generic.nfs.server.nfsd_thread_count", servers, &size, NULL, 0)) 154 rv++; 155 if (sysctlbyname("vfs.generic.nfs.server.nfsd_thread_max", maxservers, &size, NULL, 0)) 156 rv++; 157 158 return (rv); 159} 160 161/* 162 * shutdown timeout handler 163 * 164 * Double check and shut down. 165 */ 166static void 167shutdown_timer(void) 168{ 169 if (!shutdown_time_client || !shutdown_time_server) { 170 /* don't shut down yet, something's still running */ 171 if (config.verbose) { 172 int mounts, servers, maxservers; 173 get_client_and_server_state(&mounts, &servers, &maxservers); 174 syslog(LOG_DEBUG, "shutdown_timer: %ld %ld, mounts %d servers %d %d\n", 175 shutdown_time_client, shutdown_time_server, 176 mounts, servers, maxservers); 177 } 178 return; 179 } 180 181 /* shut down statd too */ 182 statd_stop(); 183 184 handle_sig_cleanup(0); 185 /*NOTREACHED*/ 186} 187 188kern_return_t 189svc_lockd_request( 190 mach_port_t mp __attribute__((unused)), 191 uint32_t vers, 192 uint32_t flags, 193 uint64_t xid, 194 int64_t flk_start, 195 int64_t flk_len, 196 int32_t flk_pid, 197 int32_t flk_type, 198 int32_t flk_whence, 199 uint32_t *sock_address, 200 uint32_t *cred, 201 uint32_t fh_len, 202 uint8_t *fh) 203{ 204 LOCKD_MSG msg; 205 int ret; 206 207 /* make sure shutdown timer is disabled */ 208 if (shutdown_time_client) { 209 shutdown_time_client = 0; 210 alarm(0); 211 } 212 213 /* 214 * Hold off getting hostname until first 215 * lock request. Otherwise we risk getting 216 * an initial ".local" name. 217 */ 218 if (hostname[0] == '\0') 219 (void)gethostname(hostname, sizeof(hostname) - 1); 220 221 /* Marshal mach arguments back into a LOCKD_MSG */ 222 msg.lm_version = vers; 223 msg.lm_flags = flags; 224 msg.lm_xid = xid; 225 msg.lm_fl.l_start = flk_start; 226 msg.lm_fl.l_len = flk_len; 227 msg.lm_fl.l_pid = flk_pid; 228 msg.lm_fl.l_type = flk_type; 229 msg.lm_fl.l_whence = flk_whence; 230 msg.lm_fh_len = fh_len; 231 bcopy(sock_address, &msg.lm_addr, sizeof(msg.lm_addr)); 232 bcopy(cred, &msg.lm_cred, sizeof(struct xucred)); 233 bcopy(fh, msg.lm_fh, NFSV3_MAX_FH_SIZE); 234 235 if (d_args) 236 show(&msg); 237 238 if (msg.lm_version != LOCKD_MSG_VERSION) { 239 syslog(LOG_ERR, "unknown msg type: %d", msg.lm_version); 240 } 241 /* 242 * Send it to the NLM server and don't grant the lock 243 * if we fail for any reason. 244 */ 245 switch (msg.lm_fl.l_type) { 246 case F_RDLCK: 247 case F_WRLCK: 248 if (msg.lm_flags & LOCKD_MSG_TEST) 249 ret = test_request(&msg); 250 else if (msg.lm_flags & LOCKD_MSG_CANCEL) 251 ret = cancel_request(&msg); 252 else 253 ret = lock_request(&msg); 254 break; 255 case F_UNLCK: 256 ret = unlock_request(&msg); 257 break; 258 default: 259 ret = 1; 260 syslog(LOG_ERR, "unknown lock type: %d", msg.lm_fl.l_type); 261 break; 262 } 263 if (ret) { 264 struct lockd_ans ans; 265 266 bzero(&ans, sizeof(ans)); 267 ans.la_xid = msg.lm_xid; 268 ans.la_errno = ENOTSUP; 269 270 if (nfslockdans(LOCKD_ANS_VERSION, &ans)) { 271 syslog(LOG_DEBUG, "process %d: %m", msg.lm_fl.l_pid); 272 } 273 } 274 return (KERN_SUCCESS); 275} 276 277/* 278 * nfsd is pinging us to let us know that it's running. 279 */ 280kern_return_t 281svc_lockd_ping(mach_port_t mp __attribute__((unused))) 282{ 283 /* make sure shutdown timer is disabled */ 284 if (shutdown_time_server) { 285 shutdown_time_server = 0; 286 alarm(0); 287 } 288 289 return (KERN_SUCCESS); 290} 291 292/* 293 * This request is called whenever either nfsd shuts down or the 294 * last (lockd-needing) NFS mount is unmounted. 295 * 296 * We take note of our current state and prepare to shutdown. 297 */ 298kern_return_t 299svc_lockd_shutdown(mach_port_t mp __attribute__((unused))) 300{ 301 int mounts, servers, maxservers; 302 struct timeval now; 303 time_t shutdown_time; 304 unsigned int delay; 305 306 if (get_client_and_server_state(&mounts, &servers, &maxservers)) { 307 syslog(LOG_ERR, "lockd_shutdown: sysctl failed"); 308 return (KERN_FAILURE); 309 } 310 311 gettimeofday(&now, NULL); 312 313 if ((!servers || !maxservers) && !shutdown_time_server) { 314 /* nfsd is no longer running, set server shutdown time */ 315 syslog(LOG_DEBUG, "lockd_shutdown: server, delay %d", config.shutdown_delay_server); 316 shutdown_time_server = now.tv_sec + config.shutdown_delay_server; 317 } 318 if (!mounts && !shutdown_time_client) { 319 /* must have just unmounted last mount, set client shutdown time */ 320 syslog(LOG_DEBUG, "lockd_shutdown: client, delay %d", config.shutdown_delay_client); 321 shutdown_time_client = now.tv_sec + config.shutdown_delay_client; 322 } 323 324 if (!shutdown_time_client || !shutdown_time_server) { 325 syslog(LOG_DEBUG, "lockd_shutdown: hold on, client %ld server %ld", shutdown_time_client, shutdown_time_server); 326 /* 327 * Either the client or server is still 328 * running, so we don't want to shut down yet. 329 */ 330 alarm(0); 331 return (KERN_SUCCESS); 332 } 333 334 /* figure out when the timer should go off */ 335 shutdown_time = MAX(shutdown_time_client, shutdown_time_server); 336 delay = shutdown_time - now.tv_sec; 337 syslog(LOG_DEBUG, "lockd_shutdown: arm timer, delay %d", delay); 338 339 /* arm the timer */ 340 alarm(delay); 341 342 return (KERN_SUCCESS); 343} 344 345static void * 346client_request_thread(void *arg __attribute__((unused))) 347{ 348 mach_msg_server(lockd_mach_server, MAX_LOCKD_MSG_SIZE, 349 lockd_receive_right, 350 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) | 351 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)); 352 353 /* Should never return */ 354 return (NULL); 355} 356 357void 358client_mach_request(void) 359{ 360#if 0 /* Currently rpc library is MT hostile, so we can't do this :( */ 361 pthread_t request_thr; 362 pthread_attr_t attr[1]; 363#endif 364 struct sigaction sigalarm; 365 kern_return_t kr; 366 int mounts, servers, maxservers; 367 struct timeval now; 368 time_t shutdown_time; 369 unsigned int delay; 370 371 /* 372 * Check in with launchd to get the receive right. 373 * N.B. Since we're using a host special port, if launchd 374 * does not have the receive right we can't get it. 375 * And since we should always be started by launchd 376 * this should always succeed. 377 */ 378 kr = bootstrap_check_in(bootstrap_port, 379 BOOTSTRAP_NAME, &lockd_receive_right); 380 if (kr != BOOTSTRAP_SUCCESS) { 381 syslog(LOG_ERR, "Could not checkin for receive right %s\n", 382 bootstrap_strerror(kr)); 383 return; 384 } 385 386 /* Setup. */ 387 (void)time(&owner.tod); 388 owner.pid = getpid(); 389 390 /* set up shutdown timer handler */ 391 sigalarm.sa_handler = (sig_t) shutdown_timer; 392 sigemptyset(&sigalarm.sa_mask); 393 sigalarm.sa_flags = SA_RESTART; 394 if (sigaction(SIGALRM, &sigalarm, NULL) != 0) { 395 syslog(LOG_WARNING, "sigaction(SIGALRM) failed: %s", 396 strerror(errno)); 397 } 398 399 /* Check the current status of the NFS server and NFS mounts */ 400 gettimeofday(&now, NULL); 401 mounts = servers = maxservers = 0; 402 if (get_client_and_server_state(&mounts, &servers, &maxservers)) 403 syslog(LOG_ERR, "lockd setup: sysctl failed"); 404 405 if (!servers || !maxservers) { 406 /* nfsd is not running, set server shutdown time */ 407 shutdown_time_server = now.tv_sec + config.shutdown_delay_server; 408 } else { 409 shutdown_time_server = 0; 410 } 411 if (!mounts) { 412 /* no NFS mounts, set client shutdown time */ 413 shutdown_time_client = now.tv_sec + config.shutdown_delay_client; 414 } else { 415 shutdown_time_client = 0; 416 } 417 418 if (shutdown_time_client && shutdown_time_server) { 419 /* No server and no mounts, so plan for shutdown. */ 420 /* Figure out when the timer should go off. */ 421 shutdown_time = MAX(shutdown_time_client, shutdown_time_server); 422 delay = shutdown_time - now.tv_sec; 423 syslog(LOG_DEBUG, "lockd setup: no client or server, arm timer, delay %d", delay); 424 /* arm the timer */ 425 alarm(delay); 426 } 427 428#if 0 429 pthread_attr_init(attr); 430 (void) pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED); 431 432 error = pthread_create(&request_thr, attr, client_request_thread, NULL); 433 if (error) { 434 syslog(LOG_ERR, "unable to create request thread: %s", 435 strerror(error)); 436 return; 437 } 438#endif 439 440 (void) client_request_thread(NULL); 441} 442 443void 444set_auth(cl, xucred) 445 CLIENT *cl; 446 struct xucred *xucred; 447{ 448 if (cl->cl_auth != NULL) 449 cl->cl_auth->ah_ops->ah_destroy(cl->cl_auth); 450 cl->cl_auth = authunix_create(hostname, 451 xucred->cr_uid, 452 xucred->cr_groups[0], 453 xucred->cr_ngroups - 1, 454 (gid_t *)&xucred->cr_groups[1]); 455} 456 457 458/* 459 * test_request -- 460 * Convert a lock LOCKD_MSG into an NLM request, and send it off. 461 */ 462int 463test_request(LOCKD_MSG *msg) 464{ 465 CLIENT *cli; 466 struct timeval timeout = {0, 0}; /* No timeout, no response. */ 467 char dummy; 468 469 if (d_calls) 470 syslog(LOG_DEBUG, "test request: %s: %s to %s", 471 (msg->lm_flags & LOCKD_MSG_NFSV3) ? "V4" : "V1/3", 472 msg->lm_fl.l_type == F_WRLCK ? "write" : "read", 473 from_addr((struct sockaddr *)&msg->lm_addr)); 474 475 if (msg->lm_flags & LOCKD_MSG_NFSV3) { 476 struct nlm4_testargs arg4; 477 478 arg4.cookie.n_bytes = (uint8_t *)&msg->lm_xid; 479 arg4.cookie.n_len = sizeof(msg->lm_xid); 480 arg4.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0; 481 arg4.alock.caller_name = hostname; 482 arg4.alock.fh.n_bytes = (uint8_t *)&msg->lm_fh; 483 arg4.alock.fh.n_len = msg->lm_fh_len; 484 arg4.alock.oh.n_bytes = (uint8_t *)&owner; 485 arg4.alock.oh.n_len = sizeof(owner); 486 arg4.alock.svid = msg->lm_fl.l_pid; 487 arg4.alock.l_offset = msg->lm_fl.l_start; 488 arg4.alock.l_len = msg->lm_fl.l_len; 489 490 if ((cli = get_client((struct sockaddr *)&msg->lm_addr, NLM_VERS4, 1, (msg->lm_flags & LOCKD_MSG_TCP))) == NULL) 491 return (1); 492 493 set_auth(cli, &msg->lm_cred); 494 (void)clnt_call(cli, NLM4_TEST_MSG, 495 (xdrproc_t)xdr_nlm4_testargs, &arg4, (xdrproc_t)xdr_void, &dummy, timeout); 496 } else { 497 struct nlm_testargs arg; 498 499 arg.cookie.n_bytes = (uint8_t *)&msg->lm_xid; 500 arg.cookie.n_len = sizeof(msg->lm_xid); 501 arg.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0; 502 arg.alock.caller_name = hostname; 503 arg.alock.fh.n_bytes = (uint8_t *)&msg->lm_fh; 504 arg.alock.fh.n_len = msg->lm_fh_len; 505 arg.alock.oh.n_bytes = (uint8_t *)&owner; 506 arg.alock.oh.n_len = sizeof(owner); 507 arg.alock.svid = msg->lm_fl.l_pid; 508 arg.alock.l_offset = msg->lm_fl.l_start; 509 arg.alock.l_len = msg->lm_fl.l_len; 510 511 if ((cli = get_client((struct sockaddr *)&msg->lm_addr, NLM_VERS, 1, (msg->lm_flags & LOCKD_MSG_TCP))) == NULL) 512 return (1); 513 514 set_auth(cli, &msg->lm_cred); 515 (void)clnt_call(cli, NLM_TEST_MSG, 516 (xdrproc_t)xdr_nlm_testargs, &arg, (xdrproc_t)xdr_void, &dummy, timeout); 517 } 518 return (0); 519} 520 521/* 522 * lock_request -- 523 * Convert a lock LOCKD_MSG into an NLM request, and send it off. 524 */ 525int 526lock_request(LOCKD_MSG *msg) 527{ 528 CLIENT *cli; 529 struct nlm4_lockargs arg4; 530 struct nlm_lockargs arg; 531 struct timeval timeout = {0, 0}; /* No timeout, no response. */ 532 char dummy; 533 534 if (d_calls) 535 syslog(LOG_DEBUG, "lock request: %s %s: %s to %s", 536 (msg->lm_flags & LOCKD_MSG_RECLAIM) ? "RECLAIM" : "", 537 (msg->lm_flags & LOCKD_MSG_NFSV3) ? "V4" : "V1/3", 538 msg->lm_fl.l_type == F_WRLCK ? "write" : "read", 539 from_addr((struct sockaddr *)&msg->lm_addr)); 540 541 monitor_lock_host_by_addr((struct sockaddr *)&msg->lm_addr); 542 543 if (msg->lm_flags & LOCKD_MSG_NFSV3) { 544 arg4.cookie.n_bytes = (uint8_t *)&msg->lm_xid; 545 arg4.cookie.n_len = sizeof(msg->lm_xid); 546 arg4.block = (msg->lm_flags & LOCKD_MSG_BLOCK) ? 1 : 0; 547 arg4.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0; 548 arg4.alock.caller_name = hostname; 549 arg4.alock.fh.n_bytes = (uint8_t *)&msg->lm_fh; 550 arg4.alock.fh.n_len = msg->lm_fh_len; 551 arg4.alock.oh.n_bytes = (uint8_t *)&owner; 552 arg4.alock.oh.n_len = sizeof(owner); 553 arg4.alock.svid = msg->lm_fl.l_pid; 554 arg4.alock.l_offset = msg->lm_fl.l_start; 555 arg4.alock.l_len = msg->lm_fl.l_len; 556 arg4.reclaim = (msg->lm_flags & LOCKD_MSG_RECLAIM) ? 1 : 0; 557 arg4.state = nsm_state; 558 559 if ((cli = get_client((struct sockaddr *)&msg->lm_addr, NLM_VERS4, 1+arg4.reclaim, (msg->lm_flags & LOCKD_MSG_TCP))) == NULL) 560 return (1); 561 562 set_auth(cli, &msg->lm_cred); 563 (void)clnt_call(cli, NLM4_LOCK_MSG, 564 (xdrproc_t)xdr_nlm4_lockargs, &arg4, (xdrproc_t)xdr_void, &dummy, timeout); 565 } else { 566 arg.cookie.n_bytes = (uint8_t *)&msg->lm_xid; 567 arg.cookie.n_len = sizeof(msg->lm_xid); 568 arg.block = (msg->lm_flags & LOCKD_MSG_BLOCK) ? 1 : 0; 569 arg.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0; 570 arg.alock.caller_name = hostname; 571 arg.alock.fh.n_bytes = (uint8_t *)&msg->lm_fh; 572 arg.alock.fh.n_len = msg->lm_fh_len; 573 arg.alock.oh.n_bytes = (uint8_t *)&owner; 574 arg.alock.oh.n_len = sizeof(owner); 575 arg.alock.svid = msg->lm_fl.l_pid; 576 arg.alock.l_offset = msg->lm_fl.l_start; 577 arg.alock.l_len = msg->lm_fl.l_len; 578 arg.reclaim = (msg->lm_flags & LOCKD_MSG_RECLAIM) ? 1 : 0; 579 arg.state = nsm_state; 580 581 if ((cli = get_client((struct sockaddr *)&msg->lm_addr, NLM_VERS, 1+arg.reclaim, (msg->lm_flags & LOCKD_MSG_TCP))) == NULL) 582 return (1); 583 584 set_auth(cli, &msg->lm_cred); 585 (void)clnt_call(cli, NLM_LOCK_MSG, 586 (xdrproc_t)xdr_nlm_lockargs, &arg, (xdrproc_t)xdr_void, &dummy, timeout); 587 } 588 return (0); 589} 590 591/* 592 * cancel_request -- 593 * Convert a lock LOCKD_MSG into an NLM request, and send it off. 594 */ 595int 596cancel_request(LOCKD_MSG *msg) 597{ 598 CLIENT *cli; 599 struct nlm4_cancargs arg4; 600 struct nlm_cancargs arg; 601 struct timeval timeout = {0, 0}; /* No timeout, no response. */ 602 char dummy; 603 604 if (d_calls) 605 syslog(LOG_DEBUG, "cancel request: %s: %s to %s", 606 (msg->lm_flags & LOCKD_MSG_NFSV3) ? "V4" : "V1/3", 607 msg->lm_fl.l_type == F_WRLCK ? "write" : "read", 608 from_addr((struct sockaddr *)&msg->lm_addr)); 609 610 if (msg->lm_flags & LOCKD_MSG_NFSV3) { 611 arg4.cookie.n_bytes = (uint8_t *)&msg->lm_xid; 612 arg4.cookie.n_len = sizeof(msg->lm_xid); 613 arg4.block = (msg->lm_flags & LOCKD_MSG_BLOCK) ? 1 : 0; 614 arg4.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0; 615 arg4.alock.caller_name = hostname; 616 arg4.alock.fh.n_bytes = (uint8_t *)&msg->lm_fh; 617 arg4.alock.fh.n_len = msg->lm_fh_len; 618 arg4.alock.oh.n_bytes = (uint8_t *)&owner; 619 arg4.alock.oh.n_len = sizeof(owner); 620 arg4.alock.svid = msg->lm_fl.l_pid; 621 arg4.alock.l_offset = msg->lm_fl.l_start; 622 arg4.alock.l_len = msg->lm_fl.l_len; 623 624 if ((cli = get_client((struct sockaddr *)&msg->lm_addr, NLM_VERS4, 1, (msg->lm_flags & LOCKD_MSG_TCP))) == NULL) 625 return (1); 626 627 set_auth(cli, &msg->lm_cred); 628 (void)clnt_call(cli, NLM4_CANCEL_MSG, 629 (xdrproc_t)xdr_nlm4_cancargs, &arg4, (xdrproc_t)xdr_void, &dummy, timeout); 630 } else { 631 arg.cookie.n_bytes = (uint8_t *)&msg->lm_xid; 632 arg.cookie.n_len = sizeof(msg->lm_xid); 633 arg.block = (msg->lm_flags & LOCKD_MSG_BLOCK) ? 1 : 0; 634 arg.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0; 635 arg.alock.caller_name = hostname; 636 arg.alock.fh.n_bytes = (uint8_t *)&msg->lm_fh; 637 arg.alock.fh.n_len = msg->lm_fh_len; 638 arg.alock.oh.n_bytes = (uint8_t *)&owner; 639 arg.alock.oh.n_len = sizeof(owner); 640 arg.alock.svid = msg->lm_fl.l_pid; 641 arg.alock.l_offset = msg->lm_fl.l_start; 642 arg.alock.l_len = msg->lm_fl.l_len; 643 644 if ((cli = get_client((struct sockaddr *)&msg->lm_addr, NLM_VERS, 1, (msg->lm_flags & LOCKD_MSG_TCP))) == NULL) 645 return (1); 646 647 set_auth(cli, &msg->lm_cred); 648 (void)clnt_call(cli, NLM_CANCEL_MSG, 649 (xdrproc_t)xdr_nlm_cancargs, &arg, (xdrproc_t)xdr_void, &dummy, timeout); 650 } 651 return (0); 652} 653 654/* 655 * unlock_request -- 656 * Convert an unlock LOCKD_MSG into an NLM request, and send it off. 657 */ 658int 659unlock_request(LOCKD_MSG *msg) 660{ 661 CLIENT *cli; 662 struct nlm4_unlockargs arg4; 663 struct nlm_unlockargs arg; 664 struct timeval timeout = {0, 0}; /* No timeout, no response. */ 665 char dummy; 666 667 if (d_calls) 668 syslog(LOG_DEBUG, "unlock request: %s: to %s", 669 (msg->lm_flags & LOCKD_MSG_NFSV3) ? "V4" : "V1/3", 670 from_addr((struct sockaddr *)&msg->lm_addr)); 671 672 if (msg->lm_flags & LOCKD_MSG_NFSV3) { 673 arg4.cookie.n_bytes = (uint8_t *)&msg->lm_xid; 674 arg4.cookie.n_len = sizeof(msg->lm_xid); 675 arg4.alock.caller_name = hostname; 676 arg4.alock.fh.n_bytes = (uint8_t *)&msg->lm_fh; 677 arg4.alock.fh.n_len = msg->lm_fh_len; 678 arg4.alock.oh.n_bytes = (uint8_t *)&owner; 679 arg4.alock.oh.n_len = sizeof(owner); 680 arg4.alock.svid = msg->lm_fl.l_pid; 681 arg4.alock.l_offset = msg->lm_fl.l_start; 682 arg4.alock.l_len = msg->lm_fl.l_len; 683 684 if ((cli = get_client((struct sockaddr *)&msg->lm_addr, NLM_VERS4, 1, (msg->lm_flags & LOCKD_MSG_TCP))) == NULL) 685 return (1); 686 687 set_auth(cli, &msg->lm_cred); 688 (void)clnt_call(cli, NLM4_UNLOCK_MSG, 689 (xdrproc_t)xdr_nlm4_unlockargs, &arg4, (xdrproc_t)xdr_void, &dummy, timeout); 690 } else { 691 arg.cookie.n_bytes = (uint8_t *)&msg->lm_xid; 692 arg.cookie.n_len = sizeof(msg->lm_xid); 693 arg.alock.caller_name = hostname; 694 arg.alock.fh.n_bytes = (uint8_t *)&msg->lm_fh; 695 arg.alock.fh.n_len = msg->lm_fh_len; 696 arg.alock.oh.n_bytes = (uint8_t *)&owner; 697 arg.alock.oh.n_len = sizeof(owner); 698 arg.alock.svid = msg->lm_fl.l_pid; 699 arg.alock.l_offset = msg->lm_fl.l_start; 700 arg.alock.l_len = msg->lm_fl.l_len; 701 702 if ((cli = get_client((struct sockaddr *)&msg->lm_addr, NLM_VERS, 1, (msg->lm_flags & LOCKD_MSG_TCP))) == NULL) 703 return (1); 704 705 set_auth(cli, &msg->lm_cred); 706 (void)clnt_call(cli, NLM_UNLOCK_MSG, 707 (xdrproc_t)xdr_nlm_unlockargs, &arg, (xdrproc_t)xdr_void, &dummy, timeout); 708 } 709 710 return (0); 711} 712 713int 714lock_answer(int version, netobj *netcookie, nlm4_lock *lock, int flags, int result) 715{ 716 struct lockd_ans ans; 717 718 ans.la_flags = 0; 719 ans.la_pid = 0; 720 721 if (flags & LOCK_ANSWER_GRANTED) 722 ans.la_flags |= LOCKD_ANS_GRANTED; 723 724 if (netcookie->n_len != sizeof(ans.la_xid)) { 725 if (lock == NULL) { /* we're screwed */ 726 syslog(LOG_ERR, "inedible nlm cookie"); 727 return -1; 728 } 729 /* no/bad cookie - need to copy lock info to identify request */ 730 ans.la_xid = 0; 731 /* copy lock info */ 732 ans.la_fh_len = lock->fh.n_len; 733 if (!lock->fh.n_len || (lock->fh.n_len > NFS_SMALLFH)) { 734 syslog(LOG_ERR, "bogus filehandle size %d in answer", lock->fh.n_len); 735 return -1; 736 } 737 memcpy(ans.la_fh, lock->fh.n_bytes, ans.la_fh_len); 738 ans.la_pid = lock->svid; 739 ans.la_start = lock->l_offset; 740 ans.la_len = lock->l_len; 741 ans.la_flags |= LOCKD_ANS_LOCK_INFO; 742 if (flags & LOCK_ANSWER_LOCK_EXCL) 743 ans.la_flags |= LOCKD_ANS_LOCK_EXCL; 744 } else { 745 memcpy(&ans.la_xid, netcookie->n_bytes, sizeof(ans.la_xid)); 746 ans.la_fh_len = 0; 747 } 748 749 if (d_calls) 750 syslog(LOG_DEBUG, "lock answer: pid %d: %s %d", ans.la_pid, 751 version == NLM_VERS4 ? "nlmv4" : "nlmv3", result); 752 753 if (version == NLM_VERS4) 754 switch (result) { 755 case nlm4_granted: 756 ans.la_errno = 0; 757 if ((flags & LOCK_ANSWER_GRANTED) && lock && 758 !(ans.la_flags & LOCKD_ANS_LOCK_INFO)) { 759 /* copy lock info */ 760 ans.la_fh_len = lock->fh.n_len; 761 if (!lock->fh.n_len || (lock->fh.n_len > NFS_SMALLFH)) { 762 syslog(LOG_ERR, "bogus filehandle size %d in answer", lock->fh.n_len); 763 return -1; 764 } 765 memcpy(ans.la_fh, lock->fh.n_bytes, ans.la_fh_len); 766 ans.la_pid = lock->svid; 767 ans.la_start = lock->l_offset; 768 ans.la_len = lock->l_len; 769 ans.la_flags |= LOCKD_ANS_LOCK_INFO; 770 if (flags & LOCK_ANSWER_LOCK_EXCL) 771 ans.la_flags |= LOCKD_ANS_LOCK_EXCL; 772 } 773 break; 774 default: 775 ans.la_errno = EACCES; 776 break; 777 case nlm4_denied: 778 if (lock == NULL) 779 ans.la_errno = EAGAIN; 780 else { 781 /* this is an answer to a nlm_test msg */ 782 ans.la_pid = lock->svid; 783 ans.la_start = lock->l_offset; 784 ans.la_len = lock->l_len; 785 ans.la_flags |= LOCKD_ANS_LOCK_INFO; 786 if (flags & LOCK_ANSWER_LOCK_EXCL) 787 ans.la_flags |= LOCKD_ANS_LOCK_EXCL; 788 ans.la_errno = 0; 789 } 790 break; 791 case nlm4_denied_nolocks: 792 ans.la_errno = ENOLCK; 793 break; 794 case nlm4_blocked: 795 ans.la_errno = EINPROGRESS; 796 break; 797 case nlm4_denied_grace_period: 798 ans.la_errno = EAGAIN; 799 ans.la_flags |= LOCKD_ANS_DENIED_GRACE; 800 break; 801 case nlm4_deadlck: 802 ans.la_errno = EDEADLK; 803 break; 804 case nlm4_rofs: 805 ans.la_errno = EROFS; 806 break; 807 case nlm4_stale_fh: 808 ans.la_errno = ESTALE; 809 break; 810 case nlm4_fbig: 811 ans.la_errno = EFBIG; 812 break; 813 case nlm4_failed: 814 ans.la_errno = EACCES; 815 break; 816 } 817 else 818 switch (result) { 819 case nlm_granted: 820 ans.la_errno = 0; 821 if ((flags & LOCK_ANSWER_GRANTED) && lock && 822 !(ans.la_flags & LOCKD_ANS_LOCK_INFO)) { 823 /* copy lock info */ 824 ans.la_fh_len = lock->fh.n_len; 825 if (!lock->fh.n_len || (lock->fh.n_len > NFS_SMALLFH)) { 826 syslog(LOG_ERR, "bogus filehandle size %d in answer", lock->fh.n_len); 827 return -1; 828 } 829 memcpy(ans.la_fh, lock->fh.n_bytes, ans.la_fh_len); 830 ans.la_pid = lock->svid; 831 ans.la_start = lock->l_offset; 832 ans.la_len = lock->l_len; 833 ans.la_flags |= LOCKD_ANS_LOCK_INFO; 834 if (flags & LOCK_ANSWER_LOCK_EXCL) 835 ans.la_flags |= LOCKD_ANS_LOCK_EXCL; 836 } 837 break; 838 default: 839 ans.la_errno = EACCES; 840 break; 841 case nlm_denied: 842 if (lock == NULL) 843 ans.la_errno = EAGAIN; 844 else { 845 /* this is an answer to a nlm_test msg */ 846 ans.la_pid = lock->svid; 847 ans.la_start = lock->l_offset; 848 ans.la_len = lock->l_len; 849 ans.la_flags |= LOCKD_ANS_LOCK_INFO; 850 if (flags & LOCK_ANSWER_LOCK_EXCL) 851 ans.la_flags |= LOCKD_ANS_LOCK_EXCL; 852 ans.la_errno = 0; 853 } 854 break; 855 case nlm_denied_nolocks: 856 ans.la_errno = ENOLCK; 857 break; 858 case nlm_blocked: 859 ans.la_errno = EINPROGRESS; 860 break; 861 case nlm_denied_grace_period: 862 ans.la_errno = EAGAIN; 863 ans.la_flags |= LOCKD_ANS_DENIED_GRACE; 864 break; 865 case nlm_deadlck: 866 ans.la_errno = EDEADLK; 867 break; 868 } 869 870 if (nfslockdans(LOCKD_ANS_VERSION, &ans)) { 871 syslog(LOG_DEBUG, "lock_answer(%d): process %d: %m", 872 result, ans.la_pid); 873 return -1; 874 } 875 return 0; 876} 877 878/* 879 * show -- 880 * Display the contents of a kernel LOCKD_MSG structure. 881 */ 882void 883show(LOCKD_MSG *mp) 884{ 885 static char hex[] = "0123456789abcdef"; 886 size_t len; 887 u_int8_t *p, *t, buf[NFS_SMALLFH*3+1]; 888 889 syslog(LOG_DEBUG, "process ID: %d\n", mp->lm_fl.l_pid); 890 891 for (t = buf, p = (u_int8_t *)mp->lm_fh, 892 len = mp->lm_fh_len; 893 len > 0; ++p, --len) { 894 *t++ = '\\'; 895 *t++ = hex[(*p & 0xf0) >> 4]; 896 *t++ = hex[*p & 0x0f]; 897 } 898 *t = '\0'; 899 900 syslog(LOG_DEBUG, "fh_len %d, fh %s\n", mp->lm_fh_len, buf); 901 902 /* Show flock structure. */ 903 syslog(LOG_DEBUG, "start %qu; len %qu; pid %d; type %d; whence %d\n", 904 mp->lm_fl.l_start, mp->lm_fl.l_len, mp->lm_fl.l_pid, 905 mp->lm_fl.l_type, mp->lm_fl.l_whence); 906 907 /* Show wait flag. */ 908 syslog(LOG_DEBUG, "wait was %s\n", (mp->lm_flags & LOCKD_MSG_BLOCK) ? "set" : "not set"); 909} 910