xref: /illumos-gate/usr/src/lib/libc/port/gen/klpdlib.c (revision 7a6d80f1660abd4755c68cbd094d4a914681d26e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include "lint.h"
28 #include "priv_private.h"
29 #include "mtlib.h"
30 #include "libc.h"
31 #include <door.h>
32 #include <errno.h>
33 #include <priv.h>
34 #include <klpd.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/klpd.h>
39 #include <sys/param.h>
40 #include <sys/syscall.h>
41 #include <unistd.h>
42 #include <netinet/in.h>
43 
44 typedef struct klpd_data {
45 	boolean_t	(*kd_callback)(void *, const priv_set_t *, void *);
46 	void		*kd_user_cookie;
47 	int		kd_doorfd;
48 } klpd_data_t;
49 
50 typedef struct klpd_ctxt {
51 	klpd_data_t	*kc_data;
52 	char		*kc_path;
53 	int		kc_int;
54 	int		kc_type;
55 } klpd_ctxt_t;
56 
57 static void
58 klpd_door_callback(void *kd_cookie, char *argp, size_t arg_size __unused,
59     door_desc_t *dp __unused, uint_t ndesc __unused)
60 {
61 	klpd_data_t *p = kd_cookie;
62 	int res;
63 	klpd_ctxt_t ctx;
64 	klpd_head_t *klh;
65 	klpd_arg_t *ka;
66 	priv_set_t *pset;
67 
68 	if (argp == DOOR_UNREF_DATA) {
69 		(void) p->kd_callback(p->kd_user_cookie, NULL, NULL);
70 		(void) door_return(NULL, 0, NULL, 0);
71 	}
72 
73 	klh = (void *)argp;
74 	ka = KLH_ARG(klh);
75 	pset = KLH_PRIVSET(klh);
76 
77 	ctx.kc_type = ka == NULL ? KLPDARG_NONE : ka->kla_type;
78 
79 	switch (ctx.kc_type) {
80 	case KLPDARG_NONE:
81 		ctx.kc_path = NULL;
82 		ctx.kc_int = -1;
83 		break;
84 	case KLPDARG_VNODE:
85 		ctx.kc_path = ka->kla_str;
86 		ctx.kc_int = -1;
87 		break;
88 	default:
89 		ctx.kc_int = ka->kla_int;
90 		ctx.kc_path = NULL;
91 		break;
92 	}
93 
94 	ctx.kc_data = p;
95 
96 	if (p->kd_callback(p->kd_user_cookie, pset, &ctx))
97 		res = 0;
98 	else
99 		res = 1;
100 
101 	(void) door_return((char *)&res, sizeof (res), NULL, 0);
102 }
103 
104 void *
105 klpd_create(boolean_t (*callback)(void *, const priv_set_t *, void *),
106     void *cookie)
107 {
108 	klpd_data_t *p = malloc(sizeof (klpd_data_t));
109 
110 	if (p == NULL)
111 		return (NULL);
112 
113 	p->kd_doorfd = door_create(klpd_door_callback, p,
114 	    DOOR_REFUSE_DESC | DOOR_UNREF);
115 	if (p->kd_doorfd == -1)
116 		goto out;
117 
118 	p->kd_user_cookie = cookie;
119 	p->kd_callback = callback;
120 
121 	return (p);
122 
123 out:
124 	free(p);
125 	return (NULL);
126 }
127 
128 int
129 klpd_register_id(const priv_set_t *set, void *handle, idtype_t type, id_t id)
130 {
131 	klpd_data_t *p = handle;
132 	priv_data_t *d;
133 
134 	LOADPRIVDATA(d);
135 
136 	/* We really need to have the privilege set as argument here */
137 	if (syscall(SYS_privsys, PRIVSYS_KLPD_REG, p->kd_doorfd, id,
138 	    set, d->pd_setsize, type) == -1)
139 		return (-1);
140 
141 	/* Registration for the current process?  Then do the thing. */
142 	if (type == P_PID && (id == 0 || (pid_t)id == getpid())) {
143 		(void) setppriv(PRIV_OFF, PRIV_INHERITABLE, set);
144 		(void) setpflags(PRIV_XPOLICY, 1);
145 	}
146 	return (0);
147 }
148 
149 int
150 klpd_register(const priv_set_t *set, void *handle)
151 {
152 	return (klpd_register_id(set, handle, P_PID, -1));
153 }
154 
155 int
156 klpd_unregister_id(void *handle, idtype_t type, id_t id)
157 {
158 	klpd_data_t *p = handle;
159 	int err;
160 
161 	err = syscall(SYS_privsys, PRIVSYS_KLPD_UNREG, p->kd_doorfd, id,
162 	    (void *)NULL, 0L, type);
163 	if (close(p->kd_doorfd) != 0)
164 		err = -1;
165 	free(p);
166 	return (err);
167 }
168 
169 int
170 klpd_unregister(void *handle)
171 {
172 	return (klpd_unregister_id(handle, P_PID, -1));
173 }
174 
175 const char *
176 klpd_getpath(void *context)
177 {
178 	klpd_ctxt_t *p = context;
179 
180 	if (p->kc_type != KLPDARG_VNODE)
181 		errno = EINVAL;
182 	return (p->kc_path);
183 }
184 
185 int
186 klpd_getport(void *context, int *proto)
187 {
188 	klpd_ctxt_t *p = context;
189 
190 	switch (p->kc_type) {
191 	case KLPDARG_TCPPORT:
192 		*proto = IPPROTO_TCP;
193 		break;
194 	case KLPDARG_UDPPORT:
195 		*proto = IPPROTO_UDP;
196 		break;
197 	case KLPDARG_SCTPPORT:
198 		*proto = IPPROTO_SCTP;
199 		break;
200 	case KLPDARG_SDPPORT:
201 		*proto = PROTO_SDP;
202 		break;
203 	default:
204 		errno = EINVAL;
205 		return (-1);
206 	}
207 	return (p->kc_int);
208 }
209 
210 int
211 klpd_getucred(ucred_t **uc, void *context __unused)
212 {
213 	return (door_ucred(uc));
214 }
215