Home | History | Annotate | Download | only in dhkeys
      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