1 /*- 2 * Copyright (c) 1997 Berkeley Software Design, Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Berkeley Software Design Inc's name may not be used to endorse or 13 * promote products derived from this software without specific prior 14 * written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * from BSDI kern.c,v 1.2 1998/11/25 22:38:27 don Exp 29 * $FreeBSD$ 30 */ 31 32 #include <sys/param.h> 33 #include <sys/mount.h> 34 #include <sys/queue.h> 35 #include <sys/socket.h> 36 #include <sys/stat.h> 37 38 #include <netinet/in.h> 39 #include <arpa/inet.h> 40 41 #include <err.h> 42 #include <errno.h> 43 #include <fcntl.h> 44 #include <paths.h> 45 #include <pwd.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <syslog.h> 50 #include <unistd.h> 51 #include <netdb.h> 52 53 #include "nlm_prot.h" 54 #include <nfs/rpcv2.h> 55 #include <nfs/nfsproto.h> 56 #include <nfsclient/nfs_lock.h> 57 58 #include "lockd.h" 59 #include "lockd_lock.h" 60 #include <nfsclient/nfs.h> 61 62 #define DAEMON_USERNAME "daemon" 63 64 /* Lock request owner. */ 65 typedef struct __owner { 66 pid_t pid; /* Process ID. */ 67 time_t tod; /* Time-of-day. */ 68 } OWNER; 69 static OWNER owner; 70 71 static char hostname[MAXHOSTNAMELEN + 1]; /* Hostname. */ 72 73 static void client_cleanup(void); 74 static void set_auth(CLIENT *cl, struct xucred *ucred); 75 int lock_request(LOCKD_MSG *); 76 int test_request(LOCKD_MSG *); 77 void show(LOCKD_MSG *); 78 int unlock_request(LOCKD_MSG *); 79 static int devfd; 80 81 static int 82 nfslockdans(int vers, struct lockd_ans *ansp) 83 { 84 85 ansp->la_vers = vers; 86 return (write(devfd, ansp, sizeof *ansp)); 87 } 88 89 /* 90 * will break because fifo needs to be repopened when EOF'd 91 */ 92 #define lockd_seteuid(uid) seteuid(uid) 93 94 #define d_calls (debug_level > 1) 95 #define d_args (debug_level > 2) 96 97 static const char * 98 from_addr(saddr) 99 struct sockaddr *saddr; 100 { 101 static char inet_buf[INET6_ADDRSTRLEN]; 102 103 if (getnameinfo(saddr, saddr->sa_len, inet_buf, sizeof(inet_buf), 104 NULL, 0, NI_NUMERICHOST) == 0) 105 return inet_buf; 106 return "???"; 107 } 108 109 void 110 client_cleanup(void) 111 { 112 (void)lockd_seteuid(0); 113 exit(-1); 114 } 115 116 /* 117 * client_request -- 118 * Loop around messages from the kernel, forwarding them off to 119 * NLM servers. 120 */ 121 pid_t 122 client_request(void) 123 { 124 LOCKD_MSG msg; 125 fd_set rdset; 126 int nr, ret; 127 pid_t child; 128 uid_t daemon_uid; 129 mode_t old_umask; 130 struct passwd *pw; 131 132 /* Open the dev . */ 133 devfd = open(_PATH_DEV _PATH_NFSLCKDEV, O_RDWR | O_NONBLOCK); 134 if (devfd < 0) { 135 syslog(LOG_ERR, "open: %s: %m", _PATH_NFSLCKDEV); 136 goto err; 137 } 138 /* 139 * Create a separate process, the client code is really a separate 140 * daemon that shares a lot of code. 141 */ 142 switch (child = fork()) { 143 case -1: 144 err(1, "fork"); 145 case 0: 146 break; 147 default: 148 return (child); 149 } 150 151 signal(SIGHUP, (sig_t)client_cleanup); 152 signal(SIGTERM, (sig_t)client_cleanup); 153 154 /* Setup. */ 155 (void)time(&owner.tod); 156 owner.pid = getpid(); 157 (void)gethostname(hostname, sizeof(hostname) - 1); 158 159 pw = getpwnam(DAEMON_USERNAME); 160 if (pw == NULL) { 161 syslog(LOG_ERR, "getpwnam: %s: %m", DAEMON_USERNAME); 162 goto err; 163 } 164 daemon_uid = pw->pw_uid; 165 /* drop our root priviledges */ 166 (void)lockd_seteuid(daemon_uid); 167 168 for (;;) { 169 /* Read the fixed length message. */ 170 if ((nr = read(devfd, &msg, sizeof(msg))) == sizeof(msg)) { 171 if (d_args) 172 show(&msg); 173 174 if (msg.lm_version != LOCKD_MSG_VERSION) { 175 syslog(LOG_ERR, 176 "unknown msg type: %d", msg.lm_version); 177 } 178 /* 179 * Send it to the NLM server and don't grant the lock 180 * if we fail for any reason. 181 */ 182 switch (msg.lm_fl.l_type) { 183 case F_RDLCK: 184 case F_WRLCK: 185 if (msg.lm_getlk) 186 ret = test_request(&msg); 187 else 188 ret = lock_request(&msg); 189 break; 190 case F_UNLCK: 191 ret = unlock_request(&msg); 192 break; 193 default: 194 ret = 1; 195 syslog(LOG_ERR, 196 "unknown lock type: %d", msg.lm_fl.l_type); 197 break; 198 } 199 if (ret) { 200 struct lockd_ans ans; 201 202 ans.la_msg_ident = msg.lm_msg_ident; 203 ans.la_errno = EHOSTUNREACH; 204 205 if (nfslockdans(LOCKD_ANS_VERSION, &ans)) { 206 syslog((errno == EPIPE ? LOG_INFO : 207 LOG_ERR), "process %lu: %m", 208 (u_long)msg.lm_msg_ident.pid); 209 } 210 } 211 } else if (nr == -1) { 212 if (errno != EAGAIN) { 213 syslog(LOG_ERR, "read: %s: %m", _PATH_NFSLCKDEV); 214 goto err; 215 } 216 } else if (nr != 0) { 217 syslog(LOG_ERR, 218 "%s: discard %d bytes", _PATH_NFSLCKDEV, nr); 219 } 220 } 221 222 /* Reached only on error. */ 223 err: 224 (void)lockd_seteuid(0); 225 _exit (1); 226 } 227 228 void 229 set_auth(cl, xucred) 230 CLIENT *cl; 231 struct xucred *xucred; 232 { 233 if (cl->cl_auth != NULL) 234 cl->cl_auth->ah_ops->ah_destroy(cl->cl_auth); 235 cl->cl_auth = authunix_create(hostname, 236 xucred->cr_uid, 237 xucred->cr_groups[0], 238 xucred->cr_ngroups - 1, 239 &xucred->cr_groups[1]); 240 } 241 242 243 /* 244 * test_request -- 245 * Convert a lock LOCKD_MSG into an NLM request, and send it off. 246 */ 247 int 248 test_request(LOCKD_MSG *msg) 249 { 250 CLIENT *cli; 251 struct timeval timeout = {0, 0}; /* No timeout, no response. */ 252 char dummy; 253 254 if (d_calls) 255 syslog(LOG_DEBUG, "test request: %s: %s to %s", 256 msg->lm_nfsv3 ? "V4" : "V1/3", 257 msg->lm_fl.l_type == F_WRLCK ? "write" : "read", 258 from_addr((struct sockaddr *)&msg->lm_addr)); 259 260 if (msg->lm_nfsv3) { 261 struct nlm4_testargs arg4; 262 263 arg4.cookie.n_bytes = (char *)&msg->lm_msg_ident; 264 arg4.cookie.n_len = sizeof(msg->lm_msg_ident); 265 arg4.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0; 266 arg4.alock.caller_name = hostname; 267 arg4.alock.fh.n_bytes = (char *)&msg->lm_fh; 268 arg4.alock.fh.n_len = msg->lm_fh_len; 269 arg4.alock.oh.n_bytes = (char *)&owner; 270 arg4.alock.oh.n_len = sizeof(owner); 271 arg4.alock.svid = msg->lm_msg_ident.pid; 272 arg4.alock.l_offset = msg->lm_fl.l_start; 273 arg4.alock.l_len = msg->lm_fl.l_len; 274 275 if ((cli = get_client( 276 (struct sockaddr *)&msg->lm_addr, 277 NLM_VERS4)) == NULL) 278 return (1); 279 280 set_auth(cli, &msg->lm_cred); 281 (void)clnt_call(cli, NLM_TEST_MSG, 282 (xdrproc_t)xdr_nlm4_testargs, &arg4, 283 (xdrproc_t)xdr_void, &dummy, timeout); 284 } else { 285 struct nlm_testargs arg; 286 287 arg.cookie.n_bytes = (char *)&msg->lm_msg_ident; 288 arg.cookie.n_len = sizeof(msg->lm_msg_ident); 289 arg.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0; 290 arg.alock.caller_name = hostname; 291 arg.alock.fh.n_bytes = (char *)&msg->lm_fh; 292 arg.alock.fh.n_len = msg->lm_fh_len; 293 arg.alock.oh.n_bytes = (char *)&owner; 294 arg.alock.oh.n_len = sizeof(owner); 295 arg.alock.svid = msg->lm_msg_ident.pid; 296 arg.alock.l_offset = msg->lm_fl.l_start; 297 arg.alock.l_len = msg->lm_fl.l_len; 298 299 if ((cli = get_client( 300 (struct sockaddr *)&msg->lm_addr, 301 NLM_VERS)) == NULL) 302 return (1); 303 304 set_auth(cli, &msg->lm_cred); 305 (void)clnt_call(cli, NLM_TEST_MSG, 306 (xdrproc_t)xdr_nlm_testargs, &arg, 307 (xdrproc_t)xdr_void, &dummy, timeout); 308 } 309 return (0); 310 } 311 312 /* 313 * lock_request -- 314 * Convert a lock LOCKD_MSG into an NLM request, and send it off. 315 */ 316 int 317 lock_request(LOCKD_MSG *msg) 318 { 319 CLIENT *cli; 320 struct nlm4_lockargs arg4; 321 struct nlm_lockargs arg; 322 struct timeval timeout = {0, 0}; /* No timeout, no response. */ 323 char dummy; 324 325 if (d_calls) 326 syslog(LOG_DEBUG, "lock request: %s: %s to %s", 327 msg->lm_nfsv3 ? "V4" : "V1/3", 328 msg->lm_fl.l_type == F_WRLCK ? "write" : "read", 329 from_addr((struct sockaddr *)&msg->lm_addr)); 330 331 if (msg->lm_nfsv3) { 332 arg4.cookie.n_bytes = (char *)&msg->lm_msg_ident; 333 arg4.cookie.n_len = sizeof(msg->lm_msg_ident); 334 arg4.block = msg->lm_wait ? 1 : 0; 335 arg4.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0; 336 arg4.alock.caller_name = hostname; 337 arg4.alock.fh.n_bytes = (char *)&msg->lm_fh; 338 arg4.alock.fh.n_len = msg->lm_fh_len; 339 arg4.alock.oh.n_bytes = (char *)&owner; 340 arg4.alock.oh.n_len = sizeof(owner); 341 arg4.alock.svid = msg->lm_msg_ident.pid; 342 arg4.alock.l_offset = msg->lm_fl.l_start; 343 arg4.alock.l_len = msg->lm_fl.l_len; 344 arg4.reclaim = 0; 345 arg4.state = nsm_state; 346 347 if ((cli = get_client( 348 (struct sockaddr *)&msg->lm_addr, 349 NLM_VERS4)) == NULL) 350 return (1); 351 352 set_auth(cli, &msg->lm_cred); 353 (void)clnt_call(cli, NLM_LOCK_MSG, 354 (xdrproc_t)xdr_nlm4_lockargs, &arg4, 355 (xdrproc_t)xdr_void, &dummy, timeout); 356 } else { 357 arg.cookie.n_bytes = (char *)&msg->lm_msg_ident; 358 arg.cookie.n_len = sizeof(msg->lm_msg_ident); 359 arg.block = msg->lm_wait ? 1 : 0; 360 arg.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0; 361 arg.alock.caller_name = hostname; 362 arg.alock.fh.n_bytes = (char *)&msg->lm_fh; 363 arg.alock.fh.n_len = msg->lm_fh_len; 364 arg.alock.oh.n_bytes = (char *)&owner; 365 arg.alock.oh.n_len = sizeof(owner); 366 arg.alock.svid = msg->lm_msg_ident.pid; 367 arg.alock.l_offset = msg->lm_fl.l_start; 368 arg.alock.l_len = msg->lm_fl.l_len; 369 arg.reclaim = 0; 370 arg.state = nsm_state; 371 372 if ((cli = get_client( 373 (struct sockaddr *)&msg->lm_addr, 374 NLM_VERS)) == NULL) 375 return (1); 376 377 set_auth(cli, &msg->lm_cred); 378 (void)clnt_call(cli, NLM_LOCK_MSG, 379 (xdrproc_t)xdr_nlm_lockargs, &arg, 380 (xdrproc_t)xdr_void, &dummy, timeout); 381 } 382 return (0); 383 } 384 385 /* 386 * unlock_request -- 387 * Convert an unlock LOCKD_MSG into an NLM request, and send it off. 388 */ 389 int 390 unlock_request(LOCKD_MSG *msg) 391 { 392 CLIENT *cli; 393 struct nlm4_unlockargs arg4; 394 struct nlm_unlockargs arg; 395 struct timeval timeout = {0, 0}; /* No timeout, no response. */ 396 char dummy; 397 398 if (d_calls) 399 syslog(LOG_DEBUG, "unlock request: %s: to %s", 400 msg->lm_nfsv3 ? "V4" : "V1/3", 401 from_addr((struct sockaddr *)&msg->lm_addr)); 402 403 if (msg->lm_nfsv3) { 404 arg4.cookie.n_bytes = (char *)&msg->lm_msg_ident; 405 arg4.cookie.n_len = sizeof(msg->lm_msg_ident); 406 arg4.alock.caller_name = hostname; 407 arg4.alock.fh.n_bytes = (char *)&msg->lm_fh; 408 arg4.alock.fh.n_len = msg->lm_fh_len; 409 arg4.alock.oh.n_bytes = (char *)&owner; 410 arg4.alock.oh.n_len = sizeof(owner); 411 arg4.alock.svid = msg->lm_msg_ident.pid; 412 arg4.alock.l_offset = msg->lm_fl.l_start; 413 arg4.alock.l_len = msg->lm_fl.l_len; 414 415 if ((cli = get_client( 416 (struct sockaddr *)&msg->lm_addr, 417 NLM_VERS4)) == NULL) 418 return (1); 419 420 set_auth(cli, &msg->lm_cred); 421 (void)clnt_call(cli, NLM_UNLOCK_MSG, 422 (xdrproc_t)xdr_nlm4_unlockargs, &arg4, 423 (xdrproc_t)xdr_void, &dummy, timeout); 424 } else { 425 arg.cookie.n_bytes = (char *)&msg->lm_msg_ident; 426 arg.cookie.n_len = sizeof(msg->lm_msg_ident); 427 arg.alock.caller_name = hostname; 428 arg.alock.fh.n_bytes = (char *)&msg->lm_fh; 429 arg.alock.fh.n_len = msg->lm_fh_len; 430 arg.alock.oh.n_bytes = (char *)&owner; 431 arg.alock.oh.n_len = sizeof(owner); 432 arg.alock.svid = msg->lm_msg_ident.pid; 433 arg.alock.l_offset = msg->lm_fl.l_start; 434 arg.alock.l_len = msg->lm_fl.l_len; 435 436 if ((cli = get_client( 437 (struct sockaddr *)&msg->lm_addr, 438 NLM_VERS)) == NULL) 439 return (1); 440 441 set_auth(cli, &msg->lm_cred); 442 (void)clnt_call(cli, NLM_UNLOCK_MSG, 443 (xdrproc_t)xdr_nlm_unlockargs, &arg, 444 (xdrproc_t)xdr_void, &dummy, timeout); 445 } 446 447 return (0); 448 } 449 450 int 451 lock_answer(int pid, netobj *netcookie, int result, int *pid_p, int version) 452 { 453 struct lockd_ans ans; 454 455 if (netcookie->n_len != sizeof(ans.la_msg_ident)) { 456 if (pid == -1) { /* we're screwed */ 457 syslog(LOG_ERR, "inedible nlm cookie"); 458 return -1; 459 } 460 ans.la_msg_ident.pid = pid; 461 ans.la_msg_ident.msg_seq = -1; 462 } else { 463 memcpy(&ans.la_msg_ident, netcookie->n_bytes, 464 sizeof(ans.la_msg_ident)); 465 } 466 467 if (d_calls) 468 syslog(LOG_DEBUG, "lock answer: pid %lu: %s %d", 469 (unsigned long)ans.la_msg_ident.pid, 470 version == NLM_VERS4 ? "nlmv4" : "nlmv3", 471 result); 472 473 ans.la_set_getlk_pid = 0; 474 if (version == NLM_VERS4) 475 switch (result) { 476 case nlm4_granted: 477 ans.la_errno = 0; 478 break; 479 default: 480 ans.la_errno = EACCES; 481 break; 482 case nlm4_denied: 483 if (pid_p == NULL) 484 ans.la_errno = EAGAIN; 485 else { 486 /* this is an answer to a nlm_test msg */ 487 ans.la_set_getlk_pid = 1; 488 ans.la_getlk_pid = *pid_p; 489 ans.la_errno = 0; 490 } 491 break; 492 case nlm4_denied_nolocks: 493 ans.la_errno = EAGAIN; 494 break; 495 case nlm4_blocked: 496 return -1; 497 /* NOTREACHED */ 498 case nlm4_denied_grace_period: 499 ans.la_errno = EAGAIN; 500 break; 501 case nlm4_deadlck: 502 ans.la_errno = EDEADLK; 503 break; 504 case nlm4_rofs: 505 ans.la_errno = EROFS; 506 break; 507 case nlm4_stale_fh: 508 ans.la_errno = ESTALE; 509 break; 510 case nlm4_fbig: 511 ans.la_errno = EFBIG; 512 break; 513 case nlm4_failed: 514 ans.la_errno = EACCES; 515 break; 516 } 517 else 518 switch (result) { 519 case nlm_granted: 520 ans.la_errno = 0; 521 break; 522 default: 523 ans.la_errno = EACCES; 524 break; 525 case nlm_denied: 526 if (pid_p == NULL) 527 ans.la_errno = EAGAIN; 528 else { 529 /* this is an answer to a nlm_test msg */ 530 ans.la_set_getlk_pid = 1; 531 ans.la_getlk_pid = *pid_p; 532 ans.la_errno = 0; 533 } 534 break; 535 case nlm_denied_nolocks: 536 ans.la_errno = EAGAIN; 537 break; 538 case nlm_blocked: 539 return -1; 540 /* NOTREACHED */ 541 case nlm_denied_grace_period: 542 ans.la_errno = EAGAIN; 543 break; 544 case nlm_deadlck: 545 ans.la_errno = EDEADLK; 546 break; 547 } 548 549 if (nfslockdans(LOCKD_ANS_VERSION, &ans)) { 550 syslog(((errno == EPIPE || errno == ESRCH) ? 551 LOG_INFO : LOG_ERR), 552 "process %lu: %m", (u_long)ans.la_msg_ident.pid); 553 return -1; 554 } 555 return 0; 556 } 557 558 /* 559 * show -- 560 * Display the contents of a kernel LOCKD_MSG structure. 561 */ 562 void 563 show(LOCKD_MSG *mp) 564 { 565 static char hex[] = "0123456789abcdef"; 566 struct fid *fidp; 567 fsid_t *fsidp; 568 size_t len; 569 u_int8_t *p, *t, buf[NFS_SMALLFH*3+1]; 570 571 syslog(LOG_DEBUG, "process ID: %lu\n", (long)mp->lm_msg_ident.pid); 572 573 fsidp = (fsid_t *)&mp->lm_fh; 574 fidp = (struct fid *)((u_int8_t *)&mp->lm_fh + sizeof(fsid_t)); 575 576 for (t = buf, p = (u_int8_t *)mp->lm_fh, 577 len = mp->lm_fh_len; 578 len > 0; ++p, --len) { 579 *t++ = '\\'; 580 *t++ = hex[(*p & 0xf0) >> 4]; 581 *t++ = hex[*p & 0x0f]; 582 } 583 *t = '\0'; 584 585 syslog(LOG_DEBUG, "fh_len %d, fh %s\n", (int)mp->lm_fh_len, buf); 586 587 /* Show flock structure. */ 588 syslog(LOG_DEBUG, "start %qu; len %qu; pid %lu; type %d; whence %d\n", 589 (unsigned long long)mp->lm_fl.l_start, 590 (unsigned long long)mp->lm_fl.l_len, (u_long)mp->lm_fl.l_pid, 591 mp->lm_fl.l_type, mp->lm_fl.l_whence); 592 593 /* Show wait flag. */ 594 syslog(LOG_DEBUG, "wait was %s\n", mp->lm_wait ? "set" : "not set"); 595 } 596