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