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