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