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