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