Merge branch 'vendor/BINUTILS_ALL'
[dragonfly.git] / sys / kern / lwkt_caps.c
1 /*
2  * Copyright (c) 2003,2004 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  * 
34  * $DragonFly: src/sys/kern/lwkt_caps.c,v 1.13 2007/02/26 21:41:08 corecode Exp $
35  */
36
37 /*
38  * This module implements the DragonFly LWKT IPC rendezvous and message
39  * passing API which operates between userland processes, between userland
40  * threads, and between userland processes and kernel threads.  This API
41  * is known as the CAPS interface.
42  *
43  * Generally speaking this module abstracts the LWKT message port interface
44  * into userland Clients and Servers rendezvous through ports named
45  * by or wildcarded by (name,uid,gid).  The kernel provides system calls 
46  * which may be assigned to the mp_* fields in a userland-supplied
47  * kernel-managed port, and a registration interface which associates an
48  * upcall with a userland port.  The kernel tracks authentication information
49  * and deals with connection failures by automatically replying to unreplied
50  * messages.
51  *
52  * From the userland perspective a client/server connection involves two
53  * message ports on the client and two message ports on the server.
54  */
55
56 #include <sys/param.h>
57 #include <sys/systm.h>
58 #include <sys/kernel.h>
59 #include <sys/sysproto.h>
60 #include <sys/malloc.h>
61 #include <sys/proc.h>
62 #include <sys/ucred.h>
63 #include <sys/caps.h>
64 #include <sys/sysctl.h>
65
66 #include <sys/mplock2.h>
67
68 #include <vm/vm.h>
69 #include <vm/vm_extern.h>
70
71 static int caps_process_msg(caps_kinfo_t caps, caps_kmsg_t msg, struct caps_sys_get_args *uap);
72 static void caps_free(caps_kinfo_t caps);
73 static void caps_free_msg(caps_kmsg_t msg);
74 static int caps_name_check(const char *name, size_t len);
75 static caps_kinfo_t caps_free_msg_mcaps(caps_kmsg_t msg);
76 static caps_kinfo_t kern_caps_sys_service(const char *name, uid_t uid, 
77                         gid_t gid, struct ucred *cred, 
78                         int flags, int *error);
79 static caps_kinfo_t kern_caps_sys_client(const char *name, uid_t uid,
80                         gid_t gid, struct ucred *cred, int flags, int *error);
81
82 #define CAPS_HSIZE      64
83 #define CAPS_HMASK      (CAPS_HSIZE - 1)
84
85 static caps_kinfo_t     caps_hash_ary[CAPS_HSIZE];
86 static int caps_waitsvc;
87
88 MALLOC_DEFINE(M_CAPS, "caps", "caps IPC messaging");
89
90 static int caps_enabled;
91 SYSCTL_INT(_kern, OID_AUTO, caps_enabled,
92         CTLFLAG_RW, &caps_enabled, 0, "Enable CAPS");
93
94 /************************************************************************
95  *                      INLINE SUPPORT FUNCTIONS                        *
96  ************************************************************************/
97
98 static __inline
99 struct caps_kinfo **
100 caps_hash(const char *name, int len)
101 {
102     int hv = 0x7123F4B3;
103
104     while (--len >= 0)
105         hv = (hv << 5) ^ name[len] ^ (hv >> 23);
106     return(&caps_hash_ary[(hv ^ (hv >> 16)) & CAPS_HMASK]);
107 }
108
109 static __inline
110 void
111 caps_hold(caps_kinfo_t caps)
112 {
113     ++caps->ci_refs;
114 }
115
116 static __inline
117 void
118 caps_drop(caps_kinfo_t caps)
119 {
120     if (--caps->ci_refs == 0)
121         caps_free(caps);
122 }
123
124 /************************************************************************
125  *                      STATIC SUPPORT FUNCTIONS                        *
126  ************************************************************************/
127
128 static
129 caps_kinfo_t
130 caps_find(const char *name, int len, uid_t uid, gid_t gid)
131 {
132     caps_kinfo_t caps;
133     struct caps_kinfo **chash;
134
135     chash = caps_hash(name, len);
136     for (caps = *chash; caps; caps = caps->ci_hnext) {
137         if ((uid == (uid_t)-1 || uid == caps->ci_uid) &&
138             (gid == (gid_t)-1 || gid == caps->ci_gid) &&
139             len == caps->ci_namelen &&
140             bcmp(name, caps->ci_name, len) == 0
141         ) {
142             caps_hold(caps);
143             break;
144         }
145     }
146     return(caps);
147 }
148
149 static
150 caps_kinfo_t
151 caps_find_id(thread_t td, int id)
152 {
153    caps_kinfo_t caps;
154
155    for (caps = td->td_caps; caps; caps = caps->ci_tdnext) {
156         if (caps->ci_id == id) {
157             caps_hold(caps);
158             break;
159         }
160    }
161    return(caps);
162 }
163
164 static
165 caps_kinfo_t
166 caps_alloc(thread_t td, const char *name, int len, uid_t uid, gid_t gid, 
167             int flags, caps_type_t type)
168 {
169     struct caps_kinfo **chash;
170     caps_kinfo_t caps;
171     caps_kinfo_t ctmp;
172
173     caps = kmalloc(offsetof(struct caps_kinfo, ci_name[len+1]), 
174                         M_CAPS, M_WAITOK|M_ZERO);
175     TAILQ_INIT(&caps->ci_msgpendq);
176     TAILQ_INIT(&caps->ci_msguserq);
177     caps->ci_uid = uid;         /* -1 == not registered for uid search */
178     caps->ci_gid = gid;         /* -1 == not registered for gid search */
179     caps->ci_type = type;
180     caps->ci_refs = 1;  /* CAPKF_TDLIST reference */
181     caps->ci_namelen = len;
182     caps->ci_flags = flags;
183     bcopy(name, caps->ci_name, len + 1);
184     if (type == CAPT_SERVICE) {
185         chash = caps_hash(caps->ci_name, len);
186         caps->ci_hnext = *chash;
187         *chash = caps;
188         caps->ci_flags |= CAPKF_HLIST;
189     }
190     if (td->td_caps) {
191         caps->ci_id = td->td_caps->ci_id + 1;
192         if (caps->ci_id < 0) {
193             /*
194              * It is virtually impossible for this case to occur.
195              */
196             caps->ci_id = 1;
197             while ((ctmp = caps_find_id(td, caps->ci_id)) != NULL) {
198                 caps_drop(ctmp);
199                 ++caps->ci_id;
200             }
201         }
202     } else {
203         caps->ci_id = 1;
204     }
205     caps->ci_flags |= CAPKF_TDLIST;
206     caps->ci_tdnext = td->td_caps;
207     caps->ci_td = td;
208     td->td_caps = caps;
209     return(caps);
210 }
211
212 static
213 caps_kmsg_t
214 caps_alloc_msg(caps_kinfo_t caps)
215 {
216     caps_kmsg_t msg;
217
218     msg = kmalloc(sizeof(struct caps_kmsg), M_CAPS, M_WAITOK|M_ZERO);
219     msg->km_msgid.c_id = (off_t)(uintptr_t)msg;
220     return(msg);
221 }
222
223 static
224 caps_kmsg_t
225 caps_find_msg(caps_kinfo_t caps, off_t msgid)
226 {
227     caps_kmsg_t msg;
228
229     TAILQ_FOREACH(msg, &caps->ci_msguserq, km_node) {
230         if (msg->km_msgid.c_id == msgid)
231             return(msg);
232     }
233     TAILQ_FOREACH(msg, &caps->ci_msgpendq, km_node) {
234         if (msg->km_msgid.c_id == msgid)
235             return(msg);
236     }
237     return(NULL);
238 }
239
240 static
241 caps_kinfo_t
242 caps_load_ccr(caps_kinfo_t caps, caps_kmsg_t msg, struct lwp *lp,
243               void *udata, int ubytes)
244 {
245     struct ucred *cr = lp ? lp->lwp_thread->td_ucred : proc0.p_ucred;
246     caps_kinfo_t rcaps;
247     int i;
248
249     /*
250      * replace km_mcaps with new VM state, return the old km_mcaps.  The
251      * caller is expected to drop the rcaps ref count on return so we do
252      * not do it ourselves.
253      */
254     rcaps = caps_free_msg_mcaps(msg);   /* can be NULL */
255     caps_hold(caps);
256     msg->km_mcaps = caps;
257     xio_init_ubuf(&msg->km_xio, udata, ubytes, XIOF_READ);
258
259     msg->km_ccr.pid = lp ? lp->lwp_proc->p_pid : -1;
260     msg->km_ccr.uid = cr->cr_ruid;
261     msg->km_ccr.euid = cr->cr_uid;
262     msg->km_ccr.gid = cr->cr_rgid;
263     msg->km_ccr.ngroups = MIN(cr->cr_ngroups, CAPS_MAXGROUPS);
264     for (i = 0; i < msg->km_ccr.ngroups; ++i)
265         msg->km_ccr.groups[i] = cr->cr_groups[i];
266     return(rcaps);
267 }
268
269 static void
270 caps_dequeue_msg(caps_kinfo_t caps, caps_kmsg_t msg)
271 {
272     if (msg->km_flags & CAPKMF_ONUSERQ)
273         TAILQ_REMOVE(&caps->ci_msguserq, msg, km_node);
274     if (msg->km_flags & CAPKMF_ONPENDQ)
275         TAILQ_REMOVE(&caps->ci_msgpendq, msg, km_node);
276     msg->km_flags &= ~(CAPKMF_ONPENDQ|CAPKMF_ONUSERQ);
277 }
278
279 static void
280 caps_put_msg(caps_kinfo_t caps, caps_kmsg_t msg, caps_msg_state_t state)
281 {
282     KKASSERT((msg->km_flags & (CAPKMF_ONUSERQ|CAPKMF_ONPENDQ)) == 0);
283
284     msg->km_flags |= CAPKMF_ONPENDQ;
285     msg->km_flags &= ~CAPKMF_PEEKED;
286     msg->km_state = state;
287     TAILQ_INSERT_TAIL(&caps->ci_msgpendq, msg, km_node);
288
289     /*
290      * Instead of waking up the service for both new messages and disposals,
291      * just wakeup the service for new messages and it will process the
292      * previous disposal in the same loop, reducing the number of context
293      * switches required to run an IPC.
294      */
295     if (state != CAPMS_DISPOSE)
296         wakeup(caps);
297     caps_drop(caps);
298 }
299
300 /*
301  * caps_free_msg_mcaps()
302  */
303 static
304 caps_kinfo_t
305 caps_free_msg_mcaps(caps_kmsg_t msg)
306 {
307     caps_kinfo_t mcaps;
308
309     mcaps = msg->km_mcaps;      /* may be NULL */
310     msg->km_mcaps = NULL;
311     if (msg->km_xio.xio_npages)
312         xio_release(&msg->km_xio);
313     return(mcaps);
314 }
315
316 /*
317  * caps_free_msg()
318  *
319  * Free a caps placeholder message.  The message must not be on any queues.
320  */
321 static void
322 caps_free_msg(caps_kmsg_t msg)
323 {
324     caps_kinfo_t rcaps;
325
326     if ((rcaps = caps_free_msg_mcaps(msg)) != NULL)
327         caps_drop(rcaps);
328     kfree(msg, M_CAPS);
329 }
330
331 /*
332  * Validate the service name
333  */
334 static int
335 caps_name_check(const char *name, size_t len)
336 {
337     size_t i;
338     char c;
339
340     for (i = len - 1; i >= 0; --i) {
341         c = name[i];
342         if (c >= '0' && c <= '9')
343             continue;
344         if (c >= 'a' && c <= 'z')
345             continue;
346         if (c >= 'A' && c <= 'Z')
347             continue;
348         if (c == '_' || c == '.')
349             continue;
350         return(EINVAL);
351     }
352     return(0);
353 }
354
355 /*
356  * caps_term()
357  *
358  * Terminate portions of a caps info structure.  This is used to close
359  * an end-point or to flush particular messages on an end-point.
360  *
361  * This function should not be called with CAPKF_TDLIST unless the caller
362  * has an additional hold on the caps structure.
363  */
364 static void
365 caps_term(caps_kinfo_t caps, int flags, caps_kinfo_t cflush)
366 {
367     struct thread *td = curthread;
368     struct caps_kinfo **scan;
369     caps_kmsg_t msg;
370
371     if (flags & CAPKF_TDLIST)
372         caps->ci_flags |= CAPKF_CLOSED;
373
374     if (flags & CAPKF_FLUSH) {
375         int mflags;
376         struct caps_kmsg_queue tmpuserq;
377         struct caps_kmsg_queue tmppendq;
378         caps_kinfo_t rcaps;
379
380         TAILQ_INIT(&tmpuserq);
381         TAILQ_INIT(&tmppendq);
382
383         while ((msg = TAILQ_FIRST(&caps->ci_msgpendq)) != NULL ||
384                (msg = TAILQ_FIRST(&caps->ci_msguserq)) != NULL
385         ) {
386             mflags = msg->km_flags & (CAPKMF_ONUSERQ|CAPKMF_ONPENDQ);
387             caps_dequeue_msg(caps, msg);
388
389             if (cflush && msg->km_mcaps != cflush) {
390                 if (mflags & CAPKMF_ONUSERQ)
391                     TAILQ_INSERT_TAIL(&tmpuserq, msg, km_node);
392                 else
393                     TAILQ_INSERT_TAIL(&tmppendq, msg, km_node);
394             } else {
395                 /*
396                  * Dispose of the message.  If the received message is a
397                  * request we must reply it.  If the received message is
398                  * a reply we must return it for disposal.  If the
399                  * received message is a disposal request we simply free it.
400                  */
401                 switch(msg->km_state) {
402                 case CAPMS_REQUEST:
403                 case CAPMS_REQUEST_RETRY:
404                     rcaps = caps_load_ccr(caps, msg, td->td_lwp, NULL, 0);
405                     if (rcaps->ci_flags & CAPKF_CLOSED) {
406                         /*
407                          * can't reply, if we never read the message (its on
408                          * the pending queue), or if we are closed ourselves,
409                          * we can just free the message.  Otherwise we have
410                          * to send ourselves a disposal request (multi-threaded
411                          * services have to deal with disposal requests for
412                          * messages that might be in progress).
413                          */
414                         if ((caps->ci_flags & CAPKF_CLOSED) ||
415                             (mflags & CAPKMF_ONPENDQ)
416                         ) {
417                             caps_free_msg(msg);
418                             caps_drop(rcaps);
419                         } else {
420                             caps_drop(rcaps);
421                             caps_hold(caps);    /* for message */
422                             caps_put_msg(caps, msg, CAPMS_DISPOSE);
423                         }
424                     } else {
425                         /*
426                          * auto-reply to the originator.  rcaps already
427                          * has a dangling hold so we do not have to hold it
428                          * again.
429                          */
430                         caps_put_msg(rcaps, msg, CAPMS_REPLY);
431                     }
432                     break;
433                 case CAPMS_REPLY:
434                 case CAPMS_REPLY_RETRY:
435                     rcaps = caps_load_ccr(caps, msg, td->td_lwp, NULL, 0);
436                     if (caps == rcaps || (rcaps->ci_flags & CAPKF_CLOSED)) {
437                         caps_free_msg(msg);     /* degenerate disposal case */
438                         caps_drop(rcaps);
439                     } else {
440                         caps_put_msg(rcaps, msg, CAPMS_DISPOSE);
441                     }
442                     break;
443                 case CAPMS_DISPOSE:
444                     caps_free_msg(msg);
445                     break;
446                 }
447             }
448         }
449         while ((msg = TAILQ_FIRST(&tmpuserq)) != NULL) {
450             TAILQ_REMOVE(&tmpuserq, msg, km_node);
451             TAILQ_INSERT_TAIL(&caps->ci_msguserq, msg, km_node);
452             msg->km_flags |= CAPKMF_ONUSERQ;
453         }
454         while ((msg = TAILQ_FIRST(&tmppendq)) != NULL) {
455             TAILQ_REMOVE(&tmppendq, msg, km_node);
456             TAILQ_INSERT_TAIL(&caps->ci_msgpendq, msg, km_node);
457             msg->km_flags |= CAPKMF_ONPENDQ;
458         }
459     }
460     if ((flags & CAPKF_HLIST) && (caps->ci_flags & CAPKF_HLIST)) {
461         for (scan = caps_hash(caps->ci_name, caps->ci_namelen);
462             *scan != caps;
463             scan = &(*scan)->ci_hnext
464         ) {
465             KKASSERT(*scan != NULL);
466         }
467         *scan = caps->ci_hnext;
468         caps->ci_hnext = (void *)-1;
469         caps->ci_flags &= ~CAPKF_HLIST;
470     }
471     if ((flags & CAPKF_TDLIST) && (caps->ci_flags & CAPKF_TDLIST)) {
472         for (scan = &caps->ci_td->td_caps;
473             *scan != caps;
474             scan = &(*scan)->ci_tdnext
475         ) {
476             KKASSERT(*scan != NULL);
477         }
478         *scan = caps->ci_tdnext;
479         caps->ci_flags &= ~CAPKF_TDLIST;
480         caps->ci_tdnext = (void *)-1;
481         caps->ci_td = NULL;
482         caps_drop(caps);
483     }
484     if ((flags & CAPKF_RCAPS) && (caps->ci_flags & CAPKF_RCAPS)) {
485         caps_kinfo_t ctmp;
486
487         caps->ci_flags &= ~CAPKF_RCAPS;
488         if ((ctmp = caps->ci_rcaps)) {
489             caps->ci_rcaps = NULL;
490             caps_term(ctmp, CAPKF_FLUSH, caps);
491             caps_drop(ctmp);
492         }
493     }
494 }
495
496 static void
497 caps_free(caps_kinfo_t caps)
498 {
499     KKASSERT(TAILQ_EMPTY(&caps->ci_msgpendq));
500     KKASSERT(TAILQ_EMPTY(&caps->ci_msguserq));
501     KKASSERT((caps->ci_flags & (CAPKF_HLIST|CAPKF_TDLIST)) == 0);
502     kfree(caps, M_CAPS);
503 }
504
505 /************************************************************************
506  *                      PROCESS SUPPORT FUNCTIONS                       *
507  ************************************************************************/
508
509 /*
510  * Create dummy entries in p2 so we can return the appropriate
511  * error code.  Robust userland code will check the error for a
512  * forked condition and reforge the connection.
513  */
514 void
515 caps_fork(struct thread *td1, struct thread *td2)
516 {
517     caps_kinfo_t caps1;
518     caps_kinfo_t caps2;
519
520     /*
521      * Create dummy entries with the same id's as the originals.  Note
522      * that service entries are not re-added to the hash table. The
523      * dummy entries return an ENOTCONN error allowing userland code to
524      * detect that a fork occured.  Userland must reconnect to the service.
525      */
526     for (caps1 = td1->td_caps; caps1; caps1 = caps1->ci_tdnext) {
527         if (caps1->ci_flags & CAPF_NOFORK)
528                 continue;
529         caps2 = caps_alloc(td2,
530                         caps1->ci_name, caps1->ci_namelen,
531                         caps1->ci_uid, caps1->ci_gid,
532                         caps1->ci_flags & CAPF_UFLAGS, CAPT_FORKED);
533         caps2->ci_id = caps1->ci_id;
534     }
535
536     /*
537      * Reverse the list order to maintain highest-id-first
538      */
539     caps2 = td2->td_caps;
540     td2->td_caps = NULL;
541     while (caps2) {
542         caps1 = caps2->ci_tdnext;
543         caps2->ci_tdnext = td2->td_caps;
544         td2->td_caps = caps2;
545         caps2 = caps1;
546     }
547 }
548
549 void
550 caps_exit(struct thread *td)
551 {
552     caps_kinfo_t caps;
553
554     while ((caps = td->td_caps) != NULL) {
555         caps_hold(caps);
556         caps_term(caps, CAPKF_TDLIST|CAPKF_HLIST|CAPKF_FLUSH|CAPKF_RCAPS, NULL);
557         caps_drop(caps);
558     }
559 }
560
561 /************************************************************************
562  *                              SYSTEM CALLS                            *
563  ************************************************************************/
564
565 /*
566  * caps_sys_service(name, uid, gid, upcid, flags);
567  *
568  * Create an IPC service using the specified name, uid, gid, and flags.
569  * Either uid or gid can be -1, but not both.  The port identifier is
570  * returned.
571  *
572  * upcid can either be an upcall or a kqueue identifier (XXX)
573  *
574  * MPALMOSTSAFE
575  */
576 int
577 sys_caps_sys_service(struct caps_sys_service_args *uap)
578 {
579     struct ucred *cred = curthread->td_ucred;
580     char name[CAPS_MAXNAMELEN];
581     caps_kinfo_t caps;
582     size_t len;
583     int error;
584
585     if (caps_enabled == 0)
586         return(EOPNOTSUPP);
587     if ((error = copyinstr(uap->name, name, CAPS_MAXNAMELEN, &len)) != 0)
588         return(error);
589     if ((ssize_t)--len <= 0)
590         return(EINVAL);
591     get_mplock();
592
593     if ((error = caps_name_check(name, len)) == 0) {
594         caps = kern_caps_sys_service(name, uap->uid, uap->gid, cred,
595                                     uap->flags & CAPF_UFLAGS, &error);
596         if (caps)
597             uap->sysmsg_result = caps->ci_id;
598     }
599     rel_mplock();
600     return(error);
601 }
602
603 /*
604  * caps_sys_client(name, uid, gid, upcid, flags);
605  *
606  * Create an IPC client connected to the specified service.  Either uid or gid
607  * may be -1, indicating a wildcard, but not both.  The port identifier is
608  * returned.
609  *
610  * upcid can either be an upcall or a kqueue identifier (XXX)
611  *
612  * MPALMOSTSAFE
613  */
614 int
615 sys_caps_sys_client(struct caps_sys_client_args *uap)
616 {
617     struct ucred *cred = curthread->td_ucred;
618     char name[CAPS_MAXNAMELEN];
619     caps_kinfo_t caps;
620     size_t len;
621     int error;
622
623     if (caps_enabled == 0)
624         return(EOPNOTSUPP);
625     if ((error = copyinstr(uap->name, name, CAPS_MAXNAMELEN, &len)) != 0)
626         return(error);
627     if ((ssize_t)--len <= 0)
628         return(EINVAL);
629     get_mplock();
630
631     if ((error = caps_name_check(name, len)) == 0) {
632         caps = kern_caps_sys_client(name, uap->uid, uap->gid, cred,
633                                     uap->flags & CAPF_UFLAGS, &error);
634         if (caps)
635             uap->sysmsg_result = caps->ci_id;
636     }
637     rel_mplock();
638     return(error);
639 }
640
641 /*
642  * MPALMOSTSAFE
643  */
644 int
645 sys_caps_sys_close(struct caps_sys_close_args *uap)
646 {
647     struct thread *td = curthread;
648     caps_kinfo_t caps;
649     int error;
650
651     get_mplock();
652
653     if ((caps = caps_find_id(td, uap->portid)) != NULL) {
654             caps_term(caps, CAPKF_TDLIST|CAPKF_HLIST|CAPKF_FLUSH|CAPKF_RCAPS,
655                       NULL);
656             caps_drop(caps);
657             error = 0;
658     } else {
659             error = EINVAL;
660     }
661     rel_mplock();
662     return(error);
663 }
664
665 /*
666  * MPALMOSTSAFE
667  */
668 int
669 sys_caps_sys_setgen(struct caps_sys_setgen_args *uap)
670 {
671     struct thread *td = curthread;
672     caps_kinfo_t caps;
673     int error;
674
675     get_mplock();
676
677     if ((caps = caps_find_id(td, uap->portid)) != NULL) {
678         if (caps->ci_type == CAPT_FORKED) {
679             error = ENOTCONN;
680         } else {
681             caps->ci_gen = uap->gen;
682             error = 0;
683         }
684         caps_drop(caps);
685     } else {
686         error = EINVAL;
687     }
688     rel_mplock();
689     return(error);
690 }
691
692 /*
693  * MPALMOSTSAFE
694  */
695 int
696 sys_caps_sys_getgen(struct caps_sys_getgen_args *uap)
697 {
698     struct thread *td = curthread;
699     caps_kinfo_t caps;
700     int error;
701
702     get_mplock();
703
704     if ((caps = caps_find_id(td, uap->portid)) != NULL) {
705         if (caps->ci_type == CAPT_FORKED) {
706             error = ENOTCONN;
707         } else if (caps->ci_rcaps == NULL) {
708             error = EINVAL;
709         } else {
710             uap->sysmsg_result64 = caps->ci_rcaps->ci_gen;
711             error = 0;
712         }
713         caps_drop(caps);
714     } else {
715         error = EINVAL;
716     }
717     rel_mplock();
718     return(error);
719 }
720
721 /*
722  * caps_sys_put(portid, msg, msgsize)
723  *
724  * Send an opaque message of the specified size to the specified port.  This
725  * function may only be used with a client port.  The message id is returned.
726  *
727  * MPALMOSTSAFE
728  */
729 int
730 sys_caps_sys_put(struct caps_sys_put_args *uap)
731 {
732     struct thread *td = curthread;
733     caps_kinfo_t caps;
734     caps_kmsg_t msg;
735     int error;
736
737     if (uap->msgsize < 0)
738         return(EINVAL);
739     get_mplock();
740
741     if ((caps = caps_find_id(td, uap->portid)) == NULL) {
742         error = EINVAL;
743         goto done;
744     }
745     if (caps->ci_type == CAPT_FORKED) {
746         error = ENOTCONN;
747     } else if (caps->ci_rcaps == NULL) {
748         error = EINVAL;
749     } else if (caps->ci_cmsgcount > CAPS_MAXINPROG) {
750         /*
751          * If this client has queued a large number of messages return
752          * ENOBUFS.  The client must process some replies before it can
753          * send new messages.  The server can also throttle a client by
754          * holding its replies.  XXX allow a server to refuse messages from
755          * a client.
756          */
757         error = ENOBUFS;
758     } else {
759         msg = caps_alloc_msg(caps);
760         uap->sysmsg_offset = msg->km_msgid.c_id;
761
762         /*
763          * If the remote end is closed return ENOTCONN immediately, otherwise
764          * send it to the remote end.
765          *
766          * Note: since this is a new message, caps_load_ccr() returns a remote
767          * caps of NULL.
768          */
769         if (caps->ci_rcaps->ci_flags & CAPKF_CLOSED) {
770             error = ENOTCONN;
771             caps_free_msg(msg);
772         } else {
773             /*
774              * new message, load_ccr returns NULL. hold rcaps for put_msg
775              */
776             error = 0;
777             caps_load_ccr(caps, msg, td->td_lwp, uap->msg, uap->msgsize);
778             caps_hold(caps->ci_rcaps);
779             ++caps->ci_cmsgcount;
780             caps_put_msg(caps->ci_rcaps, msg, CAPMS_REQUEST); /* drops rcaps */
781         }
782     }
783     caps_drop(caps);
784 done:
785     rel_mplock();
786     return(error);
787 }
788
789 /*
790  * caps_sys_reply(portid, msg, msgsize, msgid)
791  *
792  * Reply to the message referenced by the specified msgid, supplying opaque
793  * data back to the originator.
794  *
795  * MPALMOSTSAFE
796  */
797 int
798 sys_caps_sys_reply(struct caps_sys_reply_args *uap)
799 {
800     struct thread *td = curthread;
801     caps_kinfo_t caps;
802     caps_kinfo_t rcaps;
803     caps_kmsg_t msg;
804     int error;
805
806     if (uap->msgsize < 0)
807         return(EINVAL);
808     get_mplock();
809
810     if ((caps = caps_find_id(td, uap->portid)) == NULL) {
811         error = EINVAL;
812         goto done;
813     }
814     if (caps->ci_type == CAPT_FORKED) {
815         /*
816          * The caps structure is just a fork placeholder, tell the caller
817          * that he has to reconnect.
818          */
819         error = ENOTCONN;
820     } else if ((msg = caps_find_msg(caps, uap->msgcid)) == NULL) {
821         /*
822          * Could not find message being replied to (other side might have
823          * gone away).
824          */
825         error = EINVAL;
826     } else if ((msg->km_flags & CAPKMF_ONUSERQ) == 0) {
827         /*
828          * Trying to reply to a non-replyable message
829          */
830         error = EINVAL;
831     } else {
832         /*
833          * If the remote end is closed requeue to ourselves for disposal.
834          * Otherwise send the reply to the other end (the other end will
835          * return a passive DISPOSE to us when it has eaten the data)
836          */
837         error = 0;
838         caps_dequeue_msg(caps, msg);
839         if (msg->km_mcaps->ci_flags & CAPKF_CLOSED) {
840             caps_drop(caps_load_ccr(caps, msg, td->td_lwp, NULL, 0));
841             caps_hold(caps);                    /* ref for message */
842             caps_put_msg(caps, msg, CAPMS_DISPOSE);
843         } else {
844             rcaps = caps_load_ccr(caps, msg, td->td_lwp, uap->msg, uap->msgsize);
845             caps_put_msg(rcaps, msg, CAPMS_REPLY);
846         }
847     }
848     caps_drop(caps);
849 done:
850     rel_mplock();
851     return(error);
852 }
853
854 /*
855  * caps_sys_get(portid, msg, maxsize, msgid, ccr)
856  *
857  * Retrieve the next ready message on the port, store its message id in
858  * uap->msgid and return the length of the message.  If the message is too
859  * large to fit the message id, length, and creds are still returned, but
860  * the message is not dequeued (the caller is expected to call again with
861  * a larger buffer or to reply the messageid if it does not want to handle
862  * the message).
863  *
864  * EWOULDBLOCK is returned if no messages are pending.  Note that 0-length
865  * messages are perfectly acceptable so 0 can be legitimately returned.
866  *
867  * MPALMOSTSAFE
868  */
869 int
870 sys_caps_sys_get(struct caps_sys_get_args *uap)
871 {
872     struct thread *td = curthread;
873     caps_kinfo_t caps;
874     caps_kmsg_t msg;
875     int error;
876
877     if (uap->maxsize < 0)
878         return(EINVAL);
879     get_mplock();
880
881     if ((caps = caps_find_id(td, uap->portid)) != NULL) {
882         if (caps->ci_type == CAPT_FORKED) {
883             error = ENOTCONN;
884         } else if ((msg = TAILQ_FIRST(&caps->ci_msgpendq)) == NULL) {
885             error = EWOULDBLOCK;
886         } else {
887             error = caps_process_msg(caps, msg, uap);
888         }
889         caps_drop(caps);
890     } else {
891         error = EINVAL;
892     }
893     rel_mplock();
894     return(error);
895 }
896
897 /*
898  * caps_sys_wait(portid, msg, maxsize, msgid, ccr)
899  *
900  * Retrieve the next ready message on the port, store its message id in
901  * uap->msgid and return the length of the message.  If the message is too
902  * large to fit the message id, length, and creds are still returned, but
903  * the message is not dequeued (the caller is expected to call again with
904  * a larger buffer or to reply the messageid if it does not want to handle
905  * the message).
906  *
907  * This function blocks until interrupted or a message is received.
908  * Note that 0-length messages are perfectly acceptable so 0 can be
909  * legitimately returned.
910  *
911  * MPALMOSTSAFE
912  */
913 int
914 sys_caps_sys_wait(struct caps_sys_wait_args *uap)
915 {
916     struct thread *td = curthread;
917     caps_kinfo_t caps;
918     caps_kmsg_t msg;
919     int error;
920
921     if (uap->maxsize < 0)
922         return(EINVAL);
923     get_mplock();
924
925     if ((caps = caps_find_id(td, uap->portid)) != NULL) {
926         if (caps->ci_type == CAPT_FORKED) {
927             error = ENOTCONN;
928         } else {
929             error = 0;
930             while ((msg = TAILQ_FIRST(&caps->ci_msgpendq)) == NULL) {
931                 if ((error = tsleep(caps, PCATCH, "caps", 0)) != 0)
932                     break;
933             }
934             if (error == 0) {
935                 error = caps_process_msg(caps, msg,
936                                     (struct caps_sys_get_args *)uap);
937             }
938         }
939         caps_drop(caps);
940     } else {
941         error = EINVAL;
942     }
943     rel_mplock();
944     return(error);
945 }
946
947 static int
948 caps_process_msg(caps_kinfo_t caps, caps_kmsg_t msg,
949                  struct caps_sys_get_args *uap)
950 {
951     struct thread *td = curthread;
952     int error = 0;
953     int msgsize;
954     caps_kinfo_t rcaps;
955
956     msg->km_flags |= CAPKMF_PEEKED;
957     msgsize = msg->km_xio.xio_bytes;
958     if (msgsize <= uap->maxsize)
959         caps_dequeue_msg(caps, msg);
960
961     if (msg->km_xio.xio_bytes != 0) {
962         error = xio_copy_xtou(&msg->km_xio, 0, uap->msg, 
963                             min(msg->km_xio.xio_bytes, uap->maxsize));
964         if (error) {
965             if (msg->km_mcaps->ci_td && msg->km_mcaps->ci_td->td_proc) {
966                 kprintf("xio_copy_xtou: error %d from proc %d\n", 
967                         error, msg->km_mcaps->ci_td->td_proc->p_pid);
968             }
969             if (msgsize > uap->maxsize)
970                 caps_dequeue_msg(caps, msg);
971             msgsize = 0;
972             error = 0;
973         }
974     }
975
976     if (uap->msgid)
977         error = copyout(&msg->km_msgid, uap->msgid, sizeof(msg->km_msgid));
978     if (uap->ccr)
979         error = copyout(&msg->km_ccr, uap->ccr, sizeof(msg->km_ccr));
980     if (error == 0)
981         uap->sysmsg_result = msgsize;
982
983     /*
984      * If the message was dequeued we must deal with it.
985      */
986     if (msgsize <= uap->maxsize) {
987         switch(msg->km_state) {
988         case CAPMS_REQUEST:
989         case CAPMS_REQUEST_RETRY:
990             TAILQ_INSERT_TAIL(&caps->ci_msguserq, msg, km_node);
991             msg->km_flags |= CAPKMF_ONUSERQ;
992             break;
993         case CAPMS_REPLY:
994         case CAPMS_REPLY_RETRY:
995             --caps->ci_cmsgcount;
996             rcaps = caps_load_ccr(caps, msg, td->td_lwp, NULL, 0);
997             if (caps == rcaps || (rcaps->ci_flags & CAPKF_CLOSED)) {
998                 /* degenerate disposal case */
999                 caps_free_msg(msg);
1000                 caps_drop(rcaps);
1001             } else {
1002                 caps_put_msg(rcaps, msg, CAPMS_DISPOSE);
1003             }
1004             break;
1005         case CAPMS_DISPOSE:
1006             caps_free_msg(msg);
1007             break;
1008         }
1009     }
1010     return(error);
1011 }
1012
1013 /*
1014  * caps_sys_abort(portid, msgcid, flags)
1015  *
1016  *      Abort a previously sent message.  You must still wait for the message
1017  *      to be returned after sending the abort request.  This function will
1018  *      return the appropriate CAPS_ABORT_* code depending on what it had
1019  *      to do.
1020  *
1021  * MPALMOSTSAFE
1022  */
1023 int
1024 sys_caps_sys_abort(struct caps_sys_abort_args *uap)
1025 {
1026     uap->sysmsg_result = CAPS_ABORT_NOTIMPL;
1027     return(0);
1028 }
1029
1030 /*
1031  * KERNEL SYSCALL SEPARATION SUPPORT FUNCTIONS
1032  */
1033
1034 static
1035 caps_kinfo_t
1036 kern_caps_sys_service(const char *name, uid_t uid, gid_t gid,
1037                         struct ucred *cred, int flags, int *error)
1038 {
1039     struct thread *td = curthread;
1040     caps_kinfo_t caps;
1041     int len;
1042
1043     len = strlen(name);
1044
1045     /*
1046      * Make sure we can use the uid and gid
1047      */
1048     if (cred) {
1049         if (cred->cr_uid != 0 && uid != (uid_t)-1 && cred->cr_uid != uid) {
1050             *error = EPERM;
1051             return(NULL);
1052         }
1053         if (cred->cr_uid != 0 && gid != (gid_t)-1 && !groupmember(gid, cred)) {
1054             *error = EPERM;
1055             return(NULL);
1056         }
1057     }
1058
1059     /*
1060      * Handle CAPF_EXCL
1061      */
1062     if (flags & CAPF_EXCL) {
1063         if ((caps = caps_find(name, strlen(name), uid, gid)) != NULL) {
1064             caps_drop(caps);
1065             *error = EEXIST;
1066             return(NULL);
1067         }
1068     }
1069
1070     /*
1071      * Create the service
1072      */
1073     caps = caps_alloc(td, name, len,
1074                         uid, gid, flags & CAPF_UFLAGS, CAPT_SERVICE);
1075     wakeup(&caps_waitsvc);
1076     return(caps);
1077 }
1078
1079 static
1080 caps_kinfo_t
1081 kern_caps_sys_client(const char *name, uid_t uid, gid_t gid,
1082                         struct ucred *cred, int flags, int *error)
1083 {
1084     struct thread *td = curthread;
1085     caps_kinfo_t caps, rcaps;
1086     int len;
1087
1088     len = strlen(name);
1089
1090     /*
1091      * Locate the CAPS service (rcaps ref is for caps->ci_rcaps)
1092      */
1093 again:
1094     if ((rcaps = caps_find(name, len, uid, gid)) == NULL) {
1095         if (flags & CAPF_WAITSVC) {
1096             char cbuf[32];
1097             ksnprintf(cbuf, sizeof(cbuf), "C%s", name);
1098             *error = tsleep(&caps_waitsvc, PCATCH, cbuf, 0);
1099             if (*error == 0)
1100                 goto again;
1101         } else {
1102             *error = ENOENT;
1103         }
1104         return(NULL);
1105     }
1106
1107     /*
1108      * Check permissions
1109      */
1110     if (cred) {
1111         *error = EACCES;
1112         if ((flags & CAPF_USER) && (rcaps->ci_flags & CAPF_USER)) {
1113             if (rcaps->ci_uid != (uid_t)-1 && rcaps->ci_uid == cred->cr_uid)
1114                 *error = 0;
1115         }
1116         if ((flags & CAPF_GROUP) && (rcaps->ci_flags & CAPF_GROUP)) {
1117             if (rcaps->ci_gid != (gid_t)-1 && groupmember(rcaps->ci_gid, cred))
1118                 *error = 0;
1119         }
1120         if ((flags & CAPF_WORLD) && (rcaps->ci_flags & CAPF_WORLD)) {
1121             *error = 0;
1122         }
1123         if (*error) {
1124             caps_drop(rcaps);
1125             return(NULL);
1126         }
1127     } else {
1128         *error = 0;
1129     }
1130
1131     /*
1132      * Allocate the client side and connect to the server
1133      */
1134     caps = caps_alloc(td, name, len,
1135                         uid, gid, flags & CAPF_UFLAGS, CAPT_CLIENT);
1136     caps->ci_rcaps = rcaps;
1137     caps->ci_flags |= CAPKF_RCAPS;
1138     return(caps);
1139 }
1140