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