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