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