2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A#include <stdlib.h>
2N/A#include <strings.h>
2N/A#include <unistd.h>
2N/A#include <syslog.h>
2N/A#include <thread.h>
2N/A#include <synch.h>
2N/A#include <grp.h>
2N/A#include <assert.h>
2N/A#include <libintl.h>
2N/A#include <smbsrv/libsmb.h>
2N/A#include <sys/types.h>
2N/A#include <sys/stat.h>
2N/A#include <sys/param.h>
2N/A#include <sqlite3.h>
2N/A#define SMB_LGRP_POSIX_IDX 0
2N/A#define SMB_LGRP_BUILTIN_IDX 1
2N/A
2N/A#define SMB_LGRP_DB_NAME "/var/smb/smbgroup_v3.db"
2N/A#define SMB_LGRP_DB_TIMEOUT 3000 /* in millisecond */
2N/A#define SMB_LGRP_DB_VERMAJOR 1
2N/A#define SMB_LGRP_DB_VERMINOR 0
2N/A#define SMB_LGRP_DB_MAGIC 0x4C475250 /* LGRP */
2N/A
2N/A#define SMB_LGRP_DB_ORD SQLITE_OPEN_READONLY
2N/A#define SMB_LGRP_DB_ORW SQLITE_OPEN_READWRITE
2N/A#define SMB_LGRP_DB_ORWC SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
2N/A
2N/A#define SMB_LGRP_DB_ADDMEMBER 1
2N/A#define SMB_LGRP_DB_DELMEMBER 2
2N/A
2N/A/*
2N/A * members column of the groups table is an array of
2N/A * member structure smb_lgmid_t defined below.
2N/A *
2N/A * privs column of the groups table is an array of bytes
2N/A * where each byte is the id of an enable privilege
2N/A */
2N/A#define SMB_LGRP_DB_SQL \
2N/A "CREATE TABLE db_info (" \
2N/A " ver_major INTEGER," \
2N/A " ver_minor INTEGER," \
2N/A " magic INTEGER" \
2N/A ");" \
2N/A "" \
2N/A "CREATE TABLE domains (" \
2N/A " dom_idx INTEGER PRIMARY KEY," \
2N/A " dom_sid TEXT UNIQUE," \
2N/A " dom_cnt INTEGER" \
2N/A ");" \
2N/A "" \
2N/A "CREATE UNIQUE INDEX domsid_idx ON domains (dom_sid);" \
2N/A "" \
2N/A "CREATE TABLE groups (" \
2N/A " name TEXT PRIMARY KEY," \
2N/A " sid_idx INTEGER," \
2N/A " sid_rid INTEGER," \
2N/A " sid_type INTEGER," \
2N/A " sid_attrs INTEGER," \
2N/A " comment TEXT," \
2N/A " n_privs INTEGER," \
2N/A " privs BLOB," \
2N/A " n_members INTEGER," \
2N/A " members BLOB" \
2N/A ");" \
2N/A "" \
2N/A "CREATE INDEX grprid_idx ON groups (sid_rid);"
2N/A
2N/A/*
2N/A * Number of groups table columns
2N/A */
2N/A#define SMB_LGRP_GTBL_NCOL 10
2N/A
2N/A#define SMB_LGRP_GTBL_NAME 0
2N/A#define SMB_LGRP_GTBL_SIDIDX 1
2N/A#define SMB_LGRP_GTBL_SIDRID 2
2N/A#define SMB_LGRP_GTBL_SIDTYP 3
2N/A#define SMB_LGRP_GTBL_SIDATR 4
2N/A#define SMB_LGRP_GTBL_CMNT 5
2N/A#define SMB_LGRP_GTBL_NPRIVS 6
2N/A#define SMB_LGRP_GTBL_PRIVS 7
2N/A#define SMB_LGRP_GTBL_NMEMBS 8
2N/A#define SMB_LGRP_GTBL_MEMBS 9
2N/A
2N/A#define SMB_LGRP_INFO_NONE 0x00
2N/A#define SMB_LGRP_INFO_NAME 0x01
2N/A#define SMB_LGRP_INFO_CMNT 0x02
2N/A#define SMB_LGRP_INFO_SID 0x04
2N/A#define SMB_LGRP_INFO_PRIV 0x08
2N/A#define SMB_LGRP_INFO_MEMB 0x10
2N/A#define SMB_LGRP_INFO_ALL 0x1F
2N/A
2N/A#define SMB_LGRP_PGRP_GRPTMP "/etc/gtmp"
2N/A#define SMB_LGRP_PGRP_GRPBUFSIZ 5120
2N/A#define SMB_LGRP_PGRP_GROUP "/etc/group"
2N/A#define SMB_LGRP_PGRP_MAXGLEN 9 /* max length of group name */
2N/A#define SMB_LGRP_PGRP_DEFRID 99 /* max reserved id */
2N/A
2N/A#define SMB_LGRP_PGRP_NOTUNIQUE 0
2N/A#define SMB_LGRP_PGRP_RESERVED 1
2N/A#define SMB_LGRP_PGRP_UNIQUE 2
2N/A#define SMB_LGRP_PGRP_TOOBIG 3
2N/A#define SMB_LGRP_PGRP_INVALID 4
2N/A
2N/A#define NULL_MSGCHK(msg) ((msg) ? (msg) : "NULL")
2N/A
2N/A/* Member ID */
2N/Atypedef struct smb_lgmid {
2N/A uint32_t m_idx;
2N/A uint32_t m_rid;
2N/A uint16_t m_type;
2N/A} smb_lgmid_t;
2N/A
2N/A#define SMB_LGRP_MID_HEXSZ 32
2N/A
2N/A/* Member list */
2N/Atypedef struct smb_lgmlist {
2N/A uint32_t m_cnt;
2N/A char *m_ids;
2N/A} smb_lgmlist_t;
2N/A
2N/A/* Privilege ID */
2N/Atypedef uint8_t smb_lgpid_t;
2N/A
2N/A/* Privilege list */
2N/Atypedef struct smb_lgplist {
2N/A uint32_t p_cnt;
2N/A smb_lgpid_t *p_ids;
2N/A} smb_lgplist_t;
2N/A
2N/A/* Local group iterator */
2N/Astruct smb_giter {
2N/A sqlite3_stmt *sgi_vm;
2N/A sqlite3 *sgi_db;
2N/A uint32_t sgi_nerr;
2N/A};
2N/A
2N/Astatic struct {
2N/A int errnum;
2N/A char *errmsg;
2N/A} errtab[] = {
2N/A { SMB_LGRP_SUCCESS, "success" },
2N/A { SMB_LGRP_INVALID_ARG, "invalid argument" },
2N/A { SMB_LGRP_INVALID_MEMBER, "invalid member type" },
2N/A { SMB_LGRP_INVALID_NAME, "invalid name" },
2N/A { SMB_LGRP_NOT_FOUND, "group not found" },
2N/A { SMB_LGRP_EXISTS, "group exists" },
2N/A { SMB_LGRP_NO_SID, "cannot obtain a SID" },
2N/A { SMB_LGRP_NO_LOCAL_SID, "cannot get the machine SID" },
2N/A { SMB_LGRP_SID_NOTLOCAL, "local account has non-local SID" },
2N/A { SMB_LGRP_WKSID,
2N/A "operation not permitted on well-known account" },
2N/A { SMB_LGRP_NO_MEMORY, "not enough memory" },
2N/A { SMB_LGRP_DB_ERROR, "database operation error" },
2N/A { SMB_LGRP_DBINIT_ERROR, "database initialization error" },
2N/A { SMB_LGRP_INTERNAL_ERROR, "internal error" },
2N/A { SMB_LGRP_MEMBER_IN_GROUP, "member already in group" },
2N/A { SMB_LGRP_MEMBER_NOT_IN_GROUP, "not a member" },
2N/A { SMB_LGRP_NO_SUCH_PRIV, "no such privilege" },
2N/A { SMB_LGRP_NO_SUCH_DOMAIN, "no such domain SID" },
2N/A { SMB_LGRP_PRIV_HELD, "privilege already held" },
2N/A { SMB_LGRP_PRIV_NOT_HELD, "privilege not held" },
2N/A { SMB_LGRP_BAD_DATA, "bad data" },
2N/A { SMB_LGRP_NO_MORE, "no more groups" },
2N/A { SMB_LGRP_DBOPEN_FAILED, "database open failed" },
2N/A { SMB_LGRP_DBEXEC_FAILED, "database operation failed" },
2N/A { SMB_LGRP_DBINIT_FAILED, "database initialization failed" },
2N/A { SMB_LGRP_DOMLKP_FAILED, "domain SID lookup failed" },
2N/A { SMB_LGRP_DOMINS_FAILED, "domain SID insert failed" },
2N/A { SMB_LGRP_INSERT_FAILED, "group insert failed" },
2N/A { SMB_LGRP_DELETE_FAILED, "group delete failed" },
2N/A { SMB_LGRP_UPDATE_FAILED, "group update failed" },
2N/A { SMB_LGRP_LOOKUP_FAILED, "group lookup failed" },
2N/A { SMB_LGRP_OFFLINE, "local group service is offline" },
2N/A { SMB_LGRP_POSIXCREATE_FAILED, "posix group create failed" }
2N/A};
2N/A
2N/A/*
2N/A * Serialization for the local group API.
2N/A */
2N/Atypedef struct {
2N/A mutex_t lg_mutex;
2N/A cond_t lg_cv;
2N/A boolean_t lg_online;
2N/A uint32_t lg_refcnt;
2N/A smb_sid_t *lg_machine_sid;
2N/A} smb_localgrp_t;
2N/A
2N/Astatic smb_localgrp_t smb_localgrp;
2N/A
2N/Astatic boolean_t smb_lgrp_enter(void);
2N/Astatic void smb_lgrp_exit(void);
2N/Astatic int smb_lgrp_db_init(void);
2N/Astatic sqlite3 *smb_lgrp_db_open(int);
2N/Astatic void smb_lgrp_db_close(sqlite3 *);
2N/Astatic int smb_lgrp_db_setinfo(sqlite3 *);
2N/A
2N/Astatic boolean_t smb_lgrp_gtbl_exists(sqlite3 *, char *);
2N/Astatic int smb_lgrp_gtbl_lookup(sqlite3 *, int, smb_group_t *, int, ...);
2N/Astatic int smb_lgrp_gtbl_insert(sqlite3 *, smb_group_t *);
2N/Astatic int smb_lgrp_gtbl_update(sqlite3 *, char *, smb_group_t *, int);
2N/Astatic int smb_lgrp_gtbl_delete(sqlite3 *, char *);
2N/Astatic int smb_lgrp_gtbl_update_mlist(sqlite3 *, char *, smb_gsid_t *, int);
2N/Astatic int smb_lgrp_gtbl_update_plist(sqlite3 *, char *, uint8_t, boolean_t);
2N/Astatic int smb_lgrp_gtbl_count(sqlite3 *, int, int *);
2N/A
2N/Astatic int smb_lgrp_dtbl_insert(sqlite3 *, char *, uint32_t *);
2N/Astatic int smb_lgrp_dtbl_fuid(sqlite3 *, smb_sid_t *, uint16_t,
2N/A uint32_t *, uint32_t *);
2N/Astatic int smb_lgrp_dtbl_getsid(sqlite3 *, uint32_t, smb_sid_t **);
2N/A
2N/Astatic int smb_lgrp_mlist_add(smb_lgmlist_t *, smb_lgmid_t *, smb_lgmlist_t *);
2N/Astatic int smb_lgrp_mlist_del(smb_lgmlist_t *, smb_lgmid_t *, smb_lgmlist_t *);
2N/A
2N/Astatic int smb_lgrp_plist_add(smb_lgplist_t *, smb_lgpid_t, smb_lgplist_t *);
2N/Astatic int smb_lgrp_plist_del(smb_lgplist_t *, smb_lgpid_t, smb_lgplist_t *);
2N/A
2N/Astatic void smb_lgrp_encode_privset(smb_group_t *, smb_lgplist_t *);
2N/A
2N/Astatic int smb_lgrp_decode(smb_group_t *, char **, int, sqlite3 *);
2N/Astatic int smb_lgrp_decode_privset(smb_group_t *, char *, char *);
2N/Astatic int smb_lgrp_decode_members(smb_group_t *, char *, char *, sqlite3 *);
2N/A
2N/Astatic void smb_lgrp_set_default_privs(smb_group_t *);
2N/Astatic boolean_t smb_lgrp_normalize_name(char *);
2N/Astatic boolean_t smb_lgrp_chkmember(uint16_t);
2N/Astatic int smb_lgrp_getsid(int, uint32_t *, uint16_t, sqlite3 *, smb_sid_t **);
2N/Astatic int smb_lgrp_getgid(uint32_t rid, gid_t *gid);
2N/Astatic boolean_t smb_lgrp_exists(char *);
2N/Astatic int smb_lgrp_pgrp_add(char *);
2N/Astatic void smb_lgrp_free_columns(int, char **);
2N/A
2N/A/*
2N/A * smb_lgrp_add
2N/A *
2N/A * Create a local group with the given name and comment.
2N/A * This new group doesn't have any members and no enabled
2N/A * privileges.
2N/A *
2N/A * No well-known accounts can be added other than Administators,
2N/A * Backup Operators and Power Users. These built-in groups
2N/A * won't have any members when created but a set of default
2N/A * privileges will be enabled for them.
2N/A */
2N/Aint
2N/Asmb_lgrp_add(char *name, char *cmnt)
2N/A{
2N/A smb_wka_t *wka;
2N/A struct group *pxgrp;
2N/A smb_group_t grp;
2N/A smb_sid_t *sid = NULL;
2N/A sqlite3 *db;
2N/A int rc;
2N/A char gname[MAXNAMELEN];
2N/A
2N/A if (name == NULL)
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A (void) strlcpy(gname, name, MAXNAMELEN);
2N/A if (!smb_lgrp_normalize_name(gname))
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A if (cmnt && (strlen(cmnt) > SMB_LGRP_COMMENT_MAX))
2N/A return (SMB_LGRP_INVALID_ARG);
2N/A
2N/A bzero(&grp, sizeof (grp));
2N/A grp.sg_name = smb_strlwr(gname);
2N/A grp.sg_cmnt = cmnt;
2N/A
2N/A if (!smb_lgrp_enter())
2N/A return (SMB_LGRP_OFFLINE);
2N/A
2N/A wka = smb_wka_lookup_name(gname);
2N/A if (wka == NULL) {
2N/A if ((pxgrp = getgrnam(gname)) == NULL) {
2N/A if (smb_lgrp_pgrp_add(gname) != 0) {
2N/A smb_lgrp_exit();
2N/A return (SMB_LGRP_POSIXCREATE_FAILED);
2N/A }
2N/A
2N/A if ((pxgrp = getgrnam(gname)) == NULL) {
2N/A smb_lgrp_exit();
2N/A return (SMB_LGRP_NOT_FOUND);
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Make sure a local SID can be obtained
2N/A */
2N/A if (smb_idmap_getsid(pxgrp->gr_gid, SMB_IDMAP_GROUP, &sid)
2N/A != IDMAP_SUCCESS) {
2N/A smb_lgrp_exit();
2N/A return (SMB_LGRP_NO_SID);
2N/A }
2N/A
2N/A if (!smb_sid_indomain(smb_localgrp.lg_machine_sid, sid)) {
2N/A free(sid);
2N/A smb_lgrp_exit();
2N/A return (SMB_LGRP_SID_NOTLOCAL);
2N/A }
2N/A
2N/A free(sid);
2N/A grp.sg_id.gs_type = SidTypeAlias;
2N/A grp.sg_domain = SMB_DOMAIN_LOCAL;
2N/A grp.sg_rid = pxgrp->gr_gid;
2N/A } else {
2N/A if ((wka->wka_flags & SMB_WKAFLG_LGRP_ENABLE) == 0) {
2N/A /* cannot add well-known accounts */
2N/A smb_lgrp_exit();
2N/A return (SMB_LGRP_WKSID);
2N/A }
2N/A
2N/A grp.sg_id.gs_type = wka->wka_type;
2N/A if ((sid = smb_sid_fromstr(wka->wka_sid)) == NULL) {
2N/A smb_lgrp_exit();
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A }
2N/A
2N/A (void) smb_sid_getrid(sid, &grp.sg_rid);
2N/A free(sid);
2N/A grp.sg_domain = SMB_DOMAIN_BUILTIN;
2N/A grp.sg_privs = smb_privset_new();
2N/A smb_lgrp_set_default_privs(&grp);
2N/A }
2N/A
2N/A if (smb_lgrp_exists(grp.sg_name)) {
2N/A smb_lgrp_exit();
2N/A return (SMB_LGRP_EXISTS);
2N/A }
2N/A
2N/A grp.sg_attr = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT |
2N/A SE_GROUP_ENABLED;
2N/A
2N/A db = smb_lgrp_db_open(SMB_LGRP_DB_ORW);
2N/A rc = smb_lgrp_gtbl_insert(db, &grp);
2N/A smb_lgrp_db_close(db);
2N/A
2N/A smb_privset_free(grp.sg_privs);
2N/A smb_lgrp_exit();
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_rename
2N/A *
2N/A * Renames the given group
2N/A */
2N/Aint
2N/Asmb_lgrp_rename(char *name, char *new_name)
2N/A{
2N/A smb_group_t grp;
2N/A sqlite3 *db;
2N/A int rc;
2N/A char gname[MAXNAMELEN], new_gname[MAXNAMELEN];
2N/A
2N/A if (name == NULL || new_name == NULL)
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A (void) strlcpy(gname, name, MAXNAMELEN);
2N/A if (!smb_lgrp_normalize_name(gname))
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A (void) strlcpy(new_gname, new_name, MAXNAMELEN);
2N/A if (!smb_lgrp_normalize_name(new_gname))
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A if (smb_strcasecmp(gname, new_gname, 0) == 0)
2N/A return (SMB_LGRP_SUCCESS);
2N/A
2N/A /* Cannot rename well-known groups */
2N/A if (smb_wka_lookup_name(gname) != NULL)
2N/A return (SMB_LGRP_WKSID);
2N/A
2N/A /* Cannot rename to a well-known groups */
2N/A if (smb_wka_lookup_name(new_gname) != NULL)
2N/A return (SMB_LGRP_WKSID);
2N/A
2N/A grp.sg_name = new_gname;
2N/A
2N/A if (!smb_lgrp_enter())
2N/A return (SMB_LGRP_OFFLINE);
2N/A
2N/A if (getgrnam(new_gname) == NULL) {
2N/A if (smb_lgrp_pgrp_add(new_gname) != 0) {
2N/A smb_lgrp_exit();
2N/A return (SMB_LGRP_POSIXCREATE_FAILED);
2N/A }
2N/A
2N/A if (getgrnam(new_gname) == NULL) {
2N/A smb_lgrp_exit();
2N/A return (SMB_LGRP_NOT_FOUND);
2N/A }
2N/A }
2N/A
2N/A db = smb_lgrp_db_open(SMB_LGRP_DB_ORW);
2N/A rc = smb_lgrp_gtbl_update(db, gname, &grp, SMB_LGRP_GTBL_NAME);
2N/A smb_lgrp_db_close(db);
2N/A
2N/A smb_lgrp_exit();
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_delete
2N/A *
2N/A * Deletes the specified local group.
2N/A */
2N/Aint
2N/Asmb_lgrp_delete(char *name)
2N/A{
2N/A sqlite3 *db;
2N/A int rc;
2N/A char gname[MAXNAMELEN];
2N/A
2N/A if (name == NULL)
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A (void) strlcpy(gname, name, MAXNAMELEN);
2N/A if (!smb_lgrp_normalize_name(gname))
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A /* Cannot remove a built-in group */
2N/A if (smb_wka_lookup_name(gname) != NULL)
2N/A return (SMB_LGRP_WKSID);
2N/A
2N/A
2N/A if (!smb_lgrp_exists(gname))
2N/A return (SMB_LGRP_NOT_FOUND);
2N/A
2N/A if (!smb_lgrp_enter())
2N/A return (SMB_LGRP_OFFLINE);
2N/A
2N/A db = smb_lgrp_db_open(SMB_LGRP_DB_ORW);
2N/A rc = smb_lgrp_gtbl_delete(db, gname);
2N/A smb_lgrp_db_close(db);
2N/A
2N/A smb_lgrp_exit();
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_setcmnt
2N/A *
2N/A * Sets the description for the given group
2N/A */
2N/Aint
2N/Asmb_lgrp_setcmnt(char *name, char *cmnt)
2N/A{
2N/A smb_group_t grp;
2N/A sqlite3 *db;
2N/A int rc;
2N/A char gname[MAXNAMELEN];
2N/A
2N/A if (name == NULL)
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A (void) strlcpy(gname, name, MAXNAMELEN);
2N/A if (!smb_lgrp_normalize_name(gname))
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A if (cmnt && (strlen(cmnt) > SMB_LGRP_COMMENT_MAX))
2N/A return (SMB_LGRP_INVALID_ARG);
2N/A
2N/A grp.sg_cmnt = cmnt;
2N/A
2N/A if (!smb_lgrp_enter())
2N/A return (SMB_LGRP_OFFLINE);
2N/A
2N/A db = smb_lgrp_db_open(SMB_LGRP_DB_ORW);
2N/A rc = smb_lgrp_gtbl_update(db, gname, &grp, SMB_LGRP_GTBL_CMNT);
2N/A smb_lgrp_db_close(db);
2N/A
2N/A smb_lgrp_exit();
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_getcmnt
2N/A *
2N/A * Obtain the description of the specified group
2N/A */
2N/Aint
2N/Asmb_lgrp_getcmnt(char *name, char **cmnt)
2N/A{
2N/A smb_group_t grp;
2N/A sqlite3 *db;
2N/A int rc;
2N/A char gname[MAXNAMELEN];
2N/A
2N/A if (name == NULL)
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A (void) strlcpy(gname, name, MAXNAMELEN);
2N/A if (!smb_lgrp_normalize_name(gname))
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A if (cmnt == NULL)
2N/A return (SMB_LGRP_INVALID_ARG);
2N/A
2N/A if (!smb_lgrp_enter())
2N/A return (SMB_LGRP_OFFLINE);
2N/A
2N/A db = smb_lgrp_db_open(SMB_LGRP_DB_ORD);
2N/A rc = smb_lgrp_gtbl_lookup(db, SMB_LGRP_GTBL_NAME, &grp,
2N/A SMB_LGRP_INFO_CMNT, gname);
2N/A smb_lgrp_db_close(db);
2N/A smb_lgrp_exit();
2N/A
2N/A if (rc == SMB_LGRP_SUCCESS) {
2N/A *cmnt = grp.sg_cmnt;
2N/A grp.sg_cmnt = NULL;
2N/A smb_lgrp_free(&grp);
2N/A }
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * smb_lgrp_setpriv
2N/A *
2N/A * Enable/disable the specified privilge for the group
2N/A */
2N/Aint
2N/Asmb_lgrp_setpriv(char *name, uint8_t priv_lid, boolean_t enable)
2N/A{
2N/A sqlite3 *db;
2N/A int rc;
2N/A char gname[MAXNAMELEN];
2N/A
2N/A if (name == NULL)
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A (void) strlcpy(gname, name, MAXNAMELEN);
2N/A if (!smb_lgrp_normalize_name(gname))
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A if ((priv_lid < SE_MIN_LUID) || (priv_lid > SE_MAX_LUID))
2N/A return (SMB_LGRP_NO_SUCH_PRIV);
2N/A
2N/A if (!smb_lgrp_enter())
2N/A return (SMB_LGRP_OFFLINE);
2N/A
2N/A db = smb_lgrp_db_open(SMB_LGRP_DB_ORW);
2N/A rc = smb_lgrp_gtbl_update_plist(db, gname, priv_lid, enable);
2N/A smb_lgrp_db_close(db);
2N/A smb_lgrp_exit();
2N/A
2N/A if (enable) {
2N/A if (rc == SMB_LGRP_PRIV_HELD)
2N/A rc = SMB_LGRP_SUCCESS;
2N/A } else {
2N/A if (rc == SMB_LGRP_PRIV_NOT_HELD)
2N/A rc = SMB_LGRP_SUCCESS;
2N/A }
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_getpriv
2N/A *
2N/A * Obtain the status of the specified privilge for the group
2N/A */
2N/Aint
2N/Asmb_lgrp_getpriv(char *name, uint8_t priv_lid, boolean_t *enable)
2N/A{
2N/A sqlite3 *db;
2N/A smb_group_t grp;
2N/A int rc;
2N/A char gname[MAXNAMELEN];
2N/A
2N/A if (name == NULL)
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A (void) strlcpy(gname, name, MAXNAMELEN);
2N/A if (!smb_lgrp_normalize_name(gname))
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A if ((priv_lid < SE_MIN_LUID) || (priv_lid > SE_MAX_LUID))
2N/A return (SMB_LGRP_NO_SUCH_PRIV);
2N/A
2N/A if (!smb_lgrp_enter())
2N/A return (SMB_LGRP_OFFLINE);
2N/A
2N/A db = smb_lgrp_db_open(SMB_LGRP_DB_ORD);
2N/A rc = smb_lgrp_gtbl_lookup(db, SMB_LGRP_GTBL_NAME, &grp,
2N/A SMB_LGRP_INFO_PRIV, gname);
2N/A smb_lgrp_db_close(db);
2N/A smb_lgrp_exit();
2N/A
2N/A if (rc == SMB_LGRP_SUCCESS) {
2N/A *enable = (smb_privset_query(grp.sg_privs, priv_lid) == 1);
2N/A smb_lgrp_free(&grp);
2N/A }
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_add_member
2N/A *
2N/A * Add the given account to the specified group as its member.
2N/A */
2N/Aint
2N/Asmb_lgrp_add_member(char *name, smb_sid_t *msid, uint16_t sid_type)
2N/A{
2N/A sqlite3 *db;
2N/A smb_gsid_t mid;
2N/A int rc;
2N/A char gname[MAXNAMELEN];
2N/A
2N/A if (name == NULL)
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A (void) strlcpy(gname, name, MAXNAMELEN);
2N/A if (!smb_lgrp_normalize_name(gname))
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A if (!smb_sid_isvalid(msid))
2N/A return (SMB_LGRP_INVALID_ARG);
2N/A
2N/A if (!smb_lgrp_chkmember(sid_type))
2N/A return (SMB_LGRP_INVALID_MEMBER);
2N/A
2N/A mid.gs_sid = msid;
2N/A mid.gs_type = sid_type;
2N/A
2N/A if (!smb_lgrp_enter())
2N/A return (SMB_LGRP_OFFLINE);
2N/A
2N/A db = smb_lgrp_db_open(SMB_LGRP_DB_ORW);
2N/A rc = smb_lgrp_gtbl_update_mlist(db, gname, &mid, SMB_LGRP_DB_ADDMEMBER);
2N/A smb_lgrp_db_close(db);
2N/A
2N/A smb_lgrp_exit();
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_del_member
2N/A *
2N/A * Delete the specified member from the given group.
2N/A */
2N/Aint
2N/Asmb_lgrp_del_member(char *name, smb_sid_t *msid, uint16_t sid_type)
2N/A{
2N/A sqlite3 *db;
2N/A smb_gsid_t mid;
2N/A int rc;
2N/A char gname[MAXNAMELEN];
2N/A
2N/A if (name == NULL)
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A (void) strlcpy(gname, name, MAXNAMELEN);
2N/A if (!smb_lgrp_normalize_name(gname))
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A if (!smb_sid_isvalid(msid))
2N/A return (SMB_LGRP_INVALID_ARG);
2N/A
2N/A mid.gs_sid = msid;
2N/A mid.gs_type = sid_type;
2N/A
2N/A if (!smb_lgrp_enter())
2N/A return (SMB_LGRP_OFFLINE);
2N/A
2N/A db = smb_lgrp_db_open(SMB_LGRP_DB_ORW);
2N/A rc = smb_lgrp_gtbl_update_mlist(db, gname, &mid, SMB_LGRP_DB_DELMEMBER);
2N/A smb_lgrp_db_close(db);
2N/A
2N/A smb_lgrp_exit();
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_getbyname
2N/A *
2N/A * Retrieves the information of the group specified by
2N/A * the given name.
2N/A *
2N/A * Note that this function doesn't allocate the group
2N/A * structure itself only the fields, so the given grp
2N/A * pointer has to point to a group structure.
2N/A * Caller must free the allocated memories for the fields
2N/A * by calling smb_lgrp_free().
2N/A */
2N/Aint
2N/Asmb_lgrp_getbyname(char *name, smb_group_t *grp)
2N/A{
2N/A sqlite3 *db;
2N/A int rc;
2N/A char gname[MAXNAMELEN];
2N/A
2N/A if (name == NULL)
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A (void) strlcpy(gname, name, MAXNAMELEN);
2N/A if (!smb_lgrp_normalize_name(gname))
2N/A return (SMB_LGRP_INVALID_NAME);
2N/A
2N/A if (!smb_lgrp_enter())
2N/A return (SMB_LGRP_OFFLINE);
2N/A
2N/A db = smb_lgrp_db_open(SMB_LGRP_DB_ORD);
2N/A rc = smb_lgrp_gtbl_lookup(db, SMB_LGRP_GTBL_NAME, grp,
2N/A SMB_LGRP_INFO_ALL, gname);
2N/A smb_lgrp_db_close(db);
2N/A
2N/A smb_lgrp_exit();
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_getbyrid
2N/A *
2N/A * Retrieves the information of the group specified by
2N/A * the given RID and domain type.
2N/A *
2N/A * Note that this function doesn't allocate the group
2N/A * structure itself only the fields, so the given grp
2N/A * pointer has to point to a group structure.
2N/A * Caller must free the allocated memories for the fields
2N/A * by calling smb_lgrp_free().
2N/A *
2N/A * If grp is NULL no information would be returned. The
2N/A * return value of SMB_LGRP_SUCCESS will indicate that a
2N/A * group with the given information exists.
2N/A */
2N/Aint
2N/Asmb_lgrp_getbyrid(uint32_t rid, smb_domain_type_t domtype, smb_group_t *grp)
2N/A{
2N/A smb_group_t tmpgrp;
2N/A sqlite3 *db;
2N/A int infolvl = SMB_LGRP_INFO_ALL;
2N/A int rc;
2N/A
2N/A if (!smb_lgrp_enter())
2N/A return (SMB_LGRP_OFFLINE);
2N/A
2N/A if (grp == NULL) {
2N/A grp = &tmpgrp;
2N/A infolvl = SMB_LGRP_INFO_NONE;
2N/A }
2N/A
2N/A db = smb_lgrp_db_open(SMB_LGRP_DB_ORD);
2N/A rc = smb_lgrp_gtbl_lookup(db, SMB_LGRP_GTBL_SIDRID, grp, infolvl,
2N/A rid, domtype);
2N/A smb_lgrp_db_close(db);
2N/A
2N/A smb_lgrp_exit();
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * Returns the number of groups in the given domain in the
2N/A * arg 'count'. Local groups are either in BUILTIN domain
2N/A * or in machine/local domain. Groups in the machine domain
2N/A * MUST have a corresponding Solaris group at the time they
2N/A * are created, which means there is a valid GID mapping for
2N/A * their SID, therefore SMB_LGRP_POSIX_IDX is used to lookup
2N/A * groups in the machine domain.
2N/A */
2N/Aint
2N/Asmb_lgrp_numbydomain(smb_domain_type_t dom_type, int *count)
2N/A{
2N/A sqlite3 *db;
2N/A int dom_idx;
2N/A int rc;
2N/A
2N/A switch (dom_type) {
2N/A case SMB_DOMAIN_LOCAL:
2N/A dom_idx = SMB_LGRP_POSIX_IDX;
2N/A break;
2N/A case SMB_DOMAIN_BUILTIN:
2N/A dom_idx = SMB_LGRP_BUILTIN_IDX;
2N/A break;
2N/A default:
2N/A *count = 0;
2N/A return (SMB_LGRP_INVALID_ARG);
2N/A }
2N/A
2N/A if (!smb_lgrp_enter())
2N/A return (SMB_LGRP_OFFLINE);
2N/A
2N/A db = smb_lgrp_db_open(SMB_LGRP_DB_ORD);
2N/A rc = smb_lgrp_gtbl_count(db, dom_idx, count);
2N/A smb_lgrp_db_close(db);
2N/A
2N/A smb_lgrp_exit();
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_free
2N/A *
2N/A * Frees the allocated memory for the fields of the given
2N/A * group structure. Note that this function doesn't free
2N/A * the group itself.
2N/A */
2N/Avoid
2N/Asmb_lgrp_free(smb_group_t *grp)
2N/A{
2N/A int i;
2N/A
2N/A if (grp == NULL)
2N/A return;
2N/A
2N/A free(grp->sg_name);
2N/A free(grp->sg_cmnt);
2N/A smb_sid_free(grp->sg_id.gs_sid);
2N/A smb_privset_free(grp->sg_privs);
2N/A
2N/A for (i = 0; i < grp->sg_nmembers; i++)
2N/A smb_sid_free(grp->sg_members[i].gs_sid);
2N/A free(grp->sg_members);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_iteropen
2N/A *
2N/A * Allocates memory and initializes the given group iterator by opening
2N/A * the group database and creating a virtual machine
2N/A * for iteration.
2N/A */
2N/Aint
2N/Asmb_lgrp_iteropen(smb_giter_t **iterator)
2N/A{
2N/A char *sql;
2N/A int rc;
2N/A struct smb_giter *iter;
2N/A
2N/A assert(iterator);
2N/A
2N/A if (!smb_lgrp_enter())
2N/A return (SMB_LGRP_OFFLINE);
2N/A
2N/A iter = calloc(1, sizeof (struct smb_giter));
2N/A if (iter == NULL) {
2N/A smb_lgrp_exit();
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A }
2N/A
2N/A sql = sqlite3_mprintf("SELECT * FROM groups");
2N/A if (sql == NULL) {
2N/A free(iter);
2N/A smb_lgrp_exit();
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A }
2N/A
2N/A iter->sgi_db = smb_lgrp_db_open(SMB_LGRP_DB_ORD);
2N/A if (iter->sgi_db == NULL) {
2N/A sqlite3_free(sql);
2N/A free(iter);
2N/A smb_lgrp_exit();
2N/A return (SMB_LGRP_DBOPEN_FAILED);
2N/A }
2N/A
2N/A rc = sqlite3_prepare_v2(iter->sgi_db, sql, -1, &iter->sgi_vm, NULL);
2N/A sqlite3_free(sql);
2N/A if (rc != SQLITE_OK || iter->sgi_vm == NULL) {
2N/A syslog(LOG_DEBUG, "failed to create a prepared statement (%s)",
2N/A NULL_MSGCHK(sqlite3_errmsg(iter->sgi_db)));
2N/A smb_lgrp_db_close(iter->sgi_db);
2N/A free(iter);
2N/A smb_lgrp_exit();
2N/A return (SMB_LGRP_DB_ERROR);
2N/A }
2N/A
2N/A *iterator = iter;
2N/A smb_lgrp_exit();
2N/A return (SMB_LGRP_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_iterclose
2N/A *
2N/A * Closes the given group iterator and frees the memory associated with it.
2N/A */
2N/Avoid
2N/Asmb_lgrp_iterclose(smb_giter_t *iter)
2N/A{
2N/A int rc;
2N/A
2N/A assert(iter);
2N/A
2N/A if (!smb_lgrp_enter())
2N/A return;
2N/A
2N/A rc = sqlite3_finalize(iter->sgi_vm);
2N/A if (rc != SQLITE_OK)
2N/A syslog(LOG_DEBUG, "failed to destroy a VM (%s)",
2N/A NULL_MSGCHK(sqlite3_errmsg(iter->sgi_db)));
2N/A
2N/A smb_lgrp_db_close(iter->sgi_db);
2N/A free(iter);
2N/A smb_lgrp_exit();
2N/A}
2N/A
2N/A/*
2N/A * Returns B_TRUE if there has been an error during
2N/A * iteration. The passed iterator needs to be valid.
2N/A */
2N/Aboolean_t
2N/Asmb_lgrp_itererror(smb_giter_t *iter)
2N/A{
2N/A if (iter == NULL)
2N/A return (B_TRUE);
2N/A
2N/A return (iter->sgi_nerr != 0);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_iterate
2N/A *
2N/A * Iterate through group database. Valid group iterator structure,
2N/A * created via smb_lgrp_iteropen(), must be passed here.
2N/A * Group information is returned in provided group structure.
2N/A *
2N/A * Note that this function doesn't allocate the group structure itself,
2N/A * only the fields, so the given grp pointer has to point to a group structure.
2N/A * Caller must free the allocated memories for the fields by calling
2N/A * smb_lgrp_free(). Successive calls to smb_lgrp_iterate() will process the
2N/A * next row of data, until there is no more information to be processed or
2N/A * an error occurs.
2N/A *
2N/A * When the iterator finishes iterating through all the data or if there is
2N/A * an error stepping through the data, the current iterator must be closed via
2N/A * smb_lgrp_iterclose(). A new iterator must be obtained via smb_lgrp_iteropen()
2N/A * before calling smb_lgrp_iterate() again. An iterator cannot be reused without
2N/A * being reset. Currently the intended usage is that the iterator be opened,
2N/A * used and closed; thus reset is not supported.
2N/A */
2N/Aint
2N/Asmb_lgrp_iterate(smb_giter_t *iter, smb_group_t *grp)
2N/A{
2N/A char **values;
2N/A char *val;
2N/A int ncol;
2N/A int rc;
2N/A int i;
2N/A
2N/A if (iter == NULL || iter->sgi_vm == NULL || iter->sgi_db == NULL)
2N/A return (SMB_LGRP_INVALID_ARG);
2N/A
2N/A if (!smb_lgrp_enter())
2N/A return (SMB_LGRP_OFFLINE);
2N/A
2N/A for (;;) {
2N/A bzero(grp, sizeof (smb_group_t));
2N/A rc = sqlite3_step(iter->sgi_vm);
2N/A if (rc == SQLITE_DONE) {
2N/A smb_lgrp_exit();
2N/A return (SMB_LGRP_NO_MORE);
2N/A }
2N/A
2N/A if (rc != SQLITE_ROW) {
2N/A smb_lgrp_exit();
2N/A return (SMB_LGRP_DBEXEC_FAILED);
2N/A }
2N/A
2N/A ncol = sqlite3_column_count(iter->sgi_vm);
2N/A if (ncol != SMB_LGRP_GTBL_NCOL) {
2N/A smb_lgrp_exit();
2N/A return (SMB_LGRP_DB_ERROR);
2N/A }
2N/A
2N/A if ((values = calloc(ncol, sizeof (char *))) == NULL) {
2N/A smb_lgrp_exit();
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A }
2N/A
2N/A for (i = 0; i < ncol; i++) {
2N/A val = (char *)sqlite3_column_text(iter->sgi_vm, i);
2N/A if ((val == NULL) ||
2N/A ((values[i] = strdup(val)) == NULL)) {
2N/A smb_lgrp_free_columns(i, values);
2N/A smb_lgrp_exit();
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A }
2N/A }
2N/A
2N/A rc = smb_lgrp_decode(grp, values, SMB_LGRP_INFO_ALL,
2N/A iter->sgi_db);
2N/A smb_lgrp_free_columns(ncol, values);
2N/A if (rc == SMB_LGRP_SUCCESS)
2N/A break;
2N/A
2N/A iter->sgi_nerr++;
2N/A syslog(LOG_ERR, "smb_lgrp_iterate: %s", smb_lgrp_strerror(rc));
2N/A }
2N/A
2N/A smb_lgrp_exit();
2N/A return (rc);
2N/A
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_is_member
2N/A *
2N/A * Check to see if the specified account is a member of
2N/A * the given group.
2N/A */
2N/Aboolean_t
2N/Asmb_lgrp_is_member(smb_group_t *grp, smb_sid_t *sid)
2N/A{
2N/A int i;
2N/A
2N/A if (grp == NULL || grp->sg_members == NULL || sid == NULL)
2N/A return (B_FALSE);
2N/A
2N/A for (i = 0; i < grp->sg_nmembers; i++) {
2N/A if (smb_sid_cmp(grp->sg_members[i].gs_sid, sid))
2N/A return (B_TRUE);
2N/A }
2N/A
2N/A return (B_FALSE);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_strerror
2N/A *
2N/A * Returns a text for the given group error code.
2N/A */
2N/Achar *
2N/Asmb_lgrp_strerror(int errnum)
2N/A{
2N/A int i;
2N/A int nerr = (sizeof (errtab) / sizeof (errtab[0]));
2N/A
2N/A for (i = 0; i < nerr; ++i) {
2N/A if (errnum == errtab[i].errnum)
2N/A return (errtab[i].errmsg);
2N/A }
2N/A
2N/A return ("unknown local group error");
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_err_to_ntstatus
2N/A *
2N/A * This routine maps Local group operation errors to NT Status error codes.
2N/A */
2N/Auint32_t
2N/Asmb_lgrp_err_to_ntstatus(uint32_t lgrp_err)
2N/A{
2N/A int i;
2N/A static struct err_map {
2N/A uint32_t lgrp_err;
2N/A uint32_t nt_status;
2N/A } err_map[] = {
2N/A { SMB_LGRP_SUCCESS, NT_STATUS_SUCCESS },
2N/A { SMB_LGRP_INVALID_ARG, NT_STATUS_INVALID_PARAMETER },
2N/A { SMB_LGRP_INVALID_MEMBER, NT_STATUS_INVALID_MEMBER },
2N/A { SMB_LGRP_INVALID_NAME, NT_STATUS_INVALID_PARAMETER },
2N/A { SMB_LGRP_NOT_FOUND, NT_STATUS_NO_SUCH_ALIAS },
2N/A { SMB_LGRP_EXISTS, NT_STATUS_ALIAS_EXISTS },
2N/A { SMB_LGRP_NO_SID, NT_STATUS_INVALID_SID },
2N/A { SMB_LGRP_NO_LOCAL_SID, NT_STATUS_INVALID_SID },
2N/A { SMB_LGRP_SID_NOTLOCAL, NT_STATUS_INVALID_SID },
2N/A { SMB_LGRP_WKSID, NT_STATUS_INVALID_SID },
2N/A { SMB_LGRP_NO_MEMORY, NT_STATUS_NO_MEMORY },
2N/A { SMB_LGRP_DB_ERROR, NT_STATUS_INTERNAL_DB_ERROR },
2N/A { SMB_LGRP_DBINIT_ERROR, NT_STATUS_INTERNAL_DB_ERROR },
2N/A { SMB_LGRP_INTERNAL_ERROR, NT_STATUS_INTERNAL_ERROR },
2N/A { SMB_LGRP_MEMBER_IN_GROUP, NT_STATUS_MEMBER_IN_ALIAS },
2N/A { SMB_LGRP_MEMBER_NOT_IN_GROUP, NT_STATUS_MEMBER_NOT_IN_ALIAS },
2N/A { SMB_LGRP_NO_SUCH_PRIV, NT_STATUS_NO_SUCH_PRIVILEGE },
2N/A { SMB_LGRP_NO_SUCH_DOMAIN, NT_STATUS_NO_SUCH_DOMAIN },
2N/A { SMB_LGRP_PRIV_HELD, NT_STATUS_SUCCESS },
2N/A { SMB_LGRP_PRIV_NOT_HELD, NT_STATUS_PRIVILEGE_NOT_HELD },
2N/A { SMB_LGRP_BAD_DATA, NT_STATUS_DATA_ERROR },
2N/A { SMB_LGRP_NO_MORE, NT_STATUS_NO_MORE_ENTRIES },
2N/A { SMB_LGRP_DBOPEN_FAILED, NT_STATUS_INTERNAL_DB_ERROR },
2N/A { SMB_LGRP_DBEXEC_FAILED, NT_STATUS_INTERNAL_DB_ERROR },
2N/A { SMB_LGRP_DBINIT_FAILED, NT_STATUS_INTERNAL_DB_ERROR },
2N/A { SMB_LGRP_DOMLKP_FAILED, NT_STATUS_INTERNAL_DB_ERROR },
2N/A { SMB_LGRP_DOMINS_FAILED, NT_STATUS_INTERNAL_DB_ERROR },
2N/A { SMB_LGRP_INSERT_FAILED, NT_STATUS_INTERNAL_DB_ERROR },
2N/A { SMB_LGRP_DELETE_FAILED, NT_STATUS_INTERNAL_DB_ERROR },
2N/A { SMB_LGRP_UPDATE_FAILED, NT_STATUS_INTERNAL_DB_ERROR },
2N/A { SMB_LGRP_LOOKUP_FAILED, NT_STATUS_INTERNAL_DB_ERROR },
2N/A { SMB_LGRP_NOT_SUPPORTED, NT_STATUS_NOT_SUPPORTED },
2N/A { SMB_LGRP_OFFLINE, NT_STATUS_INTERNAL_ERROR },
2N/A { SMB_LGRP_POSIXCREATE_FAILED, NT_STATUS_UNSUCCESSFUL }
2N/A };
2N/A
2N/A for (i = 0; i < sizeof (err_map)/sizeof (err_map[0]); ++i) {
2N/A if (err_map[i].lgrp_err == lgrp_err)
2N/A return (err_map[i].nt_status);
2N/A }
2N/A
2N/A return (NT_STATUS_INTERNAL_ERROR);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_chkmember
2N/A *
2N/A * Determines valid account types for being member of
2N/A * a local group.
2N/A *
2N/A * Currently, we just support users as valid members.
2N/A */
2N/Astatic boolean_t
2N/Asmb_lgrp_chkmember(uint16_t sid_type)
2N/A{
2N/A return (sid_type == SidTypeUser);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_start
2N/A *
2N/A * Initializes the library private global variables.
2N/A * Create the database, if it doesn't exist, and add
2N/A * the predefined builtin groups.
2N/A */
2N/Aint
2N/Asmb_lgrp_start(void)
2N/A{
2N/A static char *builtin[] = {
2N/A "Administrators",
2N/A "Backup Operators",
2N/A "Power Users"
2N/A };
2N/A smb_wka_t *wka;
2N/A char *localsid;
2N/A int i, rc;
2N/A int ngrp = sizeof (builtin) / sizeof (builtin[0]);
2N/A
2N/A (void) mutex_lock(&smb_localgrp.lg_mutex);
2N/A
2N/A if ((localsid = smb_config_get_localsid()) == NULL) {
2N/A (void) mutex_unlock(&smb_localgrp.lg_mutex);
2N/A return (SMB_LGRP_NO_LOCAL_SID);
2N/A }
2N/A
2N/A smb_localgrp.lg_machine_sid = smb_sid_fromstr(localsid);
2N/A free(localsid);
2N/A
2N/A if (!smb_sid_isvalid(smb_localgrp.lg_machine_sid)) {
2N/A free(smb_localgrp.lg_machine_sid);
2N/A smb_localgrp.lg_machine_sid = NULL;
2N/A (void) mutex_unlock(&smb_localgrp.lg_mutex);
2N/A return (SMB_LGRP_NO_LOCAL_SID);
2N/A }
2N/A
2N/A rc = smb_lgrp_db_init();
2N/A if (rc != SMB_LGRP_SUCCESS) {
2N/A free(smb_localgrp.lg_machine_sid);
2N/A smb_localgrp.lg_machine_sid = NULL;
2N/A (void) mutex_unlock(&smb_localgrp.lg_mutex);
2N/A return (rc);
2N/A }
2N/A
2N/A smb_localgrp.lg_online = B_TRUE;
2N/A (void) mutex_unlock(&smb_localgrp.lg_mutex);
2N/A
2N/A for (i = 0; i < ngrp; i++) {
2N/A if ((wka = smb_wka_lookup_name(builtin[i])) == NULL)
2N/A continue;
2N/A
2N/A if (!smb_lgrp_exists(wka->wka_name)) {
2N/A rc = smb_lgrp_add(wka->wka_name, wka->wka_desc);
2N/A if (rc != SMB_LGRP_SUCCESS)
2N/A syslog(LOG_DEBUG, "failed to add %s group",
2N/A wka->wka_name);
2N/A }
2N/A }
2N/A
2N/A return (SMB_LGRP_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_stop
2N/A *
2N/A * Unintialize the library global private variables.
2N/A */
2N/Avoid
2N/Asmb_lgrp_stop(void)
2N/A{
2N/A (void) mutex_lock(&smb_localgrp.lg_mutex);
2N/A if (!smb_localgrp.lg_online)
2N/A return;
2N/A
2N/A smb_localgrp.lg_online = B_FALSE;
2N/A
2N/A while (smb_localgrp.lg_refcnt > 0)
2N/A (void) cond_wait(&smb_localgrp.lg_cv, &smb_localgrp.lg_mutex);
2N/A
2N/A free(smb_localgrp.lg_machine_sid);
2N/A smb_localgrp.lg_machine_sid = NULL;
2N/A (void) mutex_unlock(&smb_localgrp.lg_mutex);
2N/A}
2N/A
2N/Astatic boolean_t
2N/Asmb_lgrp_enter(void)
2N/A{
2N/A boolean_t status;
2N/A
2N/A (void) mutex_lock(&smb_localgrp.lg_mutex);
2N/A
2N/A status = smb_localgrp.lg_online;
2N/A
2N/A if (smb_localgrp.lg_online)
2N/A ++smb_localgrp.lg_refcnt;
2N/A
2N/A (void) mutex_unlock(&smb_localgrp.lg_mutex);
2N/A return (status);
2N/A}
2N/A
2N/Astatic void
2N/Asmb_lgrp_exit(void)
2N/A{
2N/A (void) mutex_lock(&smb_localgrp.lg_mutex);
2N/A assert(smb_localgrp.lg_refcnt > 0);
2N/A
2N/A if ((--smb_localgrp.lg_refcnt) == 0)
2N/A (void) cond_signal(&smb_localgrp.lg_cv);
2N/A
2N/A (void) mutex_unlock(&smb_localgrp.lg_mutex);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_db_open
2N/A *
2N/A * Opens group database with the given mode.
2N/A */
2N/Astatic sqlite3 *
2N/Asmb_lgrp_db_open(int mode)
2N/A{
2N/A sqlite3 *db;
2N/A int err;
2N/A
2N/A err = sqlite3_open_v2(SMB_LGRP_DB_NAME, &db, mode, NULL);
2N/A if (db == NULL || err != SQLITE_OK) {
2N/A syslog(LOG_ERR, "failed to open group database (%s)",
2N/A NULL_MSGCHK(sqlite3_errmsg(db)));
2N/A (void) sqlite3_close(db);
2N/A }
2N/A
2N/A return (db);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_db_close
2N/A *
2N/A * Closes the given database handle
2N/A */
2N/Astatic void
2N/Asmb_lgrp_db_close(sqlite3 *db)
2N/A{
2N/A if (db) {
2N/A (void) sqlite3_close(db);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_db_init
2N/A *
2N/A * Creates the group database based on the defined SQL statement.
2N/A * It also initializes db_info and domain tables.
2N/A */
2N/Astatic int
2N/Asmb_lgrp_db_init(void)
2N/A{
2N/A int dbrc = SQLITE_OK;
2N/A int rc = SMB_LGRP_SUCCESS;
2N/A sqlite3 *db = NULL;
2N/A char *errmsg = NULL;
2N/A int err;
2N/A
2N/A err = sqlite3_open_v2(SMB_LGRP_DB_NAME, &db, SMB_LGRP_DB_ORWC, NULL);
2N/A if (db == NULL || err != SQLITE_OK) {
2N/A syslog(LOG_ERR, "failed to create group database (%s)",
2N/A NULL_MSGCHK(sqlite3_errmsg(db)));
2N/A (void) sqlite3_close(db);
2N/A return (SMB_LGRP_DBOPEN_FAILED);
2N/A }
2N/A
2N/A (void) sqlite3_busy_timeout(db, SMB_LGRP_DB_TIMEOUT);
2N/A dbrc = sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, &errmsg);
2N/A if (dbrc != SQLITE_OK) {
2N/A syslog(LOG_DEBUG, "failed to begin database transaction (%s)",
2N/A NULL_MSGCHK(errmsg));
2N/A sqlite3_free(errmsg);
2N/A (void) sqlite3_close(db);
2N/A return (SMB_LGRP_DBEXEC_FAILED);
2N/A }
2N/A
2N/A switch (sqlite3_exec(db, SMB_LGRP_DB_SQL, NULL, NULL, &errmsg)) {
2N/A case SQLITE_ERROR:
2N/A /*
2N/A * This is the normal situation: CREATE probably failed because
2N/A * tables already exist. It may indicate an error in SQL as well
2N/A * but we cannot tell.
2N/A */
2N/A sqlite3_free(errmsg);
2N/A dbrc = sqlite3_exec(db, "ROLLBACK TRANSACTION", NULL, NULL,
2N/A &errmsg);
2N/A rc = SMB_LGRP_SUCCESS;
2N/A break;
2N/A
2N/A case SQLITE_OK:
2N/A dbrc = sqlite3_exec(db, "COMMIT TRANSACTION", NULL, NULL,
2N/A &errmsg);
2N/A if (dbrc != SQLITE_OK)
2N/A break;
2N/A rc = smb_lgrp_dtbl_insert(db, NT_BUILTIN_DOMAIN_SIDSTR,
2N/A NULL);
2N/A if (rc == SMB_LGRP_SUCCESS)
2N/A rc = smb_lgrp_db_setinfo(db);
2N/A if (rc != SMB_LGRP_SUCCESS) {
2N/A (void) sqlite3_close(db);
2N/A (void) unlink(SMB_LGRP_DB_NAME);
2N/A return (rc);
2N/A }
2N/A break;
2N/A
2N/A default:
2N/A syslog(LOG_ERR,
2N/A "failed to initialize group database (%s)", errmsg);
2N/A sqlite3_free(errmsg);
2N/A dbrc = sqlite3_exec(db, "ROLLBACK TRANSACTION", NULL, NULL,
2N/A &errmsg);
2N/A rc = SMB_LGRP_DBINIT_FAILED;
2N/A break;
2N/A }
2N/A
2N/A if (dbrc != SQLITE_OK) {
2N/A /* this is bad - database may be left in a locked state */
2N/A syslog(LOG_DEBUG, "failed to close a transaction (%s)",
2N/A NULL_MSGCHK(errmsg));
2N/A sqlite3_free(errmsg);
2N/A }
2N/A
2N/A (void) sqlite3_close(db);
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_gtbl_lookup
2N/A *
2N/A * This is a flexible lookup function for the group database.
2N/A * The key type can be specified by the 'key' arg and the actual key
2N/A * values can be passed after the 'infolvl' arg. 'infolvl' arg specifies
2N/A * what information items for the specified group is needed.
2N/A *
2N/A * Note that the function assumes the given key is unique and only
2N/A * specifies one or 0 group. The keys that are supported now are
2N/A * the group name and the group SID
2N/A *
2N/A * Note that this function doesn't allocate the group
2N/A * structure itself only the fields, so the given grp
2N/A * pointer has to point to a group structure.
2N/A * Caller must free the allocated memories for the fields
2N/A * by calling smb_lgrp_free().
2N/A */
2N/Astatic int
2N/Asmb_lgrp_gtbl_lookup(sqlite3 *db, int key, smb_group_t *grp, int infolvl, ...)
2N/A{
2N/A char *errmsg = NULL;
2N/A char *sql;
2N/A char **result;
2N/A int nrow, ncol;
2N/A int rc, dom_idx;
2N/A smb_group_t grpkey;
2N/A va_list ap;
2N/A
2N/A if (db == NULL)
2N/A return (SMB_LGRP_DBOPEN_FAILED);
2N/A
2N/A bzero(grp, sizeof (smb_group_t));
2N/A va_start(ap, infolvl);
2N/A
2N/A switch (key) {
2N/A case SMB_LGRP_GTBL_NAME:
2N/A grpkey.sg_name = va_arg(ap, char *);
2N/A sql = sqlite3_mprintf("SELECT * FROM groups WHERE name = '%s'",
2N/A grpkey.sg_name);
2N/A break;
2N/A
2N/A case SMB_LGRP_GTBL_SIDRID:
2N/A grpkey.sg_rid = va_arg(ap, uint32_t);
2N/A grpkey.sg_domain = va_arg(ap, smb_domain_type_t);
2N/A if (grpkey.sg_domain == SMB_DOMAIN_LOCAL) {
2N/A dom_idx = SMB_LGRP_POSIX_IDX;
2N/A /* need to map the given rid to a gid */
2N/A rc = smb_lgrp_getgid(grpkey.sg_rid,
2N/A (gid_t *)&grpkey.sg_rid);
2N/A if (rc != SMB_LGRP_SUCCESS) {
2N/A va_end(ap);
2N/A return (rc);
2N/A }
2N/A } else {
2N/A dom_idx = SMB_LGRP_BUILTIN_IDX;
2N/A }
2N/A
2N/A sql = sqlite3_mprintf("SELECT * FROM groups "
2N/A "WHERE (sid_idx = %d) AND (sid_rid = %u)",
2N/A dom_idx, grpkey.sg_rid);
2N/A break;
2N/A
2N/A default:
2N/A va_end(ap);
2N/A return (SMB_LGRP_INVALID_ARG);
2N/A }
2N/A
2N/A va_end(ap);
2N/A if (sql == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A rc = sqlite3_get_table(db, sql, &result, &nrow, &ncol, &errmsg);
2N/A sqlite3_free(sql);
2N/A
2N/A if (rc != SQLITE_OK) {
2N/A syslog(LOG_DEBUG, "failed to lookup (%s)", NULL_MSGCHK(errmsg));
2N/A sqlite3_free(errmsg);
2N/A return (SMB_LGRP_LOOKUP_FAILED);
2N/A }
2N/A
2N/A if (nrow == 0) {
2N/A /* group not found */
2N/A sqlite3_free_table(result);
2N/A return (SMB_LGRP_NOT_FOUND);
2N/A }
2N/A
2N/A if (nrow != 1 || ncol != SMB_LGRP_GTBL_NCOL) {
2N/A sqlite3_free_table(result);
2N/A return (SMB_LGRP_DB_ERROR);
2N/A }
2N/A
2N/A rc = smb_lgrp_decode(grp, &result[SMB_LGRP_GTBL_NCOL], infolvl, db);
2N/A sqlite3_free_table(result);
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_gtbl_exists
2N/A *
2N/A * Checks to see if the given group exists or not.
2N/A */
2N/Astatic boolean_t
2N/Asmb_lgrp_gtbl_exists(sqlite3 *db, char *gname)
2N/A{
2N/A char *errmsg = NULL;
2N/A char *sql;
2N/A char **result;
2N/A int nrow, ncol;
2N/A int rc;
2N/A
2N/A if (db == NULL)
2N/A return (B_FALSE);
2N/A
2N/A sql = sqlite3_mprintf("SELECT name FROM groups WHERE name = '%s'",
2N/A gname);
2N/A if (sql == NULL)
2N/A return (B_FALSE);
2N/A
2N/A rc = sqlite3_get_table(db, sql, &result, &nrow, &ncol, &errmsg);
2N/A sqlite3_free(sql);
2N/A
2N/A if (rc != SQLITE_OK) {
2N/A syslog(LOG_DEBUG, "failed to lookup %s (%s)",
2N/A gname, NULL_MSGCHK(errmsg));
2N/A sqlite3_free(errmsg);
2N/A return (B_FALSE);
2N/A }
2N/A
2N/A sqlite3_free_table(result);
2N/A return (nrow != 0);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_gtbl_count
2N/A *
2N/A * Counts the number of groups in the domain specified by
2N/A * 'dom_idx'
2N/A */
2N/Astatic int
2N/Asmb_lgrp_gtbl_count(sqlite3 *db, int dom_idx, int *count)
2N/A{
2N/A char *errmsg = NULL;
2N/A char *sql;
2N/A char **result;
2N/A int nrow, ncol;
2N/A int rc;
2N/A
2N/A *count = 0;
2N/A if (db == NULL)
2N/A return (SMB_LGRP_DBOPEN_FAILED);
2N/A
2N/A sql = sqlite3_mprintf("SELECT sid_idx FROM groups WHERE sid_idx = %d",
2N/A dom_idx);
2N/A if (sql == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A rc = sqlite3_get_table(db, sql, &result, &nrow, &ncol, &errmsg);
2N/A sqlite3_free(sql);
2N/A
2N/A if (rc != SQLITE_OK) {
2N/A syslog(LOG_DEBUG, "failed to count (%s)", NULL_MSGCHK(errmsg));
2N/A sqlite3_free(errmsg);
2N/A return (SMB_LGRP_LOOKUP_FAILED);
2N/A }
2N/A
2N/A sqlite3_free_table(result);
2N/A if (ncol > 1)
2N/A return (SMB_LGRP_DB_ERROR);
2N/A
2N/A *count = nrow;
2N/A return (SMB_LGRP_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_gtbl_insert
2N/A *
2N/A * Insert a record for the given group in the group database.
2N/A *
2N/A * NOTE: this function assumes that this group has no members
2N/A * at this time.
2N/A */
2N/Astatic int
2N/Asmb_lgrp_gtbl_insert(sqlite3 *db, smb_group_t *grp)
2N/A{
2N/A smb_lgpid_t privs[SE_MAX_LUID + 1];
2N/A smb_lgplist_t plist;
2N/A char *errmsg = NULL;
2N/A char *sql;
2N/A int dom_idx;
2N/A int rc;
2N/A
2N/A if (db == NULL)
2N/A return (SMB_LGRP_DBOPEN_FAILED);
2N/A
2N/A dom_idx = (grp->sg_domain == SMB_DOMAIN_LOCAL)
2N/A ? SMB_LGRP_POSIX_IDX : SMB_LGRP_BUILTIN_IDX;
2N/A
2N/A plist.p_cnt = SE_MAX_LUID;
2N/A plist.p_ids = privs;
2N/A smb_lgrp_encode_privset(grp, &plist);
2N/A
2N/A sql = sqlite3_mprintf("INSERT INTO groups "
2N/A "(name, sid_idx, sid_rid, sid_type, sid_attrs, comment, "
2N/A "n_privs, privs, n_members, members) "
2N/A "VALUES('%s', %u, %u, %u, %u, '%q', %u, '%q', %u, '%q')",
2N/A grp->sg_name, dom_idx, grp->sg_rid, grp->sg_id.gs_type,
2N/A grp->sg_attr, (grp->sg_cmnt) ? grp->sg_cmnt : "",
2N/A plist.p_cnt, (char *)plist.p_ids, 0, "");
2N/A
2N/A if (sql == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A rc = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
2N/A sqlite3_free(sql);
2N/A
2N/A if (rc != SQLITE_OK) {
2N/A syslog(LOG_DEBUG, "failed to insert %s (%s)",
2N/A grp->sg_name, NULL_MSGCHK(errmsg));
2N/A sqlite3_free(errmsg);
2N/A rc = SMB_LGRP_INSERT_FAILED;
2N/A } else {
2N/A rc = SMB_LGRP_SUCCESS;
2N/A }
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_gtbl_delete
2N/A *
2N/A * Removes the specified group from the database
2N/A */
2N/Astatic int
2N/Asmb_lgrp_gtbl_delete(sqlite3 *db, char *gname)
2N/A{
2N/A char *errmsg = NULL;
2N/A char *sql;
2N/A int rc;
2N/A
2N/A if (db == NULL)
2N/A return (SMB_LGRP_DBOPEN_FAILED);
2N/A
2N/A sql = sqlite3_mprintf("DELETE FROM groups WHERE name = '%s'", gname);
2N/A if (sql == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A rc = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
2N/A sqlite3_free(sql);
2N/A
2N/A if (rc != SQLITE_OK) {
2N/A syslog(LOG_DEBUG, "failed to delete %s (%s)",
2N/A gname, NULL_MSGCHK(errmsg));
2N/A sqlite3_free(errmsg);
2N/A rc = SMB_LGRP_DELETE_FAILED;
2N/A } else {
2N/A rc = SMB_LGRP_SUCCESS;
2N/A }
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_gtbl_update
2N/A *
2N/A * Updates the specified group information, the supported items
2N/A * are group name and comment
2N/A */
2N/Astatic int
2N/Asmb_lgrp_gtbl_update(sqlite3 *db, char *gname, smb_group_t *grp, int col_id)
2N/A{
2N/A char *errmsg = NULL;
2N/A char *sql;
2N/A int rc;
2N/A
2N/A if (db == NULL)
2N/A return (SMB_LGRP_DBOPEN_FAILED);
2N/A
2N/A /* UPDATE doesn't fail if gname doesn't exist */
2N/A if (!smb_lgrp_gtbl_exists(db, gname))
2N/A return (SMB_LGRP_NOT_FOUND);
2N/A
2N/A switch (col_id) {
2N/A case SMB_LGRP_GTBL_NAME:
2N/A if (smb_lgrp_gtbl_exists(db, grp->sg_name))
2N/A return (SMB_LGRP_EXISTS);
2N/A sql = sqlite3_mprintf("UPDATE groups SET name = '%s' "
2N/A "WHERE name = '%s'", grp->sg_name, gname);
2N/A break;
2N/A
2N/A case SMB_LGRP_GTBL_CMNT:
2N/A sql = sqlite3_mprintf("UPDATE groups SET comment = '%q' "
2N/A "WHERE name = '%s'", grp->sg_cmnt, gname);
2N/A break;
2N/A
2N/A default:
2N/A return (SMB_LGRP_INVALID_ARG);
2N/A }
2N/A
2N/A if (sql == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A rc = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
2N/A sqlite3_free(sql);
2N/A
2N/A if (rc != SQLITE_OK) {
2N/A syslog(LOG_DEBUG, "failed to update %s (%s)",
2N/A gname, NULL_MSGCHK(errmsg));
2N/A sqlite3_free(errmsg);
2N/A rc = SMB_LGRP_UPDATE_FAILED;
2N/A } else {
2N/A rc = SMB_LGRP_SUCCESS;
2N/A }
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_gtbl_update_mlist
2N/A *
2N/A * Adds/removes the specified member from the member list of the
2N/A * given group
2N/A */
2N/Astatic int
2N/Asmb_lgrp_gtbl_update_mlist(sqlite3 *db, char *gname, smb_gsid_t *member,
2N/A int flags)
2N/A{
2N/A smb_lgmlist_t new_members;
2N/A smb_lgmlist_t members;
2N/A smb_lgmid_t mid;
2N/A char *errmsg = NULL;
2N/A char *sql;
2N/A char **result;
2N/A int nrow, ncol;
2N/A int rc;
2N/A
2N/A if (db == NULL)
2N/A return (SMB_LGRP_DBOPEN_FAILED);
2N/A
2N/A sql = sqlite3_mprintf("SELECT n_members, members FROM groups "
2N/A "WHERE name = '%s'", gname);
2N/A
2N/A if (sql == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A rc = sqlite3_get_table(db, sql, &result, &nrow, &ncol, &errmsg);
2N/A sqlite3_free(sql);
2N/A
2N/A if (rc != SQLITE_OK) {
2N/A syslog(LOG_DEBUG, "failed to lookup %s (%s)",
2N/A gname, NULL_MSGCHK(errmsg));
2N/A sqlite3_free(errmsg);
2N/A return (SMB_LGRP_LOOKUP_FAILED);
2N/A }
2N/A
2N/A if (nrow == 0) {
2N/A /* group not found */
2N/A sqlite3_free_table(result);
2N/A return (SMB_LGRP_NOT_FOUND);
2N/A }
2N/A
2N/A if (nrow != 1 || ncol != 2) {
2N/A sqlite3_free_table(result);
2N/A return (SMB_LGRP_DB_ERROR);
2N/A }
2N/A
2N/A bzero(&mid, sizeof (mid));
2N/A mid.m_type = member->gs_type;
2N/A rc = smb_lgrp_dtbl_fuid(db, member->gs_sid, mid.m_type,
2N/A &mid.m_idx, &mid.m_rid);
2N/A if (rc != SMB_LGRP_SUCCESS) {
2N/A sqlite3_free_table(result);
2N/A return (rc);
2N/A }
2N/A
2N/A members.m_cnt = atoi(result[2]);
2N/A members.m_ids = result[3];
2N/A
2N/A switch (flags) {
2N/A case SMB_LGRP_DB_ADDMEMBER:
2N/A rc = smb_lgrp_mlist_add(&members, &mid, &new_members);
2N/A break;
2N/A case SMB_LGRP_DB_DELMEMBER:
2N/A rc = smb_lgrp_mlist_del(&members, &mid, &new_members);
2N/A break;
2N/A default:
2N/A rc = SMB_LGRP_INVALID_ARG;
2N/A }
2N/A
2N/A sqlite3_free_table(result);
2N/A if (rc != SMB_LGRP_SUCCESS)
2N/A return (rc);
2N/A
2N/A sql = sqlite3_mprintf("UPDATE groups SET n_members = %u, members = '%s'"
2N/A " WHERE name = '%s'", new_members.m_cnt, new_members.m_ids, gname);
2N/A
2N/A free(new_members.m_ids);
2N/A
2N/A if (sql == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A rc = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
2N/A sqlite3_free(sql);
2N/A
2N/A if (rc != SQLITE_OK) {
2N/A syslog(LOG_DEBUG, "failed to update %s (%s)", gname,
2N/A NULL_MSGCHK(errmsg));
2N/A sqlite3_free(errmsg);
2N/A rc = SMB_LGRP_UPDATE_FAILED;
2N/A } else {
2N/A rc = SMB_LGRP_SUCCESS;
2N/A }
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_gtbl_update_plist
2N/A *
2N/A * Adds/removes the specified privilege from the privilege list of the
2N/A * given group
2N/A */
2N/Astatic int
2N/Asmb_lgrp_gtbl_update_plist(sqlite3 *db, char *gname, uint8_t priv_id,
2N/A boolean_t enable)
2N/A{
2N/A char *sql;
2N/A char *errmsg = NULL;
2N/A char **result;
2N/A int nrow, ncol;
2N/A int rc;
2N/A smb_lgplist_t privs;
2N/A smb_lgplist_t new_privs;
2N/A
2N/A if (db == NULL)
2N/A return (SMB_LGRP_DBOPEN_FAILED);
2N/A
2N/A sql = sqlite3_mprintf("SELECT n_privs, privs FROM groups "
2N/A "WHERE name = '%s'", gname);
2N/A
2N/A if (sql == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A rc = sqlite3_get_table(db, sql, &result, &nrow, &ncol, &errmsg);
2N/A sqlite3_free(sql);
2N/A
2N/A if (rc != SQLITE_OK) {
2N/A syslog(LOG_DEBUG, "failed to lookup %s (%s)",
2N/A gname, NULL_MSGCHK(errmsg));
2N/A sqlite3_free(errmsg);
2N/A return (SMB_LGRP_LOOKUP_FAILED);
2N/A }
2N/A
2N/A if (nrow == 0) {
2N/A /* group not found */
2N/A sqlite3_free_table(result);
2N/A return (SMB_LGRP_NOT_FOUND);
2N/A }
2N/A
2N/A if (nrow != 1 || ncol != 2) {
2N/A sqlite3_free_table(result);
2N/A return (SMB_LGRP_DB_ERROR);
2N/A }
2N/A
2N/A privs.p_cnt = atoi(result[2]);
2N/A privs.p_ids = (smb_lgpid_t *)result[3];
2N/A
2N/A if (enable)
2N/A rc = smb_lgrp_plist_add(&privs, priv_id, &new_privs);
2N/A else
2N/A rc = smb_lgrp_plist_del(&privs, priv_id, &new_privs);
2N/A
2N/A sqlite3_free_table(result);
2N/A if (rc != SMB_LGRP_SUCCESS)
2N/A return (rc);
2N/A
2N/A sql = sqlite3_mprintf("UPDATE groups SET n_privs = %u, privs = '%q'"
2N/A " WHERE name = '%s'", new_privs.p_cnt, (char *)new_privs.p_ids,
2N/A gname);
2N/A
2N/A free(new_privs.p_ids);
2N/A
2N/A if (sql == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A rc = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
2N/A sqlite3_free(sql);
2N/A
2N/A if (rc != SQLITE_OK) {
2N/A syslog(LOG_DEBUG, "failed to update %s (%s)",
2N/A gname, NULL_MSGCHK(errmsg));
2N/A sqlite3_free(errmsg);
2N/A rc = SMB_LGRP_UPDATE_FAILED;
2N/A } else {
2N/A rc = SMB_LGRP_SUCCESS;
2N/A }
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_dtbl_insert
2N/A *
2N/A * Inserts the specified domain SID in the dmain table.
2N/A * Upon successful insert the index will be returned in
2N/A * 'dom_idx' arg.
2N/A */
2N/Astatic int
2N/Asmb_lgrp_dtbl_insert(sqlite3 *db, char *dom_sid, uint32_t *dom_idx)
2N/A{
2N/A char *errmsg = NULL;
2N/A char *sql;
2N/A int rc;
2N/A
2N/A sql = sqlite3_mprintf("INSERT INTO domains (dom_sid, dom_cnt)"
2N/A " VALUES('%s', 1);", dom_sid);
2N/A if (sql == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A rc = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
2N/A sqlite3_free(sql);
2N/A
2N/A if (rc != SQLITE_OK) {
2N/A syslog(LOG_DEBUG, "failed to insert domain SID (%s)",
2N/A NULL_MSGCHK(errmsg));
2N/A sqlite3_free(errmsg);
2N/A return (SMB_LGRP_DOMINS_FAILED);
2N/A }
2N/A
2N/A if (dom_idx)
2N/A *dom_idx = sqlite3_last_insert_rowid(db);
2N/A return (SMB_LGRP_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Returns the FUID for the given member SID. FUID's upper
2N/A * part is returned in 'dom_idx' and the lower part in 'rid'.
2N/A *
2N/A * If the given SID is mapped to a valid UID/GID then
2N/A * dom_idx = 0
2N/A * rid = UID/GID
2N/A *
2N/A * otherwise the given SID is split into a domain SID and
2N/A * a RID. The RID is returned in 'rid'. dom_idx will be the
2N/A * index of the domain SID in the domain table whether it's
2N/A * already there or it's inserted if it doesn't exist.
2N/A */
2N/Astatic int
2N/Asmb_lgrp_dtbl_fuid(sqlite3 *db, smb_sid_t *sid, uint16_t sid_type,
2N/A uint32_t *dom_idx, uint32_t *rid)
2N/A{
2N/A char sidstr[SMB_SID_STRSZ];
2N/A smb_sid_t *dom_sid;
2N/A char **result;
2N/A int nrow, ncol;
2N/A char *errmsg = NULL;
2N/A char *sql;
2N/A int rc, id_type;
2N/A
2N/A id_type = (sid_type == SidTypeUser) ? SMB_IDMAP_USER : SMB_IDMAP_GROUP;
2N/A if (smb_idmap_getid(sid, rid, &id_type) == IDMAP_SUCCESS) {
2N/A if (!IDMAP_ID_IS_EPHEMERAL(*rid)) {
2N/A *dom_idx = SMB_LGRP_POSIX_IDX;
2N/A return (SMB_LGRP_SUCCESS);
2N/A }
2N/A }
2N/A
2N/A if ((dom_sid = smb_sid_split(sid, rid)) == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A smb_sid_tostr(dom_sid, sidstr);
2N/A free(dom_sid);
2N/A
2N/A sql = sqlite3_mprintf(
2N/A "SELECT dom_idx FROM domains WHERE dom_sid = '%s'", sidstr);
2N/A if (sql == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A rc = sqlite3_get_table(db, sql, &result, &nrow, &ncol, &errmsg);
2N/A sqlite3_free(sql);
2N/A
2N/A if (rc != SQLITE_OK) {
2N/A syslog(LOG_DEBUG, "failed to lookup domain SID (%s)",
2N/A NULL_MSGCHK(errmsg));
2N/A sqlite3_free(errmsg);
2N/A return (SMB_LGRP_DOMLKP_FAILED);
2N/A }
2N/A
2N/A switch (nrow) {
2N/A case 0:
2N/A /* new domain SID; insert it into the domains table */
2N/A sqlite3_free_table(result);
2N/A return (smb_lgrp_dtbl_insert(db, sidstr, dom_idx));
2N/A
2N/A case 1:
2N/A *dom_idx = atoi(result[1]);
2N/A sqlite3_free_table(result);
2N/A return (SMB_LGRP_SUCCESS);
2N/A }
2N/A
2N/A sqlite3_free_table(result);
2N/A return (SMB_LGRP_DB_ERROR);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_dtbl_getsid
2N/A *
2N/A * Searchs the domain table for the given domain index.
2N/A * Converts the found domain SID to binary format and
2N/A * returns it in the 'sid' arg.
2N/A *
2N/A * Caller must free the returned SID by calling free().
2N/A */
2N/Astatic int
2N/Asmb_lgrp_dtbl_getsid(sqlite3 *db, uint32_t dom_idx, smb_sid_t **sid)
2N/A{
2N/A char **result;
2N/A int nrow, ncol;
2N/A char *errmsg = NULL;
2N/A char *sql;
2N/A int rc;
2N/A
2N/A sql = sqlite3_mprintf("SELECT dom_sid FROM domains WHERE dom_idx = %u",
2N/A dom_idx);
2N/A if (sql == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A rc = sqlite3_get_table(db, sql, &result, &nrow, &ncol, &errmsg);
2N/A sqlite3_free(sql);
2N/A
2N/A if (rc != SQLITE_OK) {
2N/A syslog(LOG_DEBUG, "failed to lookup domain index (%s)",
2N/A NULL_MSGCHK(errmsg));
2N/A sqlite3_free(errmsg);
2N/A return (SMB_LGRP_DOMLKP_FAILED);
2N/A }
2N/A
2N/A switch (nrow) {
2N/A case 0:
2N/A rc = SMB_LGRP_NO_SUCH_DOMAIN;
2N/A break;
2N/A
2N/A case 1:
2N/A *sid = smb_sid_fromstr(result[1]);
2N/A rc = (*sid == NULL)
2N/A ? SMB_LGRP_INTERNAL_ERROR : SMB_LGRP_SUCCESS;
2N/A break;
2N/A
2N/A default:
2N/A rc = SMB_LGRP_DB_ERROR;
2N/A break;
2N/A }
2N/A
2N/A sqlite3_free_table(result);
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_db_setinfo
2N/A *
2N/A * Initializes the db_info table upon database creation.
2N/A */
2N/Astatic int
2N/Asmb_lgrp_db_setinfo(sqlite3 *db)
2N/A{
2N/A char *errmsg = NULL;
2N/A char *sql;
2N/A int rc;
2N/A
2N/A sql = sqlite3_mprintf("INSERT INTO db_info (ver_major, ver_minor,"
2N/A " magic) VALUES (%d, %d, %u)", SMB_LGRP_DB_VERMAJOR,
2N/A SMB_LGRP_DB_VERMINOR, SMB_LGRP_DB_MAGIC);
2N/A
2N/A if (sql == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A rc = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
2N/A sqlite3_free(sql);
2N/A if (rc != SQLITE_OK) {
2N/A syslog(LOG_DEBUG, "failed to insert database information (%s)",
2N/A NULL_MSGCHK(errmsg));
2N/A sqlite3_free(errmsg);
2N/A rc = SMB_LGRP_DBINIT_ERROR;
2N/A } else {
2N/A rc = SMB_LGRP_SUCCESS;
2N/A }
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_mlist_add
2N/A *
2N/A * Adds the given member (newm) to the input member list (in_members)
2N/A * if it's not already there. The result list will be returned in
2N/A * out_members. The caller must free the allocated memory for
2N/A * out_members by calling free().
2N/A *
2N/A * in_members and out_members are hex strings.
2N/A */
2N/Astatic int
2N/Asmb_lgrp_mlist_add(smb_lgmlist_t *in_members, smb_lgmid_t *newm,
2N/A smb_lgmlist_t *out_members)
2N/A{
2N/A char mid_hex[SMB_LGRP_MID_HEXSZ];
2N/A char *in_list;
2N/A char *out_list;
2N/A int in_size;
2N/A int out_size;
2N/A int mid_hexsz;
2N/A int i;
2N/A
2N/A out_members->m_cnt = 0;
2N/A out_members->m_ids = NULL;
2N/A
2N/A bzero(mid_hex, sizeof (mid_hex));
2N/A mid_hexsz = bintohex((const char *)newm, sizeof (smb_lgmid_t),
2N/A mid_hex, sizeof (mid_hex));
2N/A
2N/A /*
2N/A * Check to see if this is already a group member
2N/A */
2N/A in_list = in_members->m_ids;
2N/A for (i = 0; i < in_members->m_cnt; i++) {
2N/A if (strncmp(in_list, mid_hex, mid_hexsz) == 0)
2N/A return (SMB_LGRP_MEMBER_IN_GROUP);
2N/A in_list += mid_hexsz;
2N/A }
2N/A
2N/A in_size = (in_members->m_ids) ? strlen(in_members->m_ids) : 0;
2N/A out_size = in_size + sizeof (mid_hex) + 1;
2N/A out_list = malloc(out_size);
2N/A if (out_list == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A bzero(out_list, out_size);
2N/A if (in_members->m_ids)
2N/A (void) strlcpy(out_list, in_members->m_ids, out_size);
2N/A (void) strcat(out_list, mid_hex);
2N/A
2N/A out_members->m_cnt = in_members->m_cnt + 1;
2N/A out_members->m_ids = out_list;
2N/A
2N/A return (SMB_LGRP_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_mlist_del
2N/A *
2N/A * Removes the given member (msid) from the input member list
2N/A * (in_members) if it's already there. The result list will b
2N/A * returned in out_members. The caller must free the allocated
2N/A * memory for out_members by calling free().
2N/A *
2N/A * in_members and out_members are hex strings.
2N/A */
2N/Astatic int
2N/Asmb_lgrp_mlist_del(smb_lgmlist_t *in_members, smb_lgmid_t *mid,
2N/A smb_lgmlist_t *out_members)
2N/A{
2N/A char mid_hex[SMB_LGRP_MID_HEXSZ];
2N/A char *in_list;
2N/A char *out_list;
2N/A int in_size;
2N/A int out_size;
2N/A int mid_hexsz;
2N/A int out_cnt;
2N/A int i;
2N/A
2N/A out_members->m_cnt = 0;
2N/A out_members->m_ids = NULL;
2N/A
2N/A if ((in_members == NULL) || (in_members->m_cnt == 0))
2N/A return (SMB_LGRP_MEMBER_NOT_IN_GROUP);
2N/A
2N/A in_size = strlen(in_members->m_ids);
2N/A out_size = in_size + sizeof (mid_hex) + 1;
2N/A out_list = malloc(out_size);
2N/A if (out_list == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A *out_list = '\0';
2N/A
2N/A bzero(mid_hex, sizeof (mid_hex));
2N/A mid_hexsz = bintohex((const char *)mid, sizeof (smb_lgmid_t),
2N/A mid_hex, sizeof (mid_hex));
2N/A
2N/A in_list = in_members->m_ids;
2N/A for (i = 0, out_cnt = 0; i < in_members->m_cnt; i++) {
2N/A if (strncmp(in_list, mid_hex, mid_hexsz)) {
2N/A (void) strncat(out_list, in_list, mid_hexsz);
2N/A out_cnt++;
2N/A }
2N/A in_list += mid_hexsz;
2N/A }
2N/A
2N/A if (out_cnt == in_members->m_cnt) {
2N/A free(out_list);
2N/A return (SMB_LGRP_MEMBER_NOT_IN_GROUP);
2N/A }
2N/A
2N/A out_members->m_cnt = out_cnt;
2N/A out_members->m_ids = out_list;
2N/A return (SMB_LGRP_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_plist_add
2N/A *
2N/A * Adds the given privilege to the input list (in_privs)
2N/A * if it's not already there. The result list is returned
2N/A * in out_privs. The caller must free the allocated memory
2N/A * for out_privs by calling free().
2N/A */
2N/Astatic int
2N/Asmb_lgrp_plist_add(smb_lgplist_t *in_privs, smb_lgpid_t priv_id,
2N/A smb_lgplist_t *out_privs)
2N/A{
2N/A int i, size;
2N/A smb_lgpid_t *pbuf;
2N/A
2N/A out_privs->p_cnt = 0;
2N/A out_privs->p_ids = NULL;
2N/A
2N/A for (i = 0; i < in_privs->p_cnt; i++) {
2N/A if (in_privs->p_ids[i] == priv_id)
2N/A return (SMB_LGRP_PRIV_HELD);
2N/A }
2N/A
2N/A size = (in_privs->p_cnt + 1) * sizeof (smb_lgpid_t) + 1;
2N/A pbuf = malloc(size);
2N/A if (pbuf == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A bzero(pbuf, size);
2N/A bcopy(in_privs->p_ids, pbuf, in_privs->p_cnt * sizeof (smb_lgpid_t));
2N/A pbuf[in_privs->p_cnt] = priv_id;
2N/A
2N/A out_privs->p_cnt = in_privs->p_cnt + 1;
2N/A out_privs->p_ids = pbuf;
2N/A
2N/A return (SMB_LGRP_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_plist_del
2N/A *
2N/A * Removes the given privilege from the input list (in_privs)
2N/A * if it's already there. The result list is returned
2N/A * in out_privs. The caller must free the allocated memory
2N/A * for out_privs by calling free().
2N/A */
2N/Astatic int
2N/Asmb_lgrp_plist_del(smb_lgplist_t *in_privs, smb_lgpid_t priv_id,
2N/A smb_lgplist_t *out_privs)
2N/A{
2N/A int i, size;
2N/A
2N/A out_privs->p_cnt = 0;
2N/A out_privs->p_ids = NULL;
2N/A
2N/A if ((in_privs == NULL) || (in_privs->p_cnt == 0))
2N/A return (SMB_LGRP_PRIV_NOT_HELD);
2N/A
2N/A size = (in_privs->p_cnt - 1) * sizeof (smb_lgpid_t) + 1;
2N/A out_privs->p_ids = malloc(size);
2N/A if (out_privs->p_ids == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A bzero(out_privs->p_ids, size);
2N/A
2N/A for (i = 0; i < in_privs->p_cnt; i++) {
2N/A if (in_privs->p_ids[i] != priv_id)
2N/A out_privs->p_ids[out_privs->p_cnt++] =
2N/A in_privs->p_ids[i];
2N/A }
2N/A
2N/A if (out_privs->p_cnt == in_privs->p_cnt) {
2N/A free(out_privs->p_ids);
2N/A out_privs->p_cnt = 0;
2N/A out_privs->p_ids = NULL;
2N/A return (SMB_LGRP_PRIV_NOT_HELD);
2N/A }
2N/A
2N/A return (SMB_LGRP_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_encode_privset
2N/A *
2N/A * Encodes given privilege set into a buffer to be stored in the group
2N/A * database. Each entry of the encoded buffer contains the privilege ID
2N/A * of an enable privilege. The returned buffer is null-terminated.
2N/A */
2N/Astatic void
2N/Asmb_lgrp_encode_privset(smb_group_t *grp, smb_lgplist_t *plist)
2N/A{
2N/A smb_privset_t *privs;
2N/A uint32_t pcnt = plist->p_cnt;
2N/A int i;
2N/A
2N/A bzero(plist->p_ids, sizeof (smb_lgpid_t) * plist->p_cnt);
2N/A plist->p_cnt = 0;
2N/A
2N/A privs = grp->sg_privs;
2N/A if ((privs == NULL) || (privs->priv_cnt == 0))
2N/A return;
2N/A
2N/A if (pcnt < privs->priv_cnt) {
2N/A assert(0);
2N/A }
2N/A
2N/A for (i = 0; i < privs->priv_cnt; i++) {
2N/A if (privs->priv[i].attrs == SE_PRIVILEGE_ENABLED) {
2N/A plist->p_ids[plist->p_cnt++] =
2N/A (uint8_t)privs->priv[i].luid.lo_part;
2N/A }
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_decode_privset
2N/A *
2N/A * Decodes the privilege information read from group table
2N/A * (nprivs, privs) into a binray format specified by the
2N/A * privilege field of smb_group_t
2N/A */
2N/Astatic int
2N/Asmb_lgrp_decode_privset(smb_group_t *grp, char *nprivs, char *privs)
2N/A{
2N/A smb_lgplist_t plist;
2N/A int i;
2N/A
2N/A plist.p_cnt = atoi(nprivs);
2N/A if (strlen(privs) != plist.p_cnt)
2N/A return (SMB_LGRP_BAD_DATA);
2N/A
2N/A plist.p_ids = (smb_lgpid_t *)privs;
2N/A grp->sg_privs = smb_privset_new();
2N/A if (grp->sg_privs == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A for (i = 0; i < plist.p_cnt; i++)
2N/A smb_privset_enable(grp->sg_privs, plist.p_ids[i]);
2N/A
2N/A return (SMB_LGRP_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_decode_members
2N/A *
2N/A * Decodes the members information read from group table
2N/A * (nmembers, members) into a binary format specified by the
2N/A * member fields of smb_group_t
2N/A */
2N/Astatic int
2N/Asmb_lgrp_decode_members(smb_group_t *grp, char *nmembers, char *members,
2N/A sqlite3 *db)
2N/A{
2N/A smb_lgmid_t *m_id;
2N/A smb_lgmid_t *m_ids;
2N/A smb_gsid_t *m_sid;
2N/A smb_gsid_t *m_sids;
2N/A int m_num;
2N/A size_t mids_size;
2N/A int i, rc;
2N/A
2N/A grp->sg_nmembers = 0;
2N/A grp->sg_members = NULL;
2N/A
2N/A m_num = atoi(nmembers);
2N/A
2N/A m_ids = calloc(m_num, sizeof (smb_lgmid_t));
2N/A if (m_ids == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A m_sids = calloc(m_num, sizeof (smb_gsid_t));
2N/A if (m_sids == NULL) {
2N/A free(m_ids);
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A }
2N/A
2N/A mids_size = m_num * sizeof (smb_lgmid_t);
2N/A (void) hextobin(members, strlen(members), (char *)m_ids, mids_size);
2N/A
2N/A m_id = m_ids;
2N/A m_sid = m_sids;
2N/A for (i = 0; i < m_num; i++, m_id++, m_sid++) {
2N/A rc = smb_lgrp_getsid(m_id->m_idx, &m_id->m_rid, m_id->m_type,
2N/A db, &m_sid->gs_sid);
2N/A
2N/A if (rc != SMB_LGRP_SUCCESS) {
2N/A free(m_ids);
2N/A for (m_sid = m_sids; m_sid->gs_sid != NULL; m_sid++)
2N/A smb_sid_free(m_sid->gs_sid);
2N/A free(m_sids);
2N/A return (rc);
2N/A }
2N/A
2N/A m_sid->gs_type = m_id->m_type;
2N/A }
2N/A
2N/A free(m_ids);
2N/A
2N/A grp->sg_nmembers = m_num;
2N/A grp->sg_members = m_sids;
2N/A return (SMB_LGRP_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_decode
2N/A *
2N/A * Fills out the fields of the given group (grp) based in the
2N/A * string information read from the group table. infolvl determines
2N/A * which fields are requested and need to be decoded.
2N/A *
2N/A * Allocated memories must be freed by calling smb_lgrp_free()
2N/A * upon successful return.
2N/A */
2N/Astatic int
2N/Asmb_lgrp_decode(smb_group_t *grp, char **values, int infolvl, sqlite3 *db)
2N/A{
2N/A uint32_t sid_idx;
2N/A int rc;
2N/A
2N/A if (infolvl == SMB_LGRP_INFO_NONE)
2N/A return (SMB_LGRP_SUCCESS);
2N/A
2N/A if (infolvl & SMB_LGRP_INFO_NAME) {
2N/A grp->sg_name = strdup(values[SMB_LGRP_GTBL_NAME]);
2N/A if (grp->sg_name == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A }
2N/A
2N/A if (infolvl & SMB_LGRP_INFO_CMNT) {
2N/A grp->sg_cmnt = strdup(values[SMB_LGRP_GTBL_CMNT]);
2N/A if (grp->sg_cmnt == NULL) {
2N/A smb_lgrp_free(grp);
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A }
2N/A }
2N/A
2N/A
2N/A if (infolvl & SMB_LGRP_INFO_SID) {
2N/A sid_idx = atoi(values[SMB_LGRP_GTBL_SIDIDX]);
2N/A grp->sg_rid = atoi(values[SMB_LGRP_GTBL_SIDRID]);
2N/A grp->sg_attr = atoi(values[SMB_LGRP_GTBL_SIDATR]);
2N/A grp->sg_id.gs_type = atoi(values[SMB_LGRP_GTBL_SIDTYP]);
2N/A rc = smb_lgrp_getsid(sid_idx, &grp->sg_rid, grp->sg_id.gs_type,
2N/A db, &grp->sg_id.gs_sid);
2N/A if (rc != SMB_LGRP_SUCCESS) {
2N/A smb_lgrp_free(grp);
2N/A return (rc);
2N/A }
2N/A grp->sg_domain = (sid_idx == SMB_LGRP_POSIX_IDX)
2N/A ? SMB_DOMAIN_LOCAL : SMB_DOMAIN_BUILTIN;
2N/A }
2N/A
2N/A if (infolvl & SMB_LGRP_INFO_PRIV) {
2N/A rc = smb_lgrp_decode_privset(grp, values[SMB_LGRP_GTBL_NPRIVS],
2N/A values[SMB_LGRP_GTBL_PRIVS]);
2N/A
2N/A if (rc != SMB_LGRP_SUCCESS) {
2N/A smb_lgrp_free(grp);
2N/A return (rc);
2N/A }
2N/A }
2N/A
2N/A if (infolvl & SMB_LGRP_INFO_MEMB) {
2N/A rc = smb_lgrp_decode_members(grp, values[SMB_LGRP_GTBL_NMEMBS],
2N/A values[SMB_LGRP_GTBL_MEMBS], db);
2N/A if (rc != SMB_LGRP_SUCCESS) {
2N/A smb_lgrp_free(grp);
2N/A return (rc);
2N/A }
2N/A }
2N/A
2N/A return (SMB_LGRP_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_normalize_name
2N/A *
2N/A * Trim whitespace, validate the group name and convert it to lowercase.
2N/A */
2N/Astatic boolean_t
2N/Asmb_lgrp_normalize_name(char *name)
2N/A{
2N/A (void) trim_whitespace(name);
2N/A
2N/A if (smb_name_validate_account(name) != ERROR_SUCCESS)
2N/A return (B_FALSE);
2N/A
2N/A (void) smb_strlwr(name);
2N/A return (B_TRUE);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_set_default_privs
2N/A *
2N/A * set default privileges for Administrators and Backup Operators
2N/A */
2N/Astatic void
2N/Asmb_lgrp_set_default_privs(smb_group_t *grp)
2N/A{
2N/A if (smb_strcasecmp(grp->sg_name, "Administrators", 0) == 0) {
2N/A smb_privset_enable(grp->sg_privs, SE_TAKE_OWNERSHIP_LUID);
2N/A return;
2N/A }
2N/A
2N/A if (smb_strcasecmp(grp->sg_name, "Backup Operators", 0) == 0) {
2N/A smb_privset_enable(grp->sg_privs, SE_BACKUP_LUID);
2N/A smb_privset_enable(grp->sg_privs, SE_RESTORE_LUID);
2N/A return;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_getsid
2N/A *
2N/A * Returns a SID based on the provided information
2N/A * If dom_idx is 0, it means 'rid' contains a UID/GID and the
2N/A * returned SID will be a local SID. If dom_idx is not 0 then
2N/A * the domain SID will be fetched from the domain table.
2N/A */
2N/Astatic int
2N/Asmb_lgrp_getsid(int dom_idx, uint32_t *rid, uint16_t sid_type,
2N/A sqlite3 *db, smb_sid_t **sid)
2N/A{
2N/A smb_sid_t *dom_sid = NULL;
2N/A smb_sid_t *res_sid = NULL;
2N/A char strsid[SMB_SID_STRSZ];
2N/A idmap_stat stat;
2N/A int id_type;
2N/A int rc;
2N/A
2N/A *sid = NULL;
2N/A if (dom_idx == SMB_LGRP_POSIX_IDX) {
2N/A id_type = (sid_type == SidTypeUser)
2N/A ? SMB_IDMAP_USER : SMB_IDMAP_GROUP;
2N/A stat = smb_idmap_getsid(*rid, id_type, &res_sid);
2N/A if (stat != IDMAP_SUCCESS) {
2N/A syslog(LOG_ERR, "smb_lgrp_getsid: "
2N/A "failed to get a SID for %s id=%u (%d)",
2N/A (id_type == SMB_IDMAP_USER) ? "user" : "group",
2N/A *rid, stat);
2N/A return (SMB_LGRP_NO_SID);
2N/A }
2N/A
2N/A /*
2N/A * Make sure the returned SID is local if the SID is of type
2N/A * Alias
2N/A */
2N/A if ((sid_type == SidTypeAlias) &&
2N/A !smb_sid_indomain(smb_localgrp.lg_machine_sid, res_sid)) {
2N/A smb_sid_tostr(res_sid, strsid);
2N/A syslog(LOG_ERR, "smb_lgrp_getsid: "
2N/A "local group is mapped to a non-local SID: %d->%s",
2N/A *rid, strsid);
2N/A smb_sid_free(res_sid);
2N/A return (SMB_LGRP_SID_NOTLOCAL);
2N/A }
2N/A
2N/A (void) smb_sid_getrid(res_sid, rid);
2N/A *sid = res_sid;
2N/A return (SMB_LGRP_SUCCESS);
2N/A }
2N/A
2N/A rc = smb_lgrp_dtbl_getsid(db, dom_idx, &dom_sid);
2N/A if (rc != SMB_LGRP_SUCCESS) {
2N/A syslog(LOG_ERR, "smb_lgrp_getsid: %s", smb_lgrp_strerror(rc));
2N/A return (SMB_LGRP_DB_ERROR);
2N/A }
2N/A
2N/A res_sid = smb_sid_splice(dom_sid, *rid);
2N/A smb_sid_free(dom_sid);
2N/A if (res_sid == NULL) {
2N/A syslog(LOG_ERR, "smb_lgrp_getsid: %s", smb_lgrp_strerror(rc));
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A }
2N/A
2N/A *sid = res_sid;
2N/A return (SMB_LGRP_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_getgid
2N/A *
2N/A * Converts given local RID to a local gid since for user
2N/A * defined local groups, gid is stored in the table.
2N/A */
2N/Astatic int
2N/Asmb_lgrp_getgid(uint32_t rid, gid_t *gid)
2N/A{
2N/A smb_sid_t *sid;
2N/A int idtype;
2N/A int rc;
2N/A
2N/A if ((sid = smb_sid_splice(smb_localgrp.lg_machine_sid, rid)) == NULL)
2N/A return (SMB_LGRP_NO_MEMORY);
2N/A
2N/A idtype = SMB_IDMAP_GROUP;
2N/A rc = smb_idmap_getid(sid, gid, &idtype);
2N/A smb_sid_free(sid);
2N/A
2N/A return ((rc == IDMAP_SUCCESS) ? SMB_LGRP_SUCCESS : SMB_LGRP_NOT_FOUND);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_exists
2N/A *
2N/A * Returns B_TRUE if the local group with the given name exists.
2N/A * Otherwise, returns B_FALSE.
2N/A */
2N/Astatic boolean_t
2N/Asmb_lgrp_exists(char *name)
2N/A{
2N/A sqlite3 *db;
2N/A boolean_t rc;
2N/A char gname[MAXNAMELEN];
2N/A
2N/A if (name == NULL)
2N/A return (B_FALSE);
2N/A
2N/A (void) strlcpy(gname, name, MAXNAMELEN);
2N/A if (!smb_lgrp_normalize_name(gname))
2N/A return (B_FALSE);
2N/A
2N/A db = smb_lgrp_db_open(SMB_LGRP_DB_ORD);
2N/A if (db == NULL)
2N/A return (B_FALSE);
2N/A
2N/A rc = smb_lgrp_gtbl_exists(db, gname);
2N/A smb_lgrp_db_close(db);
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_pgrp_valid_gname
2N/A *
2N/A * Validate posix group name string.
2N/A */
2N/Astatic int
2N/Asmb_lgrp_pgrp_valid_gname(char *group)
2N/A{
2N/A char *ptr = group;
2N/A char c;
2N/A int len = 0;
2N/A int badchar = 0;
2N/A
2N/A if (!group || !*group)
2N/A return (SMB_LGRP_PGRP_INVALID);
2N/A
2N/A for (c = *ptr; c != NULL; ptr++, c = *ptr) {
2N/A len++;
2N/A if (!isprint(c) || (c == ':') || (c == '\n'))
2N/A return (SMB_LGRP_PGRP_INVALID);
2N/A
2N/A if (!(islower(c) || isdigit(c)))
2N/A badchar++;
2N/A }
2N/A
2N/A if ((len > SMB_LGRP_PGRP_MAXGLEN - 1) || (badchar != 0))
2N/A return (SMB_LGRP_PGRP_INVALID);
2N/A
2N/A if (getgrnam(group) != NULL)
2N/A return (SMB_LGRP_PGRP_NOTUNIQUE);
2N/A
2N/A return (SMB_LGRP_PGRP_UNIQUE);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_pgrp_valid_gid
2N/A *
2N/A * Check to see that the gid is not a reserved gid
2N/A * -- nobody (60001), noaccess (60002) or nogroup (65534)
2N/A */
2N/Astatic int
2N/Asmb_lgrp_pgrp_valid_gid(gid_t gid)
2N/A{
2N/A return (gid != 60001 && gid != 60002 && gid != 65534);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_pgrp_findnextgid(void)
2N/A *
2N/A * This method finds the next valid GID.
2N/A * It iterates through the group database(s) by using the getgrent_r()
2N/A * enumeration. The enumeration list is sorted to obtain MAXUSED GID.
2N/A * The value of MAXUSED GID is incremented by 1 to obtain the highest unused
2N/A * GID. This GID value, if valid, is returned to the caller.
2N/A *
2N/A * In cases where the MAXUSED GID is less than SMB_LGRP_PGRP_DEFRID,
2N/A * SMB_LGRP_PGRP_DEFRID + 1 is returned as GID.
2N/A *
2N/A * On failure, -1 is returned. On success, a valid GID is returned.
2N/A */
2N/Astatic int
2N/Asmb_lgrp_pgrp_findnextgid(void)
2N/A{
2N/A struct group grp, *grpp;
2N/A gid_t max_used_gid = 0;
2N/A gid_t next, gid;
2N/A char *buf;
2N/A uint32_t len;
2N/A
2N/A len = sysconf(_SC_GETGR_R_SIZE_MAX);
2N/A if ((buf = malloc(len)) == NULL)
2N/A return (-1);
2N/A
2N/A errno = 0;
2N/A setgrent();
2N/A while ((grpp = getgrent_r(&grp, buf, len)) != NULL) {
2N/A next = grpp->gr_gid;
2N/A if (max_used_gid < next)
2N/A max_used_gid = next;
2N/A }
2N/A endgrent();
2N/A free(buf);
2N/A
2N/A if (errno != 0)
2N/A return (-1);
2N/A
2N/A gid = max_used_gid + 1;
2N/A if (gid < SMB_LGRP_PGRP_DEFRID)
2N/A gid = SMB_LGRP_PGRP_DEFRID + 1;
2N/A
2N/A for (;;) {
2N/A if (gid > MAXUID)
2N/A return (-1);
2N/A
2N/A if (smb_lgrp_pgrp_valid_gid(gid))
2N/A break;
2N/A gid++;
2N/A }
2N/A
2N/A return (gid);
2N/A}
2N/A
2N/A/*
2N/A * smb_lgrp_pgrp_add
2N/A *
2N/A * Create a posix group with the given name.
2N/A * This group will be added to the /etc/group file.
2N/A */
2N/Astatic int
2N/Asmb_lgrp_pgrp_add(char *group)
2N/A{
2N/A FILE *etcgrp;
2N/A FILE *etctmp;
2N/A int o_mask, gret;
2N/A int newdone = 0;
2N/A struct stat sb;
2N/A char buf[SMB_LGRP_PGRP_GRPBUFSIZ];
2N/A gid_t gid;
2N/A int rc = 0;
2N/A
2N/A rc = smb_lgrp_pgrp_valid_gname(group);
2N/A if ((rc == SMB_LGRP_PGRP_INVALID) || (rc == SMB_LGRP_PGRP_NOTUNIQUE))
2N/A return (-1);
2N/A
2N/A if ((gret = smb_lgrp_pgrp_findnextgid()) < 0)
2N/A return (-1);
2N/A gid = gret;
2N/A
2N/A if ((etcgrp = fopen(SMB_LGRP_PGRP_GROUP, "r")) == NULL)
2N/A return (-1);
2N/A
2N/A if (fstat(fileno(etcgrp), &sb) < 0)
2N/A sb.st_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
2N/A
2N/A o_mask = umask(077);
2N/A etctmp = fopen(SMB_LGRP_PGRP_GRPTMP, "w+");
2N/A (void) umask(o_mask);
2N/A
2N/A if (etctmp == NULL) {
2N/A (void) fclose(etcgrp);
2N/A return (-1);
2N/A }
2N/A
2N/A if (lockf(fileno(etctmp), F_LOCK, 0) != 0) {
2N/A (void) fclose(etcgrp);
2N/A (void) fclose(etctmp);
2N/A (void) unlink(SMB_LGRP_PGRP_GRPTMP);
2N/A return (-1);
2N/A }
2N/A
2N/A if (fchmod(fileno(etctmp), sb.st_mode) != 0 ||
2N/A fchown(fileno(etctmp), sb.st_uid, sb.st_gid) != 0) {
2N/A (void) lockf(fileno(etctmp), F_ULOCK, 0);
2N/A (void) fclose(etcgrp);
2N/A (void) fclose(etctmp);
2N/A (void) unlink(SMB_LGRP_PGRP_GRPTMP);
2N/A return (-1);
2N/A }
2N/A
2N/A while (fgets(buf, SMB_LGRP_PGRP_GRPBUFSIZ, etcgrp) != NULL) {
2N/A /* Check for NameService reference */
2N/A if (!newdone && (buf[0] == '+' || buf[0] == '-')) {
2N/A (void) fprintf(etctmp, "%s::%u:\n", group, gid);
2N/A newdone = 1;
2N/A }
2N/A
2N/A (void) fputs(buf, etctmp);
2N/A }
2N/A (void) fclose(etcgrp);
2N/A
2N/A if (!newdone)
2N/A (void) fprintf(etctmp, "%s::%u:\n", group, gid);
2N/A
2N/A if (rename(SMB_LGRP_PGRP_GRPTMP, SMB_LGRP_PGRP_GROUP) < 0) {
2N/A (void) lockf(fileno(etctmp), F_ULOCK, 0);
2N/A (void) fclose(etctmp);
2N/A (void) unlink(SMB_LGRP_PGRP_GRPTMP);
2N/A return (-1);
2N/A }
2N/A
2N/A (void) lockf(fileno(etctmp), F_ULOCK, 0);
2N/A (void) fclose(etctmp);
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * This method frees up the space allocated for columns(ncols) and their
2N/A * respective values in a single row.
2N/A */
2N/Astatic void
2N/Asmb_lgrp_free_columns(int ncol, char **values)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < ncol; i++)
2N/A free(values[i]);
2N/A free(values);
2N/A}