1:1 Userland threading stage 4.6/4:
[dragonfly.git] / sys / kern / lwkt_caps.c
1 /*
2  * Copyright (c) 2003,2004 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  * 
34  * $DragonFly: src/sys/kern/lwkt_caps.c,v 1.13 2007/02/26 21:41:08 corecode Exp $
35  */
36
37 /*
38  * This module implements the DragonFly LWKT IPC rendezvous and message
39  * passing API which operates between userland processes, between userland
40  * threads, and between userland processes and kernel threads.  This API
41  * is known as the CAPS interface.
42  *
43  * Generally speaking this module abstracts the LWKT message port interface
44  * into userland Clients and Servers rendezvous through ports named
45  * by or wildcarded by (name,uid,gid).  The kernel provides system calls 
46  * which may be assigned to the mp_* fields in a userland-supplied
47  * kernel-managed port, and a registration interface which associates an
48  * upcall with a userland port.  The kernel tracks authentication information
49  * and deals with connection failures by automatically replying to unreplied
50  * messages.
51  *
52  * From the userland perspective a client/server connection involves two
53  * message ports on the client and two message ports on the server.
54  */
55
56 #include <sys/param.h>
57 #include <sys/systm.h>
58 #include <sys/kernel.h>
59 #include <sys/sysproto.h>
60 #include <sys/malloc.h>
61 #include <sys/proc.h>
62 #include <sys/ucred.h>
63 #include <sys/caps.h>
64 #include <sys/sysctl.h>
65 #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 thread *td1, struct thread *td2)
512 {
513     caps_kinfo_t caps1;
514     caps_kinfo_t caps2;
515
516     /*
517      * Create dummy entries with the same id's as the originals.  Note
518      * that service entries are not re-added to the hash table. The
519      * dummy entries return an ENOTCONN error allowing userland code to
520      * detect that a fork occured.  Userland must reconnect to the service.
521      */
522     for (caps1 = td1->td_caps; caps1; caps1 = caps1->ci_tdnext) {
523         if (caps1->ci_flags & CAPF_NOFORK)
524                 continue;
525         caps2 = caps_alloc(td2,
526                         caps1->ci_name, caps1->ci_namelen,
527                         caps1->ci_uid, caps1->ci_gid,
528                         caps1->ci_flags & CAPF_UFLAGS, CAPT_FORKED);
529         caps2->ci_id = caps1->ci_id;
530     }
531
532     /*
533      * Reverse the list order to maintain highest-id-first
534      */
535     caps2 = td2->td_caps;
536     td2->td_caps = NULL;
537     while (caps2) {
538         caps1 = caps2->ci_tdnext;
539         caps2->ci_tdnext = td2->td_caps;
540         td2->td_caps = caps2;
541         caps2 = caps1;
542     }
543 }
544
545 void
546 caps_exit(struct thread *td)
547 {
548     caps_kinfo_t caps;
549
550     while ((caps = td->td_caps) != NULL) {
551         caps_hold(caps);
552         caps_term(caps, CAPKF_TDLIST|CAPKF_HLIST|CAPKF_FLUSH|CAPKF_RCAPS, NULL);
553         caps_drop(caps);
554     }
555 }
556
557 /************************************************************************
558  *                              SYSTEM CALLS                            *
559  ************************************************************************/
560
561 /*
562  * caps_sys_service(name, uid, gid, upcid, flags);
563  *
564  * Create an IPC service using the specified name, uid, gid, and flags.
565  * Either uid or gid can be -1, but not both.  The port identifier is
566  * returned.
567  *
568  * upcid can either be an upcall or a kqueue identifier (XXX)
569  */
570 int
571 sys_caps_sys_service(struct caps_sys_service_args *uap)
572 {
573     struct ucred *cred = curproc->p_ucred;
574     char name[CAPS_MAXNAMELEN];
575     caps_kinfo_t caps;
576     int len;
577     int error;
578
579     if (caps_enabled == 0)
580         return(EOPNOTSUPP);
581     if ((error = copyinstr(uap->name, name, CAPS_MAXNAMELEN, &len)) != 0)
582         return(error);
583     if (--len <= 0)
584         return(EINVAL);
585     if ((error = caps_name_check(name, len)) != 0)
586         return(error);
587
588     caps = kern_caps_sys_service(name, uap->uid, uap->gid, cred,
589                                 uap->flags & CAPF_UFLAGS, &error);
590     if (caps)
591         uap->sysmsg_result = caps->ci_id;
592     return(error);
593 }
594
595 /*
596  * caps_sys_client(name, uid, gid, upcid, flags);
597  *
598  * Create an IPC client connected to the specified service.  Either uid or gid
599  * may be -1, indicating a wildcard, but not both.  The port identifier is
600  * returned.
601  *
602  * upcid can either be an upcall or a kqueue identifier (XXX)
603  */
604 int
605 sys_caps_sys_client(struct caps_sys_client_args *uap)
606 {
607     struct ucred *cred = curproc->p_ucred;
608     char name[CAPS_MAXNAMELEN];
609     caps_kinfo_t caps;
610     int len;
611     int error;
612
613     if (caps_enabled == 0)
614         return(EOPNOTSUPP);
615     if ((error = copyinstr(uap->name, name, CAPS_MAXNAMELEN, &len)) != 0)
616         return(error);
617     if (--len <= 0)
618         return(EINVAL);
619     if ((error = caps_name_check(name, len)) != 0)
620         return(error);
621
622     caps = kern_caps_sys_client(name, uap->uid, uap->gid, cred,
623                                 uap->flags & CAPF_UFLAGS, &error);
624     if (caps)
625         uap->sysmsg_result = caps->ci_id;
626     return(error);
627 }
628
629 int
630 sys_caps_sys_close(struct caps_sys_close_args *uap)
631 {
632     caps_kinfo_t caps;
633
634     if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
635         return(EINVAL);
636     caps_term(caps, CAPKF_TDLIST|CAPKF_HLIST|CAPKF_FLUSH|CAPKF_RCAPS, NULL);
637     caps_drop(caps);
638     return(0);
639 }
640
641 int
642 sys_caps_sys_setgen(struct caps_sys_setgen_args *uap)
643 {
644     caps_kinfo_t caps;
645     int error;
646
647     if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
648         return(EINVAL);
649     if (caps->ci_type == CAPT_FORKED) {
650         error = ENOTCONN;
651     } else {
652         caps->ci_gen = uap->gen;
653         error = 0;
654     }
655     caps_drop(caps);
656     return(error);
657 }
658
659 int
660 sys_caps_sys_getgen(struct caps_sys_getgen_args *uap)
661 {
662     caps_kinfo_t caps;
663     int error;
664
665     if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
666         return(EINVAL);
667     if (caps->ci_type == CAPT_FORKED) {
668         error = ENOTCONN;
669     } else if (caps->ci_rcaps == NULL) {
670         error = EINVAL;
671     } else {
672         uap->sysmsg_result64 = caps->ci_rcaps->ci_gen;
673         error = 0;
674     }
675     caps_drop(caps);
676     return(error);
677 }
678
679 /*
680  * caps_sys_put(portid, msg, msgsize)
681  *
682  * Send an opaque message of the specified size to the specified port.  This
683  * function may only be used with a client port.  The message id is returned.
684  */
685 int
686 sys_caps_sys_put(struct caps_sys_put_args *uap)
687 {
688     caps_kinfo_t caps;
689     caps_kmsg_t msg;
690     struct proc *p = curproc;
691     int error;
692
693     if (uap->msgsize < 0)
694         return(EINVAL);
695     if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
696         return(EINVAL);
697     if (caps->ci_type == CAPT_FORKED) {
698         error = ENOTCONN;
699     } else if (caps->ci_rcaps == NULL) {
700         error = EINVAL;
701     } else if (caps->ci_cmsgcount > CAPS_MAXINPROG) {
702         /*
703          * If this client has queued a large number of messages return
704          * ENOBUFS.  The client must process some replies before it can
705          * send new messages.  The server can also throttle a client by
706          * holding its replies.  XXX allow a server to refuse messages from
707          * a client.
708          */
709         error = ENOBUFS;
710     } else {
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         if (caps->ci_rcaps->ci_flags & CAPKF_CLOSED) {
722             error = ENOTCONN;
723             caps_free_msg(msg);
724         } else {
725             /*
726              * new message, load_ccr returns NULL. hold rcaps for put_msg
727              */
728             error = 0;
729             caps_load_ccr(caps, msg, p, uap->msg, uap->msgsize);
730             caps_hold(caps->ci_rcaps);
731             ++caps->ci_cmsgcount;
732             caps_put_msg(caps->ci_rcaps, msg, CAPMS_REQUEST); /* drops rcaps */
733         }
734     }
735     caps_drop(caps);
736     return(error);
737 }
738
739 /*
740  * caps_sys_reply(portid, msg, msgsize, msgid)
741  *
742  * Reply to the message referenced by the specified msgid, supplying opaque
743  * data back to the originator.
744  */
745 int
746 sys_caps_sys_reply(struct caps_sys_reply_args *uap)
747 {
748     caps_kinfo_t caps;
749     caps_kinfo_t rcaps;
750     caps_kmsg_t msg;
751     struct proc *p;
752     int error;
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         /*
760          * The caps structure is just a fork placeholder, tell the caller
761          * that he has to reconnect.
762          */
763         error = ENOTCONN;
764     } else if ((msg = caps_find_msg(caps, uap->msgcid)) == NULL) {
765         /*
766          * Could not find message being replied to (other side might have
767          * gone away).
768          */
769         error = EINVAL;
770     } else if ((msg->km_flags & CAPKMF_ONUSERQ) == 0) {
771         /*
772          * Trying to reply to a non-replyable message
773          */
774         error = EINVAL;
775     } else {
776         /*
777          * If the remote end is closed requeue to ourselves for disposal.
778          * Otherwise send the reply to the other end (the other end will
779          * return a passive DISPOSE to us when it has eaten the data)
780          */
781         error = 0;
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);                    /* ref for message */
787             caps_put_msg(caps, msg, CAPMS_DISPOSE);
788         } else {
789             rcaps = caps_load_ccr(caps, msg, p, uap->msg, uap->msgsize);
790             caps_put_msg(rcaps, msg, CAPMS_REPLY);
791         }
792     }
793     caps_drop(caps);
794     return(error);
795 }
796
797 /*
798  * caps_sys_get(portid, msg, maxsize, msgid, ccr)
799  *
800  * Retrieve the next ready message on the port, store its message id in
801  * uap->msgid and return the length of the message.  If the message is too
802  * large to fit the message id, length, and creds are still returned, but
803  * the message is not dequeued (the caller is expected to call again with
804  * a larger buffer or to reply the messageid if it does not want to handle
805  * the message).
806  *
807  * EWOULDBLOCK is returned if no messages are pending.  Note that 0-length
808  * messages are perfectly acceptable so 0 can be legitimately returned.
809  */
810 int
811 sys_caps_sys_get(struct caps_sys_get_args *uap)
812 {
813     caps_kinfo_t caps;
814     caps_kmsg_t msg;
815     int error;
816
817     if (uap->maxsize < 0)
818         return(EINVAL);
819     if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
820         return(EINVAL);
821     if (caps->ci_type == CAPT_FORKED) {
822         error = ENOTCONN;
823     } else if ((msg = TAILQ_FIRST(&caps->ci_msgpendq)) == NULL) {
824         error = EWOULDBLOCK;
825     } else {
826         error = caps_process_msg(caps, msg, uap);
827     }
828     caps_drop(caps);
829     return(error);
830 }
831
832 /*
833  * caps_sys_wait(portid, msg, maxsize, msgid, ccr)
834  *
835  * Retrieve the next ready message on the port, store its message id in
836  * uap->msgid and return the length of the message.  If the message is too
837  * large to fit the message id, length, and creds are still returned, but
838  * the message is not dequeued (the caller is expected to call again with
839  * a larger buffer or to reply the messageid if it does not want to handle
840  * the message).
841  *
842  * This function blocks until interrupted or a message is received.
843  * Note that 0-length messages are perfectly acceptable so 0 can be
844  * legitimately returned.
845  */
846 int
847 sys_caps_sys_wait(struct caps_sys_wait_args *uap)
848 {
849     caps_kinfo_t caps;
850     caps_kmsg_t msg;
851     int error;
852
853     if (uap->maxsize < 0)
854         return(EINVAL);
855     if ((caps = caps_find_id(curthread, uap->portid)) == NULL)
856         return(EINVAL);
857     if (caps->ci_type == CAPT_FORKED) {
858         error = ENOTCONN;
859     } else {
860         error = 0;
861         while ((msg = TAILQ_FIRST(&caps->ci_msgpendq)) == NULL) {
862             if ((error = tsleep(caps, PCATCH, "caps", 0)) != 0)
863                 break;
864         }
865         if (error == 0) {
866             error = caps_process_msg(caps, msg, 
867                                 (struct caps_sys_get_args *)uap);
868         }
869     }
870     caps_drop(caps);
871     return(error);
872 }
873
874 static int
875 caps_process_msg(caps_kinfo_t caps, caps_kmsg_t msg, struct caps_sys_get_args *uap)
876 {
877     int error = 0;
878     int msgsize;
879     caps_kinfo_t rcaps;
880
881     msg->km_flags |= CAPKMF_PEEKED;
882     msgsize = msg->km_xio.xio_bytes;
883     if (msgsize <= uap->maxsize)
884         caps_dequeue_msg(caps, msg);
885
886     if (msg->km_xio.xio_bytes != 0) {
887         error = xio_copy_xtou(&msg->km_xio, 0, uap->msg, 
888                             min(msg->km_xio.xio_bytes, uap->maxsize));
889         if (error) {
890             if (msg->km_mcaps->ci_td && msg->km_mcaps->ci_td->td_proc) {
891                 kprintf("xio_copy_xtou: error %d from proc %d\n", 
892                         error, msg->km_mcaps->ci_td->td_proc->p_pid);
893             }
894             if (msgsize > uap->maxsize)
895                 caps_dequeue_msg(caps, msg);
896             msgsize = 0;
897             error = 0;
898         }
899     }
900
901     if (uap->msgid)
902         error = copyout(&msg->km_msgid, uap->msgid, sizeof(msg->km_msgid));
903     if (uap->ccr)
904         error = copyout(&msg->km_ccr, uap->ccr, sizeof(msg->km_ccr));
905     if (error == 0)
906         uap->sysmsg_result = msgsize;
907
908     /*
909      * If the message was dequeued we must deal with it.
910      */
911     if (msgsize <= uap->maxsize) {
912         switch(msg->km_state) {
913         case CAPMS_REQUEST:
914         case CAPMS_REQUEST_RETRY:
915             TAILQ_INSERT_TAIL(&caps->ci_msguserq, msg, km_node);
916             msg->km_flags |= CAPKMF_ONUSERQ;
917             break;
918         case CAPMS_REPLY:
919         case CAPMS_REPLY_RETRY:
920             --caps->ci_cmsgcount;
921             rcaps = caps_load_ccr(caps, msg, curproc, NULL, 0);
922             if (caps == rcaps || (rcaps->ci_flags & CAPKF_CLOSED)) {
923                 /* degenerate disposal case */
924                 caps_free_msg(msg);
925                 caps_drop(rcaps);
926             } else {
927                 caps_put_msg(rcaps, msg, CAPMS_DISPOSE);
928             }
929             break;
930         case CAPMS_DISPOSE:
931             caps_free_msg(msg);
932             break;
933         }
934     }
935     return(error);
936 }
937
938 /*
939  * caps_sys_abort(portid, msgcid, flags)
940  *
941  *      Abort a previously sent message.  You must still wait for the message
942  *      to be returned after sending the abort request.  This function will
943  *      return the appropriate CAPS_ABORT_* code depending on what it had
944  *      to do.
945  */
946 int
947 sys_caps_sys_abort(struct caps_sys_abort_args *uap)
948 {
949     uap->sysmsg_result = CAPS_ABORT_NOTIMPL;
950     return(0);
951 }
952
953 /*
954  * KERNEL SYSCALL SEPARATION SUPPORT FUNCTIONS
955  */
956
957 static
958 caps_kinfo_t
959 kern_caps_sys_service(const char *name, uid_t uid, gid_t gid,
960                         struct ucred *cred, int flags, int *error)
961 {
962     caps_kinfo_t caps;
963     int len;
964
965     len = strlen(name);
966
967     /*
968      * Make sure we can use the uid and gid
969      */
970     if (cred) {
971         if (cred->cr_uid != 0 && uid != (uid_t)-1 && cred->cr_uid != uid) {
972             *error = EPERM;
973             return(NULL);
974         }
975         if (cred->cr_uid != 0 && gid != (gid_t)-1 && !groupmember(gid, cred)) {
976             *error = EPERM;
977             return(NULL);
978         }
979     }
980
981     /*
982      * Handle CAPF_EXCL
983      */
984     if (flags & CAPF_EXCL) {
985         if ((caps = caps_find(name, strlen(name), uid, gid)) != NULL) {
986             caps_drop(caps);
987             *error = EEXIST;
988             return(NULL);
989         }
990     }
991
992     /*
993      * Create the service
994      */
995     caps = caps_alloc(curthread, name, len, 
996                         uid, gid, flags & CAPF_UFLAGS, CAPT_SERVICE);
997     wakeup(&caps_waitsvc);
998     return(caps);
999 }
1000
1001 static
1002 caps_kinfo_t
1003 kern_caps_sys_client(const char *name, uid_t uid, gid_t gid,
1004                         struct ucred *cred, int flags, int *error)
1005 {
1006     caps_kinfo_t caps, rcaps;
1007     int len;
1008
1009     len = strlen(name);
1010
1011     /*
1012      * Locate the CAPS service (rcaps ref is for caps->ci_rcaps)
1013      */
1014 again:
1015     if ((rcaps = caps_find(name, len, uid, gid)) == NULL) {
1016         if (flags & CAPF_WAITSVC) {
1017             char cbuf[32];
1018             ksnprintf(cbuf, sizeof(cbuf), "C%s", name);
1019             *error = tsleep(&caps_waitsvc, PCATCH, cbuf, 0);
1020             if (*error == 0)
1021                 goto again;
1022         } else {
1023             *error = ENOENT;
1024         }
1025         return(NULL);
1026     }
1027
1028     /*
1029      * Check permissions
1030      */
1031     if (cred) {
1032         *error = EACCES;
1033         if ((flags & CAPF_USER) && (rcaps->ci_flags & CAPF_USER)) {
1034             if (rcaps->ci_uid != (uid_t)-1 && rcaps->ci_uid == cred->cr_uid)
1035                 *error = 0;
1036         }
1037         if ((flags & CAPF_GROUP) && (rcaps->ci_flags & CAPF_GROUP)) {
1038             if (rcaps->ci_gid != (gid_t)-1 && groupmember(rcaps->ci_gid, cred))
1039                 *error = 0;
1040         }
1041         if ((flags & CAPF_WORLD) && (rcaps->ci_flags & CAPF_WORLD)) {
1042             *error = 0;
1043         }
1044         if (*error) {
1045             caps_drop(rcaps);
1046             return(NULL);
1047         }
1048     } else {
1049         *error = 0;
1050     }
1051
1052     /*
1053      * Allocate the client side and connect to the server
1054      */
1055     caps = caps_alloc(curthread, name, len, 
1056                         uid, gid, flags & CAPF_UFLAGS, CAPT_CLIENT);
1057     caps->ci_rcaps = rcaps;
1058     caps->ci_flags |= CAPKF_RCAPS;
1059     return(caps);
1060 }
1061