1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright (c) 2013 RackTop Systems.
  25  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  26  */
  27 
  28 #include <stdlib.h>
  29 #include <strings.h>
  30 #include <unistd.h>
  31 #include <syslog.h>
  32 #include <thread.h>
  33 #include <synch.h>
  34 #include <grp.h>
  35 #include <assert.h>
  36 #include <libintl.h>
  37 #include <smbsrv/libsmb.h>
  38 #include <smb_sqlite.h>
  39 #include <sys/types.h>
  40 #include <sys/stat.h>
  41 #include <sys/param.h>
  42 #include <libcmdutils.h>
  43 
  44 /*
  45  * Local domain SID (aka machine SID) is not stored in the domain table
  46  * therefore the index is 0
  47  */
  48 #define SMB_LGRP_LOCAL_IDX      0
  49 #define SMB_LGRP_BUILTIN_IDX    1
  50 
  51 #define SMB_LGRP_DB_NAME        "/var/smb/smbgroup.db"
  52 #define SMB_LGRP_DB_TIMEOUT     3000            /* in millisecond */
  53 #define SMB_LGRP_DB_VERMAJOR    1
  54 #define SMB_LGRP_DB_VERMINOR    0
  55 #define SMB_LGRP_DB_MAGIC       0x4C475250      /* LGRP */
  56 
  57 #define SMB_LGRP_DB_ORD         1               /* open read-only */
  58 #define SMB_LGRP_DB_ORW         2               /* open read/write */
  59 
  60 #define SMB_LGRP_DB_ADDMEMBER   1
  61 #define SMB_LGRP_DB_DELMEMBER   2
  62 
  63 /*
  64  * members column of the groups table is an array of
  65  * member structure smb_lgmid_t defined below.
  66  *
  67  * privs column of the groups table is an array of bytes
  68  * where each byte is the id of an enable privilege
  69  */
  70 #define SMB_LGRP_DB_SQL \
  71         "CREATE TABLE db_info ("                                \
  72         "       ver_major INTEGER,"                             \
  73         "       ver_minor INTEGER,"                             \
  74         "       magic     INTEGER"                              \
  75         ");"                                                    \
  76         ""                                                      \
  77         "CREATE TABLE domains ("                                \
  78         "       dom_idx INTEGER PRIMARY KEY,"                   \
  79         "       dom_sid TEXT UNIQUE,"                           \
  80         "       dom_cnt INTEGER"                                \
  81         ");"                                                    \
  82         ""                                                      \
  83         "CREATE UNIQUE INDEX domsid_idx ON domains (dom_sid);"  \
  84         ""                                                      \
  85         "CREATE TABLE groups ("                                 \
  86         "       name      TEXT PRIMARY KEY,"                    \
  87         "       sid_idx   INTEGER,"                             \
  88         "       sid_rid   INTEGER,"                             \
  89         "       sid_type  INTEGER,"                             \
  90         "       sid_attrs INTEGER,"                             \
  91         "       comment   TEXT,"                                \
  92         "       n_privs   INTEGER,"                             \
  93         "       privs     BLOB,"                                \
  94         "       n_members INTEGER,"                             \
  95         "       members   BLOB"                                 \
  96         ");"                                                    \
  97         ""                                                      \
  98         "CREATE INDEX grprid_idx ON groups (sid_rid);"
  99 
 100 /*
 101  * Number of groups table columns
 102  */
 103 #define SMB_LGRP_GTBL_NCOL      10
 104 
 105 #define SMB_LGRP_GTBL_NAME      0
 106 #define SMB_LGRP_GTBL_SIDIDX    1
 107 #define SMB_LGRP_GTBL_SIDRID    2
 108 #define SMB_LGRP_GTBL_SIDTYP    3
 109 #define SMB_LGRP_GTBL_SIDATR    4
 110 #define SMB_LGRP_GTBL_CMNT      5
 111 #define SMB_LGRP_GTBL_NPRIVS    6
 112 #define SMB_LGRP_GTBL_PRIVS     7
 113 #define SMB_LGRP_GTBL_NMEMBS    8
 114 #define SMB_LGRP_GTBL_MEMBS     9
 115 
 116 #define SMB_LGRP_INFO_NONE      0x00
 117 #define SMB_LGRP_INFO_NAME      0x01
 118 #define SMB_LGRP_INFO_CMNT      0x02
 119 #define SMB_LGRP_INFO_SID       0x04
 120 #define SMB_LGRP_INFO_PRIV      0x08
 121 #define SMB_LGRP_INFO_MEMB      0x10
 122 #define SMB_LGRP_INFO_ALL       0x1F
 123 
 124 #define SMB_LGRP_PGRP_GRPTMP    "/etc/gtmp"
 125 #define SMB_LGRP_PGRP_GRPBUFSIZ 5120
 126 #define SMB_LGRP_PGRP_GROUP     "/etc/group"
 127 #define SMB_LGRP_PGRP_MAXGLEN   9       /* max length of group name */
 128 #define SMB_LGRP_PGRP_DEFRID    1000    /* lowest cifs created gid */
 129 
 130 #define SMB_LGRP_PGRP_NOTUNIQUE 0
 131 #define SMB_LGRP_PGRP_RESERVED  1
 132 #define SMB_LGRP_PGRP_UNIQUE    2
 133 #define SMB_LGRP_PGRP_TOOBIG    3
 134 #define SMB_LGRP_PGRP_INVALID   4
 135 
 136 #define NULL_MSGCHK(msg)        ((msg) ? (msg) : "NULL")
 137 
 138 /* Member ID */
 139 typedef struct smb_lgmid {
 140         uint32_t m_idx;
 141         uint32_t m_rid;
 142         uint16_t m_type;
 143 } smb_lgmid_t;
 144 
 145 /* Buffer size to hold hex form of the above (>24). */
 146 #define SMB_LGRP_MID_HEXSZ      32
 147 
 148 /* Size of idx,rid parts of above, in hex form. */
 149 #define SMB_LGRP_IDXRID_LEN     16
 150 
 151 /* Member list */
 152 typedef struct smb_lgmlist {
 153         uint32_t        m_cnt;
 154         char            *m_ids;
 155 } smb_lgmlist_t;
 156 
 157 /* Privilege ID */
 158 typedef uint8_t smb_lgpid_t;
 159 
 160 /* Privilege list */
 161 typedef struct smb_lgplist {
 162         uint32_t        p_cnt;
 163         smb_lgpid_t     *p_ids;
 164 } smb_lgplist_t;
 165 
 166 static struct {
 167         int     errnum;
 168         char    *errmsg;
 169 } errtab[] = {
 170         { SMB_LGRP_SUCCESS,             "success" },
 171         { SMB_LGRP_INVALID_ARG,         "invalid argument" },
 172         { SMB_LGRP_INVALID_MEMBER,      "invalid member type" },
 173         { SMB_LGRP_INVALID_NAME,        "invalid name" },
 174         { SMB_LGRP_NOT_FOUND,           "group not found" },
 175         { SMB_LGRP_EXISTS,              "group exists" },
 176         { SMB_LGRP_NO_SID,              "cannot obtain a SID" },
 177         { SMB_LGRP_NO_LOCAL_SID,        "cannot get the machine SID" },
 178         { SMB_LGRP_SID_NOTLOCAL,        "local account has non-local SID" },
 179         { SMB_LGRP_WKSID,
 180                 "operation not permitted on well-known account" },
 181         { SMB_LGRP_NO_MEMORY,           "not enough memory" },
 182         { SMB_LGRP_DB_ERROR,            "database operation error" },
 183         { SMB_LGRP_DBINIT_ERROR,        "database initialization error" },
 184         { SMB_LGRP_INTERNAL_ERROR,      "internal error" },
 185         { SMB_LGRP_MEMBER_IN_GROUP,     "member already in group" },
 186         { SMB_LGRP_MEMBER_NOT_IN_GROUP, "not a member" },
 187         { SMB_LGRP_NO_SUCH_PRIV,        "no such privilege" },
 188         { SMB_LGRP_NO_SUCH_DOMAIN,      "no such domain SID" },
 189         { SMB_LGRP_PRIV_HELD,           "privilege already held" },
 190         { SMB_LGRP_PRIV_NOT_HELD,       "privilege not held" },
 191         { SMB_LGRP_BAD_DATA,            "bad data" },
 192         { SMB_LGRP_NO_MORE,             "no more groups" },
 193         { SMB_LGRP_DBOPEN_FAILED,       "database open failed" },
 194         { SMB_LGRP_DBEXEC_FAILED,       "database operation failed" },
 195         { SMB_LGRP_DBINIT_FAILED,       "database initialization failed" },
 196         { SMB_LGRP_DOMLKP_FAILED,       "domain SID lookup failed" },
 197         { SMB_LGRP_DOMINS_FAILED,       "domain SID insert failed" },
 198         { SMB_LGRP_INSERT_FAILED,       "group insert failed" },
 199         { SMB_LGRP_DELETE_FAILED,       "group delete failed" },
 200         { SMB_LGRP_UPDATE_FAILED,       "group update failed" },
 201         { SMB_LGRP_LOOKUP_FAILED,       "group lookup failed" },
 202         { SMB_LGRP_OFFLINE,             "local group service is offline" },
 203         { SMB_LGRP_POSIXCREATE_FAILED,  "posix group create failed" }
 204 };
 205 
 206 /*
 207  * Serialization for the local group API.
 208  */
 209 typedef struct {
 210         mutex_t         lg_mutex;
 211         cond_t          lg_cv;
 212         boolean_t       lg_online;
 213         uint32_t        lg_refcnt;
 214         smb_sid_t       *lg_machine_sid;
 215 } smb_localgrp_t;
 216 
 217 static smb_localgrp_t smb_localgrp;
 218 
 219 static boolean_t smb_lgrp_enter(void);
 220 static void smb_lgrp_exit(void);
 221 static int smb_lgrp_db_init(void);
 222 static sqlite *smb_lgrp_db_open(int);
 223 static void smb_lgrp_db_close(sqlite *);
 224 static int smb_lgrp_db_setinfo(sqlite *);
 225 
 226 static boolean_t smb_lgrp_gtbl_exists(sqlite *, char *);
 227 static int smb_lgrp_gtbl_lookup(sqlite *, int, smb_group_t *, int, ...);
 228 static int smb_lgrp_gtbl_insert(sqlite *, smb_group_t *);
 229 static int smb_lgrp_gtbl_update(sqlite *, char *, smb_group_t *, int);
 230 static int smb_lgrp_gtbl_delete(sqlite *, char *);
 231 static int smb_lgrp_gtbl_update_mlist(sqlite *, char *, smb_gsid_t *, int);
 232 static int smb_lgrp_gtbl_update_plist(sqlite *, char *, uint8_t, boolean_t);
 233 static int smb_lgrp_gtbl_count(sqlite *, int, int *);
 234 
 235 static int smb_lgrp_dtbl_insert(sqlite *, char *, uint32_t *);
 236 static int smb_lgrp_dtbl_getidx(sqlite *, smb_sid_t *, uint16_t,
 237     uint32_t *, uint32_t *);
 238 static int smb_lgrp_dtbl_getsid(sqlite *, uint32_t, smb_sid_t **);
 239 
 240 static int smb_lgrp_mlist_add(smb_lgmlist_t *, smb_lgmid_t *, smb_lgmlist_t *);
 241 static int smb_lgrp_mlist_del(smb_lgmlist_t *, smb_lgmid_t *, smb_lgmlist_t *);
 242 
 243 static int smb_lgrp_plist_add(smb_lgplist_t *, smb_lgpid_t, smb_lgplist_t *);
 244 static int smb_lgrp_plist_del(smb_lgplist_t *, smb_lgpid_t, smb_lgplist_t *);
 245 
 246 static void smb_lgrp_encode_privset(smb_group_t *, smb_lgplist_t *);
 247 
 248 static int smb_lgrp_decode(smb_group_t *, char **, int, sqlite *);
 249 static int smb_lgrp_decode_privset(smb_group_t *, char *, char *);
 250 static int smb_lgrp_decode_members(smb_group_t *, char *, char *, sqlite *);
 251 
 252 static void smb_lgrp_set_default_privs(smb_group_t *);
 253 static boolean_t smb_lgrp_normalize_name(char *);
 254 static boolean_t smb_lgrp_chkmember(uint16_t);
 255 static int smb_lgrp_getsid(int, uint32_t *, uint16_t, sqlite *, smb_sid_t **);
 256 static int smb_lgrp_getgid(uint32_t rid, gid_t *gid);
 257 static boolean_t smb_lgrp_exists(char *);
 258 static int smb_lgrp_pgrp_add(char *);
 259 
 260 /*
 261  * smb_lgrp_add
 262  *
 263  * Create a local group with the given name and comment.
 264  * This new group doesn't have any members and no enabled
 265  * privileges.
 266  *
 267  * No well-known accounts can be added other than Administators,
 268  * Backup Operators and Power Users. These built-in groups
 269  * won't have any members when created but a set of default
 270  * privileges will be enabled for them.
 271  */
 272 int
 273 smb_lgrp_add(char *gname, char *cmnt)
 274 {
 275         smb_wka_t *wka;
 276         struct group *pxgrp;
 277         smb_group_t grp;
 278         smb_sid_t *sid = NULL;
 279         sqlite *db;
 280         int rc;
 281 
 282         if (!smb_lgrp_normalize_name(gname))
 283                 return (SMB_LGRP_INVALID_NAME);
 284 
 285         if (cmnt && (strlen(cmnt) > SMB_LGRP_COMMENT_MAX))
 286                 return (SMB_LGRP_INVALID_ARG);
 287 
 288         bzero(&grp, sizeof (grp));
 289         grp.sg_name = smb_strlwr(gname);
 290         grp.sg_cmnt = cmnt;
 291 
 292         if (!smb_lgrp_enter())
 293                 return (SMB_LGRP_OFFLINE);
 294 
 295         wka = smb_wka_lookup_name(gname);
 296         if (wka == NULL) {
 297                 if ((pxgrp = getgrnam(gname)) == NULL) {
 298                         if (smb_lgrp_pgrp_add(gname) != 0) {
 299                                 smb_lgrp_exit();
 300                                 return (SMB_LGRP_POSIXCREATE_FAILED);
 301                         }
 302 
 303                         if ((pxgrp = getgrnam(gname)) == NULL) {
 304                                 smb_lgrp_exit();
 305                                 return (SMB_LGRP_NOT_FOUND);
 306                         }
 307                 }
 308 
 309                 /*
 310                  * Make sure a local SID can be obtained
 311                  */
 312                 if (smb_idmap_getsid(pxgrp->gr_gid, SMB_IDMAP_GROUP, &sid)
 313                     != IDMAP_SUCCESS) {
 314                         smb_lgrp_exit();
 315                         return (SMB_LGRP_NO_SID);
 316                 }
 317 
 318                 if (!smb_sid_indomain(smb_localgrp.lg_machine_sid, sid)) {
 319                         free(sid);
 320                         smb_lgrp_exit();
 321                         return (SMB_LGRP_SID_NOTLOCAL);
 322                 }
 323 
 324                 free(sid);
 325                 grp.sg_id.gs_type = SidTypeAlias;
 326                 grp.sg_domain = SMB_DOMAIN_LOCAL;
 327                 grp.sg_rid = pxgrp->gr_gid;
 328         } else {
 329                 if ((wka->wka_flags & SMB_WKAFLG_LGRP_ENABLE) == 0) {
 330                         /* cannot add well-known accounts */
 331                         smb_lgrp_exit();
 332                         return (SMB_LGRP_WKSID);
 333                 }
 334 
 335                 grp.sg_id.gs_type = wka->wka_type;
 336                 if ((sid = smb_sid_fromstr(wka->wka_sid)) == NULL) {
 337                         smb_lgrp_exit();
 338                         return (SMB_LGRP_NO_MEMORY);
 339                 }
 340 
 341                 (void) smb_sid_getrid(sid, &grp.sg_rid);
 342                 free(sid);
 343                 grp.sg_domain = SMB_DOMAIN_BUILTIN;
 344                 grp.sg_privs = smb_privset_new();
 345                 smb_lgrp_set_default_privs(&grp);
 346         }
 347 
 348         if (smb_lgrp_exists(grp.sg_name)) {
 349                 smb_lgrp_exit();
 350                 return (SMB_LGRP_EXISTS);
 351         }
 352 
 353         grp.sg_attr = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT |
 354             SE_GROUP_ENABLED;
 355 
 356         db = smb_lgrp_db_open(SMB_LGRP_DB_ORW);
 357         rc = smb_lgrp_gtbl_insert(db, &grp);
 358         smb_lgrp_db_close(db);
 359 
 360         smb_privset_free(grp.sg_privs);
 361         smb_lgrp_exit();
 362         return (rc);
 363 }
 364 
 365 /*
 366  * smb_lgrp_rename
 367  *
 368  * Renames the given group
 369  */
 370 int
 371 smb_lgrp_rename(char *gname, char *new_gname)
 372 {
 373         smb_group_t grp;
 374         sqlite *db;
 375         int rc;
 376 
 377         if (!smb_lgrp_normalize_name(gname))
 378                 return (SMB_LGRP_INVALID_NAME);
 379 
 380         if (!smb_lgrp_normalize_name(gname))
 381                 return (SMB_LGRP_INVALID_NAME);
 382 
 383         if (smb_strcasecmp(gname, new_gname, 0) == 0)
 384                 return (SMB_LGRP_SUCCESS);
 385 
 386         /* Cannot rename well-known groups */
 387         if (smb_wka_lookup_name(gname) != NULL)
 388                 return (SMB_LGRP_WKSID);
 389 
 390         /* Cannot rename to a well-known groups */
 391         if (smb_wka_lookup_name(new_gname) != NULL)
 392                 return (SMB_LGRP_WKSID);
 393 
 394         grp.sg_name = new_gname;
 395 
 396         if (!smb_lgrp_enter())
 397                 return (SMB_LGRP_OFFLINE);
 398 
 399         if (getgrnam(new_gname) == NULL) {
 400                 if (smb_lgrp_pgrp_add(new_gname) != 0) {
 401                         smb_lgrp_exit();
 402                         return (SMB_LGRP_POSIXCREATE_FAILED);
 403                 }
 404 
 405                 if (getgrnam(new_gname) == NULL) {
 406                         smb_lgrp_exit();
 407                         return (SMB_LGRP_NOT_FOUND);
 408                 }
 409         }
 410 
 411         db = smb_lgrp_db_open(SMB_LGRP_DB_ORW);
 412         rc = smb_lgrp_gtbl_update(db, gname, &grp, SMB_LGRP_GTBL_NAME);
 413         smb_lgrp_db_close(db);
 414 
 415         smb_lgrp_exit();
 416         return (rc);
 417 }
 418 
 419 /*
 420  * smb_lgrp_delete
 421  *
 422  * Deletes the specified local group.
 423  */
 424 int
 425 smb_lgrp_delete(char *gname)
 426 {
 427         sqlite *db;
 428         int rc;
 429 
 430         if (!smb_lgrp_normalize_name(gname))
 431                 return (SMB_LGRP_INVALID_NAME);
 432 
 433         /* Cannot remove a built-in group */
 434         if (smb_wka_lookup_name(gname) != NULL)
 435                 return (SMB_LGRP_WKSID);
 436 
 437 
 438         if (!smb_lgrp_exists(gname))
 439                 return (SMB_LGRP_NOT_FOUND);
 440 
 441         if (!smb_lgrp_enter())
 442                 return (SMB_LGRP_OFFLINE);
 443 
 444         db = smb_lgrp_db_open(SMB_LGRP_DB_ORW);
 445         rc = smb_lgrp_gtbl_delete(db, gname);
 446         smb_lgrp_db_close(db);
 447 
 448         smb_lgrp_exit();
 449         return (rc);
 450 }
 451 
 452 /*
 453  * smb_lgrp_setcmnt
 454  *
 455  * Sets the description for the given group
 456  */
 457 int
 458 smb_lgrp_setcmnt(char *gname, char *cmnt)
 459 {
 460         smb_group_t grp;
 461         sqlite *db;
 462         int rc;
 463 
 464         if (!smb_lgrp_normalize_name(gname))
 465                 return (SMB_LGRP_INVALID_NAME);
 466 
 467         if (cmnt && (strlen(cmnt) > SMB_LGRP_COMMENT_MAX))
 468                 return (SMB_LGRP_INVALID_ARG);
 469 
 470         grp.sg_cmnt = cmnt;
 471 
 472         if (!smb_lgrp_enter())
 473                 return (SMB_LGRP_OFFLINE);
 474 
 475         db = smb_lgrp_db_open(SMB_LGRP_DB_ORW);
 476         rc = smb_lgrp_gtbl_update(db, gname, &grp, SMB_LGRP_GTBL_CMNT);
 477         smb_lgrp_db_close(db);
 478 
 479         smb_lgrp_exit();
 480         return (rc);
 481 }
 482 
 483 /*
 484  * smb_lgrp_getcmnt
 485  *
 486  * Obtain the description of the specified group
 487  */
 488 int
 489 smb_lgrp_getcmnt(char *gname, char **cmnt)
 490 {
 491         smb_group_t grp;
 492         sqlite *db;
 493         int rc;
 494 
 495         if (!smb_lgrp_normalize_name(gname))
 496                 return (SMB_LGRP_INVALID_NAME);
 497 
 498         if (cmnt == NULL)
 499                 return (SMB_LGRP_INVALID_ARG);
 500 
 501         if (!smb_lgrp_enter())
 502                 return (SMB_LGRP_OFFLINE);
 503 
 504         db = smb_lgrp_db_open(SMB_LGRP_DB_ORD);
 505         rc = smb_lgrp_gtbl_lookup(db, SMB_LGRP_GTBL_NAME, &grp,
 506             SMB_LGRP_INFO_CMNT, gname);
 507         smb_lgrp_db_close(db);
 508         smb_lgrp_exit();
 509 
 510         if (rc == SMB_LGRP_SUCCESS) {
 511                 *cmnt = grp.sg_cmnt;
 512                 grp.sg_cmnt = NULL;
 513                 smb_lgrp_free(&grp);
 514         }
 515 
 516         return (rc);
 517 }
 518 
 519 
 520 /*
 521  * smb_lgrp_setpriv
 522  *
 523  * Enable/disable the specified privilge for the group
 524  */
 525 int
 526 smb_lgrp_setpriv(char *gname, uint8_t priv_lid, boolean_t enable)
 527 {
 528         sqlite *db;
 529         int rc;
 530 
 531         if (!smb_lgrp_normalize_name(gname))
 532                 return (SMB_LGRP_INVALID_NAME);
 533 
 534         if ((priv_lid < SE_MIN_LUID) || (priv_lid > SE_MAX_LUID))
 535                 return (SMB_LGRP_NO_SUCH_PRIV);
 536 
 537         if (!smb_lgrp_enter())
 538                 return (SMB_LGRP_OFFLINE);
 539 
 540         db = smb_lgrp_db_open(SMB_LGRP_DB_ORW);
 541         rc = smb_lgrp_gtbl_update_plist(db, gname, priv_lid, enable);
 542         smb_lgrp_db_close(db);
 543         smb_lgrp_exit();
 544 
 545         if (enable) {
 546                 if (rc == SMB_LGRP_PRIV_HELD)
 547                         rc = SMB_LGRP_SUCCESS;
 548         } else {
 549                 if (rc == SMB_LGRP_PRIV_NOT_HELD)
 550                         rc = SMB_LGRP_SUCCESS;
 551         }
 552 
 553         return (rc);
 554 }
 555 
 556 /*
 557  * smb_lgrp_getpriv
 558  *
 559  * Obtain the status of the specified privilge for the group
 560  */
 561 int
 562 smb_lgrp_getpriv(char *gname, uint8_t priv_lid, boolean_t *enable)
 563 {
 564         sqlite *db;
 565         smb_group_t grp;
 566         int rc;
 567 
 568         if (!smb_lgrp_normalize_name(gname))
 569                 return (SMB_LGRP_INVALID_NAME);
 570 
 571         if ((priv_lid < SE_MIN_LUID) || (priv_lid > SE_MAX_LUID))
 572                 return (SMB_LGRP_NO_SUCH_PRIV);
 573 
 574         if (!smb_lgrp_enter())
 575                 return (SMB_LGRP_OFFLINE);
 576 
 577         db = smb_lgrp_db_open(SMB_LGRP_DB_ORD);
 578         rc = smb_lgrp_gtbl_lookup(db, SMB_LGRP_GTBL_NAME, &grp,
 579             SMB_LGRP_INFO_PRIV, gname);
 580         smb_lgrp_db_close(db);
 581         smb_lgrp_exit();
 582 
 583         if (rc == SMB_LGRP_SUCCESS) {
 584                 *enable = (smb_privset_query(grp.sg_privs, priv_lid) == 1);
 585                 smb_lgrp_free(&grp);
 586         }
 587 
 588         return (rc);
 589 }
 590 
 591 /*
 592  * smb_lgrp_add_member
 593  *
 594  * Add the given account to the specified group as its member.
 595  */
 596 int
 597 smb_lgrp_add_member(char *gname, smb_sid_t *msid, uint16_t sid_type)
 598 {
 599         sqlite *db;
 600         smb_gsid_t mid;
 601         int rc;
 602 
 603         if (!smb_lgrp_normalize_name(gname))
 604                 return (SMB_LGRP_INVALID_NAME);
 605 
 606         if (!smb_sid_isvalid(msid))
 607                 return (SMB_LGRP_INVALID_ARG);
 608 
 609         if (!smb_lgrp_chkmember(sid_type))
 610                 return (SMB_LGRP_INVALID_MEMBER);
 611 
 612         mid.gs_sid = msid;
 613         mid.gs_type = sid_type;
 614 
 615         if (!smb_lgrp_enter())
 616                 return (SMB_LGRP_OFFLINE);
 617 
 618         db = smb_lgrp_db_open(SMB_LGRP_DB_ORW);
 619         rc = smb_lgrp_gtbl_update_mlist(db, gname, &mid, SMB_LGRP_DB_ADDMEMBER);
 620         smb_lgrp_db_close(db);
 621 
 622         smb_lgrp_exit();
 623         return (rc);
 624 }
 625 
 626 /*
 627  * smb_lgrp_del_member
 628  *
 629  * Delete the specified member from the given group.
 630  */
 631 int
 632 smb_lgrp_del_member(char *gname, smb_sid_t *msid, uint16_t sid_type)
 633 {
 634         sqlite *db;
 635         smb_gsid_t mid;
 636         int rc;
 637 
 638         if (!smb_lgrp_normalize_name(gname))
 639                 return (SMB_LGRP_INVALID_NAME);
 640 
 641         if (!smb_sid_isvalid(msid))
 642                 return (SMB_LGRP_INVALID_ARG);
 643 
 644         mid.gs_sid = msid;
 645         mid.gs_type = sid_type;
 646 
 647         if (!smb_lgrp_enter())
 648                 return (SMB_LGRP_OFFLINE);
 649 
 650         db = smb_lgrp_db_open(SMB_LGRP_DB_ORW);
 651         rc = smb_lgrp_gtbl_update_mlist(db, gname, &mid, SMB_LGRP_DB_DELMEMBER);
 652         smb_lgrp_db_close(db);
 653 
 654         smb_lgrp_exit();
 655         return (rc);
 656 }
 657 
 658 /*
 659  * smb_lgrp_getbyname
 660  *
 661  * Retrieves the information of the group specified by
 662  * the given name.
 663  *
 664  * Note that this function doesn't allocate the group
 665  * structure itself only the fields, so the given grp
 666  * pointer has to point to a group structure.
 667  * Caller must free the allocated memories for the fields
 668  * by calling smb_lgrp_free().
 669  */
 670 int
 671 smb_lgrp_getbyname(char *gname, smb_group_t *grp)
 672 {
 673         sqlite *db;
 674         int rc;
 675 
 676         if (!smb_lgrp_normalize_name(gname))
 677                 return (SMB_LGRP_INVALID_NAME);
 678 
 679         if (!smb_lgrp_enter())
 680                 return (SMB_LGRP_OFFLINE);
 681 
 682         db = smb_lgrp_db_open(SMB_LGRP_DB_ORD);
 683         rc = smb_lgrp_gtbl_lookup(db, SMB_LGRP_GTBL_NAME, grp,
 684             SMB_LGRP_INFO_ALL, gname);
 685         smb_lgrp_db_close(db);
 686 
 687         smb_lgrp_exit();
 688         return (rc);
 689 }
 690 
 691 /*
 692  * smb_lgrp_getbyrid
 693  *
 694  * Retrieves the information of the group specified by
 695  * the given RID and domain type.
 696  *
 697  * Note that this function doesn't allocate the group
 698  * structure itself only the fields, so the given grp
 699  * pointer has to point to a group structure.
 700  * Caller must free the allocated memories for the fields
 701  * by calling smb_lgrp_free().
 702  *
 703  * If grp is NULL no information would be returned. The
 704  * return value of SMB_LGRP_SUCCESS will indicate that a
 705  * group with the given information exists.
 706  */
 707 int
 708 smb_lgrp_getbyrid(uint32_t rid, smb_domain_type_t domtype, smb_group_t *grp)
 709 {
 710         smb_group_t tmpgrp;
 711         sqlite *db;
 712         int infolvl = SMB_LGRP_INFO_ALL;
 713         int rc;
 714 
 715         if (!smb_lgrp_enter())
 716                 return (SMB_LGRP_OFFLINE);
 717 
 718         if (grp == NULL) {
 719                 grp = &tmpgrp;
 720                 infolvl = SMB_LGRP_INFO_NONE;
 721         }
 722 
 723         db = smb_lgrp_db_open(SMB_LGRP_DB_ORD);
 724         rc = smb_lgrp_gtbl_lookup(db, SMB_LGRP_GTBL_SIDRID, grp, infolvl,
 725             rid, domtype);
 726         smb_lgrp_db_close(db);
 727 
 728         smb_lgrp_exit();
 729         return (rc);
 730 }
 731 
 732 /*
 733  * smb_lgrp_numbydomain
 734  *
 735  * Returns the number of groups in the given domain in the
 736  * arg 'count'
 737  */
 738 int
 739 smb_lgrp_numbydomain(smb_domain_type_t dom_type, int *count)
 740 {
 741         sqlite *db;
 742         int dom_idx;
 743         int rc;
 744 
 745         switch (dom_type) {
 746         case SMB_DOMAIN_LOCAL:
 747                 dom_idx = SMB_LGRP_LOCAL_IDX;
 748                 break;
 749         case SMB_DOMAIN_BUILTIN:
 750                 dom_idx = SMB_LGRP_BUILTIN_IDX;
 751                 break;
 752         default:
 753                 *count = 0;
 754                 return (SMB_LGRP_INVALID_ARG);
 755         }
 756 
 757         if (!smb_lgrp_enter())
 758                 return (SMB_LGRP_OFFLINE);
 759 
 760         db = smb_lgrp_db_open(SMB_LGRP_DB_ORD);
 761         rc = smb_lgrp_gtbl_count(db, dom_idx, count);
 762         smb_lgrp_db_close(db);
 763 
 764         smb_lgrp_exit();
 765         return (rc);
 766 }
 767 
 768 /*
 769  * smb_lgrp_free
 770  *
 771  * Frees the allocated memory for the fields of the given
 772  * group structure. Note that this function doesn't free
 773  * the group itself.
 774  */
 775 void
 776 smb_lgrp_free(smb_group_t *grp)
 777 {
 778         int i;
 779 
 780         if (grp == NULL)
 781                 return;
 782 
 783         free(grp->sg_name);
 784         free(grp->sg_cmnt);
 785         smb_sid_free(grp->sg_id.gs_sid);
 786         smb_privset_free(grp->sg_privs);
 787 
 788         for (i = 0; i < grp->sg_nmembers; i++)
 789                 smb_sid_free(grp->sg_members[i].gs_sid);
 790         free(grp->sg_members);
 791 }
 792 
 793 /*
 794  * smb_lgrp_iteropen
 795  *
 796  * Initializes the given group iterator by opening
 797  * the group database and creating a virtual machine
 798  * for iteration.
 799  */
 800 int
 801 smb_lgrp_iteropen(smb_giter_t *iter)
 802 {
 803         char *sql;
 804         char *errmsg = NULL;
 805         int rc = SMB_LGRP_SUCCESS;
 806 
 807         assert(iter);
 808 
 809         if (!smb_lgrp_enter())
 810                 return (SMB_LGRP_OFFLINE);
 811 
 812         bzero(iter, sizeof (smb_giter_t));
 813 
 814         sql = sqlite_mprintf("SELECT * FROM groups");
 815         if (sql == NULL) {
 816                 smb_lgrp_exit();
 817                 return (SMB_LGRP_NO_MEMORY);
 818         }
 819 
 820         iter->sgi_db = smb_lgrp_db_open(SMB_LGRP_DB_ORD);
 821         if (iter->sgi_db == NULL) {
 822                 sqlite_freemem(sql);
 823                 smb_lgrp_exit();
 824                 return (SMB_LGRP_DBOPEN_FAILED);
 825         }
 826 
 827         rc = sqlite_compile(iter->sgi_db, sql, NULL, &iter->sgi_vm, &errmsg);
 828         sqlite_freemem(sql);
 829 
 830         if (rc != SQLITE_OK) {
 831                 syslog(LOG_DEBUG, "failed to create a VM (%s)",
 832                     NULL_MSGCHK(errmsg));
 833                 rc = SMB_LGRP_DB_ERROR;
 834         }
 835 
 836         smb_lgrp_exit();
 837         return (rc);
 838 }
 839 
 840 /*
 841  * smb_lgrp_iterclose
 842  *
 843  * Closes the given group iterator.
 844  */
 845 void
 846 smb_lgrp_iterclose(smb_giter_t *iter)
 847 {
 848         char *errmsg = NULL;
 849         int rc;
 850 
 851         assert(iter);
 852 
 853         if (!smb_lgrp_enter())
 854                 return;
 855 
 856         rc = sqlite_finalize(iter->sgi_vm, &errmsg);
 857         if (rc != SQLITE_OK) {
 858                 syslog(LOG_DEBUG, "failed to destroy a VM (%s)",
 859                     NULL_MSGCHK(errmsg));
 860         }
 861 
 862         smb_lgrp_db_close(iter->sgi_db);
 863         smb_lgrp_exit();
 864 }
 865 
 866 /*
 867  * Returns B_TRUE if there has been an error during
 868  * iteration.
 869  */
 870 boolean_t
 871 smb_lgrp_itererror(smb_giter_t *iter)
 872 {
 873         return (iter->sgi_nerr != 0);
 874 }
 875 
 876 /*
 877  * smb_lgrp_iterate
 878  *
 879  * Iterate through group database
 880  * Group information is returned in provided group structure.
 881  *
 882  * Note that this function doesn't allocate the group
 883  * structure itself only the fields, so the given grp
 884  * pointer has to point to a group structure.
 885  * Caller must free the allocated memories for the fields
 886  * by calling smb_lgrp_free().
 887  */
 888 int
 889 smb_lgrp_iterate(smb_giter_t *iter, smb_group_t *grp)
 890 {
 891         const char **values;
 892         int ncol;
 893         int rc;
 894         int i;
 895 
 896         if (iter->sgi_vm == NULL || iter->sgi_db == NULL)
 897                 return (SMB_LGRP_INVALID_ARG);
 898 
 899         if (!smb_lgrp_enter())
 900                 return (SMB_LGRP_OFFLINE);
 901 
 902         for (;;) {
 903                 bzero(grp, sizeof (smb_group_t));
 904                 rc = sqlite_step(iter->sgi_vm, &ncol, &values, NULL);
 905                 if (rc == SQLITE_DONE) {
 906                         smb_lgrp_exit();
 907                         return (SMB_LGRP_NO_MORE);
 908                 }
 909 
 910                 if (rc != SQLITE_ROW) {
 911                         smb_lgrp_exit();
 912                         return (SMB_LGRP_DBEXEC_FAILED);
 913                 }
 914 
 915                 if (ncol != SMB_LGRP_GTBL_NCOL) {
 916                         smb_lgrp_exit();
 917                         return (SMB_LGRP_DB_ERROR);
 918                 }
 919 
 920                 for (i = 0; i < ncol; i++) {
 921                         if (values[i] == NULL) {
 922                                 smb_lgrp_exit();
 923                                 return (SMB_LGRP_DB_ERROR);
 924                         }
 925                 }
 926 
 927                 rc = smb_lgrp_decode(grp, (char **)values, SMB_LGRP_INFO_ALL,
 928                     iter->sgi_db);
 929                 if (rc == SMB_LGRP_SUCCESS)
 930                         break;
 931 
 932                 iter->sgi_nerr++;
 933                 syslog(LOG_ERR, "smb_lgrp_iterate: %s", smb_lgrp_strerror(rc));
 934         }
 935 
 936         smb_lgrp_exit();
 937         return (rc);
 938 
 939 }
 940 
 941 /*
 942  * smb_lgrp_is_member
 943  *
 944  * Check to see if the specified account is a member of
 945  * the given group.
 946  */
 947 boolean_t
 948 smb_lgrp_is_member(smb_group_t *grp, smb_sid_t *sid)
 949 {
 950         int i;
 951 
 952         if (grp == NULL || grp->sg_members == NULL || sid == NULL)
 953                 return (B_FALSE);
 954 
 955         for (i = 0; i < grp->sg_nmembers; i++) {
 956                 if (smb_sid_cmp(grp->sg_members[i].gs_sid, sid))
 957                         return (B_TRUE);
 958         }
 959 
 960         return (B_FALSE);
 961 }
 962 
 963 /*
 964  * smb_lgrp_strerror
 965  *
 966  * Returns a text for the given group error code.
 967  */
 968 char *
 969 smb_lgrp_strerror(int errnum)
 970 {
 971         int     i;
 972         int     nerr = (sizeof (errtab) / sizeof (errtab[0]));
 973 
 974         for (i = 0; i < nerr; ++i) {
 975                 if (errnum == errtab[i].errnum)
 976                         return (errtab[i].errmsg);
 977         }
 978 
 979         return ("unknown local group error");
 980 }
 981 
 982 /*
 983  * smb_lgrp_err_to_ntstatus
 984  *
 985  * This routine maps Local group operation errors to NT Status error codes.
 986  */
 987 uint32_t
 988 smb_lgrp_err_to_ntstatus(uint32_t lgrp_err)
 989 {
 990         int i;
 991         static struct err_map {
 992                 uint32_t lgrp_err;
 993                 uint32_t nt_status;
 994         } err_map[] = {
 995                 { SMB_LGRP_SUCCESS,             NT_STATUS_SUCCESS },
 996                 { SMB_LGRP_INVALID_ARG,         NT_STATUS_INVALID_PARAMETER },
 997                 { SMB_LGRP_INVALID_MEMBER,      NT_STATUS_INVALID_MEMBER },
 998                 { SMB_LGRP_INVALID_NAME,        NT_STATUS_INVALID_PARAMETER },
 999                 { SMB_LGRP_NOT_FOUND,           NT_STATUS_NO_SUCH_ALIAS },
1000                 { SMB_LGRP_EXISTS,              NT_STATUS_ALIAS_EXISTS },
1001                 { SMB_LGRP_NO_SID,              NT_STATUS_INVALID_SID },
1002                 { SMB_LGRP_NO_LOCAL_SID,        NT_STATUS_INVALID_SID },
1003                 { SMB_LGRP_SID_NOTLOCAL,        NT_STATUS_INVALID_SID },
1004                 { SMB_LGRP_WKSID,               NT_STATUS_INVALID_SID },
1005                 { SMB_LGRP_NO_MEMORY,           NT_STATUS_NO_MEMORY },
1006                 { SMB_LGRP_DB_ERROR,            NT_STATUS_INTERNAL_DB_ERROR },
1007                 { SMB_LGRP_DBINIT_ERROR,        NT_STATUS_INTERNAL_DB_ERROR },
1008                 { SMB_LGRP_INTERNAL_ERROR,      NT_STATUS_INTERNAL_ERROR },
1009                 { SMB_LGRP_MEMBER_IN_GROUP,     NT_STATUS_MEMBER_IN_ALIAS },
1010                 { SMB_LGRP_MEMBER_NOT_IN_GROUP, NT_STATUS_MEMBER_NOT_IN_ALIAS },
1011                 { SMB_LGRP_NO_SUCH_PRIV,        NT_STATUS_NO_SUCH_PRIVILEGE },
1012                 { SMB_LGRP_NO_SUCH_DOMAIN,      NT_STATUS_NO_SUCH_DOMAIN },
1013                 { SMB_LGRP_PRIV_HELD,           NT_STATUS_SUCCESS },
1014                 { SMB_LGRP_PRIV_NOT_HELD,       NT_STATUS_PRIVILEGE_NOT_HELD },
1015                 { SMB_LGRP_BAD_DATA,            NT_STATUS_DATA_ERROR },
1016                 { SMB_LGRP_NO_MORE,             NT_STATUS_NO_MORE_ENTRIES },
1017                 { SMB_LGRP_DBOPEN_FAILED,       NT_STATUS_INTERNAL_DB_ERROR },
1018                 { SMB_LGRP_DBEXEC_FAILED,       NT_STATUS_INTERNAL_DB_ERROR },
1019                 { SMB_LGRP_DBINIT_FAILED,       NT_STATUS_INTERNAL_DB_ERROR },
1020                 { SMB_LGRP_DOMLKP_FAILED,       NT_STATUS_INTERNAL_DB_ERROR },
1021                 { SMB_LGRP_DOMINS_FAILED,       NT_STATUS_INTERNAL_DB_ERROR },
1022                 { SMB_LGRP_INSERT_FAILED,       NT_STATUS_INTERNAL_DB_ERROR },
1023                 { SMB_LGRP_DELETE_FAILED,       NT_STATUS_INTERNAL_DB_ERROR },
1024                 { SMB_LGRP_UPDATE_FAILED,       NT_STATUS_INTERNAL_DB_ERROR },
1025                 { SMB_LGRP_LOOKUP_FAILED,       NT_STATUS_INTERNAL_DB_ERROR },
1026                 { SMB_LGRP_NOT_SUPPORTED,       NT_STATUS_NOT_SUPPORTED },
1027                 { SMB_LGRP_OFFLINE,             NT_STATUS_INTERNAL_ERROR },
1028                 { SMB_LGRP_POSIXCREATE_FAILED,  NT_STATUS_UNSUCCESSFUL }
1029         };
1030 
1031         for (i = 0; i < sizeof (err_map)/sizeof (err_map[0]); ++i) {
1032                 if (err_map[i].lgrp_err == lgrp_err)
1033                         return (err_map[i].nt_status);
1034         }
1035 
1036         return (NT_STATUS_INTERNAL_ERROR);
1037 }
1038 
1039 /*
1040  * smb_lgrp_chkmember
1041  *
1042  * Determines valid account types for being member of
1043  * a local group.  We really have no business trying to
1044  * keep track of the "type" of SIDs in a group, so just
1045  * validate that the SID type is a known enum value.
1046  */
1047 static boolean_t
1048 smb_lgrp_chkmember(uint16_t sid_type)
1049 {
1050         switch (sid_type) {
1051         case SidTypeNull:
1052         case SidTypeUser:
1053         case SidTypeGroup:
1054         case SidTypeAlias:
1055         case SidTypeWellKnownGroup:
1056         case SidTypeDeletedAccount:
1057         case SidTypeInvalid:
1058         case SidTypeUnknown:
1059                 return (B_TRUE);
1060         }
1061         return (B_FALSE);
1062 }
1063 
1064 /*
1065  * smb_lgrp_start
1066  *
1067  * Initializes the library private global variables.
1068  * Create the database, if it doesn't exist, and add
1069  * the predefined builtin groups.
1070  */
1071 int
1072 smb_lgrp_start(void)
1073 {
1074         static char     *builtin[] = {
1075                 "Administrators",
1076                 "Backup Operators",
1077                 "Power Users"
1078         };
1079         smb_wka_t       *wka;
1080         char            *localsid;
1081         int             i, rc;
1082         int             ngrp = sizeof (builtin) / sizeof (builtin[0]);
1083 
1084         (void) mutex_lock(&smb_localgrp.lg_mutex);
1085 
1086         if ((localsid = smb_config_get_localsid()) == NULL) {
1087                 (void) mutex_unlock(&smb_localgrp.lg_mutex);
1088                 return (SMB_LGRP_NO_LOCAL_SID);
1089         }
1090 
1091         smb_localgrp.lg_machine_sid = smb_sid_fromstr(localsid);
1092         free(localsid);
1093 
1094         if (!smb_sid_isvalid(smb_localgrp.lg_machine_sid)) {
1095                 free(smb_localgrp.lg_machine_sid);
1096                 smb_localgrp.lg_machine_sid = NULL;
1097                 (void) mutex_unlock(&smb_localgrp.lg_mutex);
1098                 return (SMB_LGRP_NO_LOCAL_SID);
1099         }
1100 
1101         rc = smb_lgrp_db_init();
1102         if (rc != SMB_LGRP_SUCCESS) {
1103                 free(smb_localgrp.lg_machine_sid);
1104                 smb_localgrp.lg_machine_sid = NULL;
1105                 (void) mutex_unlock(&smb_localgrp.lg_mutex);
1106                 return (rc);
1107         }
1108 
1109         smb_localgrp.lg_online = B_TRUE;
1110         (void) mutex_unlock(&smb_localgrp.lg_mutex);
1111 
1112         for (i = 0; i < ngrp; i++) {
1113                 char    *tname;
1114 
1115                 if ((wka = smb_wka_lookup_name(builtin[i])) == NULL)
1116                         continue;
1117 
1118                 if ((tname = strdup(wka->wka_name)) == NULL)
1119                         return (SMB_LGRP_NO_MEMORY);
1120                 if (!smb_lgrp_exists(tname)) {
1121                         rc = smb_lgrp_add(tname, wka->wka_desc);
1122                         if (rc != SMB_LGRP_SUCCESS) {
1123                                 syslog(LOG_DEBUG, "failed to add %s",
1124                                     tname);
1125                         }
1126                 }
1127                 free(tname);
1128         }
1129 
1130         return (SMB_LGRP_SUCCESS);
1131 }
1132 
1133 /*
1134  * smb_lgrp_stop
1135  *
1136  * Unintialize the library global private variables.
1137  */
1138 void
1139 smb_lgrp_stop(void)
1140 {
1141         (void) mutex_lock(&smb_localgrp.lg_mutex);
1142         if (!smb_localgrp.lg_online)
1143                 return;
1144 
1145         smb_localgrp.lg_online = B_FALSE;
1146 
1147         while (smb_localgrp.lg_refcnt > 0)
1148                 (void) cond_wait(&smb_localgrp.lg_cv, &smb_localgrp.lg_mutex);
1149 
1150         free(smb_localgrp.lg_machine_sid);
1151         smb_localgrp.lg_machine_sid = NULL;
1152         (void) mutex_unlock(&smb_localgrp.lg_mutex);
1153 }
1154 
1155 static boolean_t
1156 smb_lgrp_enter(void)
1157 {
1158         boolean_t       status;
1159 
1160         (void) mutex_lock(&smb_localgrp.lg_mutex);
1161 
1162         status = smb_localgrp.lg_online;
1163 
1164         if (smb_localgrp.lg_online)
1165                 ++smb_localgrp.lg_refcnt;
1166 
1167         (void) mutex_unlock(&smb_localgrp.lg_mutex);
1168         return (status);
1169 }
1170 
1171 static void
1172 smb_lgrp_exit(void)
1173 {
1174         (void) mutex_lock(&smb_localgrp.lg_mutex);
1175         assert(smb_localgrp.lg_refcnt > 0);
1176 
1177         if ((--smb_localgrp.lg_refcnt) == 0)
1178                 (void) cond_signal(&smb_localgrp.lg_cv);
1179 
1180         (void) mutex_unlock(&smb_localgrp.lg_mutex);
1181 }
1182 
1183 /*
1184  * smb_lgrp_db_open
1185  *
1186  * Opens group database with the given mode.
1187  */
1188 static sqlite *
1189 smb_lgrp_db_open(int mode)
1190 {
1191         sqlite *db;
1192         char *errmsg = NULL;
1193 
1194         db = sqlite_open(SMB_LGRP_DB_NAME, mode, &errmsg);
1195         if (db == NULL) {
1196                 syslog(LOG_ERR, "failed to open group database (%s)",
1197                     NULL_MSGCHK(errmsg));
1198                 sqlite_freemem(errmsg);
1199         }
1200 
1201         return (db);
1202 }
1203 
1204 /*
1205  * smb_lgrp_db_close
1206  *
1207  * Closes the given database handle
1208  */
1209 static void
1210 smb_lgrp_db_close(sqlite *db)
1211 {
1212         if (db) {
1213                 sqlite_close(db);
1214         }
1215 }
1216 
1217 /*
1218  * smb_lgrp_db_init
1219  *
1220  * Creates the group database based on the defined SQL statement.
1221  * It also initializes db_info and domain tables.
1222  */
1223 static int
1224 smb_lgrp_db_init(void)
1225 {
1226         int dbrc = SQLITE_OK;
1227         int rc = SMB_LGRP_SUCCESS;
1228         sqlite *db = NULL;
1229         char *errmsg = NULL;
1230 
1231         db = sqlite_open(SMB_LGRP_DB_NAME, 0600, &errmsg);
1232         if (db == NULL) {
1233                 syslog(LOG_ERR, "failed to create group database (%s)",
1234                     NULL_MSGCHK(errmsg));
1235                 sqlite_freemem(errmsg);
1236                 return (SMB_LGRP_DBOPEN_FAILED);
1237         }
1238 
1239         sqlite_busy_timeout(db, SMB_LGRP_DB_TIMEOUT);
1240         dbrc = sqlite_exec(db, "BEGIN TRANSACTION;", NULL, NULL, &errmsg);
1241         if (dbrc != SQLITE_OK) {
1242                 syslog(LOG_DEBUG, "failed to begin database transaction (%s)",
1243                     NULL_MSGCHK(errmsg));
1244                 sqlite_freemem(errmsg);
1245                 sqlite_close(db);
1246                 return (SMB_LGRP_DBEXEC_FAILED);
1247         }
1248 
1249         switch (sqlite_exec(db, SMB_LGRP_DB_SQL, NULL, NULL, &errmsg)) {
1250         case SQLITE_ERROR:
1251                 /*
1252                  * This is the normal situation: CREATE probably failed because
1253                  * tables already exist. It may indicate an error in SQL as well
1254                  * but we cannot tell.
1255                  */
1256                 sqlite_freemem(errmsg);
1257                 dbrc = sqlite_exec(db, "ROLLBACK TRANSACTION", NULL, NULL,
1258                     &errmsg);
1259                 rc = SMB_LGRP_SUCCESS;
1260                 break;
1261 
1262         case SQLITE_OK:
1263                 dbrc = sqlite_exec(db, "COMMIT TRANSACTION", NULL, NULL,
1264                     &errmsg);
1265                 if (dbrc != SQLITE_OK)
1266                         break;
1267                 rc = smb_lgrp_dtbl_insert(db, NT_BUILTIN_DOMAIN_SIDSTR,
1268                     NULL);
1269                 if (rc == SMB_LGRP_SUCCESS)
1270                         rc = smb_lgrp_db_setinfo(db);
1271                 if (rc != SMB_LGRP_SUCCESS) {
1272                         (void) sqlite_close(db);
1273                         (void) unlink(SMB_LGRP_DB_NAME);
1274                         return (rc);
1275                 }
1276                 break;
1277 
1278         default:
1279                 syslog(LOG_ERR,
1280                     "failed to initialize group database (%s)", errmsg);
1281                 sqlite_freemem(errmsg);
1282                 dbrc = sqlite_exec(db, "ROLLBACK TRANSACTION", NULL, NULL,
1283                     &errmsg);
1284                 rc = SMB_LGRP_DBINIT_FAILED;
1285                 break;
1286         }
1287 
1288         if (dbrc != SQLITE_OK) {
1289                 /* this is bad - database may be left in a locked state */
1290                 syslog(LOG_DEBUG, "failed to close a transaction (%s)",
1291                     NULL_MSGCHK(errmsg));
1292                 sqlite_freemem(errmsg);
1293         }
1294 
1295         (void) sqlite_close(db);
1296         return (rc);
1297 }
1298 
1299 /*
1300  * smb_lgrp_gtbl_lookup
1301  *
1302  * This is a flexible lookup function for the group database.
1303  * The key type can be specified by the 'key' arg and the actual key
1304  * values can be passed after the 'infolvl' arg. 'infolvl' arg specifies
1305  * what information items for the specified group is needed.
1306  *
1307  * Note that the function assumes the given key is unique and only
1308  * specifies one or 0 group. The keys that are supported now are
1309  * the group name and the group SID
1310  *
1311  * Note that this function doesn't allocate the group
1312  * structure itself only the fields, so the given grp
1313  * pointer has to point to a group structure.
1314  * Caller must free the allocated memories for the fields
1315  * by calling smb_lgrp_free().
1316  */
1317 static int
1318 smb_lgrp_gtbl_lookup(sqlite *db, int key, smb_group_t *grp, int infolvl, ...)
1319 {
1320         char *errmsg = NULL;
1321         char *sql;
1322         char **result;
1323         int nrow, ncol;
1324         int rc, dom_idx;
1325         smb_group_t grpkey;
1326         va_list ap;
1327 
1328         if (db == NULL)
1329                 return (SMB_LGRP_DBOPEN_FAILED);
1330 
1331         bzero(grp, sizeof (smb_group_t));
1332         va_start(ap, infolvl);
1333 
1334         switch (key) {
1335         case SMB_LGRP_GTBL_NAME:
1336                 grpkey.sg_name = va_arg(ap, char *);
1337                 sql = sqlite_mprintf("SELECT * FROM groups WHERE name = '%s'",
1338                     grpkey.sg_name);
1339                 break;
1340 
1341         case SMB_LGRP_GTBL_SIDRID:
1342                 grpkey.sg_rid = va_arg(ap, uint32_t);
1343                 grpkey.sg_domain = va_arg(ap, smb_domain_type_t);
1344                 if (grpkey.sg_domain == SMB_DOMAIN_LOCAL) {
1345                         dom_idx = SMB_LGRP_LOCAL_IDX;
1346                         /* need to map the given rid to a gid */
1347                         rc = smb_lgrp_getgid(grpkey.sg_rid,
1348                             (gid_t *)&grpkey.sg_rid);
1349                         if (rc != SMB_LGRP_SUCCESS) {
1350                                 va_end(ap);
1351                                 return (rc);
1352                         }
1353                 } else {
1354                         dom_idx = SMB_LGRP_BUILTIN_IDX;
1355                 }
1356 
1357                 sql = sqlite_mprintf("SELECT * FROM groups "
1358                     "WHERE (sid_idx = %d) AND (sid_rid = %u)",
1359                     dom_idx, grpkey.sg_rid);
1360                 break;
1361 
1362         default:
1363                 va_end(ap);
1364                 return (SMB_LGRP_INVALID_ARG);
1365         }
1366 
1367         va_end(ap);
1368         if (sql == NULL)
1369                 return (SMB_LGRP_NO_MEMORY);
1370 
1371         rc = sqlite_get_table(db, sql, &result, &nrow, &ncol, &errmsg);
1372         sqlite_freemem(sql);
1373 
1374         if (rc != SQLITE_OK) {
1375                 syslog(LOG_DEBUG, "failed to lookup (%s)", NULL_MSGCHK(errmsg));
1376                 sqlite_freemem(errmsg);
1377                 return (SMB_LGRP_LOOKUP_FAILED);
1378         }
1379 
1380         if (nrow == 0)  {
1381                 /* group not found */
1382                 sqlite_free_table(result);
1383                 return (SMB_LGRP_NOT_FOUND);
1384         }
1385 
1386         if (nrow != 1 || ncol != SMB_LGRP_GTBL_NCOL) {
1387                 sqlite_free_table(result);
1388                 return (SMB_LGRP_DB_ERROR);
1389         }
1390 
1391         rc = smb_lgrp_decode(grp, &result[SMB_LGRP_GTBL_NCOL], infolvl, db);
1392         sqlite_free_table(result);
1393         return (rc);
1394 }
1395 
1396 /*
1397  * smb_lgrp_gtbl_exists
1398  *
1399  * Checks to see if the given group exists or not.
1400  */
1401 static boolean_t
1402 smb_lgrp_gtbl_exists(sqlite *db, char *gname)
1403 {
1404         char *errmsg = NULL;
1405         char *sql;
1406         char **result;
1407         int nrow, ncol;
1408         int rc;
1409 
1410         if (db == NULL)
1411                 return (NULL);
1412 
1413         sql = sqlite_mprintf("SELECT name FROM groups WHERE name = '%s'",
1414             gname);
1415         rc = sqlite_get_table(db, sql, &result, &nrow, &ncol, &errmsg);
1416         sqlite_freemem(sql);
1417 
1418         if (rc != SQLITE_OK) {
1419                 syslog(LOG_DEBUG, "failed to lookup %s (%s)",
1420                     gname, NULL_MSGCHK(errmsg));
1421                 sqlite_freemem(errmsg);
1422                 return (B_FALSE);
1423         }
1424 
1425         sqlite_free_table(result);
1426         return (nrow != 0);
1427 }
1428 
1429 /*
1430  * smb_lgrp_gtbl_count
1431  *
1432  * Counts the number of groups in the domain specified by
1433  * 'dom_idx'
1434  */
1435 static int
1436 smb_lgrp_gtbl_count(sqlite *db, int dom_idx, int *count)
1437 {
1438         char *errmsg = NULL;
1439         char *sql;
1440         char **result;
1441         int nrow, ncol;
1442         int rc;
1443 
1444         *count = 0;
1445         if (db == NULL)
1446                 return (SMB_LGRP_DBOPEN_FAILED);
1447 
1448         sql = sqlite_mprintf("SELECT sid_idx FROM groups WHERE sid_idx = %d",
1449             dom_idx);
1450         rc = sqlite_get_table(db, sql, &result, &nrow, &ncol, &errmsg);
1451         sqlite_freemem(sql);
1452 
1453         if (rc != SQLITE_OK) {
1454                 syslog(LOG_DEBUG, "failed to count (%s)", NULL_MSGCHK(errmsg));
1455                 sqlite_freemem(errmsg);
1456                 return (SMB_LGRP_LOOKUP_FAILED);
1457         }
1458 
1459         sqlite_free_table(result);
1460         if (ncol > 1)
1461                 return (SMB_LGRP_DB_ERROR);
1462 
1463         *count = nrow;
1464         return (SMB_LGRP_SUCCESS);
1465 }
1466 
1467 /*
1468  * smb_lgrp_gtbl_insert
1469  *
1470  * Insert a record for the given group in the group database.
1471  *
1472  * NOTE: this function assumes that this group has no members
1473  * at this time.
1474  */
1475 static int
1476 smb_lgrp_gtbl_insert(sqlite *db, smb_group_t *grp)
1477 {
1478         smb_lgpid_t privs[SE_MAX_LUID + 1];
1479         smb_lgplist_t plist;
1480         char *errmsg = NULL;
1481         char *sql;
1482         int dom_idx;
1483         int rc;
1484 
1485         if (db == NULL)
1486                 return (SMB_LGRP_DBOPEN_FAILED);
1487 
1488         dom_idx = (grp->sg_domain == SMB_DOMAIN_LOCAL)
1489             ? SMB_LGRP_LOCAL_IDX : SMB_LGRP_BUILTIN_IDX;
1490 
1491         plist.p_cnt = SE_MAX_LUID;
1492         plist.p_ids = privs;
1493         smb_lgrp_encode_privset(grp, &plist);
1494 
1495         sql = sqlite_mprintf("INSERT INTO groups "
1496             "(name, sid_idx, sid_rid, sid_type, sid_attrs, comment, "
1497             "n_privs, privs, n_members, members) "
1498             "VALUES('%s', %u, %u, %u, %u, '%q', %u, '%q', %u, '%q')",
1499             grp->sg_name, dom_idx, grp->sg_rid, grp->sg_id.gs_type,
1500             grp->sg_attr, (grp->sg_cmnt) ? grp->sg_cmnt : "",
1501             plist.p_cnt, (char *)plist.p_ids, 0, "");
1502 
1503         if (sql == NULL)
1504                 return (SMB_LGRP_NO_MEMORY);
1505 
1506         rc = sqlite_exec(db, sql, NULL, NULL, &errmsg);
1507         sqlite_freemem(sql);
1508 
1509         if (rc != SQLITE_OK) {
1510                 syslog(LOG_DEBUG, "failed to insert %s (%s)",
1511                     grp->sg_name, NULL_MSGCHK(errmsg));
1512                 sqlite_freemem(errmsg);
1513                 rc = SMB_LGRP_INSERT_FAILED;
1514         } else {
1515                 rc = SMB_LGRP_SUCCESS;
1516         }
1517 
1518         return (rc);
1519 }
1520 
1521 /*
1522  * smb_lgrp_gtbl_delete
1523  *
1524  * Removes the specified group from the database
1525  */
1526 static int
1527 smb_lgrp_gtbl_delete(sqlite *db, char *gname)
1528 {
1529         char *errmsg = NULL;
1530         char *sql;
1531         int rc;
1532 
1533         if (db == NULL)
1534                 return (SMB_LGRP_DBOPEN_FAILED);
1535 
1536         sql = sqlite_mprintf("DELETE FROM groups WHERE name = '%s'", gname);
1537         if (sql == NULL)
1538                 return (SMB_LGRP_NO_MEMORY);
1539 
1540         rc = sqlite_exec(db, sql, NULL, NULL, &errmsg);
1541         sqlite_freemem(sql);
1542 
1543         if (rc != SQLITE_OK) {
1544                 syslog(LOG_DEBUG, "failed to delete %s (%s)",
1545                     gname, NULL_MSGCHK(errmsg));
1546                 sqlite_freemem(errmsg);
1547                 rc = SMB_LGRP_DELETE_FAILED;
1548         } else {
1549                 rc = SMB_LGRP_SUCCESS;
1550         }
1551 
1552         return (rc);
1553 }
1554 
1555 /*
1556  * smb_lgrp_gtbl_update
1557  *
1558  * Updates the specified group information, the supported items
1559  * are group name and comment
1560  */
1561 static int
1562 smb_lgrp_gtbl_update(sqlite *db, char *gname, smb_group_t *grp, int col_id)
1563 {
1564         char *errmsg = NULL;
1565         char *sql;
1566         int rc;
1567 
1568         if (db == NULL)
1569                 return (SMB_LGRP_DBOPEN_FAILED);
1570 
1571         /* UPDATE doesn't fail if gname doesn't exist */
1572         if (!smb_lgrp_gtbl_exists(db, gname))
1573                 return (SMB_LGRP_NOT_FOUND);
1574 
1575         switch (col_id) {
1576         case SMB_LGRP_GTBL_NAME:
1577                 if (smb_lgrp_gtbl_exists(db, grp->sg_name))
1578                         return (SMB_LGRP_EXISTS);
1579                 sql = sqlite_mprintf("UPDATE groups SET name = '%s' "
1580                     "WHERE name = '%s'", grp->sg_name, gname);
1581                 break;
1582 
1583         case SMB_LGRP_GTBL_CMNT:
1584                 sql = sqlite_mprintf("UPDATE groups SET comment = '%q' "
1585                 "WHERE name = '%s'", grp->sg_cmnt, gname);
1586                 break;
1587 
1588         default:
1589                 return (SMB_LGRP_INVALID_ARG);
1590         }
1591 
1592         if (sql == NULL)
1593                 return (SMB_LGRP_NO_MEMORY);
1594 
1595         rc = sqlite_exec(db, sql, NULL, NULL, &errmsg);
1596         sqlite_freemem(sql);
1597 
1598         if (rc != SQLITE_OK) {
1599                 syslog(LOG_DEBUG, "failed to update %s (%s)",
1600                     gname, NULL_MSGCHK(errmsg));
1601                 sqlite_freemem(errmsg);
1602                 rc = SMB_LGRP_UPDATE_FAILED;
1603         } else {
1604                 rc = SMB_LGRP_SUCCESS;
1605         }
1606 
1607         return (rc);
1608 }
1609 
1610 /*
1611  * smb_lgrp_gtbl_update_mlist
1612  *
1613  * Adds/removes the specified member from the member list of the
1614  * given group
1615  */
1616 static int
1617 smb_lgrp_gtbl_update_mlist(sqlite *db, char *gname, smb_gsid_t *member,
1618     int flags)
1619 {
1620         smb_lgmlist_t new_members;
1621         smb_lgmlist_t members;
1622         smb_lgmid_t mid;
1623         char *errmsg = NULL;
1624         char *sql;
1625         char **result;
1626         int nrow, ncol;
1627         int rc;
1628 
1629         if (db == NULL)
1630                 return (SMB_LGRP_DBOPEN_FAILED);
1631 
1632         sql = sqlite_mprintf("SELECT n_members, members FROM groups "
1633             "WHERE name = '%s'", gname);
1634 
1635         if (sql == NULL)
1636                 return (SMB_LGRP_NO_MEMORY);
1637 
1638         rc = sqlite_get_table(db, sql, &result, &nrow, &ncol, &errmsg);
1639         sqlite_freemem(sql);
1640 
1641         if (rc != SQLITE_OK) {
1642                 syslog(LOG_DEBUG, "failed to lookup %s (%s)",
1643                     gname, NULL_MSGCHK(errmsg));
1644                 sqlite_freemem(errmsg);
1645                 return (SMB_LGRP_LOOKUP_FAILED);
1646         }
1647 
1648         if (nrow == 0)  {
1649                 /* group not found */
1650                 sqlite_free_table(result);
1651                 return (SMB_LGRP_NOT_FOUND);
1652         }
1653 
1654         if (nrow != 1 || ncol != 2) {
1655                 sqlite_free_table(result);
1656                 return (SMB_LGRP_DB_ERROR);
1657         }
1658 
1659         bzero(&mid, sizeof (mid));
1660         mid.m_type = member->gs_type;
1661         rc = smb_lgrp_dtbl_getidx(db, member->gs_sid, mid.m_type,
1662             &mid.m_idx, &mid.m_rid);
1663         if (rc != SMB_LGRP_SUCCESS) {
1664                 sqlite_free_table(result);
1665                 return (rc);
1666         }
1667 
1668         members.m_cnt = atoi(result[2]);
1669         members.m_ids = result[3];
1670 
1671         switch (flags) {
1672         case SMB_LGRP_DB_ADDMEMBER:
1673                 rc = smb_lgrp_mlist_add(&members, &mid, &new_members);
1674                 break;
1675         case SMB_LGRP_DB_DELMEMBER:
1676                 rc = smb_lgrp_mlist_del(&members, &mid, &new_members);
1677                 break;
1678         default:
1679                 rc = SMB_LGRP_INVALID_ARG;
1680         }
1681 
1682         sqlite_free_table(result);
1683         if (rc != SMB_LGRP_SUCCESS)
1684                 return (rc);
1685 
1686         sql = sqlite_mprintf("UPDATE groups SET n_members = %u, members = '%s'"
1687             " WHERE name = '%s'", new_members.m_cnt, new_members.m_ids, gname);
1688 
1689         free(new_members.m_ids);
1690 
1691         if (sql == NULL)
1692                 return (SMB_LGRP_NO_MEMORY);
1693 
1694         rc = sqlite_exec(db, sql, NULL, NULL, &errmsg);
1695         sqlite_freemem(sql);
1696 
1697         if (rc != SQLITE_OK) {
1698                 syslog(LOG_DEBUG, "failed to update %s (%s)", gname,
1699                     NULL_MSGCHK(errmsg));
1700                 sqlite_freemem(errmsg);
1701                 rc = SMB_LGRP_UPDATE_FAILED;
1702         } else {
1703                 rc = SMB_LGRP_SUCCESS;
1704         }
1705 
1706         return (rc);
1707 }
1708 
1709 /*
1710  * smb_lgrp_gtbl_update_plist
1711  *
1712  * Adds/removes the specified privilege from the privilege list of the
1713  * given group
1714  */
1715 static int
1716 smb_lgrp_gtbl_update_plist(sqlite *db, char *gname, uint8_t priv_id,
1717     boolean_t enable)
1718 {
1719         char *sql;
1720         char *errmsg = NULL;
1721         char **result;
1722         int nrow, ncol;
1723         int rc;
1724         smb_lgplist_t privs;
1725         smb_lgplist_t new_privs;
1726 
1727         if (db == NULL)
1728                 return (SMB_LGRP_DBOPEN_FAILED);
1729 
1730         sql = sqlite_mprintf("SELECT n_privs, privs FROM groups "
1731             "WHERE name = '%s'", gname);
1732 
1733         if (sql == NULL)
1734                 return (SMB_LGRP_NO_MEMORY);
1735 
1736         rc = sqlite_get_table(db, sql, &result, &nrow, &ncol, &errmsg);
1737         sqlite_freemem(sql);
1738 
1739         if (rc != SQLITE_OK) {
1740                 syslog(LOG_DEBUG, "failed to lookup %s (%s)",
1741                     gname, NULL_MSGCHK(errmsg));
1742                 sqlite_freemem(errmsg);
1743                 return (SMB_LGRP_LOOKUP_FAILED);
1744         }
1745 
1746         if (nrow == 0)  {
1747                 /* group not found */
1748                 sqlite_free_table(result);
1749                 return (SMB_LGRP_NOT_FOUND);
1750         }
1751 
1752         if (nrow != 1 || ncol != 2) {
1753                 sqlite_free_table(result);
1754                 return (SMB_LGRP_DB_ERROR);
1755         }
1756 
1757         privs.p_cnt = atoi(result[2]);
1758         privs.p_ids = (smb_lgpid_t *)result[3];
1759 
1760         if (enable)
1761                 rc = smb_lgrp_plist_add(&privs, priv_id, &new_privs);
1762         else
1763                 rc = smb_lgrp_plist_del(&privs, priv_id, &new_privs);
1764 
1765         sqlite_free_table(result);
1766         if (rc != SMB_LGRP_SUCCESS)
1767                 return (rc);
1768 
1769         sql = sqlite_mprintf("UPDATE groups SET n_privs = %u, privs = '%q'"
1770             " WHERE name = '%s'", new_privs.p_cnt, (char *)new_privs.p_ids,
1771             gname);
1772 
1773         free(new_privs.p_ids);
1774 
1775         if (sql == NULL)
1776                 return (SMB_LGRP_NO_MEMORY);
1777 
1778         rc = sqlite_exec(db, sql, NULL, NULL, &errmsg);
1779         sqlite_freemem(sql);
1780 
1781         if (rc != SQLITE_OK) {
1782                 syslog(LOG_DEBUG, "failed to update %s (%s)",
1783                     gname, NULL_MSGCHK(errmsg));
1784                 sqlite_freemem(errmsg);
1785                 rc = SMB_LGRP_UPDATE_FAILED;
1786         } else {
1787                 rc = SMB_LGRP_SUCCESS;
1788         }
1789 
1790         return (rc);
1791 }
1792 
1793 /*
1794  * smb_lgrp_dtbl_insert
1795  *
1796  * Inserts the specified domain SID in the dmain table.
1797  * Upon successful insert the index will be returned in
1798  * 'dom_idx' arg.
1799  */
1800 static int
1801 smb_lgrp_dtbl_insert(sqlite *db, char *dom_sid, uint32_t *dom_idx)
1802 {
1803         char *errmsg = NULL;
1804         char *sql;
1805         int rc;
1806 
1807         sql = sqlite_mprintf("INSERT INTO domains (dom_sid, dom_cnt)"
1808             " VALUES('%s', 1);", dom_sid);
1809         if (sql == NULL)
1810                 return (SMB_LGRP_NO_MEMORY);
1811 
1812         rc = sqlite_exec(db, sql, NULL, NULL, &errmsg);
1813         sqlite_freemem(sql);
1814 
1815         if (rc != SQLITE_OK) {
1816                 syslog(LOG_DEBUG, "failed to insert domain SID (%s)",
1817                     NULL_MSGCHK(errmsg));
1818                 sqlite_freemem(errmsg);
1819                 return (SMB_LGRP_DOMINS_FAILED);
1820         }
1821 
1822         if (dom_idx)
1823                 *dom_idx = sqlite_last_insert_rowid(db);
1824         return (SMB_LGRP_SUCCESS);
1825 }
1826 
1827 /*
1828  * smb_lgrp_dtbl_getidx
1829  *
1830  * Searches the domain table for the domain SID of the
1831  * given member SID. If it finds the domain SID it'll
1832  * return the index and the RID, otherwise it'll insert
1833  * it in the domain table as a new SID.
1834  */
1835 static int
1836 smb_lgrp_dtbl_getidx(sqlite *db, smb_sid_t *sid, uint16_t sid_type,
1837     uint32_t *dom_idx, uint32_t *rid)
1838 {
1839         char sidstr[SMB_SID_STRSZ];
1840         smb_sid_t *dom_sid;
1841         char **result;
1842         int nrow, ncol;
1843         char *errmsg = NULL;
1844         char *sql;
1845         int rc;
1846 
1847         if (smb_sid_indomain(smb_localgrp.lg_machine_sid, sid)) {
1848                 /* This is a local SID */
1849                 int id_type = (sid_type == SidTypeUser)
1850                     ? SMB_IDMAP_USER : SMB_IDMAP_GROUP;
1851                 *dom_idx = SMB_LGRP_LOCAL_IDX;
1852                 if (smb_idmap_getid(sid, rid, &id_type) != IDMAP_SUCCESS)
1853                         return (SMB_LGRP_INTERNAL_ERROR);
1854 
1855                 return (SMB_LGRP_SUCCESS);
1856         }
1857 
1858         if ((dom_sid = smb_sid_split(sid, rid)) == NULL)
1859                 return (SMB_LGRP_NO_MEMORY);
1860 
1861         smb_sid_tostr(dom_sid, sidstr);
1862         free(dom_sid);
1863 
1864         sql = sqlite_mprintf("SELECT dom_idx FROM domains WHERE dom_sid = '%s'",
1865             sidstr);
1866         if (sql == NULL)
1867                 return (SMB_LGRP_NO_MEMORY);
1868 
1869         rc = sqlite_get_table(db, sql, &result, &nrow, &ncol, &errmsg);
1870         sqlite_freemem(sql);
1871 
1872         if (rc != SQLITE_OK) {
1873                 syslog(LOG_DEBUG, "failed to lookup domain SID (%s)",
1874                     NULL_MSGCHK(errmsg));
1875                 sqlite_freemem(errmsg);
1876                 return (SMB_LGRP_DOMLKP_FAILED);
1877         }
1878 
1879         switch (nrow) {
1880         case 0:
1881                 /* new domain SID; insert it into the domains table */
1882                 sqlite_free_table(result);
1883                 return (smb_lgrp_dtbl_insert(db, sidstr, dom_idx));
1884 
1885         case 1:
1886                 *dom_idx = atoi(result[1]);
1887                 sqlite_free_table(result);
1888                 return (SMB_LGRP_SUCCESS);
1889         }
1890 
1891         sqlite_free_table(result);
1892         return (SMB_LGRP_DB_ERROR);
1893 }
1894 
1895 /*
1896  * smb_lgrp_dtbl_getsid
1897  *
1898  * Searchs the domain table for the given domain index.
1899  * Converts the found domain SID to binary format and
1900  * returns it in the 'sid' arg.
1901  *
1902  * Caller must free the returned SID by calling free().
1903  */
1904 static int
1905 smb_lgrp_dtbl_getsid(sqlite *db, uint32_t dom_idx, smb_sid_t **sid)
1906 {
1907         char **result;
1908         int nrow, ncol;
1909         char *errmsg = NULL;
1910         char *sql;
1911         int rc;
1912 
1913         sql = sqlite_mprintf("SELECT dom_sid FROM domains WHERE dom_idx = %u",
1914             dom_idx);
1915         if (sql == NULL)
1916                 return (SMB_LGRP_NO_MEMORY);
1917 
1918         rc = sqlite_get_table(db, sql, &result, &nrow, &ncol, &errmsg);
1919         sqlite_freemem(sql);
1920 
1921         if (rc != SQLITE_OK) {
1922                 syslog(LOG_DEBUG, "failed to lookup domain index (%s)",
1923                     NULL_MSGCHK(errmsg));
1924                 sqlite_freemem(errmsg);
1925                 return (SMB_LGRP_DOMLKP_FAILED);
1926         }
1927 
1928         switch (nrow) {
1929         case 0:
1930                 rc = SMB_LGRP_NO_SUCH_DOMAIN;
1931                 break;
1932 
1933         case 1:
1934                 *sid = smb_sid_fromstr(result[1]);
1935                 rc = (*sid == NULL)
1936                     ? SMB_LGRP_INTERNAL_ERROR : SMB_LGRP_SUCCESS;
1937                 break;
1938 
1939         default:
1940                 rc = SMB_LGRP_DB_ERROR;
1941                 break;
1942         }
1943 
1944         sqlite_free_table(result);
1945         return (rc);
1946 }
1947 
1948 /*
1949  * smb_lgrp_db_setinfo
1950  *
1951  * Initializes the db_info table upon database creation.
1952  */
1953 static int
1954 smb_lgrp_db_setinfo(sqlite *db)
1955 {
1956         char *errmsg = NULL;
1957         char *sql;
1958         int rc;
1959 
1960         sql = sqlite_mprintf("INSERT INTO db_info (ver_major, ver_minor,"
1961             " magic) VALUES (%d, %d, %u)", SMB_LGRP_DB_VERMAJOR,
1962             SMB_LGRP_DB_VERMINOR, SMB_LGRP_DB_MAGIC);
1963 
1964         if (sql == NULL)
1965                 return (SMB_LGRP_NO_MEMORY);
1966 
1967         rc = sqlite_exec(db, sql, NULL, NULL, &errmsg);
1968         sqlite_freemem(sql);
1969         if (rc != SQLITE_OK) {
1970                 syslog(LOG_DEBUG, "failed to insert database information (%s)",
1971                     NULL_MSGCHK(errmsg));
1972                 sqlite_freemem(errmsg);
1973                 rc = SMB_LGRP_DBINIT_ERROR;
1974         } else {
1975                 rc = SMB_LGRP_SUCCESS;
1976         }
1977 
1978         return (rc);
1979 }
1980 
1981 /*
1982  * smb_lgrp_mlist_add
1983  *
1984  * Adds the given member (newm) to the input member list (in_members)
1985  * if it's not already there. The result list will be returned in
1986  * out_members. The caller must free the allocated memory for
1987  * out_members by calling free().
1988  *
1989  * in_members and out_members are hex strings.
1990  */
1991 static int
1992 smb_lgrp_mlist_add(smb_lgmlist_t *in_members, smb_lgmid_t *newm,
1993     smb_lgmlist_t *out_members)
1994 {
1995         char mid_hex[SMB_LGRP_MID_HEXSZ];
1996         char *in_list;
1997         char *out_list;
1998         int in_size;
1999         int out_size;
2000         int mid_hexsz;
2001         int i;
2002 
2003         out_members->m_cnt = 0;
2004         out_members->m_ids = NULL;
2005 
2006         bzero(mid_hex, sizeof (mid_hex));
2007         mid_hexsz = bintohex((const char *)newm, sizeof (smb_lgmid_t),
2008             mid_hex, sizeof (mid_hex));
2009 
2010         /*
2011          * Check to see if this is already a group member
2012          */
2013         in_list = in_members->m_ids;
2014         for (i = 0; i < in_members->m_cnt; i++) {
2015                 if (strncmp(in_list, mid_hex, mid_hexsz) == 0)
2016                         return (SMB_LGRP_MEMBER_IN_GROUP);
2017                 in_list += mid_hexsz;
2018         }
2019 
2020         in_size = (in_members->m_ids) ? strlen(in_members->m_ids) : 0;
2021         out_size = in_size + sizeof (mid_hex) + 1;
2022         out_list = malloc(out_size);
2023         if (out_list == NULL)
2024                 return (SMB_LGRP_NO_MEMORY);
2025 
2026         bzero(out_list, out_size);
2027         if (in_members->m_ids)
2028                 (void) strlcpy(out_list, in_members->m_ids, out_size);
2029         (void) strcat(out_list, mid_hex);
2030 
2031         out_members->m_cnt = in_members->m_cnt + 1;
2032         out_members->m_ids = out_list;
2033 
2034         return (SMB_LGRP_SUCCESS);
2035 }
2036 
2037 /*
2038  * smb_lgrp_mlist_del
2039  *
2040  * Removes the given member (msid) from the input member list
2041  * (in_members) if it's already there. The result list will b
2042  * returned in out_members. The caller must free the allocated
2043  * memory for out_members by calling free().
2044  *
2045  * in_members and out_members are hex strings.
2046  *
2047  * Note that we ignore the SID "type" when matching because
2048  * we always want to delete when the SID part matches.
2049  * The "type" part can be fiction.
2050  */
2051 static int
2052 smb_lgrp_mlist_del(smb_lgmlist_t *in_members, smb_lgmid_t *mid,
2053     smb_lgmlist_t *out_members)
2054 {
2055         char mid_hex[SMB_LGRP_MID_HEXSZ];
2056         char *in_list;
2057         char *out_list;
2058         int in_size;
2059         int out_size;
2060         int mid_hexsz;
2061         int out_cnt;
2062         int i;
2063 
2064         out_members->m_cnt = 0;
2065         out_members->m_ids = NULL;
2066 
2067         if ((in_members == NULL) || (in_members->m_cnt == 0))
2068                 return (SMB_LGRP_MEMBER_NOT_IN_GROUP);
2069 
2070         in_size = strlen(in_members->m_ids);
2071         out_size = in_size + sizeof (mid_hex) + 1;
2072         out_list = malloc(out_size);
2073         if (out_list == NULL)
2074                 return (SMB_LGRP_NO_MEMORY);
2075 
2076         *out_list = '\0';
2077 
2078         bzero(mid_hex, sizeof (mid_hex));
2079         mid_hexsz = bintohex((const char *)mid, sizeof (smb_lgmid_t),
2080             mid_hex, sizeof (mid_hex));
2081 
2082         in_list = in_members->m_ids;
2083         for (i = 0, out_cnt = 0; i < in_members->m_cnt; i++) {
2084                 /* Keep only those NOT matching in IDX,RID */
2085                 if (strncmp(in_list, mid_hex, SMB_LGRP_IDXRID_LEN)) {
2086                         (void) strncat(out_list, in_list, mid_hexsz);
2087                         out_cnt++;
2088                 }
2089                 in_list += mid_hexsz;
2090         }
2091 
2092         if (out_cnt == in_members->m_cnt) {
2093                 free(out_list);
2094                 return (SMB_LGRP_MEMBER_NOT_IN_GROUP);
2095         }
2096 
2097         out_members->m_cnt = out_cnt;
2098         out_members->m_ids = out_list;
2099         return (SMB_LGRP_SUCCESS);
2100 }
2101 
2102 /*
2103  * smb_lgrp_plist_add
2104  *
2105  * Adds the given privilege to the input list (in_privs)
2106  * if it's not already there. The result list is returned
2107  * in out_privs. The caller must free the allocated memory
2108  * for out_privs by calling free().
2109  */
2110 static int
2111 smb_lgrp_plist_add(smb_lgplist_t *in_privs, smb_lgpid_t priv_id,
2112     smb_lgplist_t *out_privs)
2113 {
2114         int i, size;
2115         smb_lgpid_t *pbuf;
2116 
2117         out_privs->p_cnt = 0;
2118         out_privs->p_ids = NULL;
2119 
2120         for (i = 0; i < in_privs->p_cnt; i++) {
2121                 if (in_privs->p_ids[i] == priv_id)
2122                         return (SMB_LGRP_PRIV_HELD);
2123         }
2124 
2125         size = (in_privs->p_cnt + 1) * sizeof (smb_lgpid_t) + 1;
2126         pbuf = malloc(size);
2127         if (pbuf == NULL)
2128                 return (SMB_LGRP_NO_MEMORY);
2129 
2130         bzero(pbuf, size);
2131         bcopy(in_privs->p_ids, pbuf, in_privs->p_cnt * sizeof (smb_lgpid_t));
2132         pbuf[in_privs->p_cnt] = priv_id;
2133 
2134         out_privs->p_cnt = in_privs->p_cnt + 1;
2135         out_privs->p_ids = pbuf;
2136 
2137         return (SMB_LGRP_SUCCESS);
2138 }
2139 
2140 /*
2141  * smb_lgrp_plist_del
2142  *
2143  * Removes the given privilege from the input list (in_privs)
2144  * if it's already there. The result list is returned
2145  * in out_privs. The caller must free the allocated memory
2146  * for out_privs by calling free().
2147  */
2148 static int
2149 smb_lgrp_plist_del(smb_lgplist_t *in_privs, smb_lgpid_t priv_id,
2150     smb_lgplist_t *out_privs)
2151 {
2152         int i, size;
2153 
2154         out_privs->p_cnt = 0;
2155         out_privs->p_ids = NULL;
2156 
2157         if ((in_privs == NULL) || (in_privs->p_cnt == 0))
2158                 return (SMB_LGRP_PRIV_NOT_HELD);
2159 
2160         size = (in_privs->p_cnt - 1) * sizeof (smb_lgpid_t) + 1;
2161         out_privs->p_ids = malloc(size);
2162         if (out_privs->p_ids == NULL)
2163                 return (SMB_LGRP_NO_MEMORY);
2164 
2165         bzero(out_privs->p_ids, size);
2166 
2167         for (i = 0; i < in_privs->p_cnt; i++) {
2168                 if (in_privs->p_ids[i] != priv_id)
2169                         out_privs->p_ids[out_privs->p_cnt++] =
2170                             in_privs->p_ids[i];
2171         }
2172 
2173         if (out_privs->p_cnt == in_privs->p_cnt) {
2174                 free(out_privs->p_ids);
2175                 out_privs->p_cnt = 0;
2176                 out_privs->p_ids = NULL;
2177                 return (SMB_LGRP_PRIV_NOT_HELD);
2178         }
2179 
2180         return (SMB_LGRP_SUCCESS);
2181 }
2182 
2183 /*
2184  * smb_lgrp_encode_privset
2185  *
2186  * Encodes given privilege set into a buffer to be stored in the group
2187  * database. Each entry of the encoded buffer contains the privilege ID
2188  * of an enable privilege. The returned buffer is null-terminated.
2189  */
2190 static void
2191 smb_lgrp_encode_privset(smb_group_t *grp, smb_lgplist_t *plist)
2192 {
2193         smb_privset_t *privs;
2194         uint32_t pcnt = plist->p_cnt;
2195         int i;
2196 
2197         bzero(plist->p_ids, sizeof (smb_lgpid_t) * plist->p_cnt);
2198         plist->p_cnt = 0;
2199 
2200         privs = grp->sg_privs;
2201         if ((privs == NULL) || (privs->priv_cnt == 0))
2202                 return;
2203 
2204         if (pcnt < privs->priv_cnt) {
2205                 assert(0);
2206         }
2207 
2208         for (i = 0; i < privs->priv_cnt; i++) {
2209                 if (privs->priv[i].attrs == SE_PRIVILEGE_ENABLED) {
2210                         plist->p_ids[plist->p_cnt++] =
2211                             (uint8_t)privs->priv[i].luid.lo_part;
2212                 }
2213         }
2214 }
2215 
2216 /*
2217  * smb_lgrp_decode_privset
2218  *
2219  * Decodes the privilege information read from group table
2220  * (nprivs, privs) into a binray format specified by the
2221  * privilege field of smb_group_t
2222  */
2223 static int
2224 smb_lgrp_decode_privset(smb_group_t *grp, char *nprivs, char *privs)
2225 {
2226         smb_lgplist_t plist;
2227         int i;
2228 
2229         plist.p_cnt = atoi(nprivs);
2230         if (strlen(privs) != plist.p_cnt)
2231                 return (SMB_LGRP_BAD_DATA);
2232 
2233         plist.p_ids = (smb_lgpid_t *)privs;
2234         grp->sg_privs = smb_privset_new();
2235         if (grp->sg_privs == NULL)
2236                 return (SMB_LGRP_NO_MEMORY);
2237 
2238         for (i = 0; i < plist.p_cnt; i++)
2239                 smb_privset_enable(grp->sg_privs, plist.p_ids[i]);
2240 
2241         return (SMB_LGRP_SUCCESS);
2242 }
2243 
2244 /*
2245  * smb_lgrp_decode_members
2246  *
2247  * Decodes the members information read from group table
2248  * (nmembers, members) into a binary format specified by the
2249  * member fields of smb_group_t
2250  */
2251 static int
2252 smb_lgrp_decode_members(smb_group_t *grp, char *nmembers, char *members,
2253     sqlite *db)
2254 {
2255         smb_lgmid_t *m_id;
2256         smb_lgmid_t *m_ids;
2257         smb_gsid_t *m_sid;
2258         smb_gsid_t *m_sids;
2259         int m_num;
2260         int mids_size;
2261         int i, rc;
2262 
2263         grp->sg_nmembers = 0;
2264         grp->sg_members = NULL;
2265 
2266         m_num = atoi(nmembers);
2267         mids_size = m_num * sizeof (smb_lgmid_t);
2268         if ((m_ids = malloc(mids_size)) == NULL)
2269                 return (SMB_LGRP_NO_MEMORY);
2270 
2271         m_sids = calloc(m_num, sizeof (smb_gsid_t));
2272         if (m_sids == NULL) {
2273                 free(m_ids);
2274                 return (SMB_LGRP_NO_MEMORY);
2275         }
2276 
2277         (void) hextobin(members, strlen(members), (char *)m_ids, mids_size);
2278 
2279         m_id = m_ids;
2280         m_sid = m_sids;
2281         for (i = 0; i < m_num; i++, m_id++, m_sid++) {
2282                 rc = smb_lgrp_getsid(m_id->m_idx, &m_id->m_rid, m_id->m_type,
2283                     db, &m_sid->gs_sid);
2284 
2285                 if (rc != SMB_LGRP_SUCCESS) {
2286                         free(m_ids);
2287                         for (m_sid = m_sids; m_sid->gs_sid != NULL; m_sid++)
2288                                 smb_sid_free(m_sid->gs_sid);
2289                         free(m_sids);
2290                         return (rc);
2291                 }
2292 
2293                 m_sid->gs_type = m_id->m_type;
2294         }
2295 
2296         free(m_ids);
2297 
2298         grp->sg_nmembers = m_num;
2299         grp->sg_members = m_sids;
2300         return (SMB_LGRP_SUCCESS);
2301 }
2302 
2303 /*
2304  * smb_lgrp_decode
2305  *
2306  * Fills out the fields of the given group (grp) based in the
2307  * string information read from the group table. infolvl determines
2308  * which fields are requested and need to be decoded.
2309  *
2310  * Allocated memories must be freed by calling smb_lgrp_free()
2311  * upon successful return.
2312  */
2313 static int
2314 smb_lgrp_decode(smb_group_t *grp, char **values, int infolvl, sqlite *db)
2315 {
2316         uint32_t sid_idx;
2317         int rc;
2318 
2319         if (infolvl == SMB_LGRP_INFO_NONE)
2320                 return (SMB_LGRP_SUCCESS);
2321 
2322         if (infolvl & SMB_LGRP_INFO_NAME) {
2323                 grp->sg_name = strdup(values[SMB_LGRP_GTBL_NAME]);
2324                 if (grp->sg_name == NULL)
2325                         return (SMB_LGRP_NO_MEMORY);
2326         }
2327 
2328         if (infolvl & SMB_LGRP_INFO_CMNT) {
2329                 grp->sg_cmnt = strdup(values[SMB_LGRP_GTBL_CMNT]);
2330                 if (grp->sg_cmnt == NULL) {
2331                         smb_lgrp_free(grp);
2332                         return (SMB_LGRP_NO_MEMORY);
2333                 }
2334         }
2335 
2336 
2337         if (infolvl & SMB_LGRP_INFO_SID) {
2338                 sid_idx = atoi(values[SMB_LGRP_GTBL_SIDIDX]);
2339                 grp->sg_rid = atoi(values[SMB_LGRP_GTBL_SIDRID]);
2340                 grp->sg_attr = atoi(values[SMB_LGRP_GTBL_SIDATR]);
2341                 grp->sg_id.gs_type = atoi(values[SMB_LGRP_GTBL_SIDTYP]);
2342                 rc = smb_lgrp_getsid(sid_idx, &grp->sg_rid, grp->sg_id.gs_type,
2343                     db, &grp->sg_id.gs_sid);
2344                 if (rc != SMB_LGRP_SUCCESS) {
2345                         smb_lgrp_free(grp);
2346                         return (rc);
2347                 }
2348                 grp->sg_domain = (sid_idx == SMB_LGRP_LOCAL_IDX)
2349                     ? SMB_DOMAIN_LOCAL : SMB_DOMAIN_BUILTIN;
2350         }
2351 
2352         if (infolvl & SMB_LGRP_INFO_PRIV) {
2353                 rc = smb_lgrp_decode_privset(grp, values[SMB_LGRP_GTBL_NPRIVS],
2354                     values[SMB_LGRP_GTBL_PRIVS]);
2355 
2356                 if (rc != SMB_LGRP_SUCCESS) {
2357                         smb_lgrp_free(grp);
2358                         return (rc);
2359                 }
2360         }
2361 
2362         if (infolvl & SMB_LGRP_INFO_MEMB) {
2363                 rc = smb_lgrp_decode_members(grp, values[SMB_LGRP_GTBL_NMEMBS],
2364                     values[SMB_LGRP_GTBL_MEMBS], db);
2365                 if (rc != SMB_LGRP_SUCCESS) {
2366                         smb_lgrp_free(grp);
2367                         return (rc);
2368                 }
2369         }
2370 
2371         return (SMB_LGRP_SUCCESS);
2372 }
2373 
2374 /*
2375  * smb_lgrp_normalize_name
2376  *
2377  * Trim whitespace, validate the group name and convert it to lowercase.
2378  */
2379 static boolean_t
2380 smb_lgrp_normalize_name(char *name)
2381 {
2382         (void) trim_whitespace(name);
2383 
2384         if (smb_name_validate_account(name) != ERROR_SUCCESS)
2385                 return (B_FALSE);
2386 
2387         (void) smb_strlwr(name);
2388         return (B_TRUE);
2389 }
2390 
2391 /*
2392  * smb_lgrp_set_default_privs
2393  *
2394  * set default privileges for Administrators and Backup Operators
2395  */
2396 static void
2397 smb_lgrp_set_default_privs(smb_group_t *grp)
2398 {
2399         if (smb_strcasecmp(grp->sg_name, "Administrators", 0) == 0) {
2400                 smb_privset_enable(grp->sg_privs, SE_TAKE_OWNERSHIP_LUID);
2401                 return;
2402         }
2403 
2404         if (smb_strcasecmp(grp->sg_name, "Backup Operators", 0) == 0) {
2405                 smb_privset_enable(grp->sg_privs, SE_BACKUP_LUID);
2406                 smb_privset_enable(grp->sg_privs, SE_RESTORE_LUID);
2407                 return;
2408         }
2409 }
2410 
2411 /*
2412  * smb_lgrp_getsid
2413  *
2414  * Returns a SID based on the provided information
2415  * If dom_idx is 0, it means 'rid' contains a UID/GID and the
2416  * returned SID will be a local SID. If dom_idx is not 0 then
2417  * the domain SID will be fetched from the domain table.
2418  */
2419 static int
2420 smb_lgrp_getsid(int dom_idx, uint32_t *rid, uint16_t sid_type,
2421     sqlite *db, smb_sid_t **sid)
2422 {
2423         smb_sid_t *dom_sid = NULL;
2424         smb_sid_t *res_sid = NULL;
2425         idmap_stat stat;
2426         int id_type;
2427         int rc;
2428 
2429         *sid = NULL;
2430         if (dom_idx == SMB_LGRP_LOCAL_IDX) {
2431                 id_type = (sid_type == SidTypeUser)
2432                     ? SMB_IDMAP_USER : SMB_IDMAP_GROUP;
2433                 stat = smb_idmap_getsid(*rid, id_type, &res_sid);
2434                 if (stat != IDMAP_SUCCESS) {
2435                         syslog(LOG_ERR, "smb_lgrp_getsid: "
2436                             "failed to get a SID for %s id=%u (%d)",
2437                             (id_type == SMB_IDMAP_USER) ? "user" : "group",
2438                             *rid, stat);
2439                         return (SMB_LGRP_NO_SID);
2440                 }
2441 
2442                 /*
2443                  * Make sure the returned SID is local
2444                  */
2445                 if (!smb_sid_indomain(smb_localgrp.lg_machine_sid, res_sid)) {
2446                         syslog(LOG_ERR, "smb_lgrp_getsid: "
2447                             "local %s (%u) is mapped to a non-local SID",
2448                             (id_type == SMB_IDMAP_USER) ? "user" : "group",
2449                             *rid);
2450                         smb_sid_free(res_sid);
2451                         return (SMB_LGRP_SID_NOTLOCAL);
2452                 }
2453 
2454                 (void) smb_sid_getrid(res_sid, rid);
2455                 *sid = res_sid;
2456                 return (SMB_LGRP_SUCCESS);
2457         }
2458 
2459         rc = smb_lgrp_dtbl_getsid(db, dom_idx, &dom_sid);
2460         if (rc != SMB_LGRP_SUCCESS) {
2461                 syslog(LOG_ERR, "smb_lgrp_getsid: %s", smb_lgrp_strerror(rc));
2462                 return (SMB_LGRP_DB_ERROR);
2463         }
2464 
2465         res_sid = smb_sid_splice(dom_sid, *rid);
2466         smb_sid_free(dom_sid);
2467         if (res_sid == NULL) {
2468                 syslog(LOG_ERR, "smb_lgrp_getsid: %s", smb_lgrp_strerror(rc));
2469                 return (SMB_LGRP_NO_MEMORY);
2470         }
2471 
2472         *sid = res_sid;
2473         return (SMB_LGRP_SUCCESS);
2474 }
2475 
2476 /*
2477  * smb_lgrp_getgid
2478  *
2479  * Converts given local RID to a local gid since for user
2480  * defined local groups, gid is stored in the table.
2481  */
2482 static int
2483 smb_lgrp_getgid(uint32_t rid, gid_t *gid)
2484 {
2485         smb_sid_t *sid;
2486         int idtype;
2487         int rc;
2488 
2489         if ((sid = smb_sid_splice(smb_localgrp.lg_machine_sid, rid)) == NULL)
2490                 return (SMB_LGRP_NO_MEMORY);
2491 
2492         idtype = SMB_IDMAP_GROUP;
2493         rc = smb_idmap_getid(sid, gid, &idtype);
2494         smb_sid_free(sid);
2495 
2496         return ((rc == IDMAP_SUCCESS) ? SMB_LGRP_SUCCESS : SMB_LGRP_NOT_FOUND);
2497 }
2498 
2499 /*
2500  * smb_lgrp_exists
2501  *
2502  * Returns B_TRUE if the local group with the given name exists.
2503  * Otherwise, returns B_FALSE.
2504  */
2505 static boolean_t
2506 smb_lgrp_exists(char *gname)
2507 {
2508         sqlite *db;
2509         boolean_t rc;
2510 
2511         if (!smb_lgrp_normalize_name(gname))
2512                 return (B_FALSE);
2513 
2514         db = smb_lgrp_db_open(SMB_LGRP_DB_ORD);
2515         if (db == NULL)
2516                 return (B_FALSE);
2517 
2518         rc = smb_lgrp_gtbl_exists(db, gname);
2519         smb_lgrp_db_close(db);
2520 
2521         return (rc);
2522 }
2523 
2524 /*
2525  * smb_lgrp_pgrp_valid_gname
2526  *
2527  * Validate posix group name string.
2528  */
2529 static int
2530 smb_lgrp_pgrp_valid_gname(char *group)
2531 {
2532         char *ptr = group;
2533         char c;
2534         int len = 0;
2535         int badchar = 0;
2536 
2537         if (!group || !*group)
2538                 return (SMB_LGRP_PGRP_INVALID);
2539 
2540         for (c = *ptr; c != NULL; ptr++, c = *ptr) {
2541                 len++;
2542                 if (!isprint(c) || (c == ':') || (c == '\n'))
2543                         return (SMB_LGRP_PGRP_INVALID);
2544 
2545                 if (!(islower(c) || isdigit(c)))
2546                         badchar++;
2547         }
2548 
2549         if ((len > SMB_LGRP_PGRP_MAXGLEN - 1) || (badchar != 0))
2550                 return (SMB_LGRP_PGRP_INVALID);
2551 
2552         if (getgrnam(group) != NULL)
2553                 return (SMB_LGRP_PGRP_NOTUNIQUE);
2554 
2555         return (SMB_LGRP_PGRP_UNIQUE);
2556 }
2557 
2558 /*
2559  * smb_lgrp_pgrp_add
2560  *
2561  * Create a posix group with the given name.
2562  * This group will be added to the /etc/group file.
2563  */
2564 static int
2565 smb_lgrp_pgrp_add(char *group)
2566 {
2567         FILE *etcgrp;
2568         FILE *etctmp;
2569         int o_mask;
2570         int newdone = 0;
2571         struct stat sb;
2572         char buf[SMB_LGRP_PGRP_GRPBUFSIZ];
2573         gid_t gid;
2574         int rc = 0;
2575 
2576         rc = smb_lgrp_pgrp_valid_gname(group);
2577         if ((rc == SMB_LGRP_PGRP_INVALID) || (rc == SMB_LGRP_PGRP_NOTUNIQUE))
2578                 return (-1);
2579 
2580         if ((findnextgid(SMB_LGRP_PGRP_DEFRID, MAXUID, &gid)) != 0)
2581                 return (-1);
2582 
2583         if ((etcgrp = fopen(SMB_LGRP_PGRP_GROUP, "r")) == NULL)
2584                 return (-1);
2585 
2586         if (fstat(fileno(etcgrp), &sb) < 0)
2587                 sb.st_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
2588 
2589         o_mask = umask(077);
2590         etctmp = fopen(SMB_LGRP_PGRP_GRPTMP, "w+");
2591         (void) umask(o_mask);
2592 
2593         if (etctmp == NULL) {
2594                 (void) fclose(etcgrp);
2595                 return (-1);
2596         }
2597 
2598         if (lockf(fileno(etctmp), F_LOCK, 0) != 0) {
2599                 (void) fclose(etcgrp);
2600                 (void) fclose(etctmp);
2601                 (void) unlink(SMB_LGRP_PGRP_GRPTMP);
2602                 return (-1);
2603         }
2604 
2605         if (fchmod(fileno(etctmp), sb.st_mode) != 0 ||
2606             fchown(fileno(etctmp), sb.st_uid, sb.st_gid) != 0) {
2607                 (void) lockf(fileno(etctmp), F_ULOCK, 0);
2608                 (void) fclose(etcgrp);
2609                 (void) fclose(etctmp);
2610                 (void) unlink(SMB_LGRP_PGRP_GRPTMP);
2611                 return (-1);
2612         }
2613 
2614         while (fgets(buf, SMB_LGRP_PGRP_GRPBUFSIZ, etcgrp) != NULL) {
2615                 /* Check for NameService reference */
2616                 if (!newdone && (buf[0] == '+' || buf[0] == '-')) {
2617                         (void) fprintf(etctmp, "%s::%u:\n", group, gid);
2618                         newdone = 1;
2619                 }
2620 
2621                 (void) fputs(buf, etctmp);
2622         }
2623         (void) fclose(etcgrp);
2624 
2625         if (!newdone)
2626                 (void) fprintf(etctmp, "%s::%u:\n", group, gid);
2627 
2628         if (rename(SMB_LGRP_PGRP_GRPTMP, SMB_LGRP_PGRP_GROUP) < 0) {
2629                 (void) lockf(fileno(etctmp), F_ULOCK, 0);
2630                 (void) fclose(etctmp);
2631                 (void) unlink(SMB_LGRP_PGRP_GRPTMP);
2632                 return (-1);
2633         }
2634 
2635         (void) lockf(fileno(etctmp), F_ULOCK, 0);
2636         (void) fclose(etctmp);
2637         return (0);
2638 }