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