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