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