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