1*f48205beScasper /* 2*f48205beScasper * CDDL HEADER START 3*f48205beScasper * 4*f48205beScasper * The contents of this file are subject to the terms of the 5*f48205beScasper * Common Development and Distribution License (the "License"). 6*f48205beScasper * You may not use this file except in compliance with the License. 7*f48205beScasper * 8*f48205beScasper * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*f48205beScasper * or http://www.opensolaris.org/os/licensing. 10*f48205beScasper * See the License for the specific language governing permissions 11*f48205beScasper * and limitations under the License. 12*f48205beScasper * 13*f48205beScasper * When distributing Covered Code, include this CDDL HEADER in each 14*f48205beScasper * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*f48205beScasper * If applicable, add the following below this CDDL HEADER, with the 16*f48205beScasper * fields enclosed by brackets "[]" replaced with your own identifying 17*f48205beScasper * information: Portions Copyright [yyyy] [name of copyright owner] 18*f48205beScasper * 19*f48205beScasper * CDDL HEADER END 20*f48205beScasper */ 21*f48205beScasper 22*f48205beScasper /* 23*f48205beScasper * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24*f48205beScasper * Use is subject to license terms. 25*f48205beScasper */ 26*f48205beScasper 27*f48205beScasper #pragma ident "%Z%%M% %I% %E% SMI" 28*f48205beScasper 29*f48205beScasper /* 30*f48205beScasper * SID system call. 31*f48205beScasper */ 32*f48205beScasper 33*f48205beScasper #include <sys/sid.h> 34*f48205beScasper #include <sys/cred.h> 35*f48205beScasper #include <sys/errno.h> 36*f48205beScasper #include <sys/systm.h> 37*f48205beScasper #include <sys/policy.h> 38*f48205beScasper #include <sys/door.h> 39*f48205beScasper 40*f48205beScasper static kmutex_t idmap_mutex; 41*f48205beScasper 42*f48205beScasper typedef struct idmap_reg { 43*f48205beScasper door_handle_t idmap_door; 44*f48205beScasper int idmap_flags; 45*f48205beScasper int idmap_ref; 46*f48205beScasper } idmap_reg_t; 47*f48205beScasper 48*f48205beScasper static idmap_reg_t *idmap_ptr; 49*f48205beScasper 50*f48205beScasper static int idmap_unreg_dh(door_handle_t); 51*f48205beScasper 52*f48205beScasper static void 53*f48205beScasper idmap_freeone(idmap_reg_t *p) 54*f48205beScasper { 55*f48205beScasper ASSERT(p->idmap_ref == 0); 56*f48205beScasper ASSERT(MUTEX_HELD(&idmap_mutex)); 57*f48205beScasper 58*f48205beScasper door_ki_rele(p->idmap_door); 59*f48205beScasper if (idmap_ptr == p) 60*f48205beScasper idmap_ptr = NULL; 61*f48205beScasper 62*f48205beScasper kmem_free(p, sizeof (*p)); 63*f48205beScasper } 64*f48205beScasper 65*f48205beScasper static int 66*f48205beScasper idmap_do_call(sidmap_call_t *callp, size_t callsz, void **resp, size_t *respsz) 67*f48205beScasper { 68*f48205beScasper door_arg_t da; 69*f48205beScasper idmap_reg_t *p; 70*f48205beScasper int ret; 71*f48205beScasper int dres; 72*f48205beScasper 73*f48205beScasper mutex_enter(&idmap_mutex); 74*f48205beScasper p = idmap_ptr; 75*f48205beScasper if (p != NULL) { 76*f48205beScasper p->idmap_ref++; 77*f48205beScasper } else { 78*f48205beScasper mutex_exit(&idmap_mutex); 79*f48205beScasper return (-1); 80*f48205beScasper } 81*f48205beScasper mutex_exit(&idmap_mutex); 82*f48205beScasper 83*f48205beScasper da.data_ptr = (char *)callp; 84*f48205beScasper da.data_size = callsz; 85*f48205beScasper da.desc_ptr = NULL; 86*f48205beScasper da.desc_num = 0; 87*f48205beScasper da.rbuf = *resp; 88*f48205beScasper da.rsize = *respsz; 89*f48205beScasper 90*f48205beScasper while ((dres = door_ki_upcall(p->idmap_door, &da)) != 0) { 91*f48205beScasper switch (dres) { 92*f48205beScasper case EINTR: 93*f48205beScasper case EAGAIN: 94*f48205beScasper delay(1); 95*f48205beScasper continue; 96*f48205beScasper case EINVAL: 97*f48205beScasper case EBADF: 98*f48205beScasper (void) idmap_unreg_dh(p->idmap_door); 99*f48205beScasper /* FALLTHROUGH */ 100*f48205beScasper default: 101*f48205beScasper ret = -1; 102*f48205beScasper goto out; 103*f48205beScasper } 104*f48205beScasper } 105*f48205beScasper *resp = da.rbuf; 106*f48205beScasper *respsz = da.rsize; 107*f48205beScasper ret = 0; 108*f48205beScasper out: 109*f48205beScasper mutex_enter(&idmap_mutex); 110*f48205beScasper if (--p->idmap_ref == 0) 111*f48205beScasper idmap_freeone(p); 112*f48205beScasper mutex_exit(&idmap_mutex); 113*f48205beScasper return (ret); 114*f48205beScasper } 115*f48205beScasper 116*f48205beScasper /* 117*f48205beScasper * Current code only attempts to map ids to sids. 118*f48205beScasper */ 119*f48205beScasper int 120*f48205beScasper idmap_call_byid(uid_t id, ksid_t *ksid) 121*f48205beScasper { 122*f48205beScasper sidmap_call_t call; 123*f48205beScasper domsid_t res, *resp = &res; 124*f48205beScasper size_t respsz = sizeof (res); 125*f48205beScasper 126*f48205beScasper call.sc_type = SIDSYS_ID2SID; 127*f48205beScasper call.sc_val.sc_id = id; 128*f48205beScasper 129*f48205beScasper if (idmap_do_call(&call, sizeof (call), (void **)&resp, &respsz) != 0) 130*f48205beScasper return (-1); 131*f48205beScasper 132*f48205beScasper ksid->ks_domain = ksid_lookupdomain(resp->ds_dom); 133*f48205beScasper ksid->ks_rid = resp->ds_rid; 134*f48205beScasper 135*f48205beScasper /* Larger SID return value; this usually happens */ 136*f48205beScasper if (resp != &res) 137*f48205beScasper kmem_free(resp, respsz); 138*f48205beScasper 139*f48205beScasper return (0); 140*f48205beScasper } 141*f48205beScasper 142*f48205beScasper uid_t 143*f48205beScasper idmap_call_bysid(ksid_t *ksid) 144*f48205beScasper { 145*f48205beScasper ksiddomain_t *domp = ksid->ks_domain; 146*f48205beScasper sidmap_call_t *callp; 147*f48205beScasper uid_t res = (uid_t)-1; 148*f48205beScasper uid_t *resp = &res; 149*f48205beScasper size_t callsz; 150*f48205beScasper size_t respsz = sizeof (res); 151*f48205beScasper 152*f48205beScasper callsz = sizeof (sidmap_call_t) + domp->kd_len; 153*f48205beScasper 154*f48205beScasper callp = kmem_alloc(callsz, KM_SLEEP); 155*f48205beScasper callp->sc_type = SIDSYS_SID2ID; 156*f48205beScasper bcopy(domp->kd_name, callp->sc_val.sc_sid.ds_dom, domp->kd_len); 157*f48205beScasper callp->sc_val.sc_sid.ds_rid = ksid->ks_rid; 158*f48205beScasper 159*f48205beScasper if (idmap_do_call(callp, callsz, (void **)&resp, &respsz) != 0) 160*f48205beScasper goto out; 161*f48205beScasper 162*f48205beScasper /* Should never happen; the original buffer should be large enough */ 163*f48205beScasper if (resp != &res) { 164*f48205beScasper kmem_free(resp, respsz); 165*f48205beScasper goto out; 166*f48205beScasper } 167*f48205beScasper 168*f48205beScasper if (respsz != sizeof (uid_t)) 169*f48205beScasper res = (uid_t)-1; 170*f48205beScasper 171*f48205beScasper out: 172*f48205beScasper kmem_free(callp, callsz); 173*f48205beScasper return (res); 174*f48205beScasper } 175*f48205beScasper 176*f48205beScasper static int 177*f48205beScasper idmap_reg(int did) 178*f48205beScasper { 179*f48205beScasper door_handle_t dh; 180*f48205beScasper idmap_reg_t *idmp; 181*f48205beScasper int err; 182*f48205beScasper 183*f48205beScasper if ((err = secpolicy_idmap(CRED())) != 0) 184*f48205beScasper return (set_errno(err)); 185*f48205beScasper 186*f48205beScasper dh = door_ki_lookup(did); 187*f48205beScasper 188*f48205beScasper if (dh == NULL) 189*f48205beScasper return (set_errno(EBADF)); 190*f48205beScasper 191*f48205beScasper idmp = kmem_alloc(sizeof (*idmp), KM_SLEEP); 192*f48205beScasper 193*f48205beScasper idmp->idmap_door = dh; 194*f48205beScasper mutex_enter(&idmap_mutex); 195*f48205beScasper if (idmap_ptr != NULL) { 196*f48205beScasper if (--idmap_ptr->idmap_ref == 0) 197*f48205beScasper idmap_freeone(idmap_ptr); 198*f48205beScasper } 199*f48205beScasper idmp->idmap_flags = 0; 200*f48205beScasper idmp->idmap_ref = 1; 201*f48205beScasper idmap_ptr = idmp; 202*f48205beScasper mutex_exit(&idmap_mutex); 203*f48205beScasper return (0); 204*f48205beScasper } 205*f48205beScasper 206*f48205beScasper static int 207*f48205beScasper idmap_unreg_dh(door_handle_t dh) 208*f48205beScasper { 209*f48205beScasper mutex_enter(&idmap_mutex); 210*f48205beScasper if (idmap_ptr == NULL || idmap_ptr->idmap_door != dh) { 211*f48205beScasper mutex_exit(&idmap_mutex); 212*f48205beScasper return (EINVAL); 213*f48205beScasper } 214*f48205beScasper 215*f48205beScasper if (idmap_ptr->idmap_flags != 0) { 216*f48205beScasper mutex_exit(&idmap_mutex); 217*f48205beScasper return (EAGAIN); 218*f48205beScasper } 219*f48205beScasper idmap_ptr->idmap_flags = 1; 220*f48205beScasper if (--idmap_ptr->idmap_ref == 0) 221*f48205beScasper idmap_freeone(idmap_ptr); 222*f48205beScasper mutex_exit(&idmap_mutex); 223*f48205beScasper return (0); 224*f48205beScasper } 225*f48205beScasper 226*f48205beScasper static int 227*f48205beScasper idmap_unreg(int did) 228*f48205beScasper { 229*f48205beScasper door_handle_t dh = door_ki_lookup(did); 230*f48205beScasper int res; 231*f48205beScasper 232*f48205beScasper if (dh == NULL) 233*f48205beScasper return (set_errno(EINVAL)); 234*f48205beScasper 235*f48205beScasper res = idmap_unreg_dh(dh); 236*f48205beScasper door_ki_rele(dh); 237*f48205beScasper 238*f48205beScasper if (res != 0) 239*f48205beScasper return (set_errno(res)); 240*f48205beScasper return (0); 241*f48205beScasper } 242*f48205beScasper 243*f48205beScasper static boolean_t 244*f48205beScasper its_my_door(void) 245*f48205beScasper { 246*f48205beScasper mutex_enter(&idmap_mutex); 247*f48205beScasper if (idmap_ptr != NULL) { 248*f48205beScasper struct door_info info; 249*f48205beScasper int err = door_ki_info(idmap_ptr->idmap_door, &info); 250*f48205beScasper if (err == 0 && info.di_target == curproc->p_pid) { 251*f48205beScasper mutex_exit(&idmap_mutex); 252*f48205beScasper return (B_TRUE); 253*f48205beScasper } 254*f48205beScasper } 255*f48205beScasper mutex_exit(&idmap_mutex); 256*f48205beScasper return (B_FALSE); 257*f48205beScasper } 258*f48205beScasper 259*f48205beScasper static uint64_t 260*f48205beScasper allocids(int flag, int nuids, int ngids) 261*f48205beScasper { 262*f48205beScasper rval_t r; 263*f48205beScasper uid_t su = 0; 264*f48205beScasper gid_t sg = 0; 265*f48205beScasper int err; 266*f48205beScasper 267*f48205beScasper if (!its_my_door()) 268*f48205beScasper return (set_errno(EPERM)); 269*f48205beScasper 270*f48205beScasper if (nuids < 0 || ngids < 0) 271*f48205beScasper return (set_errno(EINVAL)); 272*f48205beScasper 273*f48205beScasper if (flag != 0 || nuids > 0) 274*f48205beScasper err = eph_uid_alloc(flag, &su, nuids); 275*f48205beScasper if (err == 0 && (flag != 0 || ngids > 0)) 276*f48205beScasper err = eph_gid_alloc(flag, &sg, ngids); 277*f48205beScasper 278*f48205beScasper if (err != 0) 279*f48205beScasper return (set_errno(EOVERFLOW)); 280*f48205beScasper 281*f48205beScasper r.r_val1 = su; 282*f48205beScasper r.r_val2 = sg; 283*f48205beScasper return (r.r_vals); 284*f48205beScasper } 285*f48205beScasper 286*f48205beScasper uint64_t 287*f48205beScasper sidsys(int op, int flag, int nuids, int ngids) 288*f48205beScasper { 289*f48205beScasper switch (op) { 290*f48205beScasper case SIDSYS_ALLOC_IDS: 291*f48205beScasper return (allocids(flag, nuids, ngids)); 292*f48205beScasper case SIDSYS_IDMAP_REG: 293*f48205beScasper return (idmap_reg(flag)); 294*f48205beScasper case SIDSYS_IDMAP_UNREG: 295*f48205beScasper return (idmap_unreg(flag)); 296*f48205beScasper default: 297*f48205beScasper return (set_errno(EINVAL)); 298*f48205beScasper } 299*f48205beScasper } 300