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 2015 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 /*
27 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
29 */
30
31 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
32 /* All Rights Reserved */
33
34 /*
35 * Portions of this source code were derived from Berkeley 4.3 BSD
36 * under license from the Regents of the University of California.
37 */
38
39 /*
40 * key_call.c, Interface to keyserver
41 * key_encryptsession(agent, deskey, cr)-encrypt a session key to talk to agent
42 * key_decryptsession(agent, deskey) - decrypt ditto
43 * key_gendes(deskey) - generate a secure des key
44 * key_getnetname(netname, cr) - get the netname from the keyserv
45 * netname2user(...) - get unix credential for given name (kernel only)
46 */
47
48 #include <sys/param.h>
49 #include <sys/types.h>
50 #include <sys/time.h>
51 #include <sys/systm.h>
52 #include <sys/user.h>
53 #include <sys/proc.h>
54 #include <sys/pathname.h>
55 #include <sys/sysmacros.h>
56 #include <sys/vnode.h>
57 #include <sys/uio.h>
58 #include <sys/debug.h>
59 #include <sys/cmn_err.h>
60
61 #include <rpc/rpc.h>
62 #include <rpc/key_prot.h>
63
64 #define KEY_TIMEOUT 30 /* per-try timeout in seconds */
65 #define KEY_NRETRY 6 /* number of retries */
66
67 struct auth_globals {
68 struct knetconfig auth_config;
69 };
70
71 static struct timeval keytrytimeout = { KEY_TIMEOUT, 0 };
72
73 static enum clnt_stat key_call(rpcproc_t, xdrproc_t, char *, xdrproc_t, char *,
74 cred_t *);
75
76 /* ARGSUSED */
77 void *
auth_zone_init(zoneid_t zoneid)78 auth_zone_init(zoneid_t zoneid)
79 {
80 struct auth_globals *authg;
81
82 authg = kmem_zalloc(sizeof (*authg), KM_SLEEP);
83 return (authg);
84 }
85
86 /* ARGSUSED */
87 void
auth_zone_fini(zoneid_t zoneid,void * data)88 auth_zone_fini(zoneid_t zoneid, void *data)
89 {
90 struct auth_globals *authg = data;
91
92 kmem_free(authg, sizeof (*authg));
93 }
94
95 enum clnt_stat
key_encryptsession(char * remotename,des_block * deskey,cred_t * cr)96 key_encryptsession(char *remotename, des_block *deskey, cred_t *cr)
97 {
98 cryptkeyarg arg;
99 cryptkeyres res;
100 enum clnt_stat stat;
101
102 RPCLOG(8, "key_encryptsession(%s, ", remotename);
103 RPCLOG(8, "%x", *(uint32_t *)deskey);
104 RPCLOG(8, "%x)\n", *(((uint32_t *)(deskey))+1));
105
106 arg.remotename = remotename;
107 arg.deskey = *deskey;
108 if ((stat = key_call(KEY_ENCRYPT, xdr_cryptkeyarg, (char *)&arg,
109 xdr_cryptkeyres, (char *)&res, cr)) != RPC_SUCCESS) {
110 RPCLOG(1, "key_encryptsession(%d, ", (int)crgetuid(cr));
111 RPCLOG(1, "%s): ", remotename);
112 RPCLOG(1, "rpc status %d ", stat);
113 RPCLOG(1, "(%s)\n", clnt_sperrno(stat));
114 return (stat);
115 }
116
117 if (res.status != KEY_SUCCESS) {
118 RPCLOG(1, "key_encryptsession(%d, ", (int)crgetuid(cr));
119 RPCLOG(1, "%s): ", remotename);
120 RPCLOG(1, "key status %d\n", res.status);
121 return (RPC_FAILED); /* XXX */
122 }
123 *deskey = res.cryptkeyres_u.deskey;
124 return (RPC_SUCCESS);
125 }
126
127 enum clnt_stat
key_decryptsession(char * remotename,des_block * deskey)128 key_decryptsession(char *remotename, des_block *deskey)
129 {
130 cryptkeyarg arg;
131 cryptkeyres res;
132 enum clnt_stat stat;
133
134 RPCLOG(8, "key_decryptsession(%s, ", remotename);
135 RPCLOG(2, "%x", *(uint32_t *)deskey);
136 RPCLOG(2, "%x)\n", *(((uint32_t *)(deskey))+1));
137
138 arg.remotename = remotename;
139 arg.deskey = *deskey;
140 if ((stat = key_call(KEY_DECRYPT, xdr_cryptkeyarg, (char *)&arg,
141 xdr_cryptkeyres, (char *)&res, kcred)) != RPC_SUCCESS) {
142 RPCLOG(1, "key_decryptsession(%s): ", remotename);
143 RPCLOG(1, "rpc status %d ", stat);
144 RPCLOG(1, "(%s)\n", clnt_sperrno(stat));
145 return (stat);
146 }
147
148 if (res.status != KEY_SUCCESS) {
149 RPCLOG(1, "key_decryptsession(%s): ", remotename);
150 RPCLOG(1, "key status %d\n", res.status);
151 return (RPC_FAILED); /* XXX */
152 }
153 *deskey = res.cryptkeyres_u.deskey;
154 return (RPC_SUCCESS);
155 }
156
157 enum clnt_stat
key_gendes(des_block * key)158 key_gendes(des_block *key)
159 {
160
161 return (key_call(KEY_GEN, xdr_void, NULL, xdr_des_block, (char *)key,
162 CRED()));
163 }
164
165 /*
166 * Call up to keyserv to get the netname of the client based
167 * on its uid. The netname is written into the string that "netname"
168 * points to; the caller is responsible for ensuring that sufficient space
169 * is available.
170 */
171 enum clnt_stat
key_getnetname(netname,cr)172 key_getnetname(netname, cr)
173 char *netname;
174 cred_t *cr;
175 {
176 key_netstres kres;
177 enum clnt_stat stat;
178
179 /*
180 * Look up the keyserv interface routines to see if
181 * netname is stored there.
182 */
183 kres.key_netstres_u.knet.st_netname = netname;
184 if ((stat = key_call((rpcproc_t)KEY_NET_GET, xdr_void, NULL,
185 xdr_key_netstres, (char *)&kres, cr)) != RPC_SUCCESS) {
186 RPCLOG(1, "key_getnetname(%d): ", (int)crgetuid(cr));
187 RPCLOG(1, "rpc status %d ", stat);
188 RPCLOG(1, "(%s)\n", clnt_sperrno(stat));
189 return (stat);
190 }
191
192 if (kres.status != KEY_SUCCESS) {
193 RPCLOG(1, "key_getnetname(%d): ", (int)crgetuid(cr));
194 RPCLOG(1, "key status %d\n", kres.status);
195 return (RPC_FAILED);
196 }
197
198 return (RPC_SUCCESS);
199 }
200
201 enum clnt_stat
netname2user(char * name,uid_t * uid,gid_t * gid,int * len,gid_t * groups)202 netname2user(char *name, uid_t *uid, gid_t *gid, int *len, gid_t *groups)
203 {
204 struct getcredres res;
205 enum clnt_stat stat;
206
207 res.getcredres_u.cred.gids.gids_val = (uint_t *)groups;
208 if ((stat = key_call(KEY_GETCRED, xdr_netnamestr, (char *)&name,
209 xdr_getcredres, (char *)&res, CRED())) != RPC_SUCCESS) {
210 RPCLOG(1, "netname2user(%s): ", name);
211 RPCLOG(1, "rpc status %d ", stat);
212 RPCLOG(1, "(%s)\n", clnt_sperrno(stat));
213 return (stat);
214 }
215
216 if (res.status != KEY_SUCCESS) {
217 RPCLOG(1, "netname2user(%s): ", name);
218 RPCLOG(1, "key status %d\n", res.status);
219 return (RPC_FAILED); /* XXX */
220 }
221 *uid = res.getcredres_u.cred.uid;
222 *gid = res.getcredres_u.cred.gid;
223 *len = res.getcredres_u.cred.gids.gids_len;
224 return (RPC_SUCCESS);
225 }
226
227 #define NC_LOOPBACK "loopback" /* XXX */
228 char loopback_name[] = NC_LOOPBACK;
229
230 static enum clnt_stat
key_call(rpcproc_t procn,xdrproc_t xdr_args,caddr_t args,xdrproc_t xdr_rslt,caddr_t rslt,cred_t * cr)231 key_call(rpcproc_t procn, xdrproc_t xdr_args, caddr_t args,
232 xdrproc_t xdr_rslt, caddr_t rslt, cred_t *cr)
233 {
234 struct netbuf netaddr;
235 CLIENT *client;
236 enum clnt_stat stat;
237 vnode_t *vp;
238 int error;
239 struct auth_globals *authg;
240 struct knetconfig *configp;
241 k_sigset_t smask;
242
243 authg = zone_getspecific(auth_zone_key, curproc->p_zone);
244 configp = &authg->auth_config;
245
246 /* strlen("localhost.keyserv") is 17 */
247 netaddr.len = netaddr.maxlen = 17;
248 netaddr.buf = "localhost.keyserv";
249
250 /*
251 * filch a knetconfig structure.
252 */
253 if (configp->knc_rdev == 0) {
254 if ((error = lookupname("/dev/ticlts", UIO_SYSSPACE,
255 FOLLOW, NULLVPP, &vp)) != 0) {
256 RPCLOG(1, "key_call: lookupname: %d\n", error);
257 return (RPC_UNKNOWNPROTO);
258 }
259 configp->knc_rdev = vp->v_rdev;
260 configp->knc_protofmly = loopback_name;
261 VN_RELE(vp);
262 }
263 configp->knc_semantics = NC_TPI_CLTS;
264 RPCLOG(8, "key_call: procn %d, ", procn);
265 RPCLOG(8, "rdev %lx, ", configp->knc_rdev);
266 RPCLOG(8, "len %d, ", netaddr.len);
267 RPCLOG(8, "maxlen %d, ", netaddr.maxlen);
268 RPCLOG(8, "name %p\n", (void *)netaddr.buf);
269
270 /*
271 * now call the proper stuff.
272 */
273 error = clnt_tli_kcreate(configp, &netaddr, KEY_PROG, KEY_VERS,
274 0, KEY_NRETRY, cr, &client);
275
276 if (error != 0) {
277 RPCLOG(1, "key_call: clnt_tli_kcreate: error %d\n", error);
278 switch (error) {
279 case EINTR:
280 return (RPC_INTR);
281 case ETIMEDOUT:
282 return (RPC_TIMEDOUT);
283 default:
284 return (RPC_FAILED); /* XXX */
285 }
286 }
287
288 auth_destroy(client->cl_auth);
289 client->cl_auth = authloopback_create();
290 if (client->cl_auth == NULL) {
291 clnt_destroy(client);
292 RPCLOG(1, "key_call: authloopback_create: error %d\n", EINTR);
293 return (RPC_INTR);
294 }
295
296 /* Mask out all signals except SIGHUP, SIGQUIT, and SIGTERM. */
297 sigintr(&smask, 0);
298 stat = clnt_call(client, procn, xdr_args, args, xdr_rslt, rslt,
299 keytrytimeout);
300 sigunintr(&smask);
301
302 auth_destroy(client->cl_auth);
303 clnt_destroy(client);
304 if (stat != RPC_SUCCESS) {
305 RPCLOG(1, "key_call: keyserver clnt_call failed: stat %d ",
306 stat);
307 RPCLOG(1, "(%s)\n", clnt_sperrno(stat));
308 RPCLOG0(1, "\n");
309 return (stat);
310 }
311 RPCLOG(8, "key call: (%d) ok\n", procn);
312 return (RPC_SUCCESS);
313 }
314