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