root/usr/src/lib/smbsrv/libsmb/common/smb_wksids.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.
 */

#include <stdlib.h>
#include <string.h>
#include <synch.h>
#include <smbsrv/libsmb.h>

static char *wka_nbdomain[] = {
        "",
        "NT Pseudo Domain",
        "NT Authority",
        "Builtin",
        "Internet$"
};

/*
 * Predefined well known accounts table
 */
static smb_wka_t wka_tbl[] = {
        { 0, "S-1-0-0",         "Null",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 0, "S-1-1-0",         "Everyone",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 0, "S-1-2-0",         "Local",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 0, "S-1-3-0",         "Creator Owner",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 0, "S-1-3-1",         "Creator Group",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 0, "S-1-3-2",         "Creator Owner Server",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 0, "S-1-3-3",         "Creator Group Server",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 0, "S-1-3-4",         "Owner Rights",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 0, "S-1-3-5",         "Group Rights",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 1, "S-1-5",           "NT Pseudo Domain",
                SidTypeDomain, 0, NULL, NULL },
        { 2, "S-1-5-1",         "Dialup",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 2, "S-1-5-2",         "Network",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 2, "S-1-5-3",         "Batch",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 2, "S-1-5-4",         "Interactive",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 2, "S-1-5-6",         "Service",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 2, "S-1-5-7",         "Anonymous",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 2, "S-1-5-8",         "Proxy",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 2, "S-1-5-9",         "Enterprise Domain Controllers",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 2, "S-1-5-10",        "Self",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 2, "S-1-5-11",        "Authenticated Users",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 2, "S-1-5-12",        "Restricted",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 2, "S-1-5-13",        "Terminal Server User",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 2, "S-1-5-14",        "Remote Interactive Logon",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 2, "S-1-5-15",        "This Organization",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 2, "S-1-5-18",        "System",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 2, "S-1-5-19",        "Local Service",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 2, "S-1-5-20",        "Network Service",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 2, "S-1-5-33",        "Write Restricted",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 2, "S-1-5-1000",      "Other Organization",
                SidTypeWellKnownGroup, 0, NULL, NULL },
        { 3, "S-1-5-32",        "Builtin",
                SidTypeDomain, 0, NULL, NULL },
        { 4, "S-1-7",           "Internet$",
                SidTypeDomain, 0, NULL, NULL },

        { 3, "S-1-5-32-544",    "Administrators", SidTypeAlias,
            SMB_WKAFLG_LGRP_ENABLE,
            "Members can fully administer the computer/domain", NULL },
        { 3, "S-1-5-32-545",    "Users",
                SidTypeAlias, 0, NULL, NULL },
        { 3, "S-1-5-32-546",    "Guests",
                SidTypeAlias, 0, NULL, NULL },
        { 3, "S-1-5-32-547",    "Power Users", SidTypeAlias,
            SMB_WKAFLG_LGRP_ENABLE, "Members can share directories", NULL },
        { 3, "S-1-5-32-548",    "Account Operators",
                SidTypeAlias, 0, NULL, NULL },
        { 3, "S-1-5-32-549",    "Server Operators",
                SidTypeAlias, 0, NULL, NULL },
        { 3, "S-1-5-32-550",    "Print Operators",
                SidTypeAlias, 0, NULL, NULL },
        { 3, "S-1-5-32-551",    "Backup Operators", SidTypeAlias,
            SMB_WKAFLG_LGRP_ENABLE,
            "Members can bypass file security to back up files", NULL },
        { 3, "S-1-5-32-552",    "Replicator",
                SidTypeAlias, 0, NULL, NULL },
        { 3, "S-1-5-32-766",    "Current Owner",
                SidTypeAlias, 0, NULL, NULL },
        { 3, "S-1-5-32-767",    "Current Group",
                SidTypeAlias, 0, NULL, NULL },
};

#define SMB_WKA_NUM     (sizeof (wka_tbl)/sizeof (wka_tbl[0]))

static int smb_wka_init(void);
static void smb_wka_fini(void);

/*
 * Looks up well known accounts table for the given SID.
 * Upon success returns a pointer to the account entry in
 * the table, otherwise returns NULL.
 */
smb_wka_t *
smb_wka_lookup_sid(smb_sid_t *sid)
{
        smb_wka_t *entry;
        int i;

        if (!smb_wka_init())
                return (NULL);

        for (i = 0; i < SMB_WKA_NUM; ++i) {
                entry = &wka_tbl[i];

                if (entry->wka_binsid == NULL)
                        return (NULL);

                if (smb_sid_cmp(sid, entry->wka_binsid))
                        return (entry);
        }

        return (NULL);
}

/*
 * Looks up well known accounts table for the given name.
 * Upon success returns a pointer to the binary SID of the
 * entry, otherwise returns NULL.
 */
smb_sid_t *
smb_wka_get_sid(const char *name)
{
        smb_wka_t *entry;
        smb_sid_t *sid = NULL;

        if (!smb_wka_init())
                return (NULL);

        if ((entry = smb_wka_lookup_name(name)) != NULL)
                sid = entry->wka_binsid;

        return (sid);
}

/*
 * Looks up well known accounts table for the given name.
 * Upon success returns a pointer to the account entry in
 * the table, otherwise returns NULL.
 */
smb_wka_t *
smb_wka_lookup_name(const char *name)
{
        smb_wka_t *entry;
        int i;

        for (i = 0; i < SMB_WKA_NUM; ++i) {
                entry = &wka_tbl[i];

                if (!smb_strcasecmp(name, entry->wka_name, 0))
                        return (entry);
        }

        return (NULL);
}

/*
 * Lookup a name in the BUILTIN domain.
 */
smb_wka_t *
smb_wka_lookup_builtin(const char *name)
{
        smb_wka_t       *entry;
        int             i;

        for (i = 0; i < SMB_WKA_NUM; ++i) {
                entry = &wka_tbl[i];

                if (entry->wka_domidx != 3)
                        continue;

                if (!smb_strcasecmp(name, entry->wka_name, 0))
                        return (entry);
        }

        return (NULL);
}

/*
 * Returns the Netbios domain name for the given index
 */
char *
smb_wka_get_domain(int idx)
{
        if ((idx >= 0) && (idx < SMB_WKA_NUM))
                return (wka_nbdomain[idx]);

        return (NULL);
}

/*
 * This function adds well known groups to groups in a user's
 * access token (gids).
 *
 * "Network" SID is added for all users connecting over CIFS.
 *
 * "Authenticated Users" SID is added for all users except Guest
 * and Anonymous.
 *
 * "Guests" SID is added for guest users and Administrators SID
 * is added for admin users.
 */
uint32_t
smb_wka_token_groups(uint32_t flags, smb_ids_t *gids)
{
        smb_id_t *id;
        int total_cnt;

        total_cnt = gids->i_cnt + 3;

        gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t));
        if (gids->i_ids == NULL)
                return (NT_STATUS_NO_MEMORY);

        id = gids->i_ids + gids->i_cnt;
        id->i_sid = smb_sid_dup(smb_wka_get_sid("Network"));
        id->i_attrs = 0x7;
        if (id->i_sid == NULL)
                return (NT_STATUS_NO_MEMORY);
        id++;
        gids->i_cnt++;

        if ((flags & SMB_ATF_ANON) == 0) {
                if (flags & SMB_ATF_GUEST)
                        id->i_sid = smb_sid_dup(smb_wka_get_sid("Guests"));
                else
                        id->i_sid =
                            smb_sid_dup(smb_wka_get_sid("Authenticated Users"));
                id->i_attrs = 0x7;
                if (id->i_sid == NULL)
                        return (NT_STATUS_NO_MEMORY);
                id++;
                gids->i_cnt++;
        }

        if (flags & SMB_ATF_ADMIN) {
                id->i_sid = smb_sid_dup(smb_wka_get_sid("Administrators"));
                id->i_attrs = 0x7;
                if (id->i_sid == NULL)
                        return (NT_STATUS_NO_MEMORY);
                gids->i_cnt++;
        }

        return (NT_STATUS_SUCCESS);
}

/*
 * Generate binary SIDs from the string SIDs for the well-known
 * accounts table.  Callers MUST not free the binary SID pointer.
 */
static int
smb_wka_init(void)
{
        static boolean_t wka_init = B_FALSE;
        static mutex_t  wka_mutex;
        smb_wka_t       *entry;
        int             i;

        (void) mutex_lock(&wka_mutex);
        if (wka_init) {
                (void) mutex_unlock(&wka_mutex);
                return (B_TRUE);
        }

        for (i = 0; i < SMB_WKA_NUM; ++i) {
                entry = &wka_tbl[i];

                entry->wka_binsid = smb_sid_fromstr(entry->wka_sid);
                if (entry->wka_binsid == NULL) {
                        smb_wka_fini();
                        (void) mutex_unlock(&wka_mutex);
                        return (B_FALSE);
                }
        }

        wka_init = B_TRUE;
        (void) mutex_unlock(&wka_mutex);
        return (B_TRUE);
}

/*
 * Private cleanup for smb_wka_init.
 */
static void
smb_wka_fini(void)
{
        int i;

        for (i = 0; i < SMB_WKA_NUM; ++i) {
                if (wka_tbl[i].wka_binsid) {
                        free(wka_tbl[i].wka_binsid);
                        wka_tbl[i].wka_binsid = NULL;
                }
        }
}