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