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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * Portions of this source code were derived from Berkeley 4.3 BSD 31 * under license from the Regents of the University of California. 32 */ 33 34 #pragma ident "%Z%%M% %I% %E% SMI" 35 36 /* 37 * key_call.c, Interface to keyserver 38 * key_encryptsession(agent, deskey, cr)-encrypt a session key to talk to agent 39 * key_decryptsession(agent, deskey) - decrypt ditto 40 * key_gendes(deskey) - generate a secure des key 41 * key_getnetname(netname, cr) - get the netname from the keyserv 42 * netname2user(...) - get unix credential for given name (kernel only) 43 */ 44 45 #include <sys/param.h> 46 #include <sys/types.h> 47 #include <sys/time.h> 48 #include <sys/systm.h> 49 #include <sys/user.h> 50 #include <sys/proc.h> 51 #include <sys/pathname.h> 52 #include <sys/sysmacros.h> 53 #include <sys/vnode.h> 54 #include <sys/uio.h> 55 #include <sys/debug.h> 56 #include <sys/utsname.h> 57 #include <sys/cmn_err.h> 58 59 #include <rpc/rpc.h> 60 #include <rpc/key_prot.h> 61 62 #define KEY_TIMEOUT 30 /* per-try timeout in seconds */ 63 #define KEY_NRETRY 6 /* number of retries */ 64 65 struct auth_globals { 66 struct knetconfig auth_config; 67 char auth_keyname[SYS_NMLN+16]; 68 }; 69 70 static struct timeval keytrytimeout = { KEY_TIMEOUT, 0 }; 71 72 static enum clnt_stat key_call(rpcproc_t, xdrproc_t, char *, xdrproc_t, char *, 73 cred_t *); 74 75 /* ARGSUSED */ 76 void * 77 auth_zone_init(zoneid_t zoneid) 78 { 79 struct auth_globals *authg; 80 81 authg = kmem_zalloc(sizeof (*authg), KM_SLEEP); 82 return (authg); 83 } 84 85 /* ARGSUSED */ 86 void 87 auth_zone_fini(zoneid_t zoneid, void *data) 88 { 89 struct auth_globals *authg = data; 90 91 kmem_free(authg, sizeof (*authg)); 92 } 93 94 enum clnt_stat 95 key_encryptsession(char *remotename, des_block *deskey, cred_t *cr) 96 { 97 cryptkeyarg arg; 98 cryptkeyres res; 99 enum clnt_stat stat; 100 101 RPCLOG(8, "key_encryptsession(%s, ", remotename); 102 RPCLOG(8, "%x", *(uint32_t *)deskey); 103 RPCLOG(8, "%x)\n", *(((uint32_t *)(deskey))+1)); 104 105 arg.remotename = remotename; 106 arg.deskey = *deskey; 107 if ((stat = key_call(KEY_ENCRYPT, xdr_cryptkeyarg, (char *)&arg, 108 xdr_cryptkeyres, (char *)&res, cr)) != RPC_SUCCESS) { 109 RPCLOG(1, "key_encryptsession(%d, ", (int)crgetuid(cr)); 110 RPCLOG(1, "%s): ", remotename); 111 RPCLOG(1, "rpc status %d ", stat); 112 RPCLOG(1, "(%s)\n", clnt_sperrno(stat)); 113 return (stat); 114 } 115 116 if (res.status != KEY_SUCCESS) { 117 RPCLOG(1, "key_encryptsession(%d, ", (int)crgetuid(cr)); 118 RPCLOG(1, "%s): ", remotename); 119 RPCLOG(1, "key status %d\n", res.status); 120 return (RPC_FAILED); /* XXX */ 121 } 122 *deskey = res.cryptkeyres_u.deskey; 123 return (RPC_SUCCESS); 124 } 125 126 enum clnt_stat 127 key_decryptsession(char *remotename, des_block *deskey) 128 { 129 cryptkeyarg arg; 130 cryptkeyres res; 131 enum clnt_stat stat; 132 133 RPCLOG(8, "key_decryptsession(%s, ", remotename); 134 RPCLOG(2, "%x", *(uint32_t *)deskey); 135 RPCLOG(2, "%x)\n", *(((uint32_t *)(deskey))+1)); 136 137 arg.remotename = remotename; 138 arg.deskey = *deskey; 139 if ((stat = key_call(KEY_DECRYPT, xdr_cryptkeyarg, (char *)&arg, 140 xdr_cryptkeyres, (char *)&res, kcred)) != RPC_SUCCESS) { 141 RPCLOG(1, "key_decryptsession(%s): ", remotename); 142 RPCLOG(1, "rpc status %d ", stat); 143 RPCLOG(1, "(%s)\n", clnt_sperrno(stat)); 144 return (stat); 145 } 146 147 if (res.status != KEY_SUCCESS) { 148 RPCLOG(1, "key_decryptsession(%s): ", remotename); 149 RPCLOG(1, "key status %d\n", res.status); 150 return (RPC_FAILED); /* XXX */ 151 } 152 *deskey = res.cryptkeyres_u.deskey; 153 return (RPC_SUCCESS); 154 } 155 156 enum clnt_stat 157 key_gendes(des_block *key) 158 { 159 160 return (key_call(KEY_GEN, xdr_void, NULL, xdr_des_block, (char *)key, 161 CRED())); 162 } 163 164 /* 165 * Call up to keyserv to get the netname of the client based 166 * on its uid. The netname is written into the string that "netname" 167 * points to; the caller is responsible for ensuring that sufficient space 168 * is available. 169 */ 170 enum clnt_stat 171 key_getnetname(netname, cr) 172 char *netname; 173 cred_t *cr; 174 { 175 key_netstres kres; 176 enum clnt_stat stat; 177 178 /* 179 * Look up the keyserv interface routines to see if 180 * netname is stored there. 181 */ 182 kres.key_netstres_u.knet.st_netname = netname; 183 if ((stat = key_call((rpcproc_t)KEY_NET_GET, xdr_void, NULL, 184 xdr_key_netstres, (char *)&kres, cr)) != RPC_SUCCESS) { 185 RPCLOG(1, "key_getnetname(%d): ", (int)crgetuid(cr)); 186 RPCLOG(1, "rpc status %d ", stat); 187 RPCLOG(1, "(%s)\n", clnt_sperrno(stat)); 188 return (stat); 189 } 190 191 if (kres.status != KEY_SUCCESS) { 192 RPCLOG(1, "key_getnetname(%d): ", (int)crgetuid(cr)); 193 RPCLOG(1, "key status %d\n", kres.status); 194 return (RPC_FAILED); 195 } 196 197 return (RPC_SUCCESS); 198 } 199 200 enum clnt_stat 201 netname2user(char *name, uid_t *uid, gid_t *gid, int *len, gid_t *groups) 202 { 203 struct getcredres res; 204 enum clnt_stat stat; 205 206 res.getcredres_u.cred.gids.gids_val = (uint_t *)groups; 207 if ((stat = key_call(KEY_GETCRED, xdr_netnamestr, (char *)&name, 208 xdr_getcredres, (char *)&res, CRED())) != RPC_SUCCESS) { 209 RPCLOG(1, "netname2user(%s): ", name); 210 RPCLOG(1, "rpc status %d ", stat); 211 RPCLOG(1, "(%s)\n", clnt_sperrno(stat)); 212 return (stat); 213 } 214 215 if (res.status != KEY_SUCCESS) { 216 RPCLOG(1, "netname2user(%s): ", name); 217 RPCLOG(1, "key status %d\n", res.status); 218 return (RPC_FAILED); /* XXX */ 219 } 220 *uid = res.getcredres_u.cred.uid; 221 *gid = res.getcredres_u.cred.gid; 222 *len = res.getcredres_u.cred.gids.gids_len; 223 return (RPC_SUCCESS); 224 } 225 226 #define NC_LOOPBACK "loopback" /* XXX */ 227 char loopback_name[] = NC_LOOPBACK; 228 229 static enum clnt_stat 230 key_call(rpcproc_t procn, xdrproc_t xdr_args, caddr_t args, 231 xdrproc_t xdr_rslt, caddr_t rslt, cred_t *cr) 232 { 233 struct netbuf netaddr; 234 CLIENT *client; 235 enum clnt_stat stat; 236 vnode_t *vp; 237 int error; 238 struct auth_globals *authg; 239 char *keyname; 240 struct knetconfig *configp; 241 k_sigset_t smask; 242 243 authg = zone_getspecific(auth_zone_key, curproc->p_zone); 244 keyname = authg->auth_keyname; 245 configp = &authg->auth_config; 246 247 /* 248 * Using a global here is obviously busted and fraught with danger. 249 */ 250 (void) strcpy(keyname, uts_nodename()); 251 netaddr.len = strlen(keyname); 252 (void) strcpy(&keyname[netaddr.len], ".keyserv"); 253 254 netaddr.buf = keyname; 255 /* 256 * 8 = strlen(".keyserv"); 257 */ 258 netaddr.len = netaddr.maxlen = netaddr.len + 8; 259 260 /* 261 * filch a knetconfig structure. 262 */ 263 if (configp->knc_rdev == 0) { 264 if ((error = lookupname("/dev/ticlts", UIO_SYSSPACE, 265 FOLLOW, NULLVPP, &vp)) != 0) { 266 RPCLOG(1, "key_call: lookupname: %d\n", error); 267 return (RPC_UNKNOWNPROTO); 268 } 269 configp->knc_rdev = vp->v_rdev; 270 configp->knc_protofmly = loopback_name; 271 VN_RELE(vp); 272 } 273 configp->knc_semantics = NC_TPI_CLTS; 274 RPCLOG(8, "key_call: procn %d, ", procn); 275 RPCLOG(8, "rdev %lx, ", configp->knc_rdev); 276 RPCLOG(8, "len %d, ", netaddr.len); 277 RPCLOG(8, "maxlen %d, ", netaddr.maxlen); 278 RPCLOG(8, "name %p\n", (void *)netaddr.buf); 279 280 /* 281 * now call the proper stuff. 282 */ 283 error = clnt_tli_kcreate(configp, &netaddr, KEY_PROG, KEY_VERS, 284 0, KEY_NRETRY, cr, &client); 285 286 if (error != 0) { 287 RPCLOG(1, "key_call: clnt_tli_kcreate: error %d\n", error); 288 switch (error) { 289 case EINTR: 290 return (RPC_INTR); 291 case ETIMEDOUT: 292 return (RPC_TIMEDOUT); 293 default: 294 return (RPC_FAILED); /* XXX */ 295 } 296 } 297 298 auth_destroy(client->cl_auth); 299 client->cl_auth = authloopback_create(); 300 if (client->cl_auth == NULL) { 301 clnt_destroy(client); 302 RPCLOG(1, "key_call: authloopback_create: error %d\n", EINTR); 303 return (RPC_INTR); 304 } 305 306 /* Mask out all signals except SIGHUP, SIGQUIT, and SIGTERM. */ 307 sigintr(&smask, 0); 308 stat = clnt_call(client, procn, xdr_args, args, xdr_rslt, rslt, 309 keytrytimeout); 310 sigunintr(&smask); 311 312 auth_destroy(client->cl_auth); 313 clnt_destroy(client); 314 if (stat != RPC_SUCCESS) { 315 RPCLOG(1, "key_call: keyserver clnt_call failed: stat %d ", 316 stat); 317 RPCLOG(1, "(%s)\n", clnt_sperrno(stat)); 318 RPCLOG0(1, "\n"); 319 return (stat); 320 } 321 RPCLOG(8, "key call: (%d) ok\n", procn); 322 return (RPC_SUCCESS); 323 } 324