2 * Copyright (c) 2009, Sun Microsystems, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * - Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * - Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 * - Neither the name of Sun Microsystems, Inc. nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
33 #include <sys/cdefs.h>
36 * key_call.c, Interface to keyserver
38 * setsecretkey(key) - set your secret key
39 * encryptsessionkey(agent, deskey) - encrypt a session key to talk to agent
40 * decryptsessionkey(agent, deskey) - decrypt ditto
41 * gendeskey(deskey) - generate a secure des key
45 #include <reentrant.h>
52 #include <rpc/auth_unix.h>
53 #include <rpc/key_prot.h>
55 #include <netconfig.h>
56 #include <sys/utsname.h>
60 #include <sys/fcntl.h>
64 #define KEY_TIMEOUT 5 /* per-try timeout in seconds */
65 #define KEY_NRETRY 12 /* number of retries */
68 * Hack to allow the keyserver to use AUTH_DES (for authenticated
69 * NIS+ calls, for example). The only functions that get called
70 * are key_encryptsession_pk, key_decryptsession_pk, and key_gendes.
72 * The approach is to have the keyserver fill in pointers to local
73 * implementations of these functions, and to call those in key_call().
76 cryptkeyres *(*__key_encryptsession_pk_LOCAL)() = 0;
77 cryptkeyres *(*__key_decryptsession_pk_LOCAL)() = 0;
78 des_block *(*__key_gendes_LOCAL)() = 0;
80 static int key_call( u_long, xdrproc_t, void *, xdrproc_t, void *);
83 key_setsecret(secretkey)
84 const char *secretkey;
88 if (!key_call((u_long) KEY_SET, (xdrproc_t)xdr_keybuf,
90 (xdrproc_t)xdr_keystatus, &status)) {
93 if (status != KEY_SUCCESS) {
94 LIBTIRPC_DEBUG(1, ("key_setsecret: set status is nonzero"));
101 /* key_secretkey_is_set() returns 1 if the keyserver has a secret key
102 * stored for the caller's effective uid; it returns 0 otherwise
104 * N.B.: The KEY_NET_GET key call is undocumented. Applications shouldn't
105 * be using it, because it allows them to get the user's secret key.
109 key_secretkey_is_set(void)
111 struct key_netstres kres;
113 memset((void*)&kres, 0, sizeof (kres));
114 if (key_call((u_long) KEY_NET_GET, (xdrproc_t)xdr_void, NULL,
115 (xdrproc_t)xdr_key_netstres, &kres) &&
116 (kres.status == KEY_SUCCESS) &&
117 (kres.key_netstres_u.knet.st_priv_key[0] != 0)) {
118 /* avoid leaving secret key in memory */
119 memset(kres.key_netstres_u.knet.st_priv_key, 0, HEXKEYBYTES);
126 key_encryptsession_pk(remotename, remotekey, deskey)
134 arg.remotename = remotename;
135 arg.remotekey = *remotekey;
136 arg.deskey = *deskey;
137 if (!key_call((u_long)KEY_ENCRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg,
138 (xdrproc_t)xdr_cryptkeyres, &res)) {
141 if (res.status != KEY_SUCCESS) {
142 LIBTIRPC_DEBUG(1, ("key_encryptsession_pk: encrypt status is nonzero"));
145 *deskey = res.cryptkeyres_u.deskey;
150 key_decryptsession_pk(remotename, remotekey, deskey)
158 arg.remotename = remotename;
159 arg.remotekey = *remotekey;
160 arg.deskey = *deskey;
161 if (!key_call((u_long)KEY_DECRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg,
162 (xdrproc_t)xdr_cryptkeyres, &res)) {
165 if (res.status != KEY_SUCCESS) {
166 LIBTIRPC_DEBUG(1, ("key_decryptsession_pk: decrypt status is nonzero"));
169 *deskey = res.cryptkeyres_u.deskey;
174 key_encryptsession(remotename, deskey)
175 const char *remotename;
181 arg.remotename = (char *) remotename;
182 arg.deskey = *deskey;
183 if (!key_call((u_long)KEY_ENCRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg,
184 (xdrproc_t)xdr_cryptkeyres, &res)) {
187 if (res.status != KEY_SUCCESS) {
188 LIBTIRPC_DEBUG(1, ("key_encryptsession: encrypt status is nonzero"));
191 *deskey = res.cryptkeyres_u.deskey;
196 key_decryptsession(remotename, deskey)
197 const char *remotename;
203 arg.remotename = (char *) remotename;
204 arg.deskey = *deskey;
205 if (!key_call((u_long)KEY_DECRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg,
206 (xdrproc_t)xdr_cryptkeyres, &res)) {
209 if (res.status != KEY_SUCCESS) {
210 LIBTIRPC_DEBUG(1, ("key_decryptsession: decrypt status is nonzero"));
213 *deskey = res.cryptkeyres_u.deskey;
221 if (!key_call((u_long)KEY_GEN, (xdrproc_t)xdr_void, NULL,
222 (xdrproc_t)xdr_des_block, key)) {
230 struct key_netstarg *arg;
235 if (!key_call((u_long) KEY_NET_PUT, (xdrproc_t)xdr_key_netstarg, arg,
236 (xdrproc_t)xdr_keystatus, &status)){
240 if (status != KEY_SUCCESS) {
241 LIBTIRPC_DEBUG(1, ("key_setnet: key_setnet status is nonzero"));
249 key_get_conv(pkey, deskey)
255 if (!key_call((u_long) KEY_GET_CONV, (xdrproc_t)xdr_keybuf, pkey,
256 (xdrproc_t)xdr_cryptkeyres, &res)) {
259 if (res.status != KEY_SUCCESS) {
260 LIBTIRPC_DEBUG(1, ("key_get_conv: get_conv status is nonzero"));
263 *deskey = res.cryptkeyres_u.deskey;
267 struct key_call_private {
268 CLIENT *client; /* Client handle */
269 pid_t pid; /* process-id at moment of creation */
270 uid_t uid; /* user-id at last authorization */
272 static struct key_call_private *key_call_private_main = NULL;
275 key_call_destroy(void *vp)
277 struct key_call_private *kcp = (struct key_call_private *)vp;
281 clnt_destroy(kcp->client);
287 * Keep the handle cached. This call may be made quite often.
290 getkeyserv_handle(vers)
294 struct netconfig *nconf;
295 struct netconfig *tpconf;
296 struct key_call_private *kcp = key_call_private_main;
297 struct timeval wait_time;
300 extern thread_key_t key_call_key;
301 extern mutex_t tsd_lock;
303 #define TOTAL_TIMEOUT 30 /* total timeout talking to keyserver */
304 #define TOTAL_TRIES 5 /* Number of tries */
306 if (key_call_key == -1) {
307 mutex_lock(&tsd_lock);
308 if (key_call_key == -1)
309 thr_keycreate(&key_call_key, key_call_destroy);
310 mutex_unlock(&tsd_lock);
312 kcp = (struct key_call_private *)thr_getspecific(key_call_key);
313 if (kcp == (struct key_call_private *)NULL) {
314 kcp = (struct key_call_private *)malloc(sizeof (*kcp));
315 if (kcp == (struct key_call_private *)NULL) {
316 return ((CLIENT *) NULL);
318 thr_setspecific(key_call_key, (void *) kcp);
322 /* if pid has changed, destroy client and rebuild */
323 if (kcp->client != NULL && kcp->pid != getpid()) {
324 clnt_destroy(kcp->client);
328 if (kcp->client != NULL) {
329 /* if uid has changed, build client handle again */
330 if (kcp->uid != geteuid()) {
331 kcp->uid = geteuid();
332 auth_destroy(kcp->client->cl_auth);
333 kcp->client->cl_auth =
334 authsys_create("", kcp->uid, 0, 0, NULL);
335 if (kcp->client->cl_auth == NULL) {
336 clnt_destroy(kcp->client);
338 return ((CLIENT *) NULL);
341 /* Change the version number to the new one */
342 clnt_control(kcp->client, CLSET_VERS, (void *)&vers);
343 return (kcp->client);
345 if (!(localhandle = setnetconfig())) {
346 return ((CLIENT *) NULL);
349 if (uname(&u) == -1) {
350 endnetconfig(localhandle);
351 return ((CLIENT *) NULL);
353 while ((nconf = getnetconfig(localhandle)) != NULL) {
354 if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
356 * We use COTS_ORD here so that the caller can
357 * find out immediately if the server is dead.
359 if (nconf->nc_semantics == NC_TPI_COTS_ORD) {
360 kcp->client = clnt_tp_create(u.nodename,
361 KEY_PROG, vers, nconf);
369 if ((kcp->client == (CLIENT *) NULL) && (tpconf))
370 /* Now, try the CLTS or COTS loopback transport */
371 kcp->client = clnt_tp_create(u.nodename,
372 KEY_PROG, vers, tpconf);
373 endnetconfig(localhandle);
375 if (kcp->client == (CLIENT *) NULL) {
376 return ((CLIENT *) NULL);
378 kcp->uid = geteuid();
380 kcp->client->cl_auth = authsys_create("", kcp->uid, 0, 0, NULL);
381 if (kcp->client->cl_auth == NULL) {
382 clnt_destroy(kcp->client);
384 return ((CLIENT *) NULL);
387 wait_time.tv_sec = TOTAL_TIMEOUT/TOTAL_TRIES;
388 wait_time.tv_usec = 0;
389 (void) clnt_control(kcp->client, CLSET_RETRY_TIMEOUT,
391 if (clnt_control(kcp->client, CLGET_FD, (char *)&fd))
392 fcntl(fd, F_SETFD, 1); /* make it "close on exec" */
394 return (kcp->client);
397 /* returns 0 on failure, 1 on success */
400 key_call(proc, xdr_arg, arg, xdr_rslt, rslt)
408 struct timeval wait_time;
410 if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL) {
412 res = (*__key_encryptsession_pk_LOCAL)(geteuid(), arg);
413 *(cryptkeyres*)rslt = *res;
415 } else if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL) {
417 res = (*__key_decryptsession_pk_LOCAL)(geteuid(), arg);
418 *(cryptkeyres*)rslt = *res;
420 } else if (proc == KEY_GEN && __key_gendes_LOCAL) {
422 res = (*__key_gendes_LOCAL)(geteuid(), 0);
423 *(des_block*)rslt = *res;
427 if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) ||
428 (proc == KEY_NET_GET) || (proc == KEY_NET_PUT) ||
429 (proc == KEY_GET_CONV))
430 clnt = getkeyserv_handle(2); /* talk to version 2 */
432 clnt = getkeyserv_handle(1); /* talk to version 1 */
438 wait_time.tv_sec = TOTAL_TIMEOUT;
439 wait_time.tv_usec = 0;
441 if (clnt_call(clnt, proc, xdr_arg, arg, xdr_rslt, rslt,
442 wait_time) == RPC_SUCCESS) {