/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include /* defined in usr/src/libnsl/rpc/key_call.c */ extern bool_t (*__key_encryptsession_pk_LOCAL)(); extern bool_t (*__key_decryptsession_pk_LOCAL)(); extern bool_t (*__key_gendes_LOCAL)(); #define CLASSIC_PK_DH(k, a) (((k) == 192) && ((a) == 0)) /* * authsys_create_uid(uid_t uid) * * Create SYS (UNIX) style authenticator for the given uid/gid * We don't include suplementary groups, since these are of no * interest for the keyserv operations that we do. */ AUTH * authsys_create_uid(uid_t uid, gid_t gid) { char host[MAX_MACHINE_NAME + 1]; AUTH *res; if (gethostname(host, sizeof (host) - 1) == -1) { syslog(LOG_ERR, "pam_dhkeys: Can't determine hostname: %m"); return (NULL); } host[MAX_MACHINE_NAME] = '\0'; res = authsys_create(host, uid, gid, 0, (gid_t *)NULL); return (res); } /* * my_key_call(proc, xdr_arg, arg, xdr_rslt, rslt, uit, gid) * * my_key_call is a copy of key_call() from libnsl with the * added AUTHSYS rpc credential to make the keyserver use our * REAL UID instead of our EFFECTIVE UID when handling our keys. */ int my_key_call(rpcproc_t proc, xdrproc_t xdr_arg, char *arg, xdrproc_t xdr_rslt, char *rslt, uid_t uid, gid_t gid) { CLIENT *clnt; struct timeval wait_time = {0, 0}; enum clnt_stat status; int vers; if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL) { cryptkeyres res; bool_t r; r = (*__key_encryptsession_pk_LOCAL)(uid, arg, &res); if (r == TRUE) { /* LINTED pointer alignment */ *(cryptkeyres*)rslt = res; return (1); } return (0); } if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL) { cryptkeyres res; bool_t r; r = (*__key_decryptsession_pk_LOCAL)(uid, arg, &res); if (r == TRUE) { /* LINTED pointer alignment */ *(cryptkeyres*)rslt = res; return (1); } return (0); } if (proc == KEY_GEN && __key_gendes_LOCAL) { des_block res; bool_t r; r = (*__key_gendes_LOCAL)(uid, 0, &res); if (r == TRUE) { /* LINTED pointer alignment */ *(des_block*)rslt = res; return (1); } return (0); } if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) || (proc == KEY_NET_GET) || (proc == KEY_NET_PUT) || (proc == KEY_GET_CONV)) vers = 2; /* talk to version 2 */ else vers = 1; /* talk to version 1 */ clnt = clnt_door_create(KEY_PROG, vers, 0); if (clnt == NULL) return (0); clnt->cl_auth = authsys_create_uid(uid, gid); status = CLNT_CALL(clnt, proc, xdr_arg, arg, xdr_rslt, rslt, wait_time); auth_destroy(clnt->cl_auth); clnt_destroy(clnt); return (status == RPC_SUCCESS ? 1 : 0); } int key_setnet_uid(struct key_netstarg *arg, uid_t uid, gid_t gid) { keystatus status; if (!my_key_call((rpcproc_t)KEY_NET_PUT, xdr_key_netstarg, (char *)arg, xdr_keystatus, (char *)&status, uid, gid)) { return (-1); } if (status != KEY_SUCCESS) { return (-1); } return (1); } int key_setnet_g_uid(const char *netname, const char *skey, keylen_t skeylen, const char *pkey, keylen_t pkeylen, algtype_t algtype, uid_t uid, gid_t gid) { key_netstarg3 arg; keystatus status; arg.st_netname = (char *)netname; arg.algtype = algtype; if (skeylen == 0) arg.st_priv_key.keybuf3_len = 0; else arg.st_priv_key.keybuf3_len = skeylen/4 + 1; arg.st_priv_key.keybuf3_val = (char *)skey; if (pkeylen == 0) arg.st_pub_key.keybuf3_len = 0; else arg.st_pub_key.keybuf3_len = pkeylen/4 + 1; arg.st_pub_key.keybuf3_val = (char *)pkey; if (skeylen == 0) { if (pkeylen == 0) { /* debug("keylens are both 0"); */ return (-1); } arg.keylen = pkeylen; } else { if ((pkeylen != 0) && (skeylen != pkeylen)) { /* debug("keylens don't match"); */ return (-1); } arg.keylen = skeylen; } if (CLASSIC_PK_DH(arg.keylen, arg.algtype)) { key_netstarg tmp; if (skeylen != 0) { (void) memcpy(&tmp.st_priv_key, skey, sizeof (tmp.st_priv_key)); } else { (void) memset(&tmp.st_priv_key, 0, sizeof (tmp.st_priv_key)); } if (pkeylen != 0) { (void) memcpy(&tmp.st_pub_key, skey, sizeof (tmp.st_pub_key)); } else { (void) memset(&tmp.st_pub_key, 0, sizeof (tmp.st_pub_key)); } tmp.st_netname = (char *)netname; return (key_setnet_uid(&tmp, uid, gid)); } if (!my_key_call((rpcproc_t)KEY_NET_PUT_3, xdr_key_netstarg3, (char *)&arg, xdr_keystatus, (char *)&status, uid, gid)) { return (-1); } if (status != KEY_SUCCESS) { /* debug("key_setnet3 status is nonzero"); */ return (-1); } return (0); } /* * key_secretkey_is_set_uid() returns 1 if the keyserver has a secret key * stored for the caller's REAL uid; it returns 0 otherwise */ int key_secretkey_is_set_uid(uid_t uid, gid_t gid) { struct key_netstres kres; (void) memset((void*)&kres, 0, sizeof (kres)); if (my_key_call((rpcproc_t)KEY_NET_GET, xdr_void, (char *)NULL, xdr_key_netstres, (char *)&kres, uid, gid) && (kres.status == KEY_SUCCESS) && (kres.key_netstres_u.knet.st_priv_key[0] != 0)) { /* avoid leaving secret key in memory */ (void) memset(kres.key_netstres_u.knet.st_priv_key, 0, HEXKEYBYTES); xdr_free(xdr_key_netstres, (char *)&kres); return (1); } return (0); } int key_removesecret_g_uid(uid_t uid, gid_t gid) { keystatus status; if (my_key_call((rpcproc_t)KEY_CLEAR_3, xdr_void, (char *)NULL, xdr_keystatus, (char *)&status, uid, gid)) return (-1); if (status != KEY_SUCCESS) return (-1); return (0); }