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