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