xref: /titanic_52/usr/src/uts/common/rpc/sec/key_call.c (revision c2580b931007758eab8cb5ae8726ebe1588e259b)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * Portions of this source code were derived from Berkeley 4.3 BSD
32  * under license from the Regents of the University of California.
33  */
34 
35 #pragma ident	"%Z%%M%	%I%	%E% SMI"
36 
37 /*
38  * key_call.c, Interface to keyserver
39  * key_encryptsession(agent, deskey, cr)-encrypt a session key to talk to agent
40  * key_decryptsession(agent, deskey) - decrypt ditto
41  * key_gendes(deskey) - generate a secure des key
42  * key_getnetname(netname, cr) - get the netname from the keyserv
43  * netname2user(...) - get unix credential for given name (kernel only)
44  */
45 
46 #include <sys/param.h>
47 #include <sys/types.h>
48 #include <sys/time.h>
49 #include <sys/systm.h>
50 #include <sys/user.h>
51 #include <sys/proc.h>
52 #include <sys/pathname.h>
53 #include <sys/sysmacros.h>
54 #include <sys/vnode.h>
55 #include <sys/uio.h>
56 #include <sys/debug.h>
57 #include <sys/utsname.h>
58 #include <sys/cmn_err.h>
59 
60 #include <rpc/rpc.h>
61 #include <rpc/key_prot.h>
62 
63 #define	KEY_TIMEOUT	30	/* per-try timeout in seconds */
64 #define	KEY_NRETRY	6	/* number of retries */
65 
66 struct auth_globals {
67 	struct knetconfig	auth_config;
68 	char 			auth_keyname[SYS_NMLN+16];
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 *
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
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
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
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
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
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
202 netname2user(char *name, uid_t *uid, gid_t *gid, int *len, int *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
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 	char *keyname;
241 	struct knetconfig *configp;
242 	k_sigset_t smask;
243 
244 	authg = zone_getspecific(auth_zone_key, curproc->p_zone);
245 	keyname = authg->auth_keyname;
246 	configp = &authg->auth_config;
247 
248 	/*
249 	 * Using a global here is obviously busted and fraught with danger.
250 	 */
251 	(void) strcpy(keyname, uts_nodename());
252 	netaddr.len = strlen(keyname);
253 	(void) strcpy(&keyname[netaddr.len], ".keyserv");
254 
255 	netaddr.buf = keyname;
256 	/*
257 	 * 8 = strlen(".keyserv");
258 	 */
259 	netaddr.len = netaddr.maxlen = netaddr.len + 8;
260 
261 	/*
262 	 * filch a knetconfig structure.
263 	 */
264 	if (configp->knc_rdev == 0) {
265 		if ((error = lookupname("/dev/ticlts", UIO_SYSSPACE,
266 		    FOLLOW, NULLVPP, &vp)) != 0) {
267 			RPCLOG(1, "key_call: lookupname: %d\n", error);
268 			return (RPC_UNKNOWNPROTO);
269 		}
270 		configp->knc_rdev = vp->v_rdev;
271 		configp->knc_protofmly = loopback_name;
272 		VN_RELE(vp);
273 	}
274 	configp->knc_semantics = NC_TPI_CLTS;
275 	RPCLOG(8, "key_call: procn %d, ", procn);
276 	RPCLOG(8, "rdev %lx, ", configp->knc_rdev);
277 	RPCLOG(8, "len %d, ", netaddr.len);
278 	RPCLOG(8, "maxlen %d, ", netaddr.maxlen);
279 	RPCLOG(8, "name %p\n", (void *)netaddr.buf);
280 
281 	/*
282 	 * now call the proper stuff.
283 	 */
284 	error = clnt_tli_kcreate(configp, &netaddr, KEY_PROG, KEY_VERS,
285 	    0, KEY_NRETRY, cr, &client);
286 
287 	if (error != 0) {
288 		RPCLOG(1, "key_call: clnt_tli_kcreate: error %d\n", error);
289 		switch (error) {
290 		case EINTR:
291 			return (RPC_INTR);
292 		case ETIMEDOUT:
293 			return (RPC_TIMEDOUT);
294 		default:
295 			return (RPC_FAILED);	/* XXX */
296 		}
297 	}
298 
299 	auth_destroy(client->cl_auth);
300 	client->cl_auth = authloopback_create();
301 	if (client->cl_auth == NULL) {
302 		clnt_destroy(client);
303 		RPCLOG(1, "key_call: authloopback_create: error %d\n", EINTR);
304 		return (RPC_INTR);
305 	}
306 
307 	/* Mask out all signals except SIGHUP, SIGQUIT, and SIGTERM. */
308 	sigintr(&smask, 0);
309 	stat = clnt_call(client, procn, xdr_args, args, xdr_rslt, rslt,
310 	    keytrytimeout);
311 	sigunintr(&smask);
312 
313 	auth_destroy(client->cl_auth);
314 	clnt_destroy(client);
315 	if (stat != RPC_SUCCESS) {
316 		RPCLOG(1, "key_call: keyserver clnt_call failed: stat %d ",
317 		    stat);
318 		RPCLOG(1, "(%s)\n", clnt_sperrno(stat));
319 		RPCLOG0(1, "\n");
320 		return (stat);
321 	}
322 	RPCLOG(8, "key call: (%d) ok\n", procn);
323 	return (RPC_SUCCESS);
324 }
325