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