1/* 2 Unix SMB/CIFS implementation. 3 4 Winbind account management functions 5 6 Copyright (C) by Gerald (Jerry) Carter 2003 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21*/ 22 23#include "includes.h" 24#include "winbindd.h" 25 26#undef DBGC_CLASS 27#define DBGC_CLASS DBGC_WINBIND 28 29#define WBKEY_PASSWD "WBA_PASSWD" 30#define WBKEY_GROUP "WBA_GROUP" 31 32#define NUM_PW_FIELDS 7 33#define NUM_GRP_FIELDS 4 34 35/* Globals */ 36 37static TDB_CONTEXT *account_tdb; 38 39extern userdom_struct current_user_info; 40 41struct _check_primary_grp { 42 gid_t gid; 43 BOOL found; 44}; 45 46/********************************************************************** 47**********************************************************************/ 48 49static void free_winbindd_gr( WINBINDD_GR *grp ) 50{ 51 int i; 52 53 if ( !grp ) 54 return; 55 56 for ( i=0; i<grp->num_gr_mem; i++ ) 57 SAFE_FREE( grp->gr_mem[i] ); 58 59 SAFE_FREE( grp->gr_mem ); 60 61 return; 62} 63 64/***************************************************************************** 65 Initialise auto-account database. 66*****************************************************************************/ 67 68static BOOL winbindd_accountdb_init(void) 69{ 70 /* see if we've already opened the tdb */ 71 72 if ( account_tdb ) 73 return True; 74 75 /* winbindd_idmap.tdb should always be opened by the idmap_init() 76 code first */ 77 78 if ( !(account_tdb = idmap_tdb_handle()) ) { 79 DEBUG(0, ("winbindd_accountdb_init: Unable to retreive handle for database\n")); 80 return False; 81 } 82 83 /* yeah! */ 84 85 return True; 86} 87 88/********************************************************************** 89 Convert a string in /etc/passwd format to a struct passwd* entry 90**********************************************************************/ 91 92static WINBINDD_PW* string2passwd( char *string ) 93{ 94 static WINBINDD_PW pw; 95 char *p, *str; 96 char *fields[NUM_PW_FIELDS]; 97 int i; 98 99 if ( !string ) 100 return NULL; 101 102 ZERO_STRUCTP( &pw ); 103 104 DEBUG(10,("string2passwd: converting \"%s\"\n", string)); 105 106 ZERO_STRUCT( fields ); 107 108 for ( i=0, str=string; i<NUM_PW_FIELDS-1; i++ ) { 109 if ( !(p = strchr( str, ':' )) ) { 110 DEBUG(0,("string2passwd: parsing failure\n")); 111 return NULL; 112 } 113 *p = '\0'; 114 if ( str ) 115 fields[i] = str; 116 str = p + 1; 117 } 118 if ( str ) 119 fields[i] = str; 120 121 /* copy fields */ 122 123 fstrcpy( pw.pw_name, fields[0] ); 124 fstrcpy( pw.pw_passwd, fields[1] ); 125 pw.pw_uid = atoi( fields[2] ); 126 pw.pw_gid = atoi( fields[3] ); 127 fstrcpy( pw.pw_gecos, fields[4] ); 128 fstrcpy( pw.pw_dir, fields[5] ); 129 fstrcpy( pw.pw_shell, fields[6] ); 130 131 132 /* last minute sanity checks */ 133 134 if ( pw.pw_uid==0 || pw.pw_gid==0 ) { 135 DEBUG(0,("string2passwd: Failure! uid==%lu, gid==%lu\n", 136 (unsigned long)pw.pw_uid, (unsigned long)pw.pw_gid)); 137 return NULL; 138 } 139 140 DEBUG(10,("string2passwd: Success\n")); 141 142 return &pw; 143} 144 145/********************************************************************** 146 Convert a struct passwd* to a string formatted for /etc/passwd 147**********************************************************************/ 148 149static char* passwd2string( const WINBINDD_PW *pw ) 150{ 151 static pstring string; 152 int ret; 153 154 if ( !pw || !pw->pw_name ) 155 return NULL; 156 157 DEBUG(10,("passwd2string: converting passwd struct for %s\n", 158 pw->pw_name)); 159 160 ret = pstr_sprintf( string, "%s:%s:%lu:%lu:%s:%s:%s", 161 pw->pw_name, 162 pw->pw_passwd ? pw->pw_passwd : "x", 163 (unsigned long)pw->pw_uid, 164 (unsigned long)pw->pw_gid, 165 pw->pw_gecos, 166 pw->pw_dir, 167 pw->pw_shell ); 168 169 if ( ret < 0 ) { 170 DEBUG(0,("passwd2string: pstr_sprintf() failed!\n")); 171 return NULL; 172 } 173 174 return string; 175} 176 177/********************************************************************** 178 Convert a string in /etc/group format to a struct group* entry 179**********************************************************************/ 180 181static WINBINDD_GR* string2group( char *string ) 182{ 183 static WINBINDD_GR grp; 184 char *p, *str; 185 char *fields[NUM_GRP_FIELDS]; 186 int i; 187 char **gr_members = NULL; 188 int num_gr_members = 0; 189 190 if ( !string ) 191 return NULL; 192 193 ZERO_STRUCTP( &grp ); 194 195 DEBUG(10,("string2group: converting \"%s\"\n", string)); 196 197 ZERO_STRUCT( fields ); 198 199 for ( i=0, str=string; i<NUM_GRP_FIELDS-1; i++ ) { 200 if ( !(p = strchr( str, ':' )) ) { 201 DEBUG(0,("string2group: parsing failure\n")); 202 return NULL; 203 } 204 *p = '\0'; 205 if ( str ) 206 fields[i] = str; 207 str = p + 1; 208 } 209 210 /* group members */ 211 212 if ( *str ) { 213 /* we already know we have a non-empty string */ 214 215 num_gr_members = count_chars(str, ',') + 1; 216 217 /* if there was at least one comma, then there 218 are n+1 members */ 219 if ( num_gr_members ) { 220 fstring buffer; 221 222 gr_members = SMB_XMALLOC_ARRAY(char*, num_gr_members+1); 223 224 i = 0; 225 while ( next_token(&str, buffer, ",", sizeof(buffer)) && i<num_gr_members ) { 226 gr_members[i++] = smb_xstrdup(buffer); 227 } 228 229 gr_members[i] = NULL; 230 } 231 } 232 233 234 /* copy fields */ 235 236 fstrcpy( grp.gr_name, fields[0] ); 237 fstrcpy( grp.gr_passwd, fields[1] ); 238 grp.gr_gid = atoi( fields[2] ); 239 240 grp.num_gr_mem = num_gr_members; 241 grp.gr_mem = gr_members; 242 243 /* last minute sanity checks */ 244 245 if ( grp.gr_gid == 0 ) { 246 DEBUG(0,("string2group: Failure! gid==%lu\n", (unsigned long)grp.gr_gid)); 247 SAFE_FREE( gr_members ); 248 return NULL; 249 } 250 251 DEBUG(10,("string2group: Success\n")); 252 253 return &grp; 254} 255 256/********************************************************************** 257 Convert a struct group* to a string formatted for /etc/group 258**********************************************************************/ 259 260static char* group2string( const WINBINDD_GR *grp ) 261{ 262 static pstring string; 263 int ret; 264 char *member, *gr_mem_str; 265 int num_members; 266 int i, size; 267 268 if ( !grp || !grp->gr_name ) 269 return NULL; 270 271 DEBUG(10,("group2string: converting passwd struct for %s\n", 272 grp->gr_name)); 273 274 if ( grp->num_gr_mem ) { 275 int idx = 0; 276 277 member = grp->gr_mem[0]; 278 size = 0; 279 num_members = 0; 280 281 while ( member ) { 282 size += strlen(member) + 1; 283 num_members++; 284 member = grp->gr_mem[num_members]; 285 } 286 287 gr_mem_str = SMB_XMALLOC_ARRAY(char, size); 288 289 for ( i=0; i<num_members; i++ ) { 290 snprintf( &gr_mem_str[idx], size-idx, "%s,", grp->gr_mem[i] ); 291 idx += strlen(grp->gr_mem[i]) + 1; 292 } 293 /* add trailing NULL (also removes trailing ',' */ 294 gr_mem_str[size-1] = '\0'; 295 } 296 else { 297 /* no members */ 298 gr_mem_str = SMB_XMALLOC_ARRAY(char, sizeof(fstring)); 299 fstrcpy( gr_mem_str, "" ); 300 } 301 302 ret = pstr_sprintf( string, "%s:%s:%lu:%s", 303 grp->gr_name, 304 grp->gr_passwd ? grp->gr_passwd : "*", 305 (unsigned long)grp->gr_gid, 306 gr_mem_str ); 307 308 SAFE_FREE( gr_mem_str ); 309 310 if ( ret < 0 ) { 311 DEBUG(0,("group2string: pstr_sprintf() failed!\n")); 312 return NULL; 313 } 314 315 return string; 316} 317 318/********************************************************************** 319**********************************************************************/ 320 321static char* acct_userkey_byname( const char *name ) 322{ 323 static fstring key; 324 325 fstr_sprintf( key, "%s/NAME/%s", WBKEY_PASSWD, name ); 326 327 return key; 328} 329 330/********************************************************************** 331**********************************************************************/ 332 333static char* acct_userkey_byuid( uid_t uid ) 334{ 335 static fstring key; 336 337 fstr_sprintf( key, "%s/UID/%lu", WBKEY_PASSWD, (unsigned long)uid ); 338 339 return key; 340} 341 342/********************************************************************** 343**********************************************************************/ 344 345static char* acct_groupkey_byname( const char *name ) 346{ 347 static fstring key; 348 349 fstr_sprintf( key, "%s/NAME/%s", WBKEY_GROUP, name ); 350 351 return key; 352} 353 354/********************************************************************** 355**********************************************************************/ 356 357static char* acct_groupkey_bygid( gid_t gid ) 358{ 359 static fstring key; 360 361 fstr_sprintf( key, "%s/GID/%lu", WBKEY_GROUP, (unsigned long)gid ); 362 363 return key; 364} 365 366/********************************************************************** 367**********************************************************************/ 368 369WINBINDD_PW* wb_getpwnam( const char * name ) 370{ 371 char *keystr; 372 TDB_DATA data; 373 static WINBINDD_PW *pw; 374 375 if ( !account_tdb && !winbindd_accountdb_init() ) { 376 DEBUG(0,("wb_getpwnam: Failed to open winbindd account db\n")); 377 return NULL; 378 } 379 380 381 keystr = acct_userkey_byname( name ); 382 383 data = tdb_fetch_bystring( account_tdb, keystr ); 384 385 pw = NULL; 386 387 if ( data.dptr ) { 388 pw = string2passwd( data.dptr ); 389 SAFE_FREE( data.dptr ); 390 } 391 392 DEBUG(5,("wb_getpwnam: %s user (%s)\n", 393 (pw ? "Found" : "Did not find"), name )); 394 395 return pw; 396} 397 398/********************************************************************** 399**********************************************************************/ 400 401WINBINDD_PW* wb_getpwuid( const uid_t uid ) 402{ 403 char *keystr; 404 TDB_DATA data; 405 static WINBINDD_PW *pw; 406 407 if ( !account_tdb && !winbindd_accountdb_init() ) { 408 DEBUG(0,("wb_getpwuid: Failed to open winbindd account db\n")); 409 return NULL; 410 } 411 412 data = tdb_fetch_bystring( account_tdb, acct_userkey_byuid(uid) ); 413 if ( !data.dptr ) { 414 DEBUG(4,("wb_getpwuid: failed to locate uid == %lu\n", (unsigned long)uid)); 415 return NULL; 416 } 417 keystr = acct_userkey_byname( data.dptr ); 418 419 SAFE_FREE( data.dptr ); 420 421 data = tdb_fetch_bystring( account_tdb, keystr ); 422 423 pw = NULL; 424 425 if ( data.dptr ) { 426 pw = string2passwd( data.dptr ); 427 SAFE_FREE( data.dptr ); 428 } 429 430 DEBUG(5,("wb_getpwuid: %s user (uid == %lu)\n", 431 (pw ? "Found" : "Did not find"), (unsigned long)uid )); 432 433 return pw; 434} 435 436/********************************************************************** 437**********************************************************************/ 438 439static BOOL wb_storepwnam( const WINBINDD_PW *pw ) 440{ 441 char *namekey, *uidkey; 442 TDB_DATA data; 443 char *str; 444 int ret = 0; 445 fstring username; 446 447 if ( !account_tdb && !winbindd_accountdb_init() ) { 448 DEBUG(0,("wb_storepwnam: Failed to open winbindd account db\n")); 449 return False; 450 } 451 452 namekey = acct_userkey_byname( pw->pw_name ); 453 454 /* lock the main entry first */ 455 456 if ( tdb_lock_bystring(account_tdb, namekey, 0) == -1 ) { 457 DEBUG(0,("wb_storepwnam: Failed to lock %s\n", namekey)); 458 return False; 459 } 460 461 str = passwd2string( pw ); 462 463 data.dptr = str; 464 data.dsize = strlen(str) + 1; 465 466 if ( (tdb_store_bystring(account_tdb, namekey, data, TDB_REPLACE)) == -1 ) { 467 DEBUG(0,("wb_storepwnam: Failed to store \"%s\"\n", str)); 468 ret = -1; 469 goto done; 470 } 471 472 /* store the uid index */ 473 474 uidkey = acct_userkey_byuid(pw->pw_uid); 475 476 fstrcpy( username, pw->pw_name ); 477 data.dptr = username; 478 data.dsize = strlen(username) + 1; 479 480 if ( (tdb_store_bystring(account_tdb, uidkey, data, TDB_REPLACE)) == -1 ) { 481 DEBUG(0,("wb_storepwnam: Failed to store uid key \"%s\"\n", str)); 482 tdb_delete_bystring(account_tdb, namekey); 483 ret = -1; 484 goto done; 485 } 486 487 DEBUG(10,("wb_storepwnam: Success -> \"%s\"\n", str)); 488 489done: 490 tdb_unlock_bystring( account_tdb, namekey ); 491 492 return ( ret == 0 ); 493} 494 495/********************************************************************** 496**********************************************************************/ 497 498WINBINDD_GR* wb_getgrnam( const char * name ) 499{ 500 char *keystr; 501 TDB_DATA data; 502 static WINBINDD_GR *grp; 503 504 if ( !account_tdb && !winbindd_accountdb_init() ) { 505 DEBUG(0,("wb_getgrnam: Failed to open winbindd account db\n")); 506 return NULL; 507 } 508 509 510 keystr = acct_groupkey_byname( name ); 511 512 data = tdb_fetch_bystring( account_tdb, keystr ); 513 514 grp = NULL; 515 516 if ( data.dptr ) { 517 grp = string2group( data.dptr ); 518 SAFE_FREE( data.dptr ); 519 } 520 521 DEBUG(5,("wb_getgrnam: %s group (%s)\n", 522 (grp ? "Found" : "Did not find"), name )); 523 524 return grp; 525} 526 527/********************************************************************** 528**********************************************************************/ 529 530WINBINDD_GR* wb_getgrgid( gid_t gid ) 531{ 532 char *keystr; 533 TDB_DATA data; 534 static WINBINDD_GR *grp; 535 536 if ( !account_tdb && !winbindd_accountdb_init() ) { 537 DEBUG(0,("wb_getgrgid: Failed to open winbindd account db\n")); 538 return NULL; 539 } 540 541 data = tdb_fetch_bystring( account_tdb, acct_groupkey_bygid(gid) ); 542 if ( !data.dptr ) { 543 DEBUG(4,("wb_getgrgid: failed to locate gid == %lu\n", 544 (unsigned long)gid)); 545 return NULL; 546 } 547 keystr = acct_groupkey_byname( data.dptr ); 548 549 SAFE_FREE( data.dptr ); 550 551 data = tdb_fetch_bystring( account_tdb, keystr ); 552 553 grp = NULL; 554 555 if ( data.dptr ) { 556 grp = string2group( data.dptr ); 557 SAFE_FREE( data.dptr ); 558 } 559 560 DEBUG(5,("wb_getgrgid: %s group (gid == %lu)\n", 561 (grp ? "Found" : "Did not find"), (unsigned long)gid )); 562 563 return grp; 564} 565 566/********************************************************************** 567**********************************************************************/ 568 569static BOOL wb_storegrnam( const WINBINDD_GR *grp ) 570{ 571 char *namekey, *gidkey; 572 TDB_DATA data; 573 char *str; 574 int ret = 0; 575 fstring groupname; 576 577 if ( !account_tdb && !winbindd_accountdb_init() ) { 578 DEBUG(0,("wb_storepwnam: Failed to open winbindd account db\n")); 579 return False; 580 } 581 582 namekey = acct_groupkey_byname( grp->gr_name ); 583 584 /* lock the main entry first */ 585 586 if ( tdb_lock_bystring(account_tdb, namekey, 0) == -1 ) { 587 DEBUG(0,("wb_storegrnam: Failed to lock %s\n", namekey)); 588 return False; 589 } 590 591 str = group2string( grp ); 592 593 data.dptr = str; 594 data.dsize = strlen(str) + 1; 595 596 if ( (tdb_store_bystring(account_tdb, namekey, data, TDB_REPLACE)) == -1 ) { 597 DEBUG(0,("wb_storegrnam: Failed to store \"%s\"\n", str)); 598 ret = -1; 599 goto done; 600 } 601 602 /* store the gid index */ 603 604 gidkey = acct_groupkey_bygid(grp->gr_gid); 605 606 fstrcpy( groupname, grp->gr_name ); 607 data.dptr = groupname; 608 data.dsize = strlen(groupname) + 1; 609 610 if ( (tdb_store_bystring(account_tdb, gidkey, data, TDB_REPLACE)) == -1 ) { 611 DEBUG(0,("wb_storegrnam: Failed to store gid key \"%s\"\n", str)); 612 tdb_delete_bystring(account_tdb, namekey); 613 ret = -1; 614 goto done; 615 } 616 617 DEBUG(10,("wb_storegrnam: Success -> \"%s\"\n", str)); 618 619done: 620 tdb_unlock_bystring( account_tdb, namekey ); 621 622 return ( ret == 0 ); 623} 624 625/********************************************************************** 626**********************************************************************/ 627 628static BOOL wb_addgrpmember( WINBINDD_GR *grp, const char *user ) 629{ 630 int i; 631 char **members; 632 633 if ( !grp || !user ) 634 return False; 635 636 for ( i=0; i<grp->num_gr_mem; i++ ) { 637 if ( StrCaseCmp( grp->gr_mem[i], user ) == 0 ) 638 return True; 639 } 640 641 /* add one new slot and keep an extra for the terminating NULL */ 642 members = SMB_REALLOC_ARRAY( grp->gr_mem, char *, grp->num_gr_mem+2); 643 if ( !members ) 644 return False; 645 646 grp->gr_mem = members; 647 grp->gr_mem[grp->num_gr_mem++] = smb_xstrdup(user); 648 grp->gr_mem[grp->num_gr_mem] = NULL; 649 650 return True; 651} 652 653/********************************************************************** 654**********************************************************************/ 655 656static BOOL wb_delgrpmember( WINBINDD_GR *grp, const char *user ) 657{ 658 int i; 659 BOOL found = False; 660 661 if ( !grp || !user ) 662 return False; 663 664 for ( i=0; i<grp->num_gr_mem; i++ ) { 665 if ( StrCaseCmp( grp->gr_mem[i], user ) == 0 ) { 666 found = True; 667 break; 668 } 669 } 670 671 if ( !found ) 672 return False; 673 674 /* still some remaining members */ 675 676 if ( grp->num_gr_mem > 1 ) { 677 SAFE_FREE(grp->gr_mem[i]); 678 grp->num_gr_mem--; 679 grp->gr_mem[i] = grp->gr_mem[grp->num_gr_mem]; 680 grp->gr_mem[grp->num_gr_mem] = NULL; 681 } 682 else { /* last one */ 683 free_winbindd_gr( grp ); 684 grp->gr_mem = NULL; 685 grp->num_gr_mem = 0; 686 } 687 688 return True; 689} 690 691/********************************************************************** 692**********************************************************************/ 693 694static int cleangroups_traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, 695 void *state) 696{ 697 int len; 698 fstring key; 699 char *name = (char*)state; 700 701 fstr_sprintf( key, "%s/NAME", WBKEY_GROUP ); 702 len = strlen(key); 703 704 /* if this is a group entry then, check the members */ 705 706 if ( (strncmp(kbuf.dptr, key, len) == 0) && dbuf.dptr ) { 707 WINBINDD_GR *grp; 708 709 if ( !(grp = string2group( dbuf.dptr )) ) { 710 DEBUG(0,("cleangroups_traverse_fn: Failure to parse [%s]\n", 711 dbuf.dptr)); 712 return 0; 713 } 714 715 /* just try to delete the user and rely on wb_delgrpmember() 716 to tell you whether or not the group changed. This is more 717 effecient than testing group membership first since the 718 checks for deleting a user from a group is essentially the 719 same as checking if he/she is a member */ 720 721 if ( wb_delgrpmember( grp, name ) ) { 722 DEBUG(10,("cleanupgroups_traverse_fn: Removed user (%s) from group (%s)\n", 723 name, grp->gr_name)); 724 wb_storegrnam( grp ); 725 } 726 727 free_winbindd_gr( grp ); 728 } 729 730 return 0; 731} 732 733/********************************************************************** 734**********************************************************************/ 735 736static BOOL wb_delete_user( WINBINDD_PW *pw) 737{ 738 char *namekey; 739 char *uidkey; 740 741 if ( !account_tdb && !winbindd_accountdb_init() ) { 742 DEBUG(0,("wb_delete_user: Failed to open winbindd account db\n")); 743 return False; 744 } 745 746 namekey = acct_userkey_byname( pw->pw_name ); 747 748 /* lock the main entry first */ 749 750 if ( tdb_lock_bystring(account_tdb, namekey, 0) == -1 ) { 751 DEBUG(0,("wb_delete_user: Failed to lock %s\n", namekey)); 752 return False; 753 } 754 755 /* remove user from all groups */ 756 757 tdb_traverse(account_tdb, cleangroups_traverse_fn, (void *)pw->pw_name); 758 759 /* remove the user */ 760 uidkey = acct_userkey_byuid( pw->pw_uid ); 761 762 tdb_delete_bystring( account_tdb, namekey ); 763 tdb_delete_bystring( account_tdb, uidkey ); 764 765 tdb_unlock_bystring( account_tdb, namekey ); 766 767 return True; 768} 769 770/********************************************************************** 771**********************************************************************/ 772 773static int isprimarygroup_traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, 774 TDB_DATA dbuf, void *params) 775{ 776 int len; 777 fstring key; 778 struct _check_primary_grp *check = (struct _check_primary_grp*)params; 779 780 fstr_sprintf( key, "%s/NAME", WBKEY_PASSWD ); 781 len = strlen(key); 782 783 /* if this is a group entry then, check the members */ 784 785 if ( (strncmp(kbuf.dptr, key, len) == 0) && dbuf.dptr ) { 786 WINBINDD_PW *pw;; 787 788 if ( !(pw = string2passwd( dbuf.dptr )) ) { 789 DEBUG(0,("isprimarygroup_traverse_fn: Failure to parse [%s]\n", 790 dbuf.dptr)); 791 return 0; 792 } 793 794 if ( check->gid == pw->pw_gid ) { 795 check->found = True; 796 return 1; 797 } 798 } 799 800 return 0; 801} 802 803 804/********************************************************************** 805**********************************************************************/ 806 807static BOOL wb_delete_group( WINBINDD_GR *grp ) 808{ 809 struct _check_primary_grp check; 810 char *namekey; 811 char *gidkey; 812 813 if ( !account_tdb && !winbindd_accountdb_init() ) { 814 DEBUG(0,("wb_delete_group: Failed to open winbindd account db\n")); 815 return False; 816 } 817 818 /* lock the main entry first */ 819 820 namekey = acct_groupkey_byname( grp->gr_name ); 821 if ( tdb_lock_bystring(account_tdb, namekey, 0) == -1 ) { 822 DEBUG(0,("wb_delete_group: Failed to lock %s\n", namekey)); 823 return False; 824 } 825 826 /* is this group the primary group for any user? If 827 so deny delete */ 828 829 check.found = False; 830 tdb_traverse(account_tdb, isprimarygroup_traverse_fn, (void *)&check); 831 832 if ( check.found ) { 833 DEBUG(4,("wb_delete_group: Cannot delete group (%s) since it " 834 "is the primary group for some users\n", grp->gr_name)); 835 return False; 836 } 837 838 /* We're clear. Delete the group */ 839 840 DEBUG(5,("wb_delete_group: Removing group (%s)\n", grp->gr_name)); 841 842 gidkey = acct_groupkey_bygid( grp->gr_gid ); 843 844 tdb_delete_bystring( account_tdb, namekey ); 845 tdb_delete_bystring( account_tdb, gidkey ); 846 847 tdb_unlock_bystring( account_tdb, namekey ); 848 849 return True; 850} 851 852/********************************************************************** 853 Create a new "UNIX" user for the system given a username 854**********************************************************************/ 855 856enum winbindd_result winbindd_create_user(struct winbindd_cli_state *state) 857{ 858 char *user, *group; 859 unid_t id; 860 WINBINDD_PW pw, *pw_check; 861 WINBINDD_GR *wb_grp; 862 struct group *unix_grp; 863 gid_t primary_gid; 864 uint32 flags = state->request.flags; 865 uint32 rid; 866 867 if ( !state->privileged ) { 868 DEBUG(2, ("winbindd_create_user: non-privileged access denied!\n")); 869 return WINBINDD_ERROR; 870 } 871 872 /* Ensure null termination */ 873 state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0'; 874 state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0'; 875 876 user = state->request.data.acct_mgt.username; 877 group = state->request.data.acct_mgt.groupname; 878 879 DEBUG(3, ("[%5lu]: create_user: user=>(%s), group=>(%s)\n", 880 (unsigned long)state->pid, user, group)); 881 882 if ( (pw_check=wb_getpwnam(user)) != NULL ) { 883 DEBUG(0,("winbindd_create_user: Refusing to create user that already exists (%s)\n", 884 user)); 885 return WINBINDD_ERROR; 886 } 887 888 889 if ( !*group ) 890 group = lp_template_primary_group(); 891 892 /* validate the primary group 893 1) lookup in local tdb first 894 2) call getgrnam() as a last resort */ 895 896 if ( (wb_grp=wb_getgrnam(group)) != NULL ) { 897 primary_gid = wb_grp->gr_gid; 898 free_winbindd_gr( wb_grp ); 899 } 900 else if ( (unix_grp=sys_getgrnam(group)) != NULL ) { 901 primary_gid = unix_grp->gr_gid; 902 } 903 else { 904 DEBUG(2,("winbindd_create_user: Cannot validate gid for group (%s)\n", group)); 905 return WINBINDD_ERROR; 906 } 907 908 /* get a new uid */ 909 910 if ( !NT_STATUS_IS_OK(idmap_allocate_id( &id, ID_USERID)) ) { 911 DEBUG(0,("winbindd_create_user: idmap_allocate_id() failed!\n")); 912 return WINBINDD_ERROR; 913 } 914 915 /* The substitution of %U and %D in the 'template homedir' is done 916 by lp_string() calling standard_sub_basic(). */ 917 918 fstrcpy( current_user_info.smb_name, user ); 919 sub_set_smb_name( user ); 920 fstrcpy( current_user_info.domain, get_global_sam_name() ); 921 922 /* fill in the passwd struct */ 923 924 fstrcpy( pw.pw_name, user ); 925 fstrcpy( pw.pw_passwd, "x" ); 926 fstrcpy( pw.pw_gecos, user); 927 fstrcpy( pw.pw_dir, lp_template_homedir() ); 928 fstrcpy( pw.pw_shell, lp_template_shell() ); 929 930 pw.pw_uid = id.uid; 931 pw.pw_gid = primary_gid; 932 933 /* store the new entry */ 934 935 if ( !wb_storepwnam(&pw) ) 936 return WINBINDD_ERROR; 937 938 /* do we need a new RID? */ 939 940 if ( flags & WBFLAG_ALLOCATE_RID ) { 941 if ( !NT_STATUS_IS_OK(idmap_allocate_rid(&rid, USER_RID_TYPE)) ) { 942 DEBUG(0,("winbindd_create_user: RID allocation failure! Cannot create user (%s)\n", 943 user)); 944 wb_delete_user( &pw ); 945 946 return WINBINDD_ERROR; 947 } 948 949 state->response.data.rid = rid; 950 } 951 952 return WINBINDD_OK; 953} 954 955/********************************************************************** 956 Create a new "UNIX" group for the system given a username 957**********************************************************************/ 958 959enum winbindd_result winbindd_create_group(struct winbindd_cli_state *state) 960{ 961 char *group; 962 unid_t id; 963 WINBINDD_GR grp, *grp_check; 964 uint32 flags = state->request.flags; 965 uint32 rid; 966 967 if ( !state->privileged ) { 968 DEBUG(2, ("winbindd_create_group: non-privileged access denied!\n")); 969 return WINBINDD_ERROR; 970 } 971 972 /* Ensure null termination */ 973 state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0'; 974 group = state->request.data.acct_mgt.groupname; 975 976 DEBUG(3, ("[%5lu]: create_group: (%s)\n", (unsigned long)state->pid, group)); 977 978 if ( (grp_check=wb_getgrnam(group)) != NULL ) { 979 DEBUG(0,("winbindd_create_group: Refusing to create group that already exists (%s)\n", 980 group)); 981 return WINBINDD_ERROR; 982 } 983 984 /* get a new gid */ 985 986 if ( !NT_STATUS_IS_OK(idmap_allocate_id( &id, ID_GROUPID)) ) { 987 DEBUG(0,("winbindd_create_group: idmap_allocate_id() failed!\n")); 988 return WINBINDD_ERROR; 989 } 990 991 /* fill in the group struct */ 992 993 fstrcpy( grp.gr_name, group ); 994 fstrcpy( grp.gr_passwd, "*" ); 995 996 grp.gr_gid = id.gid; 997 grp.gr_mem = NULL; /* start with no members */ 998 grp.num_gr_mem = 0; 999 1000 if ( !wb_storegrnam(&grp) ) 1001 return WINBINDD_ERROR; 1002 1003 /* do we need a new RID? */ 1004 1005 if ( flags & WBFLAG_ALLOCATE_RID ) { 1006 if ( !NT_STATUS_IS_OK(idmap_allocate_rid(&rid, GROUP_RID_TYPE)) ) { 1007 DEBUG(0,("winbindd_create_group: RID allocation failure! Cannot create group (%s)\n", 1008 group)); 1009 wb_delete_group( &grp ); 1010 1011 return WINBINDD_ERROR; 1012 } 1013 1014 state->response.data.rid = rid; 1015 } 1016 1017 return WINBINDD_OK; 1018} 1019 1020/********************************************************************** 1021 Add a user to the membership for a group. 1022**********************************************************************/ 1023 1024enum winbindd_result winbindd_add_user_to_group(struct winbindd_cli_state *state) 1025{ 1026 WINBINDD_PW *pw; 1027 WINBINDD_GR *grp; 1028 char *user, *group; 1029 BOOL ret; 1030 1031 if ( !state->privileged ) { 1032 DEBUG(2, ("winbindd_add_user_to_group: non-privileged access denied!\n")); 1033 return WINBINDD_ERROR; 1034 } 1035 1036 /* Ensure null termination */ 1037 state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0'; 1038 state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0'; 1039 group = state->request.data.acct_mgt.groupname; 1040 user = state->request.data.acct_mgt.username; 1041 1042 DEBUG(3, ("[%5lu]: add_user_to_group: add %s to %s\n", (unsigned long)state->pid, 1043 user, group)); 1044 1045 /* make sure it is a valid user */ 1046 1047 if ( !(pw = wb_getpwnam( user )) ) { 1048 DEBUG(4,("winbindd_add_user_to_group: Cannot add a non-existent user\n")); 1049 return WINBINDD_ERROR; 1050 } 1051 1052 /* make sure it is a valid group */ 1053 1054 if ( !(grp = wb_getgrnam( group )) ) { 1055 DEBUG(4,("winbindd_add_user_to_group: Cannot add a user to a non-extistent group\n")); 1056 return WINBINDD_ERROR; 1057 } 1058 1059 if ( !wb_addgrpmember( grp, user ) ) 1060 return WINBINDD_ERROR; 1061 1062 ret = wb_storegrnam(grp); 1063 1064 free_winbindd_gr( grp ); 1065 1066 return ( ret ? WINBINDD_OK : WINBINDD_ERROR ); 1067} 1068 1069/********************************************************************** 1070 Remove a user from the membership of a group 1071**********************************************************************/ 1072 1073enum winbindd_result winbindd_remove_user_from_group(struct winbindd_cli_state *state) 1074{ 1075 WINBINDD_GR *grp; 1076 char *user, *group; 1077 BOOL ret; 1078 1079 if ( !state->privileged ) { 1080 DEBUG(2, ("winbindd_remove_user_from_group: non-privileged access denied!\n")); 1081 return WINBINDD_ERROR; 1082 } 1083 1084 /* Ensure null termination */ 1085 state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0'; 1086 state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0'; 1087 group = state->request.data.acct_mgt.groupname; 1088 user = state->request.data.acct_mgt.username; 1089 1090 DEBUG(3, ("[%5lu]: remove_user_from_group: delete %s from %s\n", (unsigned long)state->pid, 1091 user, group)); 1092 1093 /* don't worry about checking the username since we're removing it anyways */ 1094 1095 /* make sure it is a valid group */ 1096 1097 if ( !(grp = wb_getgrnam( group )) ) { 1098 DEBUG(4,("winbindd_remove_user_from_group: Cannot remove a user from a non-extistent group\n")); 1099 return WINBINDD_ERROR; 1100 } 1101 1102 if ( !wb_delgrpmember( grp, user ) ) 1103 return WINBINDD_ERROR; 1104 1105 ret = wb_storegrnam(grp); 1106 1107 free_winbindd_gr( grp ); 1108 1109 return ( ret ? WINBINDD_OK : WINBINDD_ERROR ); 1110} 1111 1112/********************************************************************** 1113 Set the primary group membership of a user 1114**********************************************************************/ 1115 1116enum winbindd_result winbindd_set_user_primary_group(struct winbindd_cli_state *state) 1117{ 1118 WINBINDD_PW *pw; 1119 WINBINDD_GR *grp; 1120 char *user, *group; 1121 1122 if ( !state->privileged ) { 1123 DEBUG(2, ("winbindd_set_user_primary_group: non-privileged access denied!\n")); 1124 return WINBINDD_ERROR; 1125 } 1126 1127 /* Ensure null termination */ 1128 state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0'; 1129 state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0'; 1130 group = state->request.data.acct_mgt.groupname; 1131 user = state->request.data.acct_mgt.username; 1132 1133 DEBUG(3, ("[%5lu]: set_user_primary_group: group %s for user %s\n", 1134 (unsigned long)state->pid, group, user)); 1135 1136 /* make sure it is a valid user */ 1137 1138 if ( !(pw = wb_getpwnam( user )) ) { 1139 DEBUG(4,("winbindd_add_user_to_group: Cannot add a non-existent user\n")); 1140 return WINBINDD_ERROR; 1141 } 1142 1143 /* make sure it is a valid group */ 1144 1145 if ( !(grp = wb_getgrnam( group )) ) { 1146 DEBUG(4,("winbindd_add_user_to_group: Cannot add a user to a non-extistent group\n")); 1147 return WINBINDD_ERROR; 1148 } 1149 1150 pw->pw_gid = grp->gr_gid; 1151 1152 free_winbindd_gr( grp ); 1153 1154 return ( wb_storepwnam(pw) ? WINBINDD_OK : WINBINDD_ERROR ); 1155} 1156 1157/********************************************************************** 1158 Delete a user from the winbindd account tdb. 1159**********************************************************************/ 1160 1161enum winbindd_result winbindd_delete_user(struct winbindd_cli_state *state) 1162{ 1163 WINBINDD_PW *pw; 1164 char *user; 1165 1166 if ( !state->privileged ) { 1167 DEBUG(2, ("winbindd_delete_user: non-privileged access denied!\n")); 1168 return WINBINDD_ERROR; 1169 } 1170 1171 /* Ensure null termination */ 1172 state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0'; 1173 user = state->request.data.acct_mgt.username; 1174 1175 DEBUG(3, ("[%5lu]: delete_user: %s\n", (unsigned long)state->pid, user)); 1176 1177 /* make sure it is a valid user */ 1178 1179 if ( !(pw = wb_getpwnam( user )) ) { 1180 DEBUG(4,("winbindd_delete_user: Cannot delete a non-existent user\n")); 1181 return WINBINDD_ERROR; 1182 } 1183 1184 return ( wb_delete_user(pw) ? WINBINDD_OK : WINBINDD_ERROR ); 1185} 1186 1187/********************************************************************** 1188 Delete a group from winbindd's account tdb. 1189**********************************************************************/ 1190 1191enum winbindd_result winbindd_delete_group(struct winbindd_cli_state *state) 1192{ 1193 WINBINDD_GR *grp; 1194 char *group; 1195 BOOL ret; 1196 1197 if ( !state->privileged ) { 1198 DEBUG(2, ("winbindd_delete_group: non-privileged access denied!\n")); 1199 return WINBINDD_ERROR; 1200 } 1201 1202 /* Ensure null termination */ 1203 state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.groupname)-1]='\0'; 1204 group = state->request.data.acct_mgt.groupname; 1205 1206 DEBUG(3, ("[%5lu]: delete_group: %s\n", (unsigned long)state->pid, group)); 1207 1208 /* make sure it is a valid group */ 1209 1210 if ( !(grp = wb_getgrnam( group )) ) { 1211 DEBUG(4,("winbindd_delete_group: Cannot delete a non-existent group\n")); 1212 return WINBINDD_ERROR; 1213 } 1214 1215 ret = wb_delete_group(grp); 1216 1217 free_winbindd_gr( grp ); 1218 1219 return ( ret ? WINBINDD_OK : WINBINDD_ERROR ); 1220} 1221 1222 1223 1224