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
klpd_door_callback(void * kd_cookie,char * argp,size_t arg_size __unused,door_desc_t * dp __unused,uint_t ndesc __unused)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 *
klpd_create(boolean_t (* callback)(void *,const priv_set_t *,void *),void * cookie)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
klpd_register_id(const priv_set_t * set,void * handle,idtype_t type,id_t id)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
klpd_register(const priv_set_t * set,void * handle)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
klpd_unregister_id(void * handle,idtype_t type,id_t id)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
klpd_unregister(void * handle)170 klpd_unregister(void *handle)
171 {
172 return (klpd_unregister_id(handle, P_PID, -1));
173 }
174
175 const char *
klpd_getpath(void * context)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
klpd_getport(void * context,int * proto)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
klpd_getucred(ucred_t ** uc,void * context __unused)211 klpd_getucred(ucred_t **uc, void *context __unused)
212 {
213 return (door_ucred(uc));
214 }
215