10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*4321Scasper * Common Development and Distribution License (the "License"). 6*4321Scasper * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*4321Scasper * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 270Sstevel@tonic-gate /* All Rights Reserved */ 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD 310Sstevel@tonic-gate * under license from the Regents of the University of California. 320Sstevel@tonic-gate */ 330Sstevel@tonic-gate 340Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 350Sstevel@tonic-gate 360Sstevel@tonic-gate /* 370Sstevel@tonic-gate * key_call.c, Interface to keyserver 380Sstevel@tonic-gate * key_encryptsession(agent, deskey, cr)-encrypt a session key to talk to agent 390Sstevel@tonic-gate * key_decryptsession(agent, deskey) - decrypt ditto 400Sstevel@tonic-gate * key_gendes(deskey) - generate a secure des key 410Sstevel@tonic-gate * key_getnetname(netname, cr) - get the netname from the keyserv 420Sstevel@tonic-gate * netname2user(...) - get unix credential for given name (kernel only) 430Sstevel@tonic-gate */ 440Sstevel@tonic-gate 450Sstevel@tonic-gate #include <sys/param.h> 460Sstevel@tonic-gate #include <sys/types.h> 470Sstevel@tonic-gate #include <sys/time.h> 480Sstevel@tonic-gate #include <sys/systm.h> 490Sstevel@tonic-gate #include <sys/user.h> 500Sstevel@tonic-gate #include <sys/proc.h> 510Sstevel@tonic-gate #include <sys/pathname.h> 520Sstevel@tonic-gate #include <sys/sysmacros.h> 530Sstevel@tonic-gate #include <sys/vnode.h> 540Sstevel@tonic-gate #include <sys/uio.h> 550Sstevel@tonic-gate #include <sys/debug.h> 560Sstevel@tonic-gate #include <sys/utsname.h> 570Sstevel@tonic-gate #include <sys/cmn_err.h> 580Sstevel@tonic-gate 590Sstevel@tonic-gate #include <rpc/rpc.h> 600Sstevel@tonic-gate #include <rpc/key_prot.h> 610Sstevel@tonic-gate 620Sstevel@tonic-gate #define KEY_TIMEOUT 30 /* per-try timeout in seconds */ 630Sstevel@tonic-gate #define KEY_NRETRY 6 /* number of retries */ 640Sstevel@tonic-gate 650Sstevel@tonic-gate struct auth_globals { 660Sstevel@tonic-gate struct knetconfig auth_config; 670Sstevel@tonic-gate char auth_keyname[SYS_NMLN+16]; 680Sstevel@tonic-gate }; 690Sstevel@tonic-gate 700Sstevel@tonic-gate static struct timeval keytrytimeout = { KEY_TIMEOUT, 0 }; 710Sstevel@tonic-gate 720Sstevel@tonic-gate static enum clnt_stat key_call(rpcproc_t, xdrproc_t, char *, xdrproc_t, char *, 730Sstevel@tonic-gate cred_t *); 740Sstevel@tonic-gate 750Sstevel@tonic-gate /* ARGSUSED */ 760Sstevel@tonic-gate void * 770Sstevel@tonic-gate auth_zone_init(zoneid_t zoneid) 780Sstevel@tonic-gate { 790Sstevel@tonic-gate struct auth_globals *authg; 800Sstevel@tonic-gate 810Sstevel@tonic-gate authg = kmem_zalloc(sizeof (*authg), KM_SLEEP); 820Sstevel@tonic-gate return (authg); 830Sstevel@tonic-gate } 840Sstevel@tonic-gate 850Sstevel@tonic-gate /* ARGSUSED */ 860Sstevel@tonic-gate void 870Sstevel@tonic-gate auth_zone_fini(zoneid_t zoneid, void *data) 880Sstevel@tonic-gate { 890Sstevel@tonic-gate struct auth_globals *authg = data; 900Sstevel@tonic-gate 910Sstevel@tonic-gate kmem_free(authg, sizeof (*authg)); 920Sstevel@tonic-gate } 930Sstevel@tonic-gate 940Sstevel@tonic-gate enum clnt_stat 950Sstevel@tonic-gate key_encryptsession(char *remotename, des_block *deskey, cred_t *cr) 960Sstevel@tonic-gate { 970Sstevel@tonic-gate cryptkeyarg arg; 980Sstevel@tonic-gate cryptkeyres res; 990Sstevel@tonic-gate enum clnt_stat stat; 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate RPCLOG(8, "key_encryptsession(%s, ", remotename); 1020Sstevel@tonic-gate RPCLOG(8, "%x", *(uint32_t *)deskey); 1030Sstevel@tonic-gate RPCLOG(8, "%x)\n", *(((uint32_t *)(deskey))+1)); 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate arg.remotename = remotename; 1060Sstevel@tonic-gate arg.deskey = *deskey; 1070Sstevel@tonic-gate if ((stat = key_call(KEY_ENCRYPT, xdr_cryptkeyarg, (char *)&arg, 1080Sstevel@tonic-gate xdr_cryptkeyres, (char *)&res, cr)) != RPC_SUCCESS) { 1090Sstevel@tonic-gate RPCLOG(1, "key_encryptsession(%d, ", (int)crgetuid(cr)); 1100Sstevel@tonic-gate RPCLOG(1, "%s): ", remotename); 1110Sstevel@tonic-gate RPCLOG(1, "rpc status %d ", stat); 1120Sstevel@tonic-gate RPCLOG(1, "(%s)\n", clnt_sperrno(stat)); 1130Sstevel@tonic-gate return (stat); 1140Sstevel@tonic-gate } 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate if (res.status != KEY_SUCCESS) { 1170Sstevel@tonic-gate RPCLOG(1, "key_encryptsession(%d, ", (int)crgetuid(cr)); 1180Sstevel@tonic-gate RPCLOG(1, "%s): ", remotename); 1190Sstevel@tonic-gate RPCLOG(1, "key status %d\n", res.status); 1200Sstevel@tonic-gate return (RPC_FAILED); /* XXX */ 1210Sstevel@tonic-gate } 1220Sstevel@tonic-gate *deskey = res.cryptkeyres_u.deskey; 1230Sstevel@tonic-gate return (RPC_SUCCESS); 1240Sstevel@tonic-gate } 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate enum clnt_stat 1270Sstevel@tonic-gate key_decryptsession(char *remotename, des_block *deskey) 1280Sstevel@tonic-gate { 1290Sstevel@tonic-gate cryptkeyarg arg; 1300Sstevel@tonic-gate cryptkeyres res; 1310Sstevel@tonic-gate enum clnt_stat stat; 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate RPCLOG(8, "key_decryptsession(%s, ", remotename); 1340Sstevel@tonic-gate RPCLOG(2, "%x", *(uint32_t *)deskey); 1350Sstevel@tonic-gate RPCLOG(2, "%x)\n", *(((uint32_t *)(deskey))+1)); 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate arg.remotename = remotename; 1380Sstevel@tonic-gate arg.deskey = *deskey; 1390Sstevel@tonic-gate if ((stat = key_call(KEY_DECRYPT, xdr_cryptkeyarg, (char *)&arg, 1400Sstevel@tonic-gate xdr_cryptkeyres, (char *)&res, kcred)) != RPC_SUCCESS) { 1410Sstevel@tonic-gate RPCLOG(1, "key_decryptsession(%s): ", remotename); 1420Sstevel@tonic-gate RPCLOG(1, "rpc status %d ", stat); 1430Sstevel@tonic-gate RPCLOG(1, "(%s)\n", clnt_sperrno(stat)); 1440Sstevel@tonic-gate return (stat); 1450Sstevel@tonic-gate } 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate if (res.status != KEY_SUCCESS) { 1480Sstevel@tonic-gate RPCLOG(1, "key_decryptsession(%s): ", remotename); 1490Sstevel@tonic-gate RPCLOG(1, "key status %d\n", res.status); 1500Sstevel@tonic-gate return (RPC_FAILED); /* XXX */ 1510Sstevel@tonic-gate } 1520Sstevel@tonic-gate *deskey = res.cryptkeyres_u.deskey; 1530Sstevel@tonic-gate return (RPC_SUCCESS); 1540Sstevel@tonic-gate } 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate enum clnt_stat 1570Sstevel@tonic-gate key_gendes(des_block *key) 1580Sstevel@tonic-gate { 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate return (key_call(KEY_GEN, xdr_void, NULL, xdr_des_block, (char *)key, 1610Sstevel@tonic-gate CRED())); 1620Sstevel@tonic-gate } 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate /* 1650Sstevel@tonic-gate * Call up to keyserv to get the netname of the client based 1660Sstevel@tonic-gate * on its uid. The netname is written into the string that "netname" 1670Sstevel@tonic-gate * points to; the caller is responsible for ensuring that sufficient space 1680Sstevel@tonic-gate * is available. 1690Sstevel@tonic-gate */ 1700Sstevel@tonic-gate enum clnt_stat 1710Sstevel@tonic-gate key_getnetname(netname, cr) 1720Sstevel@tonic-gate char *netname; 1730Sstevel@tonic-gate cred_t *cr; 1740Sstevel@tonic-gate { 1750Sstevel@tonic-gate key_netstres kres; 1760Sstevel@tonic-gate enum clnt_stat stat; 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate /* 1790Sstevel@tonic-gate * Look up the keyserv interface routines to see if 1800Sstevel@tonic-gate * netname is stored there. 1810Sstevel@tonic-gate */ 1820Sstevel@tonic-gate kres.key_netstres_u.knet.st_netname = netname; 1830Sstevel@tonic-gate if ((stat = key_call((rpcproc_t)KEY_NET_GET, xdr_void, NULL, 1840Sstevel@tonic-gate xdr_key_netstres, (char *)&kres, cr)) != RPC_SUCCESS) { 1850Sstevel@tonic-gate RPCLOG(1, "key_getnetname(%d): ", (int)crgetuid(cr)); 1860Sstevel@tonic-gate RPCLOG(1, "rpc status %d ", stat); 1870Sstevel@tonic-gate RPCLOG(1, "(%s)\n", clnt_sperrno(stat)); 1880Sstevel@tonic-gate return (stat); 1890Sstevel@tonic-gate } 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate if (kres.status != KEY_SUCCESS) { 1920Sstevel@tonic-gate RPCLOG(1, "key_getnetname(%d): ", (int)crgetuid(cr)); 1930Sstevel@tonic-gate RPCLOG(1, "key status %d\n", kres.status); 1940Sstevel@tonic-gate return (RPC_FAILED); 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate return (RPC_SUCCESS); 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate enum clnt_stat 201*4321Scasper netname2user(char *name, uid_t *uid, gid_t *gid, int *len, gid_t *groups) 2020Sstevel@tonic-gate { 2030Sstevel@tonic-gate struct getcredres res; 2040Sstevel@tonic-gate enum clnt_stat stat; 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate res.getcredres_u.cred.gids.gids_val = (uint_t *)groups; 2070Sstevel@tonic-gate if ((stat = key_call(KEY_GETCRED, xdr_netnamestr, (char *)&name, 2080Sstevel@tonic-gate xdr_getcredres, (char *)&res, CRED())) != RPC_SUCCESS) { 2090Sstevel@tonic-gate RPCLOG(1, "netname2user(%s): ", name); 2100Sstevel@tonic-gate RPCLOG(1, "rpc status %d ", stat); 2110Sstevel@tonic-gate RPCLOG(1, "(%s)\n", clnt_sperrno(stat)); 2120Sstevel@tonic-gate return (stat); 2130Sstevel@tonic-gate } 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate if (res.status != KEY_SUCCESS) { 2160Sstevel@tonic-gate RPCLOG(1, "netname2user(%s): ", name); 2170Sstevel@tonic-gate RPCLOG(1, "key status %d\n", res.status); 2180Sstevel@tonic-gate return (RPC_FAILED); /* XXX */ 2190Sstevel@tonic-gate } 2200Sstevel@tonic-gate *uid = res.getcredres_u.cred.uid; 2210Sstevel@tonic-gate *gid = res.getcredres_u.cred.gid; 2220Sstevel@tonic-gate *len = res.getcredres_u.cred.gids.gids_len; 2230Sstevel@tonic-gate return (RPC_SUCCESS); 2240Sstevel@tonic-gate } 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate #define NC_LOOPBACK "loopback" /* XXX */ 2270Sstevel@tonic-gate char loopback_name[] = NC_LOOPBACK; 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate static enum clnt_stat 2300Sstevel@tonic-gate key_call(rpcproc_t procn, xdrproc_t xdr_args, caddr_t args, 2310Sstevel@tonic-gate xdrproc_t xdr_rslt, caddr_t rslt, cred_t *cr) 2320Sstevel@tonic-gate { 2330Sstevel@tonic-gate struct netbuf netaddr; 2340Sstevel@tonic-gate CLIENT *client; 2350Sstevel@tonic-gate enum clnt_stat stat; 2360Sstevel@tonic-gate vnode_t *vp; 2370Sstevel@tonic-gate int error; 2380Sstevel@tonic-gate struct auth_globals *authg; 2390Sstevel@tonic-gate char *keyname; 2400Sstevel@tonic-gate struct knetconfig *configp; 2410Sstevel@tonic-gate k_sigset_t smask; 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate authg = zone_getspecific(auth_zone_key, curproc->p_zone); 2440Sstevel@tonic-gate keyname = authg->auth_keyname; 2450Sstevel@tonic-gate configp = &authg->auth_config; 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate /* 2480Sstevel@tonic-gate * Using a global here is obviously busted and fraught with danger. 2490Sstevel@tonic-gate */ 2500Sstevel@tonic-gate (void) strcpy(keyname, uts_nodename()); 2510Sstevel@tonic-gate netaddr.len = strlen(keyname); 2520Sstevel@tonic-gate (void) strcpy(&keyname[netaddr.len], ".keyserv"); 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate netaddr.buf = keyname; 2550Sstevel@tonic-gate /* 2560Sstevel@tonic-gate * 8 = strlen(".keyserv"); 2570Sstevel@tonic-gate */ 2580Sstevel@tonic-gate netaddr.len = netaddr.maxlen = netaddr.len + 8; 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate /* 2610Sstevel@tonic-gate * filch a knetconfig structure. 2620Sstevel@tonic-gate */ 2630Sstevel@tonic-gate if (configp->knc_rdev == 0) { 2640Sstevel@tonic-gate if ((error = lookupname("/dev/ticlts", UIO_SYSSPACE, 2650Sstevel@tonic-gate FOLLOW, NULLVPP, &vp)) != 0) { 2660Sstevel@tonic-gate RPCLOG(1, "key_call: lookupname: %d\n", error); 2670Sstevel@tonic-gate return (RPC_UNKNOWNPROTO); 2680Sstevel@tonic-gate } 2690Sstevel@tonic-gate configp->knc_rdev = vp->v_rdev; 2700Sstevel@tonic-gate configp->knc_protofmly = loopback_name; 2710Sstevel@tonic-gate VN_RELE(vp); 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate configp->knc_semantics = NC_TPI_CLTS; 2740Sstevel@tonic-gate RPCLOG(8, "key_call: procn %d, ", procn); 2750Sstevel@tonic-gate RPCLOG(8, "rdev %lx, ", configp->knc_rdev); 2760Sstevel@tonic-gate RPCLOG(8, "len %d, ", netaddr.len); 2770Sstevel@tonic-gate RPCLOG(8, "maxlen %d, ", netaddr.maxlen); 2780Sstevel@tonic-gate RPCLOG(8, "name %p\n", (void *)netaddr.buf); 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate /* 2810Sstevel@tonic-gate * now call the proper stuff. 2820Sstevel@tonic-gate */ 2830Sstevel@tonic-gate error = clnt_tli_kcreate(configp, &netaddr, KEY_PROG, KEY_VERS, 2840Sstevel@tonic-gate 0, KEY_NRETRY, cr, &client); 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate if (error != 0) { 2870Sstevel@tonic-gate RPCLOG(1, "key_call: clnt_tli_kcreate: error %d\n", error); 2880Sstevel@tonic-gate switch (error) { 2890Sstevel@tonic-gate case EINTR: 2900Sstevel@tonic-gate return (RPC_INTR); 2910Sstevel@tonic-gate case ETIMEDOUT: 2920Sstevel@tonic-gate return (RPC_TIMEDOUT); 2930Sstevel@tonic-gate default: 2940Sstevel@tonic-gate return (RPC_FAILED); /* XXX */ 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate } 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate auth_destroy(client->cl_auth); 2990Sstevel@tonic-gate client->cl_auth = authloopback_create(); 3000Sstevel@tonic-gate if (client->cl_auth == NULL) { 3010Sstevel@tonic-gate clnt_destroy(client); 3020Sstevel@tonic-gate RPCLOG(1, "key_call: authloopback_create: error %d\n", EINTR); 3030Sstevel@tonic-gate return (RPC_INTR); 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate /* Mask out all signals except SIGHUP, SIGQUIT, and SIGTERM. */ 3070Sstevel@tonic-gate sigintr(&smask, 0); 3080Sstevel@tonic-gate stat = clnt_call(client, procn, xdr_args, args, xdr_rslt, rslt, 3090Sstevel@tonic-gate keytrytimeout); 3100Sstevel@tonic-gate sigunintr(&smask); 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate auth_destroy(client->cl_auth); 3130Sstevel@tonic-gate clnt_destroy(client); 3140Sstevel@tonic-gate if (stat != RPC_SUCCESS) { 3150Sstevel@tonic-gate RPCLOG(1, "key_call: keyserver clnt_call failed: stat %d ", 3160Sstevel@tonic-gate stat); 3170Sstevel@tonic-gate RPCLOG(1, "(%s)\n", clnt_sperrno(stat)); 3180Sstevel@tonic-gate RPCLOG0(1, "\n"); 3190Sstevel@tonic-gate return (stat); 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate RPCLOG(8, "key call: (%d) ok\n", procn); 3220Sstevel@tonic-gate return (RPC_SUCCESS); 3230Sstevel@tonic-gate } 324