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