root/usr/src/uts/common/syscall/sidsys.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * SID system call.
 */

#include <sys/sid.h>
#include <sys/cred.h>
#include <sys/errno.h>
#include <sys/systm.h>
#include <sys/policy.h>
#include <sys/door.h>
#include <sys/kidmap.h>
#include <sys/proc.h>

static uint64_t
allocids(int flag, int nuids, int ngids)
{
        rval_t r;
        uid_t su = 0;
        gid_t sg = 0;
        struct door_info di;
        door_handle_t dh;
        int err;
        zone_t *zone = crgetzone(CRED());

        dh = idmap_get_door(zone);

        if (dh == NULL)
                return (set_errno(EPERM));

        if ((err = door_ki_info(dh, &di)) != 0) {
                door_ki_rele(dh);
                return (set_errno(err));
        }

        door_ki_rele(dh);

        if (curproc->p_pid != di.di_target)
                return (set_errno(EPERM));

        if (flag)
                idmap_purge_cache(zone);

        if (nuids < 0 || ngids < 0)
                return (set_errno(EINVAL));

        if (flag != 0 || nuids > 0)
                err = eph_uid_alloc(zone, flag, &su, nuids);
        if (err == 0 && (flag != 0 || ngids > 0))
                err = eph_gid_alloc(zone, flag, &sg, ngids);

        if (err != 0)
                return (set_errno(EOVERFLOW));

        r.r_val1 = su;
        r.r_val2 = sg;
        return (r.r_vals);
}

static int
idmap_reg(int did)
{
        door_handle_t dh;
        int err;
        cred_t *cr = CRED();

        if ((err = secpolicy_idmap(cr)) != 0)
                return (set_errno(err));

        dh = door_ki_lookup(did);

        if (dh == NULL)
                return (set_errno(EBADF));

        if ((err = idmap_reg_dh(crgetzone(cr), dh)) != 0)
                return (set_errno(err));

        return (0);
}

static int
idmap_unreg(int did)
{
        door_handle_t dh = door_ki_lookup(did);
        int res;
        zone_t *zone;

        if (dh == NULL)
                return (set_errno(EINVAL));

        zone = crgetzone(CRED());
        res = idmap_unreg_dh(zone, dh);
        door_ki_rele(dh);

        if (res != 0)
                return (set_errno(res));
        return (0);
}

static uint64_t
idmap_flush_kcache(void)
{
        struct door_info di;
        door_handle_t dh;
        int err;
        zone_t *zone = crgetzone(CRED());

        dh = idmap_get_door(zone);

        if (dh == NULL)
                return (set_errno(EPERM));

        if ((err = door_ki_info(dh, &di)) != 0) {
                door_ki_rele(dh);
                return (set_errno(err));
        }

        door_ki_rele(dh);

        if (curproc->p_pid != di.di_target)
                return (set_errno(EPERM));

        idmap_purge_cache(zone);

        return (0);
}

uint64_t
sidsys(int op, int flag, int nuids, int ngids)
{
        switch (op) {
        case SIDSYS_ALLOC_IDS:
                return (allocids(flag, nuids, ngids));
        case SIDSYS_IDMAP_REG:
                return (idmap_reg(flag));
        case SIDSYS_IDMAP_UNREG:
                return (idmap_unreg(flag));
        case SIDSYS_IDMAP_FLUSH_KCACHE:
                return (idmap_flush_kcache());
        default:
                return (set_errno(EINVAL));
        }
}