sidsys.c revision 4321:a8930ec16e52
1131087Smarcel/* 2131087Smarcel * CDDL HEADER START 3131087Smarcel * 4131087Smarcel * The contents of this file are subject to the terms of the 5131087Smarcel * Common Development and Distribution License (the "License"). 6131087Smarcel * You may not use this file except in compliance with the License. 7131087Smarcel * 8131087Smarcel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9131087Smarcel * or http://www.opensolaris.org/os/licensing. 10131087Smarcel * See the License for the specific language governing permissions 11131087Smarcel * and limitations under the License. 12131087Smarcel * 13131087Smarcel * When distributing Covered Code, include this CDDL HEADER in each 14131087Smarcel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15131087Smarcel * If applicable, add the following below this CDDL HEADER, with the 16131087Smarcel * fields enclosed by brackets "[]" replaced with your own identifying 17131087Smarcel * information: Portions Copyright [yyyy] [name of copyright owner] 18131087Smarcel * 19131087Smarcel * CDDL HEADER END 20131087Smarcel */ 21131087Smarcel 22131087Smarcel/* 23131087Smarcel * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24131087Smarcel * Use is subject to license terms. 25131087Smarcel */ 26131087Smarcel 27131087Smarcel#pragma ident "%Z%%M% %I% %E% SMI" 28131087Smarcel 29131087Smarcel/* 30131087Smarcel * SID system call. 31131087Smarcel */ 32131087Smarcel 33131087Smarcel#include <sys/sid.h> 34131087Smarcel#include <sys/cred.h> 35131087Smarcel#include <sys/errno.h> 36131087Smarcel#include <sys/systm.h> 37131087Smarcel#include <sys/policy.h> 38131087Smarcel#include <sys/door.h> 39131087Smarcel 40131087Smarcelstatic kmutex_t idmap_mutex; 41131087Smarcel 42131087Smarceltypedef struct idmap_reg { 43131087Smarcel door_handle_t idmap_door; 44131087Smarcel int idmap_flags; 45131087Smarcel int idmap_ref; 46131087Smarcel} idmap_reg_t; 47131087Smarcel 48131087Smarcelstatic idmap_reg_t *idmap_ptr; 49131087Smarcel 50131087Smarcelstatic int idmap_unreg_dh(door_handle_t); 51131087Smarcel 52131087Smarcelstatic void 53131087Smarcelidmap_freeone(idmap_reg_t *p) 54131087Smarcel{ 55131087Smarcel ASSERT(p->idmap_ref == 0); 56131087Smarcel ASSERT(MUTEX_HELD(&idmap_mutex)); 57131087Smarcel 58131087Smarcel door_ki_rele(p->idmap_door); 59131087Smarcel if (idmap_ptr == p) 60131087Smarcel idmap_ptr = NULL; 61131087Smarcel 62131087Smarcel kmem_free(p, sizeof (*p)); 63131087Smarcel} 64131087Smarcel 65131087Smarcelstatic int 66131087Smarcelidmap_do_call(sidmap_call_t *callp, size_t callsz, void **resp, size_t *respsz) 67131087Smarcel{ 68131087Smarcel door_arg_t da; 69131087Smarcel idmap_reg_t *p; 70131087Smarcel int ret; 71131087Smarcel int dres; 72131087Smarcel 73131087Smarcel mutex_enter(&idmap_mutex); 74131087Smarcel p = idmap_ptr; 75131087Smarcel if (p != NULL) { 76131087Smarcel p->idmap_ref++; 77131087Smarcel } else { 78131087Smarcel mutex_exit(&idmap_mutex); 79131087Smarcel return (-1); 80131087Smarcel } 81131087Smarcel mutex_exit(&idmap_mutex); 82131087Smarcel 83131087Smarcel da.data_ptr = (char *)callp; 84131087Smarcel da.data_size = callsz; 85131087Smarcel da.desc_ptr = NULL; 86131087Smarcel da.desc_num = 0; 87131087Smarcel da.rbuf = *resp; 88131087Smarcel da.rsize = *respsz; 89131087Smarcel 90131087Smarcel while ((dres = door_ki_upcall(p->idmap_door, &da)) != 0) { 91131087Smarcel switch (dres) { 92131087Smarcel case EINTR: 93131087Smarcel case EAGAIN: 94131087Smarcel delay(1); 95131087Smarcel continue; 96131087Smarcel case EINVAL: 97131087Smarcel case EBADF: 98131087Smarcel (void) idmap_unreg_dh(p->idmap_door); 99131087Smarcel /* FALLTHROUGH */ 100131087Smarcel default: 101131087Smarcel ret = -1; 102131087Smarcel goto out; 103131087Smarcel } 104131087Smarcel } 105131087Smarcel *resp = da.rbuf; 106131087Smarcel *respsz = da.rsize; 107131087Smarcel ret = 0; 108131087Smarcelout: 109131087Smarcel mutex_enter(&idmap_mutex); 110131087Smarcel if (--p->idmap_ref == 0) 111131087Smarcel idmap_freeone(p); 112131087Smarcel mutex_exit(&idmap_mutex); 113131087Smarcel return (ret); 114131087Smarcel} 115131087Smarcel 116131087Smarcel/* 117131087Smarcel * Current code only attempts to map ids to sids. 118131087Smarcel */ 119131087Smarcelint 120131087Smarcelidmap_call_byid(uid_t id, ksid_t *ksid) 121131087Smarcel{ 122131087Smarcel sidmap_call_t call; 123131087Smarcel domsid_t res, *resp = &res; 124131087Smarcel size_t respsz = sizeof (res); 125131087Smarcel 126131087Smarcel call.sc_type = SIDSYS_ID2SID; 127131087Smarcel call.sc_val.sc_id = id; 128131087Smarcel 129131087Smarcel if (idmap_do_call(&call, sizeof (call), (void **)&resp, &respsz) != 0) 130131087Smarcel return (-1); 131131087Smarcel 132131087Smarcel ksid->ks_domain = ksid_lookupdomain(resp->ds_dom); 133131087Smarcel ksid->ks_rid = resp->ds_rid; 134131087Smarcel 135131087Smarcel /* Larger SID return value; this usually happens */ 136131087Smarcel if (resp != &res) 137131087Smarcel kmem_free(resp, respsz); 138131087Smarcel 139131087Smarcel return (0); 140131087Smarcel} 141131087Smarcel 142131087Smarceluid_t 143131087Smarcelidmap_call_bysid(ksid_t *ksid) 144131087Smarcel{ 145131087Smarcel ksiddomain_t *domp = ksid->ks_domain; 146131087Smarcel sidmap_call_t *callp; 147131087Smarcel uid_t res = (uid_t)-1; 148131087Smarcel uid_t *resp = &res; 149131087Smarcel size_t callsz; 150131087Smarcel size_t respsz = sizeof (res); 151131087Smarcel 152131087Smarcel callsz = sizeof (sidmap_call_t) + domp->kd_len; 153131087Smarcel 154131087Smarcel callp = kmem_alloc(callsz, KM_SLEEP); 155131087Smarcel callp->sc_type = SIDSYS_SID2ID; 156131087Smarcel bcopy(domp->kd_name, callp->sc_val.sc_sid.ds_dom, domp->kd_len); 157131087Smarcel callp->sc_val.sc_sid.ds_rid = ksid->ks_rid; 158131087Smarcel 159131087Smarcel if (idmap_do_call(callp, callsz, (void **)&resp, &respsz) != 0) 160131087Smarcel goto out; 161131087Smarcel 162131087Smarcel /* Should never happen; the original buffer should be large enough */ 163131087Smarcel if (resp != &res) { 164131087Smarcel kmem_free(resp, respsz); 165146818Sdfr goto out; 166131087Smarcel } 167131087Smarcel 168131087Smarcel if (respsz != sizeof (uid_t)) 169131087Smarcel res = (uid_t)-1; 170131087Smarcel 171131087Smarcelout: 172131087Smarcel kmem_free(callp, callsz); 173131087Smarcel return (res); 174131087Smarcel} 175131087Smarcel 176131087Smarcelstatic int 177138383Smarcelidmap_reg(int did) 178131087Smarcel{ 179138383Smarcel door_handle_t dh; 180131087Smarcel idmap_reg_t *idmp; 181131087Smarcel int err; 182131087Smarcel 183131087Smarcel if ((err = secpolicy_idmap(CRED())) != 0) 184131087Smarcel return (set_errno(err)); 185131087Smarcel 186131087Smarcel dh = door_ki_lookup(did); 187131087Smarcel 188131087Smarcel if (dh == NULL) 189131087Smarcel return (set_errno(EBADF)); 190131087Smarcel 191131087Smarcel idmp = kmem_alloc(sizeof (*idmp), KM_SLEEP); 192131087Smarcel 193131087Smarcel idmp->idmap_door = dh; 194131087Smarcel mutex_enter(&idmap_mutex); 195131087Smarcel if (idmap_ptr != NULL) { 196131087Smarcel if (--idmap_ptr->idmap_ref == 0) 197131087Smarcel idmap_freeone(idmap_ptr); 198131087Smarcel } 199131087Smarcel idmp->idmap_flags = 0; 200131087Smarcel idmp->idmap_ref = 1; 201131087Smarcel idmap_ptr = idmp; 202131087Smarcel mutex_exit(&idmap_mutex); 203131087Smarcel return (0); 204131087Smarcel} 205131087Smarcel 206131087Smarcelstatic int 207131087Smarcelidmap_unreg_dh(door_handle_t dh) 208131087Smarcel{ 209131087Smarcel mutex_enter(&idmap_mutex); 210131087Smarcel if (idmap_ptr == NULL || idmap_ptr->idmap_door != dh) { 211131087Smarcel mutex_exit(&idmap_mutex); 212131087Smarcel return (EINVAL); 213131087Smarcel } 214131087Smarcel 215131087Smarcel if (idmap_ptr->idmap_flags != 0) { 216131087Smarcel mutex_exit(&idmap_mutex); 217131087Smarcel return (EAGAIN); 218131087Smarcel } 219131087Smarcel idmap_ptr->idmap_flags = 1; 220131087Smarcel if (--idmap_ptr->idmap_ref == 0) 221131087Smarcel idmap_freeone(idmap_ptr); 222131087Smarcel mutex_exit(&idmap_mutex); 223131087Smarcel return (0); 224131087Smarcel} 225131087Smarcel 226131087Smarcelstatic int 227131087Smarcelidmap_unreg(int did) 228131087Smarcel{ 229131087Smarcel door_handle_t dh = door_ki_lookup(did); 230131087Smarcel int res; 231131087Smarcel 232131087Smarcel if (dh == NULL) 233131087Smarcel return (set_errno(EINVAL)); 234131087Smarcel 235131087Smarcel res = idmap_unreg_dh(dh); 236131087Smarcel door_ki_rele(dh); 237131087Smarcel 238131087Smarcel if (res != 0) 239131087Smarcel return (set_errno(res)); 240131087Smarcel return (0); 241131087Smarcel} 242131087Smarcel 243131087Smarcelstatic boolean_t 244131087Smarcelits_my_door(void) 245131087Smarcel{ 246131087Smarcel mutex_enter(&idmap_mutex); 247131087Smarcel if (idmap_ptr != NULL) { 248131087Smarcel struct door_info info; 249131087Smarcel int err = door_ki_info(idmap_ptr->idmap_door, &info); 250131087Smarcel if (err == 0 && info.di_target == curproc->p_pid) { 251131087Smarcel mutex_exit(&idmap_mutex); 252131087Smarcel return (B_TRUE); 253131087Smarcel } 254131087Smarcel } 255131087Smarcel mutex_exit(&idmap_mutex); 256131087Smarcel return (B_FALSE); 257131087Smarcel} 258131087Smarcel 259131087Smarcelstatic uint64_t 260131087Smarcelallocids(int flag, int nuids, int ngids) 261131087Smarcel{ 262131087Smarcel rval_t r; 263131087Smarcel uid_t su = 0; 264131087Smarcel gid_t sg = 0; 265131087Smarcel int err; 266131087Smarcel 267131087Smarcel if (!its_my_door()) 268131087Smarcel return (set_errno(EPERM)); 269131087Smarcel 270131087Smarcel if (nuids < 0 || ngids < 0) 271131087Smarcel return (set_errno(EINVAL)); 272131087Smarcel 273131087Smarcel if (flag != 0 || nuids > 0) 274131087Smarcel err = eph_uid_alloc(flag, &su, nuids); 275131087Smarcel if (err == 0 && (flag != 0 || ngids > 0)) 276131087Smarcel err = eph_gid_alloc(flag, &sg, ngids); 277131087Smarcel 278131087Smarcel if (err != 0) 279131087Smarcel return (set_errno(EOVERFLOW)); 280131087Smarcel 281131087Smarcel r.r_val1 = su; 282131087Smarcel r.r_val2 = sg; 283131087Smarcel return (r.r_vals); 284131087Smarcel} 285131087Smarcel 286131087Smarceluint64_t 287131087Smarcelsidsys(int op, int flag, int nuids, int ngids) 288131087Smarcel{ 289131087Smarcel switch (op) { 290131087Smarcel case SIDSYS_ALLOC_IDS: 291131087Smarcel return (allocids(flag, nuids, ngids)); 292131087Smarcel case SIDSYS_IDMAP_REG: 293131087Smarcel return (idmap_reg(flag)); 294131087Smarcel case SIDSYS_IDMAP_UNREG: 295131087Smarcel return (idmap_unreg(flag)); 296131087Smarcel default: 297131087Smarcel return (set_errno(EINVAL)); 298131087Smarcel } 299131087Smarcel} 300131087Smarcel