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