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 char *tname; 1108 1109 if ((wka = smb_wka_lookup_name(builtin[i])) == NULL) 1110 continue; 1111 1112 if ((tname = strdup(wka->wka_name)) == NULL) 1113 return (SMB_LGRP_NO_MEMORY); 1114 if (!smb_lgrp_exists(tname)) { 1115 rc = smb_lgrp_add(tname, wka->wka_desc); 1116 if (rc != SMB_LGRP_SUCCESS) { 1117 syslog(LOG_DEBUG, "failed to add %s", 1118 tname); 1119 } 1120 } 1121 free(tname); 1122 } 1123 1124 return (SMB_LGRP_SUCCESS); 1125 } 1126 1127 /* 1128 * smb_lgrp_stop 1129 * 1130 * Unintialize the library global private variables. 1131 */ 1132 void 1133 smb_lgrp_stop(void) 1134 { 1135 (void) mutex_lock(&smb_localgrp.lg_mutex); 1136 if (!smb_localgrp.lg_online) 1137 return; 1138 1139 smb_localgrp.lg_online = B_FALSE; 1140 1141 while (smb_localgrp.lg_refcnt > 0) 1142 (void) cond_wait(&smb_localgrp.lg_cv, &smb_localgrp.lg_mutex); 1143 1144 free(smb_localgrp.lg_machine_sid); 1145 smb_localgrp.lg_machine_sid = NULL; 1146 (void) mutex_unlock(&smb_localgrp.lg_mutex); 1147 } 1148 1149 static boolean_t 1150 smb_lgrp_enter(void) 1151 { 1152 boolean_t status; 1153 1154 (void) mutex_lock(&smb_localgrp.lg_mutex); 1155 1156 status = smb_localgrp.lg_online; 1157 1158 if (smb_localgrp.lg_online) 1159 ++smb_localgrp.lg_refcnt; 1160 1161 (void) mutex_unlock(&smb_localgrp.lg_mutex); 1162 return (status); 1163 } 1164 1165 static void 1166 smb_lgrp_exit(void) 1167 { 1168 (void) mutex_lock(&smb_localgrp.lg_mutex); 1169 assert(smb_localgrp.lg_refcnt > 0); 1170 1171 if ((--smb_localgrp.lg_refcnt) == 0) 1172 (void) cond_signal(&smb_localgrp.lg_cv); 1173 1174 (void) mutex_unlock(&smb_localgrp.lg_mutex); 1175 } 1176 1177 /* 1178 * smb_lgrp_db_open 1179 * 1180 * Opens group database with the given mode. 1181 */ 1182 static sqlite * 1183 smb_lgrp_db_open(int mode) 1184 { 1185 sqlite *db; 1186 char *errmsg = NULL; 1187 1188 db = sqlite_open(SMB_LGRP_DB_NAME, mode, &errmsg); 1189 if (db == NULL) { 1190 syslog(LOG_ERR, "failed to open group database (%s)", 1191 NULL_MSGCHK(errmsg)); 1192 sqlite_freemem(errmsg); 1193 } 1194 1195 return (db); 1196 } 1197 1198 /* 1199 * smb_lgrp_db_close 1200 * 1201 * Closes the given database handle 1202 */ 1203 static void 1204 smb_lgrp_db_close(sqlite *db) 1205 { 1206 if (db) { 1207 sqlite_close(db); 1208 } 1209 } 1210 1211 /* 1212 * smb_lgrp_db_init 1213 * 1214 * Creates the group database based on the defined SQL statement. 1215 * It also initializes db_info and domain tables. 1216 */ 1217 static int 1218 smb_lgrp_db_init(void) 1219 { 1220 int dbrc = SQLITE_OK; 1221 int rc = SMB_LGRP_SUCCESS; 1222 sqlite *db = NULL; 1223 char *errmsg = NULL; 1224 1225 db = sqlite_open(SMB_LGRP_DB_NAME, 0600, &errmsg); 1226 if (db == NULL) { 1227 syslog(LOG_ERR, "failed to create group database (%s)", 1228 NULL_MSGCHK(errmsg)); 1229 sqlite_freemem(errmsg); 1230 return (SMB_LGRP_DBOPEN_FAILED); 1231 } 1232 1233 sqlite_busy_timeout(db, SMB_LGRP_DB_TIMEOUT); 1234 dbrc = sqlite_exec(db, "BEGIN TRANSACTION;", NULL, NULL, &errmsg); 1235 if (dbrc != SQLITE_OK) { 1236 syslog(LOG_DEBUG, "failed to begin database transaction (%s)", 1237 NULL_MSGCHK(errmsg)); 1238 sqlite_freemem(errmsg); 1239 sqlite_close(db); 1240 return (SMB_LGRP_DBEXEC_FAILED); 1241 } 1242 1243 switch (sqlite_exec(db, SMB_LGRP_DB_SQL, NULL, NULL, &errmsg)) { 1244 case SQLITE_ERROR: 1245 /* 1246 * This is the normal situation: CREATE probably failed because 1247 * tables already exist. It may indicate an error in SQL as well 1248 * but we cannot tell. 1249 */ 1250 sqlite_freemem(errmsg); 1251 dbrc = sqlite_exec(db, "ROLLBACK TRANSACTION", NULL, NULL, 1252 &errmsg); 1253 rc = SMB_LGRP_SUCCESS; 1254 break; 1255 1256 case SQLITE_OK: 1257 dbrc = sqlite_exec(db, "COMMIT TRANSACTION", NULL, NULL, 1258 &errmsg); 1259 if (dbrc != SQLITE_OK) 1260 break; 1261 rc = smb_lgrp_dtbl_insert(db, NT_BUILTIN_DOMAIN_SIDSTR, 1262 NULL); 1263 if (rc == SMB_LGRP_SUCCESS) 1264 rc = smb_lgrp_db_setinfo(db); 1265 if (rc != SMB_LGRP_SUCCESS) { 1266 (void) sqlite_close(db); 1267 (void) unlink(SMB_LGRP_DB_NAME); 1268 return (rc); 1269 } 1270 break; 1271 1272 default: 1273 syslog(LOG_ERR, 1274 "failed to initialize group database (%s)", errmsg); 1275 sqlite_freemem(errmsg); 1276 dbrc = sqlite_exec(db, "ROLLBACK TRANSACTION", NULL, NULL, 1277 &errmsg); 1278 rc = SMB_LGRP_DBINIT_FAILED; 1279 break; 1280 } 1281 1282 if (dbrc != SQLITE_OK) { 1283 /* this is bad - database may be left in a locked state */ 1284 syslog(LOG_DEBUG, "failed to close a transaction (%s)", 1285 NULL_MSGCHK(errmsg)); 1286 sqlite_freemem(errmsg); 1287 } 1288 1289 (void) sqlite_close(db); 1290 return (rc); 1291 } 1292 1293 /* 1294 * smb_lgrp_gtbl_lookup 1295 * 1296 * This is a flexible lookup function for the group database. 1297 * The key type can be specified by the 'key' arg and the actual key 1298 * values can be passed after the 'infolvl' arg. 'infolvl' arg specifies 1299 * what information items for the specified group is needed. 1300 * 1301 * Note that the function assumes the given key is unique and only 1302 * specifies one or 0 group. The keys that are supported now are 1303 * the group name and the group SID 1304 * 1305 * Note that this function doesn't allocate the group 1306 * structure itself only the fields, so the given grp 1307 * pointer has to point to a group structure. 1308 * Caller must free the allocated memories for the fields 1309 * by calling smb_lgrp_free(). 1310 */ 1311 static int 1312 smb_lgrp_gtbl_lookup(sqlite *db, int key, smb_group_t *grp, int infolvl, ...) 1313 { 1314 char *errmsg = NULL; 1315 char *sql; 1316 char **result; 1317 int nrow, ncol; 1318 int rc, dom_idx; 1319 smb_group_t grpkey; 1320 va_list ap; 1321 1322 if (db == NULL) 1323 return (SMB_LGRP_DBOPEN_FAILED); 1324 1325 bzero(grp, sizeof (smb_group_t)); 1326 va_start(ap, infolvl); 1327 1328 switch (key) { 1329 case SMB_LGRP_GTBL_NAME: 1330 grpkey.sg_name = va_arg(ap, char *); 1331 sql = sqlite_mprintf("SELECT * FROM groups WHERE name = '%s'", 1332 grpkey.sg_name); 1333 break; 1334 1335 case SMB_LGRP_GTBL_SIDRID: 1336 grpkey.sg_rid = va_arg(ap, uint32_t); 1337 grpkey.sg_domain = va_arg(ap, smb_domain_type_t); 1338 if (grpkey.sg_domain == SMB_DOMAIN_LOCAL) { 1339 dom_idx = SMB_LGRP_LOCAL_IDX; 1340 /* need to map the given rid to a gid */ 1341 rc = smb_lgrp_getgid(grpkey.sg_rid, 1342 (gid_t *)&grpkey.sg_rid); 1343 if (rc != SMB_LGRP_SUCCESS) { 1344 va_end(ap); 1345 return (rc); 1346 } 1347 } else { 1348 dom_idx = SMB_LGRP_BUILTIN_IDX; 1349 } 1350 1351 sql = sqlite_mprintf("SELECT * FROM groups " 1352 "WHERE (sid_idx = %d) AND (sid_rid = %u)", 1353 dom_idx, grpkey.sg_rid); 1354 break; 1355 1356 default: 1357 va_end(ap); 1358 return (SMB_LGRP_INVALID_ARG); 1359 } 1360 1361 va_end(ap); 1362 if (sql == NULL) 1363 return (SMB_LGRP_NO_MEMORY); 1364 1365 rc = sqlite_get_table(db, sql, &result, &nrow, &ncol, &errmsg); 1366 sqlite_freemem(sql); 1367 1368 if (rc != SQLITE_OK) { 1369 syslog(LOG_DEBUG, "failed to lookup (%s)", NULL_MSGCHK(errmsg)); 1370 sqlite_freemem(errmsg); 1371 return (SMB_LGRP_LOOKUP_FAILED); 1372 } 1373 1374 if (nrow == 0) { 1375 /* group not found */ 1376 sqlite_free_table(result); 1377 return (SMB_LGRP_NOT_FOUND); 1378 } 1379 1380 if (nrow != 1 || ncol != SMB_LGRP_GTBL_NCOL) { 1381 sqlite_free_table(result); 1382 return (SMB_LGRP_DB_ERROR); 1383 } 1384 1385 rc = smb_lgrp_decode(grp, &result[SMB_LGRP_GTBL_NCOL], infolvl, db); 1386 sqlite_free_table(result); 1387 return (rc); 1388 } 1389 1390 /* 1391 * smb_lgrp_gtbl_exists 1392 * 1393 * Checks to see if the given group exists or not. 1394 */ 1395 static boolean_t 1396 smb_lgrp_gtbl_exists(sqlite *db, char *gname) 1397 { 1398 char *errmsg = NULL; 1399 char *sql; 1400 char **result; 1401 int nrow, ncol; 1402 int rc; 1403 1404 if (db == NULL) 1405 return (NULL); 1406 1407 sql = sqlite_mprintf("SELECT name FROM groups WHERE name = '%s'", 1408 gname); 1409 rc = sqlite_get_table(db, sql, &result, &nrow, &ncol, &errmsg); 1410 sqlite_freemem(sql); 1411 1412 if (rc != SQLITE_OK) { 1413 syslog(LOG_DEBUG, "failed to lookup %s (%s)", 1414 gname, NULL_MSGCHK(errmsg)); 1415 sqlite_freemem(errmsg); 1416 return (B_FALSE); 1417 } 1418 1419 sqlite_free_table(result); 1420 return (nrow != 0); 1421 } 1422 1423 /* 1424 * smb_lgrp_gtbl_count 1425 * 1426 * Counts the number of groups in the domain specified by 1427 * 'dom_idx' 1428 */ 1429 static int 1430 smb_lgrp_gtbl_count(sqlite *db, int dom_idx, int *count) 1431 { 1432 char *errmsg = NULL; 1433 char *sql; 1434 char **result; 1435 int nrow, ncol; 1436 int rc; 1437 1438 *count = 0; 1439 if (db == NULL) 1440 return (SMB_LGRP_DBOPEN_FAILED); 1441 1442 sql = sqlite_mprintf("SELECT sid_idx FROM groups WHERE sid_idx = %d", 1443 dom_idx); 1444 rc = sqlite_get_table(db, sql, &result, &nrow, &ncol, &errmsg); 1445 sqlite_freemem(sql); 1446 1447 if (rc != SQLITE_OK) { 1448 syslog(LOG_DEBUG, "failed to count (%s)", NULL_MSGCHK(errmsg)); 1449 sqlite_freemem(errmsg); 1450 return (SMB_LGRP_LOOKUP_FAILED); 1451 } 1452 1453 sqlite_free_table(result); 1454 if (ncol > 1) 1455 return (SMB_LGRP_DB_ERROR); 1456 1457 *count = nrow; 1458 return (SMB_LGRP_SUCCESS); 1459 } 1460 1461 /* 1462 * smb_lgrp_gtbl_insert 1463 * 1464 * Insert a record for the given group in the group database. 1465 * 1466 * NOTE: this function assumes that this group has no members 1467 * at this time. 1468 */ 1469 static int 1470 smb_lgrp_gtbl_insert(sqlite *db, smb_group_t *grp) 1471 { 1472 smb_lgpid_t privs[SE_MAX_LUID + 1]; 1473 smb_lgplist_t plist; 1474 char *errmsg = NULL; 1475 char *sql; 1476 int dom_idx; 1477 int rc; 1478 1479 if (db == NULL) 1480 return (SMB_LGRP_DBOPEN_FAILED); 1481 1482 dom_idx = (grp->sg_domain == SMB_DOMAIN_LOCAL) 1483 ? SMB_LGRP_LOCAL_IDX : SMB_LGRP_BUILTIN_IDX; 1484 1485 plist.p_cnt = SE_MAX_LUID; 1486 plist.p_ids = privs; 1487 smb_lgrp_encode_privset(grp, &plist); 1488 1489 sql = sqlite_mprintf("INSERT INTO groups " 1490 "(name, sid_idx, sid_rid, sid_type, sid_attrs, comment, " 1491 "n_privs, privs, n_members, members) " 1492 "VALUES('%s', %u, %u, %u, %u, '%q', %u, '%q', %u, '%q')", 1493 grp->sg_name, dom_idx, grp->sg_rid, grp->sg_id.gs_type, 1494 grp->sg_attr, (grp->sg_cmnt) ? grp->sg_cmnt : "", 1495 plist.p_cnt, (char *)plist.p_ids, 0, ""); 1496 1497 if (sql == NULL) 1498 return (SMB_LGRP_NO_MEMORY); 1499 1500 rc = sqlite_exec(db, sql, NULL, NULL, &errmsg); 1501 sqlite_freemem(sql); 1502 1503 if (rc != SQLITE_OK) { 1504 syslog(LOG_DEBUG, "failed to insert %s (%s)", 1505 grp->sg_name, NULL_MSGCHK(errmsg)); 1506 sqlite_freemem(errmsg); 1507 rc = SMB_LGRP_INSERT_FAILED; 1508 } else { 1509 rc = SMB_LGRP_SUCCESS; 1510 } 1511 1512 return (rc); 1513 } 1514 1515 /* 1516 * smb_lgrp_gtbl_delete 1517 * 1518 * Removes the specified group from the database 1519 */ 1520 static int 1521 smb_lgrp_gtbl_delete(sqlite *db, char *gname) 1522 { 1523 char *errmsg = NULL; 1524 char *sql; 1525 int rc; 1526 1527 if (db == NULL) 1528 return (SMB_LGRP_DBOPEN_FAILED); 1529 1530 sql = sqlite_mprintf("DELETE FROM groups WHERE name = '%s'", gname); 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 delete %s (%s)", 1539 gname, NULL_MSGCHK(errmsg)); 1540 sqlite_freemem(errmsg); 1541 rc = SMB_LGRP_DELETE_FAILED; 1542 } else { 1543 rc = SMB_LGRP_SUCCESS; 1544 } 1545 1546 return (rc); 1547 } 1548 1549 /* 1550 * smb_lgrp_gtbl_update 1551 * 1552 * Updates the specified group information, the supported items 1553 * are group name and comment 1554 */ 1555 static int 1556 smb_lgrp_gtbl_update(sqlite *db, char *gname, smb_group_t *grp, int col_id) 1557 { 1558 char *errmsg = NULL; 1559 char *sql; 1560 int rc; 1561 1562 if (db == NULL) 1563 return (SMB_LGRP_DBOPEN_FAILED); 1564 1565 /* UPDATE doesn't fail if gname doesn't exist */ 1566 if (!smb_lgrp_gtbl_exists(db, gname)) 1567 return (SMB_LGRP_NOT_FOUND); 1568 1569 switch (col_id) { 1570 case SMB_LGRP_GTBL_NAME: 1571 if (smb_lgrp_gtbl_exists(db, grp->sg_name)) 1572 return (SMB_LGRP_EXISTS); 1573 sql = sqlite_mprintf("UPDATE groups SET name = '%s' " 1574 "WHERE name = '%s'", grp->sg_name, gname); 1575 break; 1576 1577 case SMB_LGRP_GTBL_CMNT: 1578 sql = sqlite_mprintf("UPDATE groups SET comment = '%q' " 1579 "WHERE name = '%s'", grp->sg_cmnt, gname); 1580 break; 1581 1582 default: 1583 return (SMB_LGRP_INVALID_ARG); 1584 } 1585 1586 if (sql == NULL) 1587 return (SMB_LGRP_NO_MEMORY); 1588 1589 rc = sqlite_exec(db, sql, NULL, NULL, &errmsg); 1590 sqlite_freemem(sql); 1591 1592 if (rc != SQLITE_OK) { 1593 syslog(LOG_DEBUG, "failed to update %s (%s)", 1594 gname, NULL_MSGCHK(errmsg)); 1595 sqlite_freemem(errmsg); 1596 rc = SMB_LGRP_UPDATE_FAILED; 1597 } else { 1598 rc = SMB_LGRP_SUCCESS; 1599 } 1600 1601 return (rc); 1602 } 1603 1604 /* 1605 * smb_lgrp_gtbl_update_mlist 1606 * 1607 * Adds/removes the specified member from the member list of the 1608 * given group 1609 */ 1610 static int 1611 smb_lgrp_gtbl_update_mlist(sqlite *db, char *gname, smb_gsid_t *member, 1612 int flags) 1613 { 1614 smb_lgmlist_t new_members; 1615 smb_lgmlist_t members; 1616 smb_lgmid_t mid; 1617 char *errmsg = NULL; 1618 char *sql; 1619 char **result; 1620 int nrow, ncol; 1621 int rc; 1622 1623 if (db == NULL) 1624 return (SMB_LGRP_DBOPEN_FAILED); 1625 1626 sql = sqlite_mprintf("SELECT n_members, members FROM groups " 1627 "WHERE name = '%s'", gname); 1628 1629 if (sql == NULL) 1630 return (SMB_LGRP_NO_MEMORY); 1631 1632 rc = sqlite_get_table(db, sql, &result, &nrow, &ncol, &errmsg); 1633 sqlite_freemem(sql); 1634 1635 if (rc != SQLITE_OK) { 1636 syslog(LOG_DEBUG, "failed to lookup %s (%s)", 1637 gname, NULL_MSGCHK(errmsg)); 1638 sqlite_freemem(errmsg); 1639 return (SMB_LGRP_LOOKUP_FAILED); 1640 } 1641 1642 if (nrow == 0) { 1643 /* group not found */ 1644 sqlite_free_table(result); 1645 return (SMB_LGRP_NOT_FOUND); 1646 } 1647 1648 if (nrow != 1 || ncol != 2) { 1649 sqlite_free_table(result); 1650 return (SMB_LGRP_DB_ERROR); 1651 } 1652 1653 bzero(&mid, sizeof (mid)); 1654 mid.m_type = member->gs_type; 1655 rc = smb_lgrp_dtbl_getidx(db, member->gs_sid, mid.m_type, 1656 &mid.m_idx, &mid.m_rid); 1657 if (rc != SMB_LGRP_SUCCESS) { 1658 sqlite_free_table(result); 1659 return (rc); 1660 } 1661 1662 members.m_cnt = atoi(result[2]); 1663 members.m_ids = result[3]; 1664 1665 switch (flags) { 1666 case SMB_LGRP_DB_ADDMEMBER: 1667 rc = smb_lgrp_mlist_add(&members, &mid, &new_members); 1668 break; 1669 case SMB_LGRP_DB_DELMEMBER: 1670 rc = smb_lgrp_mlist_del(&members, &mid, &new_members); 1671 break; 1672 default: 1673 rc = SMB_LGRP_INVALID_ARG; 1674 } 1675 1676 sqlite_free_table(result); 1677 if (rc != SMB_LGRP_SUCCESS) 1678 return (rc); 1679 1680 sql = sqlite_mprintf("UPDATE groups SET n_members = %u, members = '%s'" 1681 " WHERE name = '%s'", new_members.m_cnt, new_members.m_ids, gname); 1682 1683 free(new_members.m_ids); 1684 1685 if (sql == NULL) 1686 return (SMB_LGRP_NO_MEMORY); 1687 1688 rc = sqlite_exec(db, sql, NULL, NULL, &errmsg); 1689 sqlite_freemem(sql); 1690 1691 if (rc != SQLITE_OK) { 1692 syslog(LOG_DEBUG, "failed to update %s (%s)", gname, 1693 NULL_MSGCHK(errmsg)); 1694 sqlite_freemem(errmsg); 1695 rc = SMB_LGRP_UPDATE_FAILED; 1696 } else { 1697 rc = SMB_LGRP_SUCCESS; 1698 } 1699 1700 return (rc); 1701 } 1702 1703 /* 1704 * smb_lgrp_gtbl_update_plist 1705 * 1706 * Adds/removes the specified privilege from the privilege list of the 1707 * given group 1708 */ 1709 static int 1710 smb_lgrp_gtbl_update_plist(sqlite *db, char *gname, uint8_t priv_id, 1711 boolean_t enable) 1712 { 1713 char *sql; 1714 char *errmsg = NULL; 1715 char **result; 1716 int nrow, ncol; 1717 int rc; 1718 smb_lgplist_t privs; 1719 smb_lgplist_t new_privs; 1720 1721 if (db == NULL) 1722 return (SMB_LGRP_DBOPEN_FAILED); 1723 1724 sql = sqlite_mprintf("SELECT n_privs, privs FROM groups " 1725 "WHERE name = '%s'", gname); 1726 1727 if (sql == NULL) 1728 return (SMB_LGRP_NO_MEMORY); 1729 1730 rc = sqlite_get_table(db, sql, &result, &nrow, &ncol, &errmsg); 1731 sqlite_freemem(sql); 1732 1733 if (rc != SQLITE_OK) { 1734 syslog(LOG_DEBUG, "failed to lookup %s (%s)", 1735 gname, NULL_MSGCHK(errmsg)); 1736 sqlite_freemem(errmsg); 1737 return (SMB_LGRP_LOOKUP_FAILED); 1738 } 1739 1740 if (nrow == 0) { 1741 /* group not found */ 1742 sqlite_free_table(result); 1743 return (SMB_LGRP_NOT_FOUND); 1744 } 1745 1746 if (nrow != 1 || ncol != 2) { 1747 sqlite_free_table(result); 1748 return (SMB_LGRP_DB_ERROR); 1749 } 1750 1751 privs.p_cnt = atoi(result[2]); 1752 privs.p_ids = (smb_lgpid_t *)result[3]; 1753 1754 if (enable) 1755 rc = smb_lgrp_plist_add(&privs, priv_id, &new_privs); 1756 else 1757 rc = smb_lgrp_plist_del(&privs, priv_id, &new_privs); 1758 1759 sqlite_free_table(result); 1760 if (rc != SMB_LGRP_SUCCESS) 1761 return (rc); 1762 1763 sql = sqlite_mprintf("UPDATE groups SET n_privs = %u, privs = '%q'" 1764 " WHERE name = '%s'", new_privs.p_cnt, (char *)new_privs.p_ids, 1765 gname); 1766 1767 free(new_privs.p_ids); 1768 1769 if (sql == NULL) 1770 return (SMB_LGRP_NO_MEMORY); 1771 1772 rc = sqlite_exec(db, sql, NULL, NULL, &errmsg); 1773 sqlite_freemem(sql); 1774 1775 if (rc != SQLITE_OK) { 1776 syslog(LOG_DEBUG, "failed to update %s (%s)", 1777 gname, NULL_MSGCHK(errmsg)); 1778 sqlite_freemem(errmsg); 1779 rc = SMB_LGRP_UPDATE_FAILED; 1780 } else { 1781 rc = SMB_LGRP_SUCCESS; 1782 } 1783 1784 return (rc); 1785 } 1786 1787 /* 1788 * smb_lgrp_dtbl_insert 1789 * 1790 * Inserts the specified domain SID in the dmain table. 1791 * Upon successful insert the index will be returned in 1792 * 'dom_idx' arg. 1793 */ 1794 static int 1795 smb_lgrp_dtbl_insert(sqlite *db, char *dom_sid, uint32_t *dom_idx) 1796 { 1797 char *errmsg = NULL; 1798 char *sql; 1799 int rc; 1800 1801 sql = sqlite_mprintf("INSERT INTO domains (dom_sid, dom_cnt)" 1802 " VALUES('%s', 1);", dom_sid); 1803 if (sql == NULL) 1804 return (SMB_LGRP_NO_MEMORY); 1805 1806 rc = sqlite_exec(db, sql, NULL, NULL, &errmsg); 1807 sqlite_freemem(sql); 1808 1809 if (rc != SQLITE_OK) { 1810 syslog(LOG_DEBUG, "failed to insert domain SID (%s)", 1811 NULL_MSGCHK(errmsg)); 1812 sqlite_freemem(errmsg); 1813 return (SMB_LGRP_DOMINS_FAILED); 1814 } 1815 1816 if (dom_idx) 1817 *dom_idx = sqlite_last_insert_rowid(db); 1818 return (SMB_LGRP_SUCCESS); 1819 } 1820 1821 /* 1822 * smb_lgrp_dtbl_getidx 1823 * 1824 * Searches the domain table for the domain SID of the 1825 * given member SID. If it finds the domain SID it'll 1826 * return the index and the RID, otherwise it'll insert 1827 * it in the domain table as a new SID. 1828 */ 1829 static int 1830 smb_lgrp_dtbl_getidx(sqlite *db, smb_sid_t *sid, uint16_t sid_type, 1831 uint32_t *dom_idx, uint32_t *rid) 1832 { 1833 char sidstr[SMB_SID_STRSZ]; 1834 smb_sid_t *dom_sid; 1835 char **result; 1836 int nrow, ncol; 1837 char *errmsg = NULL; 1838 char *sql; 1839 int rc; 1840 1841 if (smb_sid_indomain(smb_localgrp.lg_machine_sid, sid)) { 1842 /* This is a local SID */ 1843 int id_type = (sid_type == SidTypeUser) 1844 ? SMB_IDMAP_USER : SMB_IDMAP_GROUP; 1845 *dom_idx = SMB_LGRP_LOCAL_IDX; 1846 if (smb_idmap_getid(sid, rid, &id_type) != IDMAP_SUCCESS) 1847 return (SMB_LGRP_INTERNAL_ERROR); 1848 1849 return (SMB_LGRP_SUCCESS); 1850 } 1851 1852 if ((dom_sid = smb_sid_split(sid, rid)) == NULL) 1853 return (SMB_LGRP_NO_MEMORY); 1854 1855 smb_sid_tostr(dom_sid, sidstr); 1856 free(dom_sid); 1857 1858 sql = sqlite_mprintf("SELECT dom_idx FROM domains WHERE dom_sid = '%s'", 1859 sidstr); 1860 if (sql == NULL) 1861 return (SMB_LGRP_NO_MEMORY); 1862 1863 rc = sqlite_get_table(db, sql, &result, &nrow, &ncol, &errmsg); 1864 sqlite_freemem(sql); 1865 1866 if (rc != SQLITE_OK) { 1867 syslog(LOG_DEBUG, "failed to lookup domain SID (%s)", 1868 NULL_MSGCHK(errmsg)); 1869 sqlite_freemem(errmsg); 1870 return (SMB_LGRP_DOMLKP_FAILED); 1871 } 1872 1873 switch (nrow) { 1874 case 0: 1875 /* new domain SID; insert it into the domains table */ 1876 sqlite_free_table(result); 1877 return (smb_lgrp_dtbl_insert(db, sidstr, dom_idx)); 1878 1879 case 1: 1880 *dom_idx = atoi(result[1]); 1881 sqlite_free_table(result); 1882 return (SMB_LGRP_SUCCESS); 1883 } 1884 1885 sqlite_free_table(result); 1886 return (SMB_LGRP_DB_ERROR); 1887 } 1888 1889 /* 1890 * smb_lgrp_dtbl_getsid 1891 * 1892 * Searchs the domain table for the given domain index. 1893 * Converts the found domain SID to binary format and 1894 * returns it in the 'sid' arg. 1895 * 1896 * Caller must free the returned SID by calling free(). 1897 */ 1898 static int 1899 smb_lgrp_dtbl_getsid(sqlite *db, uint32_t dom_idx, smb_sid_t **sid) 1900 { 1901 char **result; 1902 int nrow, ncol; 1903 char *errmsg = NULL; 1904 char *sql; 1905 int rc; 1906 1907 sql = sqlite_mprintf("SELECT dom_sid FROM domains WHERE dom_idx = %u", 1908 dom_idx); 1909 if (sql == NULL) 1910 return (SMB_LGRP_NO_MEMORY); 1911 1912 rc = sqlite_get_table(db, sql, &result, &nrow, &ncol, &errmsg); 1913 sqlite_freemem(sql); 1914 1915 if (rc != SQLITE_OK) { 1916 syslog(LOG_DEBUG, "failed to lookup domain index (%s)", 1917 NULL_MSGCHK(errmsg)); 1918 sqlite_freemem(errmsg); 1919 return (SMB_LGRP_DOMLKP_FAILED); 1920 } 1921 1922 switch (nrow) { 1923 case 0: 1924 rc = SMB_LGRP_NO_SUCH_DOMAIN; 1925 break; 1926 1927 case 1: 1928 *sid = smb_sid_fromstr(result[1]); 1929 rc = (*sid == NULL) 1930 ? SMB_LGRP_INTERNAL_ERROR : SMB_LGRP_SUCCESS; 1931 break; 1932 1933 default: 1934 rc = SMB_LGRP_DB_ERROR; 1935 break; 1936 } 1937 1938 sqlite_free_table(result); 1939 return (rc); 1940 } 1941 1942 /* 1943 * smb_lgrp_db_setinfo 1944 * 1945 * Initializes the db_info table upon database creation. 1946 */ 1947 static int 1948 smb_lgrp_db_setinfo(sqlite *db) 1949 { 1950 char *errmsg = NULL; 1951 char *sql; 1952 int rc; 1953 1954 sql = sqlite_mprintf("INSERT INTO db_info (ver_major, ver_minor," 1955 " magic) VALUES (%d, %d, %u)", SMB_LGRP_DB_VERMAJOR, 1956 SMB_LGRP_DB_VERMINOR, SMB_LGRP_DB_MAGIC); 1957 1958 if (sql == NULL) 1959 return (SMB_LGRP_NO_MEMORY); 1960 1961 rc = sqlite_exec(db, sql, NULL, NULL, &errmsg); 1962 sqlite_freemem(sql); 1963 if (rc != SQLITE_OK) { 1964 syslog(LOG_DEBUG, "failed to insert database information (%s)", 1965 NULL_MSGCHK(errmsg)); 1966 sqlite_freemem(errmsg); 1967 rc = SMB_LGRP_DBINIT_ERROR; 1968 } else { 1969 rc = SMB_LGRP_SUCCESS; 1970 } 1971 1972 return (rc); 1973 } 1974 1975 /* 1976 * smb_lgrp_mlist_add 1977 * 1978 * Adds the given member (newm) to the input member list (in_members) 1979 * if it's not already there. The result list will be returned in 1980 * out_members. The caller must free the allocated memory for 1981 * out_members by calling free(). 1982 * 1983 * in_members and out_members are hex strings. 1984 */ 1985 static int 1986 smb_lgrp_mlist_add(smb_lgmlist_t *in_members, smb_lgmid_t *newm, 1987 smb_lgmlist_t *out_members) 1988 { 1989 char mid_hex[SMB_LGRP_MID_HEXSZ]; 1990 char *in_list; 1991 char *out_list; 1992 int in_size; 1993 int out_size; 1994 int mid_hexsz; 1995 int i; 1996 1997 out_members->m_cnt = 0; 1998 out_members->m_ids = NULL; 1999 2000 bzero(mid_hex, sizeof (mid_hex)); 2001 mid_hexsz = bintohex((const char *)newm, sizeof (smb_lgmid_t), 2002 mid_hex, sizeof (mid_hex)); 2003 2004 /* 2005 * Check to see if this is already a group member 2006 */ 2007 in_list = in_members->m_ids; 2008 for (i = 0; i < in_members->m_cnt; i++) { 2009 if (strncmp(in_list, mid_hex, mid_hexsz) == 0) 2010 return (SMB_LGRP_MEMBER_IN_GROUP); 2011 in_list += mid_hexsz; 2012 } 2013 2014 in_size = (in_members->m_ids) ? strlen(in_members->m_ids) : 0; 2015 out_size = in_size + sizeof (mid_hex) + 1; 2016 out_list = malloc(out_size); 2017 if (out_list == NULL) 2018 return (SMB_LGRP_NO_MEMORY); 2019 2020 bzero(out_list, out_size); 2021 if (in_members->m_ids) 2022 (void) strlcpy(out_list, in_members->m_ids, out_size); 2023 (void) strcat(out_list, mid_hex); 2024 2025 out_members->m_cnt = in_members->m_cnt + 1; 2026 out_members->m_ids = out_list; 2027 2028 return (SMB_LGRP_SUCCESS); 2029 } 2030 2031 /* 2032 * smb_lgrp_mlist_del 2033 * 2034 * Removes the given member (msid) from the input member list 2035 * (in_members) if it's already there. The result list will b 2036 * returned in out_members. The caller must free the allocated 2037 * memory for out_members by calling free(). 2038 * 2039 * in_members and out_members are hex strings. 2040 */ 2041 static int 2042 smb_lgrp_mlist_del(smb_lgmlist_t *in_members, smb_lgmid_t *mid, 2043 smb_lgmlist_t *out_members) 2044 { 2045 char mid_hex[SMB_LGRP_MID_HEXSZ]; 2046 char *in_list; 2047 char *out_list; 2048 int in_size; 2049 int out_size; 2050 int mid_hexsz; 2051 int out_cnt; 2052 int i; 2053 2054 out_members->m_cnt = 0; 2055 out_members->m_ids = NULL; 2056 2057 if ((in_members == NULL) || (in_members->m_cnt == 0)) 2058 return (SMB_LGRP_MEMBER_NOT_IN_GROUP); 2059 2060 in_size = strlen(in_members->m_ids); 2061 out_size = in_size + sizeof (mid_hex) + 1; 2062 out_list = malloc(out_size); 2063 if (out_list == NULL) 2064 return (SMB_LGRP_NO_MEMORY); 2065 2066 *out_list = '\0'; 2067 2068 bzero(mid_hex, sizeof (mid_hex)); 2069 mid_hexsz = bintohex((const char *)mid, sizeof (smb_lgmid_t), 2070 mid_hex, sizeof (mid_hex)); 2071 2072 in_list = in_members->m_ids; 2073 for (i = 0, out_cnt = 0; i < in_members->m_cnt; i++) { 2074 if (strncmp(in_list, mid_hex, mid_hexsz)) { 2075 (void) strncat(out_list, in_list, mid_hexsz); 2076 out_cnt++; 2077 } 2078 in_list += mid_hexsz; 2079 } 2080 2081 if (out_cnt == in_members->m_cnt) { 2082 free(out_list); 2083 return (SMB_LGRP_MEMBER_NOT_IN_GROUP); 2084 } 2085 2086 out_members->m_cnt = out_cnt; 2087 out_members->m_ids = out_list; 2088 return (SMB_LGRP_SUCCESS); 2089 } 2090 2091 /* 2092 * smb_lgrp_plist_add 2093 * 2094 * Adds the given privilege to the input list (in_privs) 2095 * if it's not already there. The result list is returned 2096 * in out_privs. The caller must free the allocated memory 2097 * for out_privs by calling free(). 2098 */ 2099 static int 2100 smb_lgrp_plist_add(smb_lgplist_t *in_privs, smb_lgpid_t priv_id, 2101 smb_lgplist_t *out_privs) 2102 { 2103 int i, size; 2104 smb_lgpid_t *pbuf; 2105 2106 out_privs->p_cnt = 0; 2107 out_privs->p_ids = NULL; 2108 2109 for (i = 0; i < in_privs->p_cnt; i++) { 2110 if (in_privs->p_ids[i] == priv_id) 2111 return (SMB_LGRP_PRIV_HELD); 2112 } 2113 2114 size = (in_privs->p_cnt + 1) * sizeof (smb_lgpid_t) + 1; 2115 pbuf = malloc(size); 2116 if (pbuf == NULL) 2117 return (SMB_LGRP_NO_MEMORY); 2118 2119 bzero(pbuf, size); 2120 bcopy(in_privs->p_ids, pbuf, in_privs->p_cnt * sizeof (smb_lgpid_t)); 2121 pbuf[in_privs->p_cnt] = priv_id; 2122 2123 out_privs->p_cnt = in_privs->p_cnt + 1; 2124 out_privs->p_ids = pbuf; 2125 2126 return (SMB_LGRP_SUCCESS); 2127 } 2128 2129 /* 2130 * smb_lgrp_plist_del 2131 * 2132 * Removes the given privilege from the input list (in_privs) 2133 * if it's already there. The result list is returned 2134 * in out_privs. The caller must free the allocated memory 2135 * for out_privs by calling free(). 2136 */ 2137 static int 2138 smb_lgrp_plist_del(smb_lgplist_t *in_privs, smb_lgpid_t priv_id, 2139 smb_lgplist_t *out_privs) 2140 { 2141 int i, size; 2142 2143 out_privs->p_cnt = 0; 2144 out_privs->p_ids = NULL; 2145 2146 if ((in_privs == NULL) || (in_privs->p_cnt == 0)) 2147 return (SMB_LGRP_PRIV_NOT_HELD); 2148 2149 size = (in_privs->p_cnt - 1) * sizeof (smb_lgpid_t) + 1; 2150 out_privs->p_ids = malloc(size); 2151 if (out_privs->p_ids == NULL) 2152 return (SMB_LGRP_NO_MEMORY); 2153 2154 bzero(out_privs->p_ids, size); 2155 2156 for (i = 0; i < in_privs->p_cnt; i++) { 2157 if (in_privs->p_ids[i] != priv_id) 2158 out_privs->p_ids[out_privs->p_cnt++] = 2159 in_privs->p_ids[i]; 2160 } 2161 2162 if (out_privs->p_cnt == in_privs->p_cnt) { 2163 free(out_privs->p_ids); 2164 out_privs->p_cnt = 0; 2165 out_privs->p_ids = NULL; 2166 return (SMB_LGRP_PRIV_NOT_HELD); 2167 } 2168 2169 return (SMB_LGRP_SUCCESS); 2170 } 2171 2172 /* 2173 * smb_lgrp_encode_privset 2174 * 2175 * Encodes given privilege set into a buffer to be stored in the group 2176 * database. Each entry of the encoded buffer contains the privilege ID 2177 * of an enable privilege. The returned buffer is null-terminated. 2178 */ 2179 static void 2180 smb_lgrp_encode_privset(smb_group_t *grp, smb_lgplist_t *plist) 2181 { 2182 smb_privset_t *privs; 2183 uint32_t pcnt = plist->p_cnt; 2184 int i; 2185 2186 bzero(plist->p_ids, sizeof (smb_lgpid_t) * plist->p_cnt); 2187 plist->p_cnt = 0; 2188 2189 privs = grp->sg_privs; 2190 if ((privs == NULL) || (privs->priv_cnt == 0)) 2191 return; 2192 2193 if (pcnt < privs->priv_cnt) { 2194 assert(0); 2195 } 2196 2197 for (i = 0; i < privs->priv_cnt; i++) { 2198 if (privs->priv[i].attrs == SE_PRIVILEGE_ENABLED) { 2199 plist->p_ids[plist->p_cnt++] = 2200 (uint8_t)privs->priv[i].luid.lo_part; 2201 } 2202 } 2203 } 2204 2205 /* 2206 * smb_lgrp_decode_privset 2207 * 2208 * Decodes the privilege information read from group table 2209 * (nprivs, privs) into a binray format specified by the 2210 * privilege field of smb_group_t 2211 */ 2212 static int 2213 smb_lgrp_decode_privset(smb_group_t *grp, char *nprivs, char *privs) 2214 { 2215 smb_lgplist_t plist; 2216 int i; 2217 2218 plist.p_cnt = atoi(nprivs); 2219 if (strlen(privs) != plist.p_cnt) 2220 return (SMB_LGRP_BAD_DATA); 2221 2222 plist.p_ids = (smb_lgpid_t *)privs; 2223 grp->sg_privs = smb_privset_new(); 2224 if (grp->sg_privs == NULL) 2225 return (SMB_LGRP_NO_MEMORY); 2226 2227 for (i = 0; i < plist.p_cnt; i++) 2228 smb_privset_enable(grp->sg_privs, plist.p_ids[i]); 2229 2230 return (SMB_LGRP_SUCCESS); 2231 } 2232 2233 /* 2234 * smb_lgrp_decode_members 2235 * 2236 * Decodes the members information read from group table 2237 * (nmembers, members) into a binary format specified by the 2238 * member fields of smb_group_t 2239 */ 2240 static int 2241 smb_lgrp_decode_members(smb_group_t *grp, char *nmembers, char *members, 2242 sqlite *db) 2243 { 2244 smb_lgmid_t *m_id; 2245 smb_lgmid_t *m_ids; 2246 smb_gsid_t *m_sid; 2247 smb_gsid_t *m_sids; 2248 int m_num; 2249 int mids_size; 2250 int i, rc; 2251 2252 grp->sg_nmembers = 0; 2253 grp->sg_members = NULL; 2254 2255 m_num = atoi(nmembers); 2256 mids_size = m_num * sizeof (smb_lgmid_t); 2257 if ((m_ids = malloc(mids_size)) == NULL) 2258 return (SMB_LGRP_NO_MEMORY); 2259 2260 m_sids = calloc(m_num, sizeof (smb_gsid_t)); 2261 if (m_sids == NULL) { 2262 free(m_ids); 2263 return (SMB_LGRP_NO_MEMORY); 2264 } 2265 2266 (void) hextobin(members, strlen(members), (char *)m_ids, mids_size); 2267 2268 m_id = m_ids; 2269 m_sid = m_sids; 2270 for (i = 0; i < m_num; i++, m_id++, m_sid++) { 2271 rc = smb_lgrp_getsid(m_id->m_idx, &m_id->m_rid, m_id->m_type, 2272 db, &m_sid->gs_sid); 2273 2274 if (rc != SMB_LGRP_SUCCESS) { 2275 free(m_ids); 2276 for (m_sid = m_sids; m_sid->gs_sid != NULL; m_sid++) 2277 smb_sid_free(m_sid->gs_sid); 2278 free(m_sids); 2279 return (rc); 2280 } 2281 2282 m_sid->gs_type = m_id->m_type; 2283 } 2284 2285 free(m_ids); 2286 2287 grp->sg_nmembers = m_num; 2288 grp->sg_members = m_sids; 2289 return (SMB_LGRP_SUCCESS); 2290 } 2291 2292 /* 2293 * smb_lgrp_decode 2294 * 2295 * Fills out the fields of the given group (grp) based in the 2296 * string information read from the group table. infolvl determines 2297 * which fields are requested and need to be decoded. 2298 * 2299 * Allocated memories must be freed by calling smb_lgrp_free() 2300 * upon successful return. 2301 */ 2302 static int 2303 smb_lgrp_decode(smb_group_t *grp, char **values, int infolvl, sqlite *db) 2304 { 2305 uint32_t sid_idx; 2306 int rc; 2307 2308 if (infolvl == SMB_LGRP_INFO_NONE) 2309 return (SMB_LGRP_SUCCESS); 2310 2311 if (infolvl & SMB_LGRP_INFO_NAME) { 2312 grp->sg_name = strdup(values[SMB_LGRP_GTBL_NAME]); 2313 if (grp->sg_name == NULL) 2314 return (SMB_LGRP_NO_MEMORY); 2315 } 2316 2317 if (infolvl & SMB_LGRP_INFO_CMNT) { 2318 grp->sg_cmnt = strdup(values[SMB_LGRP_GTBL_CMNT]); 2319 if (grp->sg_cmnt == NULL) { 2320 smb_lgrp_free(grp); 2321 return (SMB_LGRP_NO_MEMORY); 2322 } 2323 } 2324 2325 2326 if (infolvl & SMB_LGRP_INFO_SID) { 2327 sid_idx = atoi(values[SMB_LGRP_GTBL_SIDIDX]); 2328 grp->sg_rid = atoi(values[SMB_LGRP_GTBL_SIDRID]); 2329 grp->sg_attr = atoi(values[SMB_LGRP_GTBL_SIDATR]); 2330 grp->sg_id.gs_type = atoi(values[SMB_LGRP_GTBL_SIDTYP]); 2331 rc = smb_lgrp_getsid(sid_idx, &grp->sg_rid, grp->sg_id.gs_type, 2332 db, &grp->sg_id.gs_sid); 2333 if (rc != SMB_LGRP_SUCCESS) { 2334 smb_lgrp_free(grp); 2335 return (rc); 2336 } 2337 grp->sg_domain = (sid_idx == SMB_LGRP_LOCAL_IDX) 2338 ? SMB_DOMAIN_LOCAL : SMB_DOMAIN_BUILTIN; 2339 } 2340 2341 if (infolvl & SMB_LGRP_INFO_PRIV) { 2342 rc = smb_lgrp_decode_privset(grp, values[SMB_LGRP_GTBL_NPRIVS], 2343 values[SMB_LGRP_GTBL_PRIVS]); 2344 2345 if (rc != SMB_LGRP_SUCCESS) { 2346 smb_lgrp_free(grp); 2347 return (rc); 2348 } 2349 } 2350 2351 if (infolvl & SMB_LGRP_INFO_MEMB) { 2352 rc = smb_lgrp_decode_members(grp, values[SMB_LGRP_GTBL_NMEMBS], 2353 values[SMB_LGRP_GTBL_MEMBS], db); 2354 if (rc != SMB_LGRP_SUCCESS) { 2355 smb_lgrp_free(grp); 2356 return (rc); 2357 } 2358 } 2359 2360 return (SMB_LGRP_SUCCESS); 2361 } 2362 2363 /* 2364 * smb_lgrp_normalize_name 2365 * 2366 * Trim whitespace, validate the group name and convert it to lowercase. 2367 */ 2368 static boolean_t 2369 smb_lgrp_normalize_name(char *name) 2370 { 2371 (void) trim_whitespace(name); 2372 2373 if (smb_name_validate_account(name) != ERROR_SUCCESS) 2374 return (B_FALSE); 2375 2376 (void) smb_strlwr(name); 2377 return (B_TRUE); 2378 } 2379 2380 /* 2381 * smb_lgrp_set_default_privs 2382 * 2383 * set default privileges for Administrators and Backup Operators 2384 */ 2385 static void 2386 smb_lgrp_set_default_privs(smb_group_t *grp) 2387 { 2388 if (smb_strcasecmp(grp->sg_name, "Administrators", 0) == 0) { 2389 smb_privset_enable(grp->sg_privs, SE_TAKE_OWNERSHIP_LUID); 2390 return; 2391 } 2392 2393 if (smb_strcasecmp(grp->sg_name, "Backup Operators", 0) == 0) { 2394 smb_privset_enable(grp->sg_privs, SE_BACKUP_LUID); 2395 smb_privset_enable(grp->sg_privs, SE_RESTORE_LUID); 2396 return; 2397 } 2398 } 2399 2400 /* 2401 * smb_lgrp_getsid 2402 * 2403 * Returns a SID based on the provided information 2404 * If dom_idx is 0, it means 'rid' contains a UID/GID and the 2405 * returned SID will be a local SID. If dom_idx is not 0 then 2406 * the domain SID will be fetched from the domain table. 2407 */ 2408 static int 2409 smb_lgrp_getsid(int dom_idx, uint32_t *rid, uint16_t sid_type, 2410 sqlite *db, smb_sid_t **sid) 2411 { 2412 smb_sid_t *dom_sid = NULL; 2413 smb_sid_t *res_sid = NULL; 2414 idmap_stat stat; 2415 int id_type; 2416 int rc; 2417 2418 *sid = NULL; 2419 if (dom_idx == SMB_LGRP_LOCAL_IDX) { 2420 id_type = (sid_type == SidTypeUser) 2421 ? SMB_IDMAP_USER : SMB_IDMAP_GROUP; 2422 stat = smb_idmap_getsid(*rid, id_type, &res_sid); 2423 if (stat != IDMAP_SUCCESS) { 2424 syslog(LOG_ERR, "smb_lgrp_getsid: " 2425 "failed to get a SID for %s id=%u (%d)", 2426 (id_type == SMB_IDMAP_USER) ? "user" : "group", 2427 *rid, stat); 2428 return (SMB_LGRP_NO_SID); 2429 } 2430 2431 /* 2432 * Make sure the returned SID is local 2433 */ 2434 if (!smb_sid_indomain(smb_localgrp.lg_machine_sid, res_sid)) { 2435 syslog(LOG_ERR, "smb_lgrp_getsid: " 2436 "local %s (%u) is mapped to a non-local SID", 2437 (id_type == SMB_IDMAP_USER) ? "user" : "group", 2438 *rid); 2439 smb_sid_free(res_sid); 2440 return (SMB_LGRP_SID_NOTLOCAL); 2441 } 2442 2443 (void) smb_sid_getrid(res_sid, rid); 2444 *sid = res_sid; 2445 return (SMB_LGRP_SUCCESS); 2446 } 2447 2448 rc = smb_lgrp_dtbl_getsid(db, dom_idx, &dom_sid); 2449 if (rc != SMB_LGRP_SUCCESS) { 2450 syslog(LOG_ERR, "smb_lgrp_getsid: %s", smb_lgrp_strerror(rc)); 2451 return (SMB_LGRP_DB_ERROR); 2452 } 2453 2454 res_sid = smb_sid_splice(dom_sid, *rid); 2455 smb_sid_free(dom_sid); 2456 if (res_sid == NULL) { 2457 syslog(LOG_ERR, "smb_lgrp_getsid: %s", smb_lgrp_strerror(rc)); 2458 return (SMB_LGRP_NO_MEMORY); 2459 } 2460 2461 *sid = res_sid; 2462 return (SMB_LGRP_SUCCESS); 2463 } 2464 2465 /* 2466 * smb_lgrp_getgid 2467 * 2468 * Converts given local RID to a local gid since for user 2469 * defined local groups, gid is stored in the table. 2470 */ 2471 static int 2472 smb_lgrp_getgid(uint32_t rid, gid_t *gid) 2473 { 2474 smb_sid_t *sid; 2475 int idtype; 2476 int rc; 2477 2478 if ((sid = smb_sid_splice(smb_localgrp.lg_machine_sid, rid)) == NULL) 2479 return (SMB_LGRP_NO_MEMORY); 2480 2481 idtype = SMB_IDMAP_GROUP; 2482 rc = smb_idmap_getid(sid, gid, &idtype); 2483 smb_sid_free(sid); 2484 2485 return ((rc == IDMAP_SUCCESS) ? SMB_LGRP_SUCCESS : SMB_LGRP_NOT_FOUND); 2486 } 2487 2488 /* 2489 * smb_lgrp_exists 2490 * 2491 * Returns B_TRUE if the local group with the given name exists. 2492 * Otherwise, returns B_FALSE. 2493 */ 2494 static boolean_t 2495 smb_lgrp_exists(char *gname) 2496 { 2497 sqlite *db; 2498 boolean_t rc; 2499 2500 if (!smb_lgrp_normalize_name(gname)) 2501 return (B_FALSE); 2502 2503 db = smb_lgrp_db_open(SMB_LGRP_DB_ORD); 2504 if (db == NULL) 2505 return (B_FALSE); 2506 2507 rc = smb_lgrp_gtbl_exists(db, gname); 2508 smb_lgrp_db_close(db); 2509 2510 return (rc); 2511 } 2512 2513 /* 2514 * smb_lgrp_pgrp_valid_gname 2515 * 2516 * Validate posix group name string. 2517 */ 2518 static int 2519 smb_lgrp_pgrp_valid_gname(char *group) 2520 { 2521 char *ptr = group; 2522 char c; 2523 int len = 0; 2524 int badchar = 0; 2525 2526 if (!group || !*group) 2527 return (SMB_LGRP_PGRP_INVALID); 2528 2529 for (c = *ptr; c != NULL; ptr++, c = *ptr) { 2530 len++; 2531 if (!isprint(c) || (c == ':') || (c == '\n')) 2532 return (SMB_LGRP_PGRP_INVALID); 2533 2534 if (!(islower(c) || isdigit(c))) 2535 badchar++; 2536 } 2537 2538 if ((len > SMB_LGRP_PGRP_MAXGLEN - 1) || (badchar != 0)) 2539 return (SMB_LGRP_PGRP_INVALID); 2540 2541 if (getgrnam(group) != NULL) 2542 return (SMB_LGRP_PGRP_NOTUNIQUE); 2543 2544 return (SMB_LGRP_PGRP_UNIQUE); 2545 } 2546 2547 /* 2548 * smb_lgrp_pgrp_valid_gid 2549 * 2550 * Check to see that the gid is not a reserved gid 2551 * -- nobody (60001), noaccess (60002) or nogroup (65534) 2552 */ 2553 static int 2554 smb_lgrp_pgrp_valid_gid(gid_t gid) 2555 { 2556 return (gid != 60001 && gid != 60002 && gid != 65534); 2557 } 2558 2559 /* 2560 * smb_lgrp_pgrp_findnextgid(void) 2561 * 2562 * This method finds the next valid GID. 2563 * It sorts the used GIDs in decreasing order to return MAXUSED + 1. 2564 * It then adds one to obtain the next valid GID. 2565 * On failure, -1 is returned. On success, a valid GID is returned. 2566 */ 2567 static int 2568 smb_lgrp_pgrp_findnextgid(void) 2569 { 2570 FILE *fptr; 2571 gid_t last, next; 2572 int gid; 2573 2574 if ((fptr = popen("exec sh -c " 2575 "\"getent group|cut -f3 -d:|sort -nr|uniq \" 2>/dev/null", 2576 "r")) == NULL) 2577 return (-1); 2578 2579 if (fscanf(fptr, "%u\n", &next) == EOF) { 2580 (void) pclose(fptr); 2581 return (SMB_LGRP_PGRP_DEFRID + 1); 2582 } 2583 2584 last = MAXUID; 2585 gid = -1; 2586 do { 2587 if (!smb_lgrp_pgrp_valid_gid(next)) 2588 continue; 2589 2590 if (next <= SMB_LGRP_PGRP_DEFRID) { 2591 if (last != SMB_LGRP_PGRP_DEFRID + 1) 2592 gid = SMB_LGRP_PGRP_DEFRID + 1; 2593 break; 2594 } 2595 2596 if ((gid = next + 1) != last) { 2597 while (!smb_lgrp_pgrp_valid_gid((gid_t)gid)) 2598 gid++; 2599 if (gid > 0 && gid < last) 2600 break; 2601 } 2602 2603 gid = -1; 2604 last = next; 2605 } while (fscanf(fptr, "%u\n", &next) != EOF); 2606 2607 (void) pclose(fptr); 2608 return (gid); 2609 } 2610 2611 /* 2612 * smb_lgrp_pgrp_add 2613 * 2614 * Create a posix group with the given name. 2615 * This group will be added to the /etc/group file. 2616 */ 2617 static int 2618 smb_lgrp_pgrp_add(char *group) 2619 { 2620 FILE *etcgrp; 2621 FILE *etctmp; 2622 int o_mask, gret; 2623 int newdone = 0; 2624 struct stat sb; 2625 char buf[SMB_LGRP_PGRP_GRPBUFSIZ]; 2626 gid_t gid; 2627 int rc = 0; 2628 2629 rc = smb_lgrp_pgrp_valid_gname(group); 2630 if ((rc == SMB_LGRP_PGRP_INVALID) || (rc == SMB_LGRP_PGRP_NOTUNIQUE)) 2631 return (-1); 2632 2633 if ((gret = smb_lgrp_pgrp_findnextgid()) < 0) 2634 return (-1); 2635 gid = gret; 2636 2637 if ((etcgrp = fopen(SMB_LGRP_PGRP_GROUP, "r")) == NULL) 2638 return (-1); 2639 2640 if (fstat(fileno(etcgrp), &sb) < 0) 2641 sb.st_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH; 2642 2643 o_mask = umask(077); 2644 etctmp = fopen(SMB_LGRP_PGRP_GRPTMP, "w+"); 2645 (void) umask(o_mask); 2646 2647 if (etctmp == NULL) { 2648 (void) fclose(etcgrp); 2649 return (-1); 2650 } 2651 2652 if (lockf(fileno(etctmp), F_LOCK, 0) != 0) { 2653 (void) fclose(etcgrp); 2654 (void) fclose(etctmp); 2655 (void) unlink(SMB_LGRP_PGRP_GRPTMP); 2656 return (-1); 2657 } 2658 2659 if (fchmod(fileno(etctmp), sb.st_mode) != 0 || 2660 fchown(fileno(etctmp), sb.st_uid, sb.st_gid) != 0) { 2661 (void) lockf(fileno(etctmp), F_ULOCK, 0); 2662 (void) fclose(etcgrp); 2663 (void) fclose(etctmp); 2664 (void) unlink(SMB_LGRP_PGRP_GRPTMP); 2665 return (-1); 2666 } 2667 2668 while (fgets(buf, SMB_LGRP_PGRP_GRPBUFSIZ, etcgrp) != NULL) { 2669 /* Check for NameService reference */ 2670 if (!newdone && (buf[0] == '+' || buf[0] == '-')) { 2671 (void) fprintf(etctmp, "%s::%u:\n", group, gid); 2672 newdone = 1; 2673 } 2674 2675 (void) fputs(buf, etctmp); 2676 } 2677 (void) fclose(etcgrp); 2678 2679 if (!newdone) 2680 (void) fprintf(etctmp, "%s::%u:\n", group, gid); 2681 2682 if (rename(SMB_LGRP_PGRP_GRPTMP, SMB_LGRP_PGRP_GROUP) < 0) { 2683 (void) lockf(fileno(etctmp), F_ULOCK, 0); 2684 (void) fclose(etctmp); 2685 (void) unlink(SMB_LGRP_PGRP_GRPTMP); 2686 return (-1); 2687 } 2688 2689 (void) lockf(fileno(etctmp), F_ULOCK, 0); 2690 (void) fclose(etctmp); 2691 return (0); 2692 } 2693