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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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