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 2005 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 <sys/types.h>
30 #include <unistd.h>
31 #include <rpc/rpc.h>
32 #include <rpc/key_prot.h>
33 #include <rpcsvc/nis_dhext.h>
34 #include <syslog.h>
35 #include <note.h>
36 
37 /* defined in usr/src/libnsl/rpc/key_call.c */
38 extern bool_t (*__key_encryptsession_pk_LOCAL)();
39 extern bool_t (*__key_decryptsession_pk_LOCAL)();
40 extern bool_t (*__key_gendes_LOCAL)();
41 
42 #define	CLASSIC_PK_DH(k, a)	(((k) == 192) && ((a) == 0))
43 
44 /*
45  * authsys_create_uid(uid_t uid)
46  *
47  * Create SYS (UNIX) style authenticator for the given uid/gid
48  * We don't include suplementary groups, since these are of no
49  * interest for the keyserv operations that we do.
50  */
51 AUTH *
52 authsys_create_uid(uid_t uid, gid_t gid)
53 {
54 	char	host[MAX_MACHINE_NAME + 1];
55 	AUTH	*res;
56 
57 	if (gethostname(host, sizeof (host) - 1) == -1) {
58 		syslog(LOG_ERR,
59 			"pam_dhkeys: Can't determine hostname: %m");
60 		return (NULL);
61 	}
62 	host[MAX_MACHINE_NAME] = '\0';
63 
64 	res = authsys_create(host, uid, gid, 0, (gid_t *)NULL);
65 
66 	return (res);
67 }
68 
69 /*
70  * my_key_call(proc, xdr_arg, arg, xdr_rslt, rslt, uit, gid)
71  *
72  * my_key_call is a copy of key_call() from libnsl with the
73  * added AUTHSYS rpc credential to make the keyserver use our
74  * REAL UID instead of our EFFECTIVE UID when handling our keys.
75  */
76 int
77 my_key_call(rpcproc_t proc, xdrproc_t xdr_arg, char *arg,
78 		xdrproc_t xdr_rslt, char *rslt, uid_t uid, gid_t gid)
79 {
80 	CLIENT		*clnt;
81 	struct timeval	wait_time = {0, 0};
82 	enum clnt_stat	status;
83 	int		vers;
84 
85 	if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL) {
86 		cryptkeyres res;
87 		bool_t r;
88 		r = (*__key_encryptsession_pk_LOCAL)(uid, arg, &res);
89 		if (r == TRUE) {
90 			/* LINTED pointer alignment */
91 			*(cryptkeyres*)rslt = res;
92 			return (1);
93 		}
94 		return (0);
95 	}
96 	if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL) {
97 		cryptkeyres res;
98 		bool_t r;
99 		r = (*__key_decryptsession_pk_LOCAL)(uid, arg, &res);
100 		if (r == TRUE) {
101 			/* LINTED pointer alignment */
102 			*(cryptkeyres*)rslt = res;
103 			return (1);
104 		}
105 		return (0);
106 	}
107 	if (proc == KEY_GEN && __key_gendes_LOCAL) {
108 		des_block res;
109 		bool_t r;
110 		r = (*__key_gendes_LOCAL)(uid, 0, &res);
111 		if (r == TRUE) {
112 			/* LINTED pointer alignment */
113 			*(des_block*)rslt = res;
114 			return (1);
115 		}
116 		return (0);
117 	}
118 
119 	if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) ||
120 	    (proc == KEY_NET_GET) || (proc == KEY_NET_PUT) ||
121 	    (proc == KEY_GET_CONV))
122 		vers = 2;	/* talk to version 2 */
123 	else
124 		vers = 1;	/* talk to version 1 */
125 
126 	clnt = clnt_door_create(KEY_PROG, vers, 0);
127 
128 	if (clnt == NULL)
129 		return (0);
130 
131 	clnt->cl_auth = authsys_create_uid(uid, gid);
132 
133 	status = CLNT_CALL(clnt, proc, xdr_arg, arg, xdr_rslt,
134 			rslt, wait_time);
135 
136 	auth_destroy(clnt->cl_auth);
137 	clnt_destroy(clnt);
138 
139 	return (status == RPC_SUCCESS ? 1 : 0);
140 }
141 
142 int
143 key_setnet_uid(struct key_netstarg *arg, uid_t uid, gid_t gid)
144 {
145 	keystatus status;
146 
147 	if (!my_key_call((rpcproc_t)KEY_NET_PUT, xdr_key_netstarg,
148 	    (char *)arg, xdr_keystatus, (char *)&status, uid, gid)) {
149 		return (-1);
150 	}
151 	if (status != KEY_SUCCESS) {
152 		return (-1);
153 	}
154 
155 	return (1);
156 }
157 
158 int
159 key_setnet_g_uid(const char *netname, const char *skey, keylen_t skeylen,
160     const char *pkey, keylen_t pkeylen, algtype_t algtype,
161     uid_t uid, gid_t gid)
162 {
163 	key_netstarg3 arg;
164 	keystatus status;
165 
166 	arg.st_netname = (char *)netname;
167 	arg.algtype = algtype;
168 
169 	if (skeylen == 0)
170 		arg.st_priv_key.keybuf3_len = 0;
171 	else
172 		arg.st_priv_key.keybuf3_len = skeylen/4 + 1;
173 
174 	arg.st_priv_key.keybuf3_val = (char *)skey;
175 
176 	if (pkeylen == 0)
177 		arg.st_pub_key.keybuf3_len = 0;
178 	else
179 		arg.st_pub_key.keybuf3_len = pkeylen/4 + 1;
180 
181 	arg.st_pub_key.keybuf3_val = (char *)pkey;
182 
183 	if (skeylen == 0) {
184 		if (pkeylen == 0) {
185 			/* debug("keylens are both 0"); */
186 			return (-1);
187 		}
188 		arg.keylen = pkeylen;
189 	} else {
190 		if ((pkeylen != 0) && (skeylen != pkeylen)) {
191 			/* debug("keylens don't match"); */
192 			return (-1);
193 		}
194 		arg.keylen = skeylen;
195 	}
196 
197 	if (CLASSIC_PK_DH(arg.keylen, arg.algtype)) {
198 		key_netstarg tmp;
199 
200 		if (skeylen != 0) {
201 			(void) memcpy(&tmp.st_priv_key, skey,
202 				sizeof (tmp.st_priv_key));
203 		} else {
204 			(void) memset(&tmp.st_priv_key, 0,
205 			    sizeof (tmp.st_priv_key));
206 		}
207 		if (pkeylen != 0) {
208 			(void) memcpy(&tmp.st_pub_key, skey,
209 			    sizeof (tmp.st_pub_key));
210 		} else {
211 			(void) memset(&tmp.st_pub_key, 0,
212 			    sizeof (tmp.st_pub_key));
213 		}
214 		tmp.st_netname = (char *)netname;
215 		return (key_setnet_uid(&tmp, uid, gid));
216 	}
217 
218 	if (!my_key_call((rpcproc_t)KEY_NET_PUT_3, xdr_key_netstarg3,
219 	    (char *)&arg, xdr_keystatus, (char *)&status, uid, gid)) {
220 		return (-1);
221 	}
222 
223 	if (status != KEY_SUCCESS) {
224 		/* debug("key_setnet3 status is nonzero"); */
225 		return (-1);
226 	}
227 	return (0);
228 }
229 
230 
231 /*
232  * key_secretkey_is_set_uid() returns 1 if the keyserver has a secret key
233  * stored for the caller's REAL uid; it returns 0 otherwise
234  */
235 int
236 key_secretkey_is_set_uid(uid_t uid, gid_t gid)
237 {
238 	struct key_netstres 	kres;
239 
240 	(void) memset((void*)&kres, 0, sizeof (kres));
241 
242 	if (my_key_call((rpcproc_t)KEY_NET_GET, xdr_void, (char *)NULL,
243 			xdr_key_netstres, (char *)&kres, uid, gid) &&
244 	    (kres.status == KEY_SUCCESS) &&
245 	    (kres.key_netstres_u.knet.st_priv_key[0] != 0)) {
246 		/* avoid leaving secret key in memory */
247 		(void) memset(kres.key_netstres_u.knet.st_priv_key, 0,
248 		    HEXKEYBYTES);
249 		xdr_free(xdr_key_netstres, (char *)&kres);
250 		return (1);
251 	}
252 	return (0);
253 }
254 
255 int
256 key_removesecret_g_uid(uid_t uid, gid_t gid)
257 {
258 	keystatus status;
259 
260 	if (my_key_call((rpcproc_t)KEY_CLEAR_3, xdr_void, (char *)NULL,
261 	    xdr_keystatus, (char *)&status, uid, gid))
262 		return (-1);
263 
264 	if (status != KEY_SUCCESS)
265 		return (-1);
266 
267 	return (0);
268 }
269