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