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