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