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