Change CAPS over to use XIO instead of the vmspace_copy() junk it was using
[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.3 2004/03/31 19:28:29 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,
232                 void *udata, int ubytes)
233 {
234     int i;
235     struct ucred *cr = p->p_ucred;
236     caps_kinfo_t rcaps;
237
238     /*
239      * replace km_mcaps with new VM state, return the old km_mcaps.  The
240      * caller is expected to drop the rcaps ref count on return so we do
241      * not do it ourselves.
242      */
243     rcaps = caps_free_msg_mcaps(msg);   /* can be NULL */
244     caps_hold(caps);
245     msg->km_mcaps = caps;
246     xio_init_ubuf(&msg->km_xio, udata, ubytes, XIOF_READ);
247
248     msg->km_ccr.pid = p ? p->p_pid : -1;
249     msg->km_ccr.uid = cr->cr_ruid;
250     msg->km_ccr.euid = cr->cr_uid;
251     msg->km_ccr.gid = cr->cr_rgid;
252     msg->km_ccr.ngroups = MIN(cr->cr_ngroups, CAPS_MAXGROUPS);
253     for (i = 0; i < msg->km_ccr.ngroups; ++i)
254         msg->km_ccr.groups[i] = cr->cr_groups[i];
255     return(rcaps);
256 }
257
258 static void
259 caps_dequeue_msg(caps_kinfo_t caps, caps_kmsg_t msg)
260 {
261     if (msg->km_flags & CAPKMF_ONUSERQ)
262         TAILQ_REMOVE(&caps->ci_msguserq, msg, km_node);
263     if (msg->km_flags & CAPKMF_ONPENDQ)
264         TAILQ_REMOVE(&caps->ci_msgpendq, msg, km_node);
265     msg->km_flags &= ~(CAPKMF_ONPENDQ|CAPKMF_ONUSERQ);
266 }
267
268 static void
269 caps_put_msg(caps_kinfo_t caps, caps_kmsg_t msg, caps_msg_state_t state)
270 {
271     KKASSERT((msg->km_flags & (CAPKMF_ONUSERQ|CAPKMF_ONPENDQ)) == 0);
272
273     msg->km_flags |= CAPKMF_ONPENDQ;
274     msg->km_flags &= ~CAPKMF_PEEKED;
275     msg->km_state = state;
276     TAILQ_INSERT_TAIL(&caps->ci_msgpendq, msg, km_node);
277
278     /*
279      * Instead of waking up the service for both new messages and disposals,
280      * just wakeup the service for new messages and it will process the
281      * previous disposal in the same loop, reducing the number of context
282      * switches required to run an IPC.
283      */
284     if (state != CAPMS_DISPOSE)
285         wakeup(caps);
286     caps_drop(caps);
287 }
288
289 /*
290  * caps_free_msg_mcaps()
291  */
292 static
293 caps_kinfo_t
294 caps_free_msg_mcaps(caps_kmsg_t msg)
295 {
296     caps_kinfo_t mcaps;
297
298     mcaps = msg->km_mcaps;      /* may be NULL */
299     msg->km_mcaps = NULL;
300     if (msg->km_xio.xio_npages)
301         xio_release(&msg->km_xio);
302     return(mcaps);
303 }
304
305 /*
306  * caps_free_msg()
307  *
308  * Free a caps placeholder message.  The message must not be on any queues.
309  */
310 static void
311 caps_free_msg(caps_kmsg_t msg)
312 {
313     caps_kinfo_t rcaps;
314
315     if ((rcaps = caps_free_msg_mcaps(msg)) != NULL)
316         caps_drop(rcaps);
317     free(msg, M_CAPS);
318 }
319
320 /*
321  * Validate the service name
322  */
323 static int
324 caps_name_check(const char *name, int len)
325 {
326     int i;
327     char c;
328
329     for (i = len - 1; i >= 0; --i) {
330         c = name[i];
331         if (c >= '0' && c <= '9')
332             continue;
333         if (c >= 'a' && c <= 'z')
334             continue;
335         if (c >= 'A' && c <= 'Z')
336             continue;
337         if (c == '_' || c == '.')
338             continue;
339         return(EINVAL);
340     }
341     return(0);
342 }
343
344 /*
345  * caps_term()
346  *
347  * Terminate portions of a caps info structure.  This is used to close
348  * an end-point or to flush particular messages on an end-point.
349  *
350  * This function should not be called with CAPKF_TDLIST unless the caller
351  * has an additional hold on the caps structure.
352  */
353 static void
354 caps_term(caps_kinfo_t caps, int flags, caps_kinfo_t cflush)
355 {
356     struct caps_kinfo **scan;
357     caps_kmsg_t msg;
358
359     if (flags & CAPKF_TDLIST)
360         caps->ci_flags |= CAPKF_CLOSED;
361
362     if (flags & CAPKF_FLUSH) {
363         int mflags;
364         struct caps_kmsg_queue tmpuserq;
365         struct caps_kmsg_queue tmppendq;
366         caps_kinfo_t rcaps;
367
368         TAILQ_INIT(&tmpuserq);
369         TAILQ_INIT(&tmppendq);
370
371         while ((msg = TAILQ_FIRST(&caps->ci_msgpendq)) != NULL ||
372                (msg = TAILQ_FIRST(&caps->ci_msguserq)) != NULL
373         ) {
374             mflags = msg->km_flags & (CAPKMF_ONUSERQ|CAPKMF_ONPENDQ);
375             caps_dequeue_msg(caps, msg);
376
377             if (cflush && msg->km_mcaps != cflush) {
378                 if (mflags & CAPKMF_ONUSERQ)
379                     TAILQ_INSERT_TAIL(&tmpuserq, msg, km_node);
380                 else
381                     TAILQ_INSERT_TAIL(&tmppendq, msg, km_node);
382             } else {
383                 /*
384                  * Dispose of the message.  If the received message is a
385                  * request we must reply it.  If the received message is
386                  * a reply we must return it for disposal.  If the
387                  * received message is a disposal request we simply free it.
388                  */
389                 switch(msg->km_state) {
390                 case CAPMS_REQUEST:
391                 case CAPMS_REQUEST_RETRY:
392                     rcaps = caps_load_ccr(caps, msg, curproc, NULL, 0);
393                     if (rcaps->ci_flags & CAPKF_CLOSED) {
394                         /*
395                          * can't reply, if we never read the message (its on
396                          * the pending queue), or if we are closed ourselves,
397                          * we can just free the message.  Otherwise we have
398                          * to send ourselves a disposal request (multi-threaded
399                          * services have to deal with disposal requests for
400                          * messages that might be in progress).
401                          */
402                         if ((caps->ci_flags & CAPKF_CLOSED) ||
403                             (mflags & CAPKMF_ONPENDQ)
404                         ) {
405                             caps_free_msg(msg);
406                             caps_drop(rcaps);
407                         } else {
408                             caps_drop(rcaps);
409                             caps_hold(caps);    /* for message */
410                             caps_put_msg(caps, msg, CAPMS_DISPOSE);
411                         }
412                     } else {
413                         /*
414                          * auto-reply to the originator.  rcaps already
415                          * has a dangling hold so we do not have to hold it
416                          * again.
417                          */
418                         caps_put_msg(rcaps, msg, CAPMS_REPLY);
419                     }
420                     break;
421                 case CAPMS_REPLY:
422                 case CAPMS_REPLY_RETRY:
423                     rcaps = caps_load_ccr(caps, msg, curproc, NULL, 0);
424                     if (caps == rcaps || (rcaps->ci_flags & CAPKF_CLOSED)) {
425                         caps_free_msg(msg);     /* degenerate disposal case */
426                         caps_drop(rcaps);
427                     } else {
428                         caps_put_msg(rcaps, msg, CAPMS_DISPOSE);
429                     }
430                     break;
431                 case CAPMS_DISPOSE:
432                     caps_free_msg(msg);
433                     break;
434                 }
435             }
436         }
437         while ((msg = TAILQ_FIRST(&tmpuserq)) != NULL) {
438             TAILQ_REMOVE(&tmpuserq, msg, km_node);
439             TAILQ_INSERT_TAIL(&caps->ci_msguserq, msg, km_node);
440             msg->km_flags |= CAPKMF_ONUSERQ;
441         }
442         while ((msg = TAILQ_FIRST(&tmppendq)) != NULL) {
443             TAILQ_REMOVE(&tmppendq, msg, km_node);
444             TAILQ_INSERT_TAIL(&caps->ci_msgpendq, msg, km_node);
445             msg->km_flags |= CAPKMF_ONPENDQ;
446         }
447     }
448     if ((flags & CAPKF_HLIST) && (caps->ci_flags & CAPKF_HLIST)) {
449         for (scan = caps_hash(caps->ci_name, caps->ci_namelen);
450             *scan != caps;
451             scan = &(*scan)->ci_hnext
452         ) {
453             KKASSERT(*scan != NULL);
454         }
455         *scan = caps->ci_hnext;
456         caps->ci_hnext = (void *)-1;
457         caps->ci_flags &= ~CAPKF_HLIST;
458     }
459     if ((flags & CAPKF_TDLIST) && (caps->ci_flags & CAPKF_TDLIST)) {
460         for (scan = &caps->ci_td->td_caps;
461             *scan != caps;
462             scan = &(*scan)->ci_tdnext
463         ) {
464             KKASSERT(*scan != NULL);
465         }
466         *scan = caps->ci_tdnext;
467         caps->ci_flags &= ~CAPKF_TDLIST;
468         caps->ci_tdnext = (void *)-1;
469         caps->ci_td = NULL;
470         caps_drop(caps);
471     }
472     if ((flags & CAPKF_RCAPS) && (caps->ci_flags & CAPKF_RCAPS)) {
473         caps_kinfo_t ctmp;
474
475         caps->ci_flags &= ~CAPKF_RCAPS;
476         if ((ctmp = caps->ci_rcaps)) {
477             caps->ci_rcaps = NULL;
478             caps_term(ctmp, CAPKF_FLUSH, caps);
479             caps_drop(ctmp);
480         }
481     }
482 }
483
484 static void
485 caps_free(caps_kinfo_t caps)
486 {
487     KKASSERT(TAILQ_EMPTY(&caps->ci_msgpendq));
488     KKASSERT(TAILQ_EMPTY(&caps->ci_msguserq));
489     KKASSERT((caps->ci_flags & (CAPKF_HLIST|CAPKF_TDLIST)) == 0);
490     free(caps, M_CAPS);
491 }
492
493 /************************************************************************
494  *                      PROCESS SUPPORT FUNCTIONS                       *
495  ************************************************************************/
496
497 /*
498  * Create dummy entries in p2 so we can return the appropriate
499  * error code.  Robust userland code will check the error for a
500  * forked condition and reforge the connection.
501  */
502 void
503 caps_fork(struct proc *p1, struct proc *p2, int flags)
504 {
505     caps_kinfo_t caps1;
506     caps_kinfo_t caps2;
507     thread_t td1;
508     thread_t td2;
509
510     td1 = p1->p_thread;
511     td2 = p2->p_thread;
512
513     /*
514      * Create dummy entries with the same id's as the originals.  Note
515      * that service entries are not re-added to the hash table. The
516      * dummy entries return an ENOTCONN error allowing userland code to
517      * detect that a fork occured.  Userland must reconnect to the service.
518      */
519     for (caps1 = td1->td_caps; caps1; caps1 = caps1->ci_tdnext) {
520         if (caps1->ci_flags & CAPF_NOFORK)
521                 continue;
522         caps2 = caps_alloc(td2,
523                         caps1->ci_name, caps1->ci_namelen,
524                         caps1->ci_uid, caps1->ci_gid,
525                         caps1->ci_flags & CAPF_UFLAGS, CAPT_FORKED);
526         caps2->ci_id = caps1->ci_id;
527     }
528
529     /*
530      * Reverse the list order to maintain highest-id-first
531      */
532     caps2 = td2->td_caps;
533     td2->td_caps = NULL;
534     while (caps2) {
535         caps1 = caps2->ci_tdnext;
536         caps2->ci_tdnext = td2->td_caps;
537         td2->td_caps = caps2;
538         caps2 = caps1;
539     }
540 }
541
542 void
543 caps_exit(struct thread *td)
544 {
545     caps_kinfo_t caps;
546
547     while ((caps = td->td_caps) != NULL) {
548         caps_hold(caps);
549         caps_term(caps, CAPKF_TDLIST|CAPKF_HLIST|CAPKF_FLUSH|CAPKF_RCAPS, NULL);
550         caps_drop(caps);
551     }
552 }
553
554 /************************************************************************
555  *                              SYSTEM CALLS                            *
556  ************************************************************************/
557
558 /*
559  * caps_sys_service(name, uid, gid, upcid, flags);
560  *
561  * Create an IPC service using the specified name, uid, gid, and flags.
562  * Either uid or gid can be -1, but not both.  The port identifier is
563  * returned.
564  *
565  * upcid can either be an upcall or a kqueue identifier (XXX)
566  */
567 int
568 caps_sys_service(struct caps_sys_service_args *uap)
569 {
570     struct ucred *cred = curproc->p_ucred;
571     char name[CAPS_MAXNAMELEN];
572     caps_kinfo_t caps;
573     int len;
574     int error;
575
576     if (caps_enabled == 0)
577         return(EOPNOTSUPP);
578     if ((error = copyinstr(uap->name, name, CAPS_MAXNAMELEN, &len)) != 0)
579         return(error);
580     if (--len <= 0)
581         return(EINVAL);
582     if ((error = caps_name_check(name, len)) != 0)
583         return(error);
584
585     caps = kern_caps_sys_service(name, uap->uid, uap->gid, cred,
586                                 uap->flags & CAPF_UFLAGS, &error);
587     if (caps)
588         uap->sysmsg_result = caps->ci_id;
589     return(error);
590 }
591
592 /*
593  * caps_sys_client(name, uid, gid, upcid, flags);
594  *
595  * Create an IPC client connected to the specified service.  Either uid or gid
596  * may be -1, indicating a wildcard, but not both.  The port identifier is
597  * returned.
598  *
599  * upcid can either be an upcall or a kqueue identifier (XXX)
600  */
601 int
602 caps_sys_client(struct caps_sys_client_args *uap)
603 {
604     struct ucred *cred = curproc->p_ucred;
605     char name[CAPS_MAXNAMELEN];
606     caps_kinfo_t caps;
607     int len;
608     int error;
609
610     if (caps_enabled == 0)
611         return(EOPNOTSUPP);
612     if ((error = copyinstr(uap->name, name, CAPS_MAXNAMELEN, &len)) != 0)
613         return(error);
614     if (--len <= 0)
615         return(EINVAL);
616     if ((error = caps_name_check(name, len)) != 0)
617         return(error);
618
619     caps = kern_caps_sys_client(name, uap->uid, uap->gid, cred,
620                                 uap->flags & CAPF_UFLAGS, &error);
621     if (caps)
622         uap->sysmsg_result = caps->ci_id;
623     return(error);
624 }
625
626 int
627 caps_sys_close(struct caps_sys_close_args *uap)
628 {
629     caps_kinfo_t caps;
630
631     if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
632         return(EINVAL);
633     caps_term(caps, CAPKF_TDLIST|CAPKF_HLIST|CAPKF_FLUSH|CAPKF_RCAPS, NULL);
634     caps_drop(caps);
635     return(0);
636 }
637
638 int
639 caps_sys_setgen(struct caps_sys_setgen_args *uap)
640 {
641     caps_kinfo_t caps;
642     int error;
643
644     if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
645         return(EINVAL);
646     if (caps->ci_type == CAPT_FORKED) {
647         error = ENOTCONN;
648     } else {
649         caps->ci_gen = uap->gen;
650         error = 0;
651     }
652     caps_drop(caps);
653     return(error);
654 }
655
656 int
657 caps_sys_getgen(struct caps_sys_getgen_args *uap)
658 {
659     caps_kinfo_t caps;
660     int error;
661
662     if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
663         return(EINVAL);
664     if (caps->ci_type == CAPT_FORKED) {
665         error = ENOTCONN;
666     } else if (caps->ci_rcaps == NULL) {
667         error = EINVAL;
668     } else {
669         uap->sysmsg_result64 = caps->ci_rcaps->ci_gen;
670         error = 0;
671     }
672     caps_drop(caps);
673     return(error);
674 }
675
676 /*
677  * caps_sys_put(portid, msg, msgsize)
678  *
679  * Send an opaque message of the specified size to the specified port.  This
680  * function may only be used with a client port.  The message id is returned.
681  */
682 int
683 caps_sys_put(struct caps_sys_put_args *uap)
684 {
685     caps_kinfo_t caps;
686     caps_kmsg_t msg;
687     struct proc *p = curproc;
688     int error;
689
690     if (uap->msgsize < 0)
691         return(EINVAL);
692     if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
693         return(EINVAL);
694     if (caps->ci_type == CAPT_FORKED) {
695         error = ENOTCONN;
696     } else if (caps->ci_rcaps == NULL) {
697         error = EINVAL;
698     } else if (caps->ci_cmsgcount > CAPS_MAXINPROG) {
699         /*
700          * If this client has queued a large number of messages return
701          * ENOBUFS.  The client must process some replies before it can
702          * send new messages.  The server can also throttle a client by
703          * holding its replies.  XXX allow a server to refuse messages from
704          * a client.
705          */
706         error = ENOBUFS;
707     } else {
708         msg = caps_alloc_msg(caps);
709         uap->sysmsg_offset = msg->km_msgid.c_id;
710
711         /*
712          * If the remote end is closed return ENOTCONN immediately, otherwise
713          * send it to the remote end.
714          *
715          * Note: since this is a new message, caps_load_ccr() returns a remote
716          * caps of NULL.
717          */
718         if (caps->ci_rcaps->ci_flags & CAPKF_CLOSED) {
719             error = ENOTCONN;
720             caps_free_msg(msg);
721         } else {
722             /*
723              * new message, load_ccr returns NULL. hold rcaps for put_msg
724              */
725             error = 0;
726             caps_load_ccr(caps, msg, p, uap->msg, uap->msgsize);
727             caps_hold(caps->ci_rcaps);
728             ++caps->ci_cmsgcount;
729             caps_put_msg(caps->ci_rcaps, msg, CAPMS_REQUEST); /* drops rcaps */
730         }
731     }
732     caps_drop(caps);
733     return(error);
734 }
735
736 /*
737  * caps_sys_reply(portid, msg, msgsize, msgid)
738  *
739  * Reply to the message referenced by the specified msgid, supplying opaque
740  * data back to the originator.
741  */
742 int
743 caps_sys_reply(struct caps_sys_reply_args *uap)
744 {
745     caps_kinfo_t caps;
746     caps_kinfo_t rcaps;
747     caps_kmsg_t msg;
748     struct proc *p;
749     int error;
750
751     if (uap->msgsize < 0)
752         return(EINVAL);
753     if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
754         return(EINVAL);
755     if (caps->ci_type == CAPT_FORKED) {
756         /*
757          * The caps structure is just a fork placeholder, tell the caller
758          * that he has to reconnect.
759          */
760         error = ENOTCONN;
761     } else if ((msg = caps_find_msg(caps, uap->msgcid)) == NULL) {
762         /*
763          * Could not find message being replied to (other side might have
764          * gone away).
765          */
766         error = EINVAL;
767     } else if ((msg->km_flags & CAPKMF_ONUSERQ) == 0) {
768         /*
769          * Trying to reply to a non-replyable message
770          */
771         error = EINVAL;
772     } else {
773         /*
774          * If the remote end is closed requeue to ourselves for disposal.
775          * Otherwise send the reply to the other end (the other end will
776          * return a passive DISPOSE to us when it has eaten the data)
777          */
778         error = 0;
779         caps_dequeue_msg(caps, msg);
780         p = curproc;
781         if (msg->km_mcaps->ci_flags & CAPKF_CLOSED) {
782             caps_drop(caps_load_ccr(caps, msg, p, NULL, 0));
783             caps_hold(caps);                    /* ref for message */
784             caps_put_msg(caps, msg, CAPMS_DISPOSE);
785         } else {
786             rcaps = caps_load_ccr(caps, msg, p, uap->msg, uap->msgsize);
787             caps_put_msg(rcaps, msg, CAPMS_REPLY);
788         }
789     }
790     caps_drop(caps);
791     return(error);
792 }
793
794 /*
795  * caps_sys_get(portid, msg, maxsize, msgid, ccr)
796  *
797  * Retrieve the next ready message on the port, store its message id in
798  * uap->msgid and return the length of the message.  If the message is too
799  * large to fit the message id, length, and creds are still returned, but
800  * the message is not dequeued (the caller is expected to call again with
801  * a larger buffer or to reply the messageid if it does not want to handle
802  * the message).
803  *
804  * EWOULDBLOCK is returned if no messages are pending.  Note that 0-length
805  * messages are perfectly acceptable so 0 can be legitimately returned.
806  */
807 int
808 caps_sys_get(struct caps_sys_get_args *uap)
809 {
810     caps_kinfo_t caps;
811     caps_kmsg_t msg;
812     int error;
813
814     if (uap->maxsize < 0)
815         return(EINVAL);
816     if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
817         return(EINVAL);
818     if (caps->ci_type == CAPT_FORKED) {
819         error = ENOTCONN;
820     } else if ((msg = TAILQ_FIRST(&caps->ci_msgpendq)) == NULL) {
821         error = EWOULDBLOCK;
822     } else {
823         error = caps_process_msg(caps, msg, uap);
824     }
825     caps_drop(caps);
826     return(error);
827 }
828
829 /*
830  * caps_sys_wait(portid, msg, maxsize, msgid, ccr)
831  *
832  * Retrieve the next ready message on the port, store its message id in
833  * uap->msgid and return the length of the message.  If the message is too
834  * large to fit the message id, length, and creds are still returned, but
835  * the message is not dequeued (the caller is expected to call again with
836  * a larger buffer or to reply the messageid if it does not want to handle
837  * the message).
838  *
839  * This function blocks until interrupted or a message is received.
840  * Note that 0-length messages are perfectly acceptable so 0 can be
841  * legitimately returned.
842  */
843 int
844 caps_sys_wait(struct caps_sys_wait_args *uap)
845 {
846     caps_kinfo_t caps;
847     caps_kmsg_t msg;
848     int error;
849
850     if (uap->maxsize < 0)
851         return(EINVAL);
852     if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
853         return(EINVAL);
854     if (caps->ci_type == CAPT_FORKED) {
855         error = ENOTCONN;
856     } else {
857         error = 0;
858         while ((msg = TAILQ_FIRST(&caps->ci_msgpendq)) == NULL) {
859             if ((error = tsleep(caps, PCATCH, "caps", 0)) != 0)
860                 break;
861         }
862         if (error == 0) {
863             error = caps_process_msg(caps, msg, 
864                                 (struct caps_sys_get_args *)uap);
865         }
866     }
867     caps_drop(caps);
868     return(error);
869 }
870
871 static int
872 caps_process_msg(caps_kinfo_t caps, caps_kmsg_t msg, struct caps_sys_get_args *uap)
873 {
874     int error = 0;
875     int msgsize;
876     caps_kinfo_t rcaps;
877
878     msg->km_flags |= CAPKMF_PEEKED;
879     msgsize = msg->km_xio.xio_bytes;
880     if (msgsize <= uap->maxsize)
881         caps_dequeue_msg(caps, msg);
882
883     if (msg->km_xio.xio_bytes != 0) {
884         struct proc *rp = msg->km_mcaps->ci_td->td_proc;
885         KKASSERT(rp != NULL);
886         error = xio_copy_xtou(&msg->km_xio, uap->msg, 
887                             min(msg->km_xio.xio_bytes, uap->maxsize));
888         if (error) {
889             printf("xio_copy_xtou: error %d from proc %d\n", error, rp->p_pid);
890             if (msgsize > uap->maxsize)
891                 caps_dequeue_msg(caps, msg);
892             msgsize = 0;
893             error = 0;
894         }
895     }
896
897     if (uap->msgid)
898         error = copyout(&msg->km_msgid, uap->msgid, sizeof(msg->km_msgid));
899     if (uap->ccr)
900         error = copyout(&msg->km_ccr, uap->ccr, sizeof(msg->km_ccr));
901     if (error == 0)
902         uap->sysmsg_result = msgsize;
903
904     /*
905      * If the message was dequeued we must deal with it.
906      */
907     if (msgsize <= uap->maxsize) {
908         switch(msg->km_state) {
909         case CAPMS_REQUEST:
910         case CAPMS_REQUEST_RETRY:
911             TAILQ_INSERT_TAIL(&caps->ci_msguserq, msg, km_node);
912             msg->km_flags |= CAPKMF_ONUSERQ;
913             break;
914         case CAPMS_REPLY:
915         case CAPMS_REPLY_RETRY:
916             --caps->ci_cmsgcount;
917             rcaps = caps_load_ccr(caps, msg, curproc, NULL, 0);
918             if (caps == rcaps || (rcaps->ci_flags & CAPKF_CLOSED)) {
919                 /* degenerate disposal case */
920                 caps_free_msg(msg);
921                 caps_drop(rcaps);
922             } else {
923                 caps_put_msg(rcaps, msg, CAPMS_DISPOSE);
924             }
925             break;
926         case CAPMS_DISPOSE:
927             caps_free_msg(msg);
928             break;
929         }
930     }
931     return(error);
932 }
933
934 /*
935  * caps_sys_abort(portid, msgcid, flags)
936  *
937  *      Abort a previously sent message.  You must still wait for the message
938  *      to be returned after sending the abort request.  This function will
939  *      return the appropriate CAPS_ABORT_* code depending on what it had
940  *      to do.
941  */
942 int
943 caps_sys_abort(struct caps_sys_abort_args *uap)
944 {
945     uap->sysmsg_result = CAPS_ABORT_NOTIMPL;
946     return(0);
947 }
948
949 /*
950  * KERNEL SYSCALL SEPARATION SUPPORT FUNCTIONS
951  */
952
953 static
954 caps_kinfo_t
955 kern_caps_sys_service(const char *name, uid_t uid, gid_t gid,
956                         struct ucred *cred, int flags, int *error)
957 {
958     caps_kinfo_t caps;
959     int len;
960
961     len = strlen(name);
962
963     /*
964      * Make sure we can use the uid and gid
965      */
966     if (cred) {
967         if (cred->cr_uid != 0 && uid != (uid_t)-1 && cred->cr_uid != uid) {
968             *error = EPERM;
969             return(NULL);
970         }
971         if (cred->cr_uid != 0 && gid != (gid_t)-1 && !groupmember(gid, cred)) {
972             *error = EPERM;
973             return(NULL);
974         }
975     }
976
977     /*
978      * Handle CAPF_EXCL
979      */
980     if (flags & CAPF_EXCL) {
981         if ((caps = caps_find(name, strlen(name), uid, gid)) != NULL) {
982             caps_drop(caps);
983             *error = EEXIST;
984             return(NULL);
985         }
986     }
987
988     /*
989      * Create the service
990      */
991     caps = caps_alloc(curthread, name, len, 
992                         uid, gid, flags & CAPF_UFLAGS, CAPT_SERVICE);
993     wakeup(&caps_waitsvc);
994     return(caps);
995 }
996
997 static
998 caps_kinfo_t
999 kern_caps_sys_client(const char *name, uid_t uid, gid_t gid,
1000                         struct ucred *cred, int flags, int *error)
1001 {
1002     caps_kinfo_t caps, rcaps;
1003     int len;
1004
1005     len = strlen(name);
1006
1007     /*
1008      * Locate the CAPS service (rcaps ref is for caps->ci_rcaps)
1009      */
1010 again:
1011     if ((rcaps = caps_find(name, len, uid, gid)) == NULL) {
1012         if (flags & CAPF_WAITSVC) {
1013             char cbuf[32];
1014             snprintf(cbuf, sizeof(cbuf), "C%s", name);
1015             *error = tsleep(&caps_waitsvc, PCATCH, cbuf, 0);
1016             if (*error == 0)
1017                 goto again;
1018         } else {
1019             *error = ENOENT;
1020         }
1021         return(NULL);
1022     }
1023
1024     /*
1025      * Check permissions
1026      */
1027     if (cred) {
1028         *error = EACCES;
1029         if ((flags & CAPF_USER) && (rcaps->ci_flags & CAPF_USER)) {
1030             if (rcaps->ci_uid != (uid_t)-1 && rcaps->ci_uid == cred->cr_uid)
1031                 *error = 0;
1032         }
1033         if ((flags & CAPF_GROUP) && (rcaps->ci_flags & CAPF_GROUP)) {
1034             if (rcaps->ci_gid != (gid_t)-1 && groupmember(rcaps->ci_gid, cred))
1035                 *error = 0;
1036         }
1037         if ((flags & CAPF_WORLD) && (rcaps->ci_flags & CAPF_WORLD)) {
1038             *error = 0;
1039         }
1040         if (*error) {
1041             caps_drop(rcaps);
1042             return(NULL);
1043         }
1044     } else {
1045         *error = 0;
1046     }
1047
1048     /*
1049      * Allocate the client side and connect to the server
1050      */
1051     caps = caps_alloc(curthread, name, len, 
1052                         uid, gid, flags & CAPF_UFLAGS, CAPT_CLIENT);
1053     caps->ci_rcaps = rcaps;
1054     caps->ci_flags |= CAPKF_RCAPS;
1055     return(caps);
1056 }
1057