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