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