xref: /illumos-gate/usr/src/lib/libc/port/gen/klpdlib.c (revision ca9327a6de44d69ddab3668cc1e143ce781387a3)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include "synonyms.h"
30 
31 #include "priv_private.h"
32 #include "mtlib.h"
33 #include "libc.h"
34 
35 #include <door.h>
36 #include <errno.h>
37 #include <priv.h>
38 #include <klpd.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <sys/klpd.h>
43 #include <sys/param.h>
44 #include <sys/syscall.h>
45 #include <unistd.h>
46 #include <netinet/in.h>
47 
48 typedef struct klpd_data {
49 	boolean_t	(*kd_callback)(void *, const priv_set_t *, void *);
50 	void		*kd_user_cookie;
51 	int		kd_doorfd;
52 } klpd_data_t;
53 
54 typedef struct klpd_ctxt {
55 	klpd_data_t	*kc_data;
56 	char		*kc_path;
57 	int		kc_int;
58 	int		kc_type;
59 } klpd_ctxt_t;
60 
61 /* ARGSUSED */
62 static void
63 klpd_door_callback(void *kd_cookie, char *argp, size_t arg_size,
64     door_desc_t *dp, uint_t ndesc)
65 {
66 	klpd_data_t *p = kd_cookie;
67 	int res;
68 	klpd_ctxt_t ctx;
69 	klpd_head_t *klh;
70 	klpd_arg_t *ka;
71 	priv_set_t *pset;
72 
73 	if (argp == DOOR_UNREF_DATA) {
74 		(void) p->kd_callback(p->kd_user_cookie, NULL, NULL);
75 		(void) door_return(NULL, 0, NULL, 0);
76 	}
77 
78 	klh = (void *)argp;
79 	ka = KLH_ARG(klh);
80 	pset = KLH_PRIVSET(klh);
81 
82 	ctx.kc_type = ka == NULL ? KLPDARG_NONE : ka->kla_type;
83 
84 	switch (ctx.kc_type) {
85 	case KLPDARG_NONE:
86 		ctx.kc_path = NULL;
87 		ctx.kc_int = -1;
88 		break;
89 	case KLPDARG_VNODE:
90 		ctx.kc_path = ka->kla_str;
91 		ctx.kc_int = -1;
92 		break;
93 	default:
94 		ctx.kc_int = ka->kla_int;
95 		ctx.kc_path = NULL;
96 		break;
97 	}
98 
99 	ctx.kc_data = p;
100 
101 	if (p->kd_callback(p->kd_user_cookie, pset, &ctx))
102 		res = 0;
103 	else
104 		res = 1;
105 
106 	(void) door_return((char *)&res, sizeof (res), NULL, 0);
107 }
108 
109 void *
110 klpd_create(boolean_t (*callback)(void *, const priv_set_t *, void *),
111     void *cookie)
112 {
113 	klpd_data_t *p = malloc(sizeof (klpd_data_t));
114 
115 	if (p == NULL)
116 		return (NULL);
117 
118 	p->kd_doorfd = door_create(klpd_door_callback, p,
119 	    DOOR_REFUSE_DESC | DOOR_UNREF);
120 	if (p->kd_doorfd == -1)
121 		goto out;
122 
123 	p->kd_user_cookie = cookie;
124 	p->kd_callback = callback;
125 
126 	return (p);
127 
128 out:
129 	free(p);
130 	return (NULL);
131 }
132 
133 int
134 klpd_register_id(const priv_set_t *set, void *handle, idtype_t type, id_t id)
135 {
136 	klpd_data_t *p = handle;
137 	priv_data_t *d;
138 
139 	LOADPRIVDATA(d);
140 
141 	/* We really need to have the privilege set as argument here */
142 	if (syscall(SYS_privsys, PRIVSYS_KLPD_REG, p->kd_doorfd, id,
143 	    set, d->pd_setsize, type) == -1)
144 		return (-1);
145 
146 	/* Registration for the current process?  Then do the thing. */
147 	if (type == P_PID && (id == 0 || (pid_t)id == getpid())) {
148 		(void) setppriv(PRIV_OFF, PRIV_INHERITABLE, set);
149 		(void) setpflags(PRIV_XPOLICY, 1);
150 	}
151 	return (0);
152 }
153 
154 int
155 klpd_register(const priv_set_t *set, void *handle)
156 {
157 	return (klpd_register_id(set, handle, P_PID, -1));
158 }
159 
160 int
161 klpd_unregister_id(void *handle, idtype_t type, id_t id)
162 {
163 	klpd_data_t *p = handle;
164 	int err;
165 
166 	err = syscall(SYS_privsys, PRIVSYS_KLPD_UNREG, p->kd_doorfd, id,
167 	    (void *)NULL, 0L, type);
168 	if (close(p->kd_doorfd) != 0)
169 		err = -1;
170 	free(p);
171 	return (err);
172 }
173 
174 int
175 klpd_unregister(void *handle)
176 {
177 	return (klpd_unregister_id(handle, P_PID, -1));
178 }
179 
180 const char *
181 klpd_getpath(void *context)
182 {
183 	klpd_ctxt_t *p = context;
184 
185 	if (p->kc_type != KLPDARG_VNODE)
186 		errno = EINVAL;
187 	return (p->kc_path);
188 }
189 
190 int
191 klpd_getport(void *context, int *proto)
192 {
193 	klpd_ctxt_t *p = context;
194 
195 	switch (p->kc_type) {
196 	case KLPDARG_TCPPORT:
197 		*proto = IPPROTO_TCP;
198 		break;
199 	case KLPDARG_UDPPORT:
200 		*proto = IPPROTO_UDP;
201 		break;
202 	case KLPDARG_SCTPPORT:
203 		*proto = IPPROTO_SCTP;
204 		break;
205 	case KLPDARG_SDPPORT:
206 		*proto = PROTO_SDP;
207 		break;
208 	default:
209 		errno = EINVAL;
210 		return (-1);
211 	}
212 	return (p->kc_int);
213 }
214 
215 /*ARGSUSED*/
216 int
217 klpd_getucred(ucred_t **uc, void *context)
218 {
219 	return (door_ucred(uc));
220 }
221