Fix "ls: not found" problem during buildworld. mdate.sh script
[dragonfly.git] / sys / kern / lwkt_caps.c
blob648247ce2c2ad897cbebbf237a2f6fd14191a83a
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:
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.
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.
34 * $DragonFly: src/sys/kern/lwkt_caps.c,v 1.6 2005/03/01 23:35:13 dillon Exp $
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.
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.
52 * From the userland perspective a client/server connection involves two
53 * message ports on the client and two message ports on the server.
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>
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);
79 #define CAPS_HSIZE 64
80 #define CAPS_HMASK (CAPS_HSIZE - 1)
82 static caps_kinfo_t caps_hash_ary[CAPS_HSIZE];
83 static int caps_waitsvc;
85 MALLOC_DEFINE(M_CAPS, "caps", "caps IPC messaging");
87 static int caps_enabled;
88 SYSCTL_INT(_kern, OID_AUTO, caps_enabled,
89 CTLFLAG_RW, &caps_enabled, 0, "Enable CAPS");
91 /************************************************************************
92 * INLINE SUPPORT FUNCTIONS *
93 ************************************************************************/
95 static __inline
96 struct caps_kinfo **
97 caps_hash(const char *name, int len)
99 int hv = 0x7123F4B3;
101 while (--len >= 0)
102 hv = (hv << 5) ^ name[len] ^ (hv >> 23);
103 return(&caps_hash_ary[(hv ^ (hv >> 16)) & CAPS_HMASK]);
106 static __inline
107 void
108 caps_hold(caps_kinfo_t caps)
110 ++caps->ci_refs;
113 static __inline
114 void
115 caps_drop(caps_kinfo_t caps)
117 if (--caps->ci_refs == 0)
118 caps_free(caps);
121 /************************************************************************
122 * STATIC SUPPORT FUNCTIONS *
123 ************************************************************************/
125 static
126 caps_kinfo_t
127 caps_find(const char *name, int len, uid_t uid, gid_t gid)
129 caps_kinfo_t caps;
130 struct caps_kinfo **chash;
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
139 caps_hold(caps);
140 break;
143 return(caps);
146 static
147 caps_kinfo_t
148 caps_find_id(thread_t td, int id)
150 caps_kinfo_t caps;
152 for (caps = td->td_caps; caps; caps = caps->ci_tdnext) {
153 if (caps->ci_id == id) {
154 caps_hold(caps);
155 break;
158 return(caps);
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)
166 struct caps_kinfo **chash;
167 caps_kinfo_t caps;
168 caps_kinfo_t ctmp;
170 caps = malloc(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;
187 if (td->td_caps) {
188 caps->ci_id = td->td_caps->ci_id + 1;
189 if (caps->ci_id < 0) {
191 * It is virtually impossible for this case to occur.
193 caps->ci_id = 1;
194 while ((ctmp = caps_find_id(td, caps->ci_id)) != NULL) {
195 caps_drop(ctmp);
196 ++caps->ci_id;
199 } else {
200 caps->ci_id = 1;
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);
209 static
210 caps_kmsg_t
211 caps_alloc_msg(caps_kinfo_t caps)
213 caps_kmsg_t msg;
215 msg = malloc(sizeof(struct caps_kmsg), M_CAPS, M_WAITOK|M_ZERO);
216 msg->km_msgid.c_id = (off_t)(uintptr_t)msg;
217 return(msg);
220 static
221 caps_kmsg_t
222 caps_find_msg(caps_kinfo_t caps, off_t msgid)
224 caps_kmsg_t msg;
226 TAILQ_FOREACH(msg, &caps->ci_msguserq, km_node) {
227 if (msg->km_msgid.c_id == msgid)
228 return(msg);
230 TAILQ_FOREACH(msg, &caps->ci_msgpendq, km_node) {
231 if (msg->km_msgid.c_id == msgid)
232 return(msg);
234 return(NULL);
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)
242 int i;
243 struct ucred *cr = p->p_ucred;
244 caps_kinfo_t rcaps;
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.
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);
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);
266 static void
267 caps_dequeue_msg(caps_kinfo_t caps, caps_kmsg_t msg)
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);
276 static void
277 caps_put_msg(caps_kinfo_t caps, caps_kmsg_t msg, caps_msg_state_t state)
279 KKASSERT((msg->km_flags & (CAPKMF_ONUSERQ|CAPKMF_ONPENDQ)) == 0);
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);
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.
292 if (state != CAPMS_DISPOSE)
293 wakeup(caps);
294 caps_drop(caps);
298 * caps_free_msg_mcaps()
300 static
301 caps_kinfo_t
302 caps_free_msg_mcaps(caps_kmsg_t msg)
304 caps_kinfo_t mcaps;
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);
314 * caps_free_msg()
316 * Free a caps placeholder message. The message must not be on any queues.
318 static void
319 caps_free_msg(caps_kmsg_t msg)
321 caps_kinfo_t rcaps;
323 if ((rcaps = caps_free_msg_mcaps(msg)) != NULL)
324 caps_drop(rcaps);
325 free(msg, M_CAPS);
329 * Validate the service name
331 static int
332 caps_name_check(const char *name, int len)
334 int i;
335 char c;
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);
349 return(0);
353 * caps_term()
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.
358 * This function should not be called with CAPKF_TDLIST unless the caller
359 * has an additional hold on the caps structure.
361 static void
362 caps_term(caps_kinfo_t caps, int flags, caps_kinfo_t cflush)
364 struct caps_kinfo **scan;
365 caps_kmsg_t msg;
367 if (flags & CAPKF_TDLIST)
368 caps->ci_flags |= CAPKF_CLOSED;
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;
376 TAILQ_INIT(&tmpuserq);
377 TAILQ_INIT(&tmppendq);
379 while ((msg = TAILQ_FIRST(&caps->ci_msgpendq)) != NULL ||
380 (msg = TAILQ_FIRST(&caps->ci_msguserq)) != NULL
382 mflags = msg->km_flags & (CAPKMF_ONUSERQ|CAPKMF_ONPENDQ);
383 caps_dequeue_msg(caps, msg);
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 {
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.
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) {
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).
410 if ((caps->ci_flags & CAPKF_CLOSED) ||
411 (mflags & CAPKMF_ONPENDQ)
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);
420 } else {
422 * auto-reply to the originator. rcaps already
423 * has a dangling hold so we do not have to hold it
424 * again.
426 caps_put_msg(rcaps, msg, CAPMS_REPLY);
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);
438 break;
439 case CAPMS_DISPOSE:
440 caps_free_msg(msg);
441 break;
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;
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;
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
461 KKASSERT(*scan != NULL);
463 *scan = caps->ci_hnext;
464 caps->ci_hnext = (void *)-1;
465 caps->ci_flags &= ~CAPKF_HLIST;
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
472 KKASSERT(*scan != NULL);
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);
480 if ((flags & CAPKF_RCAPS) && (caps->ci_flags & CAPKF_RCAPS)) {
481 caps_kinfo_t ctmp;
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);
492 static void
493 caps_free(caps_kinfo_t caps)
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 free(caps, M_CAPS);
501 /************************************************************************
502 * PROCESS SUPPORT FUNCTIONS *
503 ************************************************************************/
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.
510 void
511 caps_fork(struct proc *p1, struct proc *p2, int flags)
513 caps_kinfo_t caps1;
514 caps_kinfo_t caps2;
515 thread_t td1;
516 thread_t td2;
518 td1 = p1->p_thread;
519 td2 = p2->p_thread;
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.
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;
538 * Reverse the list order to maintain highest-id-first
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;
550 void
551 caps_exit(struct thread *td)
553 caps_kinfo_t caps;
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);
562 /************************************************************************
563 * SYSTEM CALLS *
564 ************************************************************************/
567 * caps_sys_service(name, uid, gid, upcid, flags);
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.
573 * upcid can either be an upcall or a kqueue identifier (XXX)
576 caps_sys_service(struct caps_sys_service_args *uap)
578 struct ucred *cred = curproc->p_ucred;
579 char name[CAPS_MAXNAMELEN];
580 caps_kinfo_t caps;
581 int len;
582 int error;
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);
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);
601 * caps_sys_client(name, uid, gid, upcid, flags);
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.
607 * upcid can either be an upcall or a kqueue identifier (XXX)
610 caps_sys_client(struct caps_sys_client_args *uap)
612 struct ucred *cred = curproc->p_ucred;
613 char name[CAPS_MAXNAMELEN];
614 caps_kinfo_t caps;
615 int len;
616 int error;
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);
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);
635 caps_sys_close(struct caps_sys_close_args *uap)
637 caps_kinfo_t caps;
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);
647 caps_sys_setgen(struct caps_sys_setgen_args *uap)
649 caps_kinfo_t caps;
650 int error;
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;
660 caps_drop(caps);
661 return(error);
665 caps_sys_getgen(struct caps_sys_getgen_args *uap)
667 caps_kinfo_t caps;
668 int error;
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;
680 caps_drop(caps);
681 return(error);
685 * caps_sys_put(portid, msg, msgsize)
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.
691 caps_sys_put(struct caps_sys_put_args *uap)
693 caps_kinfo_t caps;
694 caps_kmsg_t msg;
695 struct proc *p = curproc;
696 int error;
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) {
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.
714 error = ENOBUFS;
715 } else {
716 msg = caps_alloc_msg(caps);
717 uap->sysmsg_offset = msg->km_msgid.c_id;
720 * If the remote end is closed return ENOTCONN immediately, otherwise
721 * send it to the remote end.
723 * Note: since this is a new message, caps_load_ccr() returns a remote
724 * caps of NULL.
726 if (caps->ci_rcaps->ci_flags & CAPKF_CLOSED) {
727 error = ENOTCONN;
728 caps_free_msg(msg);
729 } else {
731 * new message, load_ccr returns NULL. hold rcaps for put_msg
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 */
740 caps_drop(caps);
741 return(error);
745 * caps_sys_reply(portid, msg, msgsize, msgid)
747 * Reply to the message referenced by the specified msgid, supplying opaque
748 * data back to the originator.
751 caps_sys_reply(struct caps_sys_reply_args *uap)
753 caps_kinfo_t caps;
754 caps_kinfo_t rcaps;
755 caps_kmsg_t msg;
756 struct proc *p;
757 int error;
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) {
765 * The caps structure is just a fork placeholder, tell the caller
766 * that he has to reconnect.
768 error = ENOTCONN;
769 } else if ((msg = caps_find_msg(caps, uap->msgcid)) == NULL) {
771 * Could not find message being replied to (other side might have
772 * gone away).
774 error = EINVAL;
775 } else if ((msg->km_flags & CAPKMF_ONUSERQ) == 0) {
777 * Trying to reply to a non-replyable message
779 error = EINVAL;
780 } else {
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)
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);
798 caps_drop(caps);
799 return(error);
803 * caps_sys_get(portid, msg, maxsize, msgid, ccr)
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).
812 * EWOULDBLOCK is returned if no messages are pending. Note that 0-length
813 * messages are perfectly acceptable so 0 can be legitimately returned.
816 caps_sys_get(struct caps_sys_get_args *uap)
818 caps_kinfo_t caps;
819 caps_kmsg_t msg;
820 int error;
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);
833 caps_drop(caps);
834 return(error);
838 * caps_sys_wait(portid, msg, maxsize, msgid, ccr)
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).
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.
852 caps_sys_wait(struct caps_sys_wait_args *uap)
854 caps_kinfo_t caps;
855 caps_kmsg_t msg;
856 int error;
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;
870 if (error == 0) {
871 error = caps_process_msg(caps, msg,
872 (struct caps_sys_get_args *)uap);
875 caps_drop(caps);
876 return(error);
879 static int
880 caps_process_msg(caps_kinfo_t caps, caps_kmsg_t msg, struct caps_sys_get_args *uap)
882 int error = 0;
883 int msgsize;
884 caps_kinfo_t rcaps;
886 msg->km_flags |= CAPKMF_PEEKED;
887 msgsize = msg->km_xio.xio_bytes;
888 if (msgsize <= uap->maxsize)
889 caps_dequeue_msg(caps, msg);
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);
899 if (msgsize > uap->maxsize)
900 caps_dequeue_msg(caps, msg);
901 msgsize = 0;
902 error = 0;
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;
914 * If the message was dequeued we must deal with it.
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);
934 break;
935 case CAPMS_DISPOSE:
936 caps_free_msg(msg);
937 break;
940 return(error);
944 * caps_sys_abort(portid, msgcid, flags)
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.
952 caps_sys_abort(struct caps_sys_abort_args *uap)
954 uap->sysmsg_result = CAPS_ABORT_NOTIMPL;
955 return(0);
959 * KERNEL SYSCALL SEPARATION SUPPORT FUNCTIONS
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)
967 caps_kinfo_t caps;
968 int len;
970 len = strlen(name);
973 * Make sure we can use the uid and gid
975 if (cred) {
976 if (cred->cr_uid != 0 && uid != (uid_t)-1 && cred->cr_uid != uid) {
977 *error = EPERM;
978 return(NULL);
980 if (cred->cr_uid != 0 && gid != (gid_t)-1 && !groupmember(gid, cred)) {
981 *error = EPERM;
982 return(NULL);
987 * Handle CAPF_EXCL
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);
998 * Create the service
1000 caps = caps_alloc(curthread, name, len,
1001 uid, gid, flags & CAPF_UFLAGS, CAPT_SERVICE);
1002 wakeup(&caps_waitsvc);
1003 return(caps);
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)
1011 caps_kinfo_t caps, rcaps;
1012 int len;
1014 len = strlen(name);
1017 * Locate the CAPS service (rcaps ref is for caps->ci_rcaps)
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;
1030 return(NULL);
1034 * Check permissions
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;
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;
1046 if ((flags & CAPF_WORLD) && (rcaps->ci_flags & CAPF_WORLD)) {
1047 *error = 0;
1049 if (*error) {
1050 caps_drop(rcaps);
1051 return(NULL);
1053 } else {
1054 *error = 0;
1058 * Allocate the client side and connect to the server
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);