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