Additional CAPS IPC work. Add additional system calls to allow a CAPS
[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.2 2004/03/06 22:14:09 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 int caps_name_check(const char *name, int len);
64 static caps_kinfo_t caps_free_msg_mcaps(caps_kmsg_t msg);
65 static caps_kinfo_t kern_caps_sys_service(const char *name, uid_t uid, 
66                         gid_t gid, struct ucred *cred, 
67                         int flags, int *error);
68 static caps_kinfo_t kern_caps_sys_client(const char *name, uid_t uid,
69                         gid_t gid, struct ucred *cred, int flags, int *error);
70
71 #define CAPS_HSIZE      64
72 #define CAPS_HMASK      (CAPS_HSIZE - 1)
73
74 static caps_kinfo_t     caps_hash_ary[CAPS_HSIZE];
75 static int caps_waitsvc;
76
77 MALLOC_DEFINE(M_CAPS, "caps", "caps IPC messaging");
78
79 static int caps_enabled;
80 SYSCTL_INT(_kern, OID_AUTO, caps_enabled,
81         CTLFLAG_RW, &caps_enabled, 0, "Enable CAPS");
82
83 /************************************************************************
84  *                      INLINE SUPPORT FUNCTIONS                        *
85  ************************************************************************/
86
87 static __inline
88 struct caps_kinfo **
89 caps_hash(const char *name, int len)
90 {
91     int hv = 0x7123F4B3;
92
93     while (--len >= 0)
94         hv = (hv << 5) ^ name[len] ^ (hv >> 23);
95     return(&caps_hash_ary[(hv ^ (hv >> 16)) & CAPS_HMASK]);
96 }
97
98 static __inline
99 void
100 caps_hold(caps_kinfo_t caps)
101 {
102     ++caps->ci_refs;
103 }
104
105 static __inline
106 void
107 caps_drop(caps_kinfo_t caps)
108 {
109     if (--caps->ci_refs == 0)
110         caps_free(caps);
111 }
112
113 /************************************************************************
114  *                      STATIC SUPPORT FUNCTIONS                        *
115  ************************************************************************/
116
117 static
118 caps_kinfo_t
119 caps_find(const char *name, int len, uid_t uid, gid_t gid)
120 {
121     caps_kinfo_t caps;
122     struct caps_kinfo **chash;
123
124     chash = caps_hash(name, len);
125     for (caps = *chash; caps; caps = caps->ci_hnext) {
126         if ((uid == (uid_t)-1 || uid == caps->ci_uid) &&
127             (gid == (gid_t)-1 || gid == caps->ci_gid) &&
128             len == caps->ci_namelen &&
129             bcmp(name, caps->ci_name, len) == 0
130         ) {
131             caps_hold(caps);
132             break;
133         }
134     }
135     return(caps);
136 }
137
138 static
139 caps_kinfo_t
140 caps_find_id(thread_t td, int id)
141 {
142    caps_kinfo_t caps;
143
144    for (caps = td->td_caps; caps; caps = caps->ci_tdnext) {
145         if (caps->ci_id == id) {
146             caps_hold(caps);
147             break;
148         }
149    }
150    return(caps);
151 }
152
153 static
154 caps_kinfo_t
155 caps_alloc(thread_t td, const char *name, int len, uid_t uid, gid_t gid, 
156             int flags, caps_type_t type)
157 {
158     struct caps_kinfo **chash;
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(td, 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  * Validate the service name
329  */
330 static int
331 caps_name_check(const char *name, int len)
332 {
333     int i;
334     char c;
335
336     for (i = len - 1; i >= 0; --i) {
337         c = name[i];
338         if (c >= '0' && c <= '9')
339             continue;
340         if (c >= 'a' && c <= 'z')
341             continue;
342         if (c >= 'A' && c <= 'Z')
343             continue;
344         if (c == '_' || c == '.')
345             continue;
346         return(EINVAL);
347     }
348     return(0);
349 }
350
351 /*
352  * caps_term()
353  *
354  * Terminate portions of a caps info structure.  This is used to close
355  * an end-point or to flush particular messages on an end-point.
356  *
357  * This function should not be called with CAPKF_TDLIST unless the caller
358  * has an additional hold on the caps structure.
359  */
360 static void
361 caps_term(caps_kinfo_t caps, int flags, caps_kinfo_t cflush)
362 {
363     struct caps_kinfo **scan;
364     caps_kmsg_t msg;
365
366     if (flags & CAPKF_TDLIST)
367         caps->ci_flags |= CAPKF_CLOSED;
368
369     if (flags & CAPKF_FLUSH) {
370         int mflags;
371         struct caps_kmsg_queue tmpuserq;
372         struct caps_kmsg_queue tmppendq;
373         caps_kinfo_t rcaps;
374
375         TAILQ_INIT(&tmpuserq);
376         TAILQ_INIT(&tmppendq);
377
378         while ((msg = TAILQ_FIRST(&caps->ci_msgpendq)) != NULL ||
379                (msg = TAILQ_FIRST(&caps->ci_msguserq)) != NULL
380         ) {
381             mflags = msg->km_flags & (CAPKMF_ONUSERQ|CAPKMF_ONPENDQ);
382             caps_dequeue_msg(caps, msg);
383
384             if (cflush && msg->km_mcaps != cflush) {
385                 if (mflags & CAPKMF_ONUSERQ)
386                     TAILQ_INSERT_TAIL(&tmpuserq, msg, km_node);
387                 else
388                     TAILQ_INSERT_TAIL(&tmppendq, msg, km_node);
389             } else {
390                 /*
391                  * Dispose of the message.  If the received message is a
392                  * request we must reply it.  If the received message is
393                  * a reply we must return it for disposal.  If the
394                  * received message is a disposal request we simply free it.
395                  */
396                 switch(msg->km_state) {
397                 case CAPMS_REQUEST:
398                 case CAPMS_REQUEST_RETRY:
399                     rcaps = caps_load_ccr(caps, msg, curproc, NULL, 0);
400                     if (rcaps->ci_flags & CAPKF_CLOSED) {
401                         /*
402                          * can't reply, if we never read the message (its on
403                          * the pending queue), or if we are closed ourselves,
404                          * we can just free the message.  Otherwise we have
405                          * to send ourselves a disposal request (multi-threaded
406                          * services have to deal with disposal requests for
407                          * messages that might be in progress).
408                          */
409                         if ((caps->ci_flags & CAPKF_CLOSED) ||
410                             (mflags & CAPKMF_ONPENDQ)
411                         ) {
412                             caps_free_msg(msg);
413                             caps_drop(rcaps);
414                         } else {
415                             caps_drop(rcaps);
416                             caps_hold(caps);
417                             caps_put_msg(caps, msg, CAPMS_DISPOSE);
418                         }
419                     } else {
420                         /*
421                          * auto-reply to the originator.
422                          */
423                         caps_put_msg(rcaps, msg, CAPMS_REPLY);
424                     }
425                     break;
426                 case CAPMS_REPLY:
427                 case CAPMS_REPLY_RETRY:
428                     rcaps = caps_load_ccr(caps, msg, curproc, NULL, 0);
429                     if (caps == rcaps || (rcaps->ci_flags & CAPKF_CLOSED)) {
430                         caps_free_msg(msg);     /* degenerate disposal case */
431                         caps_drop(rcaps);
432                     } else {
433                         caps_put_msg(rcaps, msg, CAPMS_DISPOSE);
434                     }
435                     break;
436                 case CAPMS_DISPOSE:
437                     caps_free_msg(msg);
438                     break;
439                 }
440             }
441         }
442         while ((msg = TAILQ_FIRST(&tmpuserq)) != NULL) {
443             TAILQ_REMOVE(&tmpuserq, msg, km_node);
444             TAILQ_INSERT_TAIL(&caps->ci_msguserq, msg, km_node);
445             msg->km_flags |= CAPKMF_ONUSERQ;
446         }
447         while ((msg = TAILQ_FIRST(&tmppendq)) != NULL) {
448             TAILQ_REMOVE(&tmppendq, msg, km_node);
449             TAILQ_INSERT_TAIL(&caps->ci_msgpendq, msg, km_node);
450             msg->km_flags |= CAPKMF_ONPENDQ;
451         }
452     }
453     if ((flags & CAPKF_HLIST) && (caps->ci_flags & CAPKF_HLIST)) {
454         for (scan = caps_hash(caps->ci_name, caps->ci_namelen);
455             *scan != caps;
456             scan = &(*scan)->ci_hnext
457         ) {
458             KKASSERT(*scan != NULL);
459         }
460         *scan = caps->ci_hnext;
461         caps->ci_hnext = (void *)-1;
462         caps->ci_flags &= ~CAPKF_HLIST;
463     }
464     if ((flags & CAPKF_TDLIST) && (caps->ci_flags & CAPKF_TDLIST)) {
465         while (caps->ci_mrefs) {
466             caps->ci_flags |= CAPKF_MWAIT;
467             tsleep(caps, 0, "cexit", 0);
468         }
469         for (scan = &caps->ci_td->td_caps;
470             *scan != caps;
471             scan = &(*scan)->ci_tdnext
472         ) {
473             KKASSERT(*scan != NULL);
474         }
475         *scan = caps->ci_tdnext;
476         caps->ci_flags &= ~CAPKF_TDLIST;
477         caps->ci_tdnext = (void *)-1;
478         caps->ci_td = NULL;
479         caps_drop(caps);
480     }
481     if ((flags & CAPKF_RCAPS) && (caps->ci_flags & CAPKF_RCAPS)) {
482         caps_kinfo_t ctmp;
483
484         caps->ci_flags &= ~CAPKF_RCAPS;
485         if ((ctmp = caps->ci_rcaps)) {
486             caps->ci_rcaps = NULL;
487             caps_term(ctmp, CAPKF_FLUSH, caps);
488             caps_drop(ctmp);
489         }
490     }
491 }
492
493 static void
494 caps_free(caps_kinfo_t caps)
495 {
496     KKASSERT(TAILQ_EMPTY(&caps->ci_msgpendq));
497     KKASSERT(TAILQ_EMPTY(&caps->ci_msguserq));
498     KKASSERT((caps->ci_flags & (CAPKF_HLIST|CAPKF_TDLIST)) == 0);
499     free(caps, M_CAPS);
500 }
501
502 /************************************************************************
503  *                      PROCESS SUPPORT FUNCTIONS                       *
504  ************************************************************************/
505
506 /*
507  * Create dummy entries in p2 so we can return the appropriate
508  * error code.  Robust userland code will check the error for a
509  * forked condition and reforge the connection.
510  */
511 void
512 caps_fork(struct proc *p1, struct proc *p2, int flags)
513 {
514     caps_kinfo_t caps1;
515     caps_kinfo_t caps2;
516     thread_t td1;
517     thread_t td2;
518
519     td1 = p1->p_thread;
520     td2 = p2->p_thread;
521
522     /*
523      * Create dummy entries with the same id's as the originals.  Note
524      * that service entries are not re-added to the hash table. The
525      * dummy entries return an ENOTCONN error allowing userland code to
526      * detect that a fork occured.  Userland must reconnect to the service.
527      */
528     for (caps1 = td1->td_caps; caps1; caps1 = caps1->ci_tdnext) {
529         if (caps1->ci_flags & CAPF_NOFORK)
530                 continue;
531         caps2 = caps_alloc(td2,
532                         caps1->ci_name, caps1->ci_namelen,
533                         caps1->ci_uid, caps1->ci_gid,
534                         caps1->ci_flags & CAPF_UFLAGS, CAPT_FORKED);
535         caps2->ci_id = caps1->ci_id;
536     }
537
538     /*
539      * Reverse the list order to maintain highest-id-first
540      */
541     caps2 = td2->td_caps;
542     td2->td_caps = NULL;
543     while (caps2) {
544         caps1 = caps2->ci_tdnext;
545         caps2->ci_tdnext = td2->td_caps;
546         td2->td_caps = caps2;
547         caps2 = caps1;
548     }
549 }
550
551 void
552 caps_exit(struct thread *td)
553 {
554     caps_kinfo_t caps;
555
556     while ((caps = td->td_caps) != NULL) {
557         caps_hold(caps);
558         caps_term(caps, CAPKF_TDLIST|CAPKF_HLIST|CAPKF_FLUSH|CAPKF_RCAPS, NULL);
559         caps_drop(caps);
560     }
561 }
562
563 /************************************************************************
564  *                              SYSTEM CALLS                            *
565  ************************************************************************/
566
567 /*
568  * caps_sys_service(name, uid, gid, upcid, flags);
569  *
570  * Create an IPC service using the specified name, uid, gid, and flags.
571  * Either uid or gid can be -1, but not both.  The port identifier is
572  * returned.
573  *
574  * upcid can either be an upcall or a kqueue identifier (XXX)
575  */
576 int
577 caps_sys_service(struct caps_sys_service_args *uap)
578 {
579     struct ucred *cred = curproc->p_ucred;
580     char name[CAPS_MAXNAMELEN];
581     caps_kinfo_t caps;
582     int 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 (--len <= 0)
590         return(EINVAL);
591     if ((error = caps_name_check(name, len)) != 0)
592         return(error);
593
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     return(error);
599 }
600
601 /*
602  * caps_sys_client(name, uid, gid, upcid, flags);
603  *
604  * Create an IPC client connected to the specified service.  Either uid or gid
605  * may be -1, indicating a wildcard, but not both.  The port identifier is
606  * returned.
607  *
608  * upcid can either be an upcall or a kqueue identifier (XXX)
609  */
610 int
611 caps_sys_client(struct caps_sys_client_args *uap)
612 {
613     struct ucred *cred = curproc->p_ucred;
614     char name[CAPS_MAXNAMELEN];
615     caps_kinfo_t caps;
616     int len;
617     int error;
618
619     if (caps_enabled == 0)
620         return(EOPNOTSUPP);
621     if ((error = copyinstr(uap->name, name, CAPS_MAXNAMELEN, &len)) != 0)
622         return(error);
623     if (--len <= 0)
624         return(EINVAL);
625     if ((error = caps_name_check(name, len)) != 0)
626         return(error);
627
628     caps = kern_caps_sys_client(name, uap->uid, uap->gid, cred,
629                                 uap->flags & CAPF_UFLAGS, &error);
630     if (caps)
631         uap->sysmsg_result = caps->ci_id;
632     return(error);
633 }
634
635 int
636 caps_sys_close(struct caps_sys_close_args *uap)
637 {
638     caps_kinfo_t caps;
639
640     if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
641         return(EINVAL);
642     caps_term(caps, CAPKF_TDLIST|CAPKF_HLIST|CAPKF_FLUSH|CAPKF_RCAPS, NULL);
643     caps_drop(caps);
644     return(0);
645 }
646
647 int
648 caps_sys_setgen(struct caps_sys_setgen_args *uap)
649 {
650     caps_kinfo_t caps;
651
652     if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
653         return(EINVAL);
654     if (caps->ci_type == CAPT_FORKED)
655         return(ENOTCONN);
656     caps->ci_gen = uap->gen;
657     return(0);
658 }
659
660 int
661 caps_sys_getgen(struct caps_sys_getgen_args *uap)
662 {
663     caps_kinfo_t caps;
664
665     if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
666         return(EINVAL);
667     if (caps->ci_type == CAPT_FORKED)
668         return(ENOTCONN);
669     if (caps->ci_rcaps == NULL)
670         return(EINVAL);
671     uap->sysmsg_result64 = caps->ci_rcaps->ci_gen;
672     return(0);
673 }
674
675 /*
676  * caps_sys_put(portid, msg, msgsize)
677  *
678  * Send an opaque message of the specified size to the specified port.  This
679  * function may only be used with a client port.  The message id is returned.
680  */
681 int
682 caps_sys_put(struct caps_sys_put_args *uap)
683 {
684     caps_kinfo_t caps;
685     caps_kmsg_t msg;
686     struct proc *p = curproc;
687     int error;
688
689     if (uap->msgsize < 0)
690         return(EINVAL);
691     if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
692         return(EINVAL);
693     if (caps->ci_type == CAPT_FORKED)
694         return(ENOTCONN);
695     if (caps->ci_rcaps == NULL) {
696         caps_drop(caps);
697         return(EINVAL);
698     }
699
700     /*
701      * If this client has queued a large number of messages return
702      * ENOBUFS.  The client must process some replies before it can
703      * send new messages.  The server can also throttle a client by
704      * holding its replies.  XXX allow a server to refuse messages from
705      * a client.
706      */
707     if (caps->ci_cmsgcount > CAPS_MAXINPROG) {
708         caps_drop(caps);
709         return(ENOBUFS);
710     }
711     msg = caps_alloc_msg(caps);
712     uap->sysmsg_offset = msg->km_msgid.c_id;
713
714     /*
715      * If the remote end is closed return ENOTCONN immediately, otherwise
716      * send it to the remote end.
717      *
718      * Note: since this is a new message, caps_load_ccr() returns a remote
719      * caps of NULL.
720      */
721     error = 0;
722     if (caps->ci_rcaps->ci_flags & CAPKF_CLOSED) {
723         error = ENOTCONN;
724         caps_free_msg(msg);
725 #if 0
726         caps_load_ccr(caps, msg, p, NULL, 0);   /* returns NULL */
727         caps_hold(caps);
728         caps_put_msg(caps, msg, CAPMS_REPLY);   /* drops caps */
729 #endif
730     } else {
731         caps_load_ccr(caps, msg, p, uap->msg, uap->msgsize); /* returns NULL */
732         caps_hold(caps->ci_rcaps);                        /* need ref */
733         ++caps->ci_cmsgcount;
734         caps_put_msg(caps->ci_rcaps, msg, CAPMS_REQUEST); /* drops rcaps */
735     }
736     caps_drop(caps);
737     return(error);
738 }
739
740 /*
741  * caps_sys_reply(portid, msg, msgsize, msgid)
742  *
743  * Reply to the message referenced by the specified msgid, supplying opaque
744  * data back to the originator.
745  */
746 int
747 caps_sys_reply(struct caps_sys_reply_args *uap)
748 {
749     caps_kinfo_t caps;
750     caps_kinfo_t rcaps;
751     caps_kmsg_t msg;
752     struct proc *p;
753
754     if (uap->msgsize < 0)
755         return(EINVAL);
756     if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
757         return(EINVAL);
758     if (caps->ci_type == CAPT_FORKED)
759         return(ENOTCONN);
760
761     /*
762      * Can't find message to reply to
763      */
764     if ((msg = caps_find_msg(caps, uap->msgcid)) == NULL) {
765         caps_drop(caps);
766         return(EINVAL);
767     }
768
769     /*
770      * Trying to reply to a non-replyable message
771      */
772     if ((msg->km_flags & CAPKMF_ONUSERQ) == 0) {
773         caps_drop(caps);
774         return(EINVAL);
775     }
776
777     /*
778      * If the remote end is closed requeue to ourselves for disposal.
779      * Otherwise send the reply to the other end (the other end will
780      * return a passive DISPOSE to us when it has eaten the data)
781      */
782     caps_dequeue_msg(caps, msg);
783     p = curproc;
784     if (msg->km_mcaps->ci_flags & CAPKF_CLOSED) {
785         caps_drop(caps_load_ccr(caps, msg, p, NULL, 0));
786         caps_hold(caps);
787         caps_put_msg(caps, msg, CAPMS_DISPOSE); /* drops caps */
788     } else {
789         rcaps = caps_load_ccr(caps, msg, p, uap->msg, uap->msgsize);
790         caps_put_msg(rcaps, msg, CAPMS_REPLY);
791     }
792     caps_drop(caps);
793     return(0);
794 }
795
796 /*
797  * caps_sys_get(portid, msg, maxsize, msgid, ccr)
798  *
799  * Retrieve the next ready message on the port, store its message id in
800  * uap->msgid and return the length of the message.  If the message is too
801  * large to fit the message id, length, and creds are still returned, but
802  * the message is not dequeued (the caller is expected to call again with
803  * a larger buffer or to reply the messageid if it does not want to handle
804  * the message).
805  *
806  * EWOULDBLOCK is returned if no messages are pending.  Note that 0-length
807  * messages are perfectly acceptable so 0 can be legitimately returned.
808  */
809 int
810 caps_sys_get(struct caps_sys_get_args *uap)
811 {
812     caps_kinfo_t caps;
813     caps_kmsg_t msg;
814
815     if (uap->maxsize < 0)
816         return(EINVAL);
817     if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
818         return(EINVAL);
819     if (caps->ci_type == CAPT_FORKED)
820         return(ENOTCONN);
821     if ((msg = TAILQ_FIRST(&caps->ci_msgpendq)) == NULL) {
822         caps_drop(caps);
823         return(EWOULDBLOCK);
824     }
825     return(caps_process_msg(caps, msg, uap));
826 }
827
828 /*
829  * caps_sys_wait(portid, msg, maxsize, msgid, ccr)
830  *
831  * Retrieve the next ready message on the port, store its message id in
832  * uap->msgid and return the length of the message.  If the message is too
833  * large to fit the message id, length, and creds are still returned, but
834  * the message is not dequeued (the caller is expected to call again with
835  * a larger buffer or to reply the messageid if it does not want to handle
836  * the message).
837  *
838  * This function blocks until interrupted or a message is received.
839  * Note that 0-length messages are perfectly acceptable so 0 can be
840  * legitimately returned.
841  */
842 int
843 caps_sys_wait(struct caps_sys_wait_args *uap)
844 {
845     caps_kinfo_t caps;
846     caps_kmsg_t msg;
847     int error;
848
849     if (uap->maxsize < 0)
850         return(EINVAL);
851     if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
852         return(EINVAL);
853     if (caps->ci_type == CAPT_FORKED)
854         return(ENOTCONN);
855     while ((msg = TAILQ_FIRST(&caps->ci_msgpendq)) == NULL) {
856         if ((error = tsleep(caps, PCATCH, "caps", 0)) != 0) {
857             caps_drop(caps);
858             return(error);
859         }
860     }
861     return(caps_process_msg(caps, msg, (struct caps_sys_get_args *)uap));
862 }
863
864 static int
865 caps_process_msg(caps_kinfo_t caps, caps_kmsg_t msg, struct caps_sys_get_args *uap)
866 {
867     int error = 0;
868     int msgsize;
869     caps_kinfo_t rcaps;
870
871     msg->km_flags |= CAPKMF_PEEKED;
872     msgsize = msg->km_umsg_size;
873     if (msgsize <= uap->maxsize)
874         caps_dequeue_msg(caps, msg);
875
876     if (msg->km_umsg_size != 0) {
877         struct proc *rp = msg->km_mcaps->ci_td->td_proc;
878         KKASSERT(rp != NULL);
879         error = vmspace_copy(rp->p_vmspace, (vm_offset_t)msg->km_umsg,
880                             curproc->p_vmspace, (vm_offset_t)uap->msg, 
881                             min(msgsize, uap->maxsize), uap->maxsize);
882         if (error) {
883             printf("vmspace_copy: error %d from proc %d\n", error, rp->p_pid);
884             if (msgsize > uap->maxsize)
885                 caps_dequeue_msg(caps, msg);
886             msgsize = 0;
887             error = 0;
888         }
889     }
890
891     if (uap->msgid)
892         error = copyout(&msg->km_msgid, uap->msgid, sizeof(msg->km_msgid));
893     if (uap->ccr)
894         error = copyout(&msg->km_ccr, uap->ccr, sizeof(msg->km_ccr));
895     if (error == 0)
896         uap->sysmsg_result = msgsize;
897
898     /*
899      * If the message was dequeued we must deal with it.
900      */
901     if (msgsize <= uap->maxsize) {
902         switch(msg->km_state) {
903         case CAPMS_REQUEST:
904         case CAPMS_REQUEST_RETRY:
905             TAILQ_INSERT_TAIL(&caps->ci_msguserq, msg, km_node);
906             msg->km_flags |= CAPKMF_ONUSERQ;
907             break;
908         case CAPMS_REPLY:
909         case CAPMS_REPLY_RETRY:
910             --caps->ci_cmsgcount;
911             rcaps = caps_load_ccr(caps, msg, curproc, NULL, 0);
912             if (caps == rcaps || (rcaps->ci_flags & CAPKF_CLOSED)) {
913                 /* degenerate disposal case */
914                 caps_free_msg(msg);
915                 caps_drop(rcaps);
916             } else {
917                 caps_put_msg(rcaps, msg, CAPMS_DISPOSE);
918             }
919             break;
920         case CAPMS_DISPOSE:
921             caps_free_msg(msg);
922             break;
923         }
924     }
925     caps_drop(caps);
926     return(error);
927 }
928
929 /*
930  * caps_sys_abort(portid, msgcid, flags)
931  *
932  *      Abort a previously sent message.  You must still wait for the message
933  *      to be returned after sending the abort request.  This function will
934  *      return the appropriate CAPS_ABORT_* code depending on what it had
935  *      to do.
936  */
937 int
938 caps_sys_abort(struct caps_sys_abort_args *uap)
939 {
940     uap->sysmsg_result = CAPS_ABORT_NOTIMPL;
941     return(0);
942 }
943
944 /*
945  * KERNEL SYSCALL SEPARATION SUPPORT FUNCTIONS
946  */
947
948 static
949 caps_kinfo_t
950 kern_caps_sys_service(const char *name, uid_t uid, gid_t gid,
951                         struct ucred *cred, int flags, int *error)
952 {
953     caps_kinfo_t caps;
954     int len;
955
956     len = strlen(name);
957
958     /*
959      * Make sure we can use the uid and gid
960      */
961     if (cred) {
962         if (cred->cr_uid != 0 && uid != (uid_t)-1 && cred->cr_uid != uid) {
963             *error = EPERM;
964             return(NULL);
965         }
966         if (cred->cr_uid != 0 && gid != (gid_t)-1 && !groupmember(gid, cred)) {
967             *error = EPERM;
968             return(NULL);
969         }
970     }
971
972     /*
973      * Handle CAPF_EXCL
974      */
975     if (flags & CAPF_EXCL) {
976         if ((caps = caps_find(name, strlen(name), uid, gid)) != NULL) {
977             caps_drop(caps);
978             *error = EEXIST;
979             return(NULL);
980         }
981     }
982
983     /*
984      * Create the service
985      */
986     caps = caps_alloc(curthread, name, len, 
987                         uid, gid, flags & CAPF_UFLAGS, CAPT_SERVICE);
988     wakeup(&caps_waitsvc);
989     return(caps);
990 }
991
992 static
993 caps_kinfo_t
994 kern_caps_sys_client(const char *name, uid_t uid, gid_t gid,
995                         struct ucred *cred, int flags, int *error)
996 {
997     caps_kinfo_t caps, rcaps;
998     int len;
999
1000     len = strlen(name);
1001
1002     /*
1003      * Locate the CAPS service (rcaps ref is for caps->ci_rcaps)
1004      */
1005 again:
1006     if ((rcaps = caps_find(name, len, uid, gid)) == NULL) {
1007         if (flags & CAPF_WAITSVC) {
1008             char cbuf[32];
1009             snprintf(cbuf, sizeof(cbuf), "C%s", name);
1010             *error = tsleep(&caps_waitsvc, PCATCH, cbuf, 0);
1011             if (*error == 0)
1012                 goto again;
1013         } else {
1014             *error = ENOENT;
1015         }
1016         return(NULL);
1017     }
1018
1019     /*
1020      * Check permissions
1021      */
1022     if (cred) {
1023         *error = EACCES;
1024         if ((flags & CAPF_USER) && (rcaps->ci_flags & CAPF_USER)) {
1025             if (rcaps->ci_uid != (uid_t)-1 && rcaps->ci_uid == cred->cr_uid)
1026                 *error = 0;
1027         }
1028         if ((flags & CAPF_GROUP) && (rcaps->ci_flags & CAPF_GROUP)) {
1029             if (rcaps->ci_gid != (gid_t)-1 && groupmember(rcaps->ci_gid, cred))
1030                 *error = 0;
1031         }
1032         if ((flags & CAPF_WORLD) && (rcaps->ci_flags & CAPF_WORLD)) {
1033             *error = 0;
1034         }
1035         if (*error) {
1036             caps_drop(rcaps);
1037             return(NULL);
1038         }
1039     } else {
1040         *error = 0;
1041     }
1042
1043     /*
1044      * Allocate the client side and connect to the server
1045      */
1046     caps = caps_alloc(curthread, name, len, 
1047                         uid, gid, flags & CAPF_UFLAGS, CAPT_CLIENT);
1048     caps->ci_rcaps = rcaps;
1049     caps->ci_flags |= CAPKF_RCAPS;
1050     return(caps);
1051 }
1052