1/* 2 * Unix SMB/CIFS implementation. 3 * SMB parameters and setup 4 * Copyright (C) Andrew Tridgell 1992-1998 5 * Modified by Jeremy Allison 1995. 6 * Modified by Gerald (Jerry) Carter 2000-2001,2003 7 * Modified by Andrew Bartlett 2002. 8 * 9 * This program is free software; you can redistribute it and/or modify it under 10 * the terms of the GNU General Public License as published by the Free 11 * Software Foundation; either version 2 of the License, or (at your option) 12 * any later version. 13 * 14 * This program is distributed in the hope that it will be useful, but WITHOUT 15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 17 * more details. 18 * 19 * You should have received a copy of the GNU General Public License along with 20 * this program; if not, write to the Free Software Foundation, Inc., 675 21 * Mass Ave, Cambridge, MA 02139, USA. 22 */ 23 24#include "includes.h" 25 26#undef DBGC_CLASS 27#define DBGC_CLASS DBGC_PASSDB 28 29/* 30 smb_passwd is analogous to sam_passwd used everywhere 31 else. However, smb_passwd is limited to the information 32 stored by an smbpasswd entry 33 */ 34 35struct smb_passwd 36{ 37 uint32 smb_userid; /* this is actually the unix uid_t */ 38 const char *smb_name; /* username string */ 39 40 const unsigned char *smb_passwd; /* Null if no password */ 41 const unsigned char *smb_nt_passwd; /* Null if no password */ 42 43 uint16 acct_ctrl; /* account info (ACB_xxxx bit-mask) */ 44 time_t pass_last_set_time; /* password last set time */ 45}; 46 47struct smbpasswd_privates 48{ 49 /* used for maintain locks on the smbpasswd file */ 50 int pw_file_lock_depth; 51 52 /* Global File pointer */ 53 FILE *pw_file; 54 55 /* formerly static variables */ 56 struct smb_passwd pw_buf; 57 pstring user_name; 58 unsigned char smbpwd[16]; 59 unsigned char smbntpwd[16]; 60 61 /* retrive-once info */ 62 const char *smbpasswd_file; 63}; 64 65enum pwf_access_type { PWF_READ, PWF_UPDATE, PWF_CREATE }; 66 67/*************************************************************** 68 Lock an fd. Abandon after waitsecs seconds. 69****************************************************************/ 70 71static BOOL pw_file_lock(int fd, int type, int secs, int *plock_depth) 72{ 73 if (fd < 0) { 74 return False; 75 } 76 77 if(*plock_depth == 0) { 78 if (!do_file_lock(fd, secs, type)) { 79 DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n", 80 strerror(errno))); 81 return False; 82 } 83 } 84 85 (*plock_depth)++; 86 87 return True; 88} 89 90/*************************************************************** 91 Unlock an fd. Abandon after waitsecs seconds. 92****************************************************************/ 93 94static BOOL pw_file_unlock(int fd, int *plock_depth) 95{ 96 BOOL ret=True; 97 98 if (fd == 0 || *plock_depth == 0) { 99 return True; 100 } 101 102 if(*plock_depth == 1) { 103 ret = do_file_lock(fd, 5, F_UNLCK); 104 } 105 106 if (*plock_depth > 0) { 107 (*plock_depth)--; 108 } 109 110 if(!ret) { 111 DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n", 112 strerror(errno))); 113 } 114 return ret; 115} 116 117/************************************************************** 118 Intialize a smb_passwd struct 119 *************************************************************/ 120 121static void pdb_init_smb(struct smb_passwd *user) 122{ 123 if (user == NULL) 124 return; 125 ZERO_STRUCTP (user); 126 127 user->pass_last_set_time = (time_t)0; 128} 129 130/*************************************************************** 131 Internal fn to enumerate the smbpasswd list. Returns a void pointer 132 to ensure no modification outside this module. Checks for atomic 133 rename of smbpasswd file on update or create once the lock has 134 been granted to prevent race conditions. JRA. 135****************************************************************/ 136 137static FILE *startsmbfilepwent(const char *pfile, enum pwf_access_type type, int *lock_depth) 138{ 139 FILE *fp = NULL; 140 const char *open_mode = NULL; 141 int race_loop = 0; 142 int lock_type = F_RDLCK; 143 144 if (!*pfile) { 145 DEBUG(0, ("startsmbfilepwent: No SMB password file set\n")); 146 return (NULL); 147 } 148 149 switch(type) { 150 case PWF_READ: 151 open_mode = "rb"; 152 lock_type = F_RDLCK; 153 break; 154 case PWF_UPDATE: 155 open_mode = "r+b"; 156 lock_type = F_WRLCK; 157 break; 158 case PWF_CREATE: 159 /* 160 * Ensure atomic file creation. 161 */ 162 { 163 int i, fd = -1; 164 165 for(i = 0; i < 5; i++) { 166 if((fd = sys_open(pfile, O_CREAT|O_TRUNC|O_EXCL|O_RDWR, 0600))!=-1) { 167 break; 168 } 169 sys_usleep(200); /* Spin, spin... */ 170 } 171 if(fd == -1) { 172 DEBUG(0,("startsmbfilepwent_internal: too many race conditions \ 173creating file %s\n", pfile)); 174 return NULL; 175 } 176 close(fd); 177 open_mode = "r+b"; 178 lock_type = F_WRLCK; 179 break; 180 } 181 } 182 183 for(race_loop = 0; race_loop < 5; race_loop++) { 184 DEBUG(10, ("startsmbfilepwent_internal: opening file %s\n", pfile)); 185 186 if((fp = sys_fopen(pfile, open_mode)) == NULL) { 187 188 /* 189 * If smbpasswd file doesn't exist, then create new one. This helps to avoid 190 * confusing error msg when adding user account first time. 191 */ 192 if (errno == ENOENT) { 193 if ((fp = sys_fopen(pfile, "a+")) != NULL) { 194 DEBUG(0, ("startsmbfilepwent_internal: file %s did not \ 195exist. File successfully created.\n", pfile)); 196 } else { 197 DEBUG(0, ("startsmbfilepwent_internal: file %s did not \ 198exist. Couldn't create new one. Error was: %s", 199 pfile, strerror(errno))); 200 return NULL; 201 } 202 } else { 203 DEBUG(0, ("startsmbfilepwent_internal: unable to open file %s. \ 204Error was: %s\n", pfile, strerror(errno))); 205 return NULL; 206 } 207 } 208 209 if (!pw_file_lock(fileno(fp), lock_type, 5, lock_depth)) { 210 DEBUG(0, ("startsmbfilepwent_internal: unable to lock file %s. \ 211Error was %s\n", pfile, strerror(errno) )); 212 fclose(fp); 213 return NULL; 214 } 215 216 /* 217 * Only check for replacement races on update or create. 218 * For read we don't mind if the data is one record out of date. 219 */ 220 221 if(type == PWF_READ) { 222 break; 223 } else { 224 SMB_STRUCT_STAT sbuf1, sbuf2; 225 226 /* 227 * Avoid the potential race condition between the open and the lock 228 * by doing a stat on the filename and an fstat on the fd. If the 229 * two inodes differ then someone did a rename between the open and 230 * the lock. Back off and try the open again. Only do this 5 times to 231 * prevent infinate loops. JRA. 232 */ 233 234 if (sys_stat(pfile,&sbuf1) != 0) { 235 DEBUG(0, ("startsmbfilepwent_internal: unable to stat file %s. \ 236Error was %s\n", pfile, strerror(errno))); 237 pw_file_unlock(fileno(fp), lock_depth); 238 fclose(fp); 239 return NULL; 240 } 241 242 if (sys_fstat(fileno(fp),&sbuf2) != 0) { 243 DEBUG(0, ("startsmbfilepwent_internal: unable to fstat file %s. \ 244Error was %s\n", pfile, strerror(errno))); 245 pw_file_unlock(fileno(fp), lock_depth); 246 fclose(fp); 247 return NULL; 248 } 249 250 if( sbuf1.st_ino == sbuf2.st_ino) { 251 /* No race. */ 252 break; 253 } 254 255 /* 256 * Race occurred - back off and try again... 257 */ 258 259 pw_file_unlock(fileno(fp), lock_depth); 260 fclose(fp); 261 } 262 } 263 264 if(race_loop == 5) { 265 DEBUG(0, ("startsmbfilepwent_internal: too many race conditions opening file %s\n", pfile)); 266 return NULL; 267 } 268 269 /* Set a buffer to do more efficient reads */ 270 setvbuf(fp, (char *)NULL, _IOFBF, 1024); 271 272 /* Make sure it is only rw by the owner */ 273#ifdef HAVE_FCHMOD 274 if(fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) { 275#else 276 if(chmod(pfile, S_IRUSR|S_IWUSR) == -1) { 277#endif 278 DEBUG(0, ("startsmbfilepwent_internal: failed to set 0600 permissions on password file %s. \ 279Error was %s\n.", pfile, strerror(errno) )); 280 pw_file_unlock(fileno(fp), lock_depth); 281 fclose(fp); 282 return NULL; 283 } 284 285 /* We have a lock on the file. */ 286 return fp; 287} 288 289/*************************************************************** 290 End enumeration of the smbpasswd list. 291****************************************************************/ 292 293static void endsmbfilepwent(FILE *fp, int *lock_depth) 294{ 295 if (!fp) { 296 return; 297 } 298 299 pw_file_unlock(fileno(fp), lock_depth); 300 fclose(fp); 301 DEBUG(7, ("endsmbfilepwent_internal: closed password file.\n")); 302} 303 304/************************************************************************* 305 Routine to return the next entry in the smbpasswd list. 306 *************************************************************************/ 307 308static struct smb_passwd *getsmbfilepwent(struct smbpasswd_privates *smbpasswd_state, FILE *fp) 309{ 310 /* Static buffers we will return. */ 311 struct smb_passwd *pw_buf = &smbpasswd_state->pw_buf; 312 char *user_name = smbpasswd_state->user_name; 313 unsigned char *smbpwd = smbpasswd_state->smbpwd; 314 unsigned char *smbntpwd = smbpasswd_state->smbntpwd; 315 char linebuf[256]; 316 unsigned char c; 317 unsigned char *p; 318 long uidval; 319 size_t linebuf_len; 320 321 if(fp == NULL) { 322 DEBUG(0,("getsmbfilepwent: Bad password file pointer.\n")); 323 return NULL; 324 } 325 326 pdb_init_smb(pw_buf); 327 pw_buf->acct_ctrl = ACB_NORMAL; 328 329 /* 330 * Scan the file, a line at a time and check if the name matches. 331 */ 332 while (!feof(fp)) { 333 linebuf[0] = '\0'; 334 335 fgets(linebuf, 256, fp); 336 if (ferror(fp)) { 337 return NULL; 338 } 339 340 /* 341 * Check if the string is terminated with a newline - if not 342 * then we must keep reading and discard until we get one. 343 */ 344 if ((linebuf_len = strlen(linebuf)) == 0) { 345 continue; 346 } 347 348 if (linebuf[linebuf_len - 1] != '\n') { 349 c = '\0'; 350 while (!ferror(fp) && !feof(fp)) { 351 c = fgetc(fp); 352 if (c == '\n') { 353 break; 354 } 355 } 356 } else { 357 linebuf[linebuf_len - 1] = '\0'; 358 } 359 360#ifdef DEBUG_PASSWORD 361 DEBUG(100, ("getsmbfilepwent: got line |%s|\n", linebuf)); 362#endif 363 if ((linebuf[0] == 0) && feof(fp)) { 364 DEBUG(4, ("getsmbfilepwent: end of file reached\n")); 365 break; 366 } 367 368 /* 369 * The line we have should be of the form :- 370 * 371 * username:uid:32hex bytes:[Account type]:LCT-12345678....other flags presently 372 * ignored.... 373 * 374 * or, 375 * 376 * username:uid:32hex bytes:32hex bytes:[Account type]:LCT-12345678....ignored.... 377 * 378 * if Windows NT compatible passwords are also present. 379 * [Account type] is an ascii encoding of the type of account. 380 * LCT-(8 hex digits) is the time_t value of the last change time. 381 */ 382 383 if (linebuf[0] == '#' || linebuf[0] == '\0') { 384 DEBUG(6, ("getsmbfilepwent: skipping comment or blank line\n")); 385 continue; 386 } 387 p = (unsigned char *) strchr_m(linebuf, ':'); 388 if (p == NULL) { 389 DEBUG(0, ("getsmbfilepwent: malformed password entry (no :)\n")); 390 continue; 391 } 392 393 /* 394 * As 256 is shorter than a pstring we don't need to check 395 * length here - if this ever changes.... 396 */ 397 SMB_ASSERT(sizeof(pstring) > sizeof(linebuf)); 398 399 strncpy(user_name, linebuf, PTR_DIFF(p, linebuf)); 400 user_name[PTR_DIFF(p, linebuf)] = '\0'; 401 402 /* Get smb uid. */ 403 404 p++; /* Go past ':' */ 405 406 if(*p == '-') { 407 DEBUG(0, ("getsmbfilepwent: user name %s has a negative uid.\n", user_name)); 408 continue; 409 } 410 411 if (!isdigit(*p)) { 412 DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (uid not number)\n", 413 user_name)); 414 continue; 415 } 416 417 uidval = atoi((char *) p); 418 419 while (*p && isdigit(*p)) { 420 p++; 421 } 422 423 if (*p != ':') { 424 DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (no : after uid)\n", 425 user_name)); 426 continue; 427 } 428 429 pw_buf->smb_name = user_name; 430 pw_buf->smb_userid = uidval; 431 432 /* 433 * Now get the password value - this should be 32 hex digits 434 * which are the ascii representations of a 16 byte string. 435 * Get two at a time and put them into the password. 436 */ 437 438 /* Skip the ':' */ 439 p++; 440 441 if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) { 442 DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (passwd too short)\n", 443 user_name )); 444 continue; 445 } 446 447 if (p[32] != ':') { 448 DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (no terminating :)\n", 449 user_name)); 450 continue; 451 } 452 453 if (strnequal((char *) p, "NO PASSWORD", 11)) { 454 pw_buf->smb_passwd = NULL; 455 pw_buf->acct_ctrl |= ACB_PWNOTREQ; 456 } else { 457 if (*p == '*' || *p == 'X') { 458 /* NULL LM password */ 459 pw_buf->smb_passwd = NULL; 460 DEBUG(10, ("getsmbfilepwent: LM password for user %s invalidated\n", user_name)); 461 } else if (pdb_gethexpwd((char *)p, smbpwd)) { 462 pw_buf->smb_passwd = smbpwd; 463 } else { 464 pw_buf->smb_passwd = NULL; 465 DEBUG(0, ("getsmbfilepwent: Malformed Lanman password entry for user %s \ 466(non hex chars)\n", user_name)); 467 } 468 } 469 470 /* 471 * Now check if the NT compatible password is 472 * available. 473 */ 474 pw_buf->smb_nt_passwd = NULL; 475 p += 33; /* Move to the first character of the line after the lanman password. */ 476 if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) { 477 if (*p != '*' && *p != 'X') { 478 if(pdb_gethexpwd((char *)p,smbntpwd)) { 479 pw_buf->smb_nt_passwd = smbntpwd; 480 } 481 } 482 p += 33; /* Move to the first character of the line after the NT password. */ 483 } 484 485 DEBUG(5,("getsmbfilepwent: returning passwd entry for user %s, uid %ld\n", 486 user_name, uidval)); 487 488 if (*p == '[') { 489 unsigned char *end_p = (unsigned char *)strchr_m((char *)p, ']'); 490 pw_buf->acct_ctrl = pdb_decode_acct_ctrl((char*)p); 491 492 /* Must have some account type set. */ 493 if(pw_buf->acct_ctrl == 0) { 494 pw_buf->acct_ctrl = ACB_NORMAL; 495 } 496 497 /* Now try and get the last change time. */ 498 if(end_p) { 499 p = end_p + 1; 500 } 501 if(*p == ':') { 502 p++; 503 if(*p && (StrnCaseCmp((char *)p, "LCT-", 4)==0)) { 504 int i; 505 p += 4; 506 for(i = 0; i < 8; i++) { 507 if(p[i] == '\0' || !isxdigit(p[i])) { 508 break; 509 } 510 } 511 if(i == 8) { 512 /* 513 * p points at 8 characters of hex digits - 514 * read into a time_t as the seconds since 515 * 1970 that the password was last changed. 516 */ 517 pw_buf->pass_last_set_time = (time_t)strtol((char *)p, NULL, 16); 518 } 519 } 520 } 521 } else { 522 /* 'Old' style file. Fake up based on user name. */ 523 /* 524 * Currently trust accounts are kept in the same 525 * password file as 'normal accounts'. If this changes 526 * we will have to fix this code. JRA. 527 */ 528 if(pw_buf->smb_name[strlen(pw_buf->smb_name) - 1] == '$') { 529 pw_buf->acct_ctrl &= ~ACB_NORMAL; 530 pw_buf->acct_ctrl |= ACB_WSTRUST; 531 } 532 } 533 534 return pw_buf; 535 } 536 537 DEBUG(5,("getsmbfilepwent: end of file reached.\n")); 538 return NULL; 539} 540 541/************************************************************************ 542 Create a new smbpasswd entry - malloced space returned. 543*************************************************************************/ 544 545static char *format_new_smbpasswd_entry(const struct smb_passwd *newpwd) 546{ 547 int new_entry_length; 548 char *new_entry; 549 char *p; 550 551 new_entry_length = strlen(newpwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + 552 NEW_PW_FORMAT_SPACE_PADDED_LEN + 1 + 13 + 2; 553 554 if((new_entry = (char *)SMB_MALLOC( new_entry_length )) == NULL) { 555 DEBUG(0, ("format_new_smbpasswd_entry: Malloc failed adding entry for user %s.\n", 556 newpwd->smb_name )); 557 return NULL; 558 } 559 560 slprintf(new_entry, new_entry_length - 1, "%s:%u:", newpwd->smb_name, (unsigned)newpwd->smb_userid); 561 562 p = new_entry+strlen(new_entry); 563 pdb_sethexpwd(p, newpwd->smb_passwd, newpwd->acct_ctrl); 564 p+=strlen(p); 565 *p = ':'; 566 p++; 567 568 pdb_sethexpwd(p, newpwd->smb_nt_passwd, newpwd->acct_ctrl); 569 p+=strlen(p); 570 *p = ':'; 571 p++; 572 573 /* Add the account encoding and the last change time. */ 574 slprintf((char *)p, new_entry_length - 1 - (p - new_entry), "%s:LCT-%08X:\n", 575 pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN), 576 (uint32)newpwd->pass_last_set_time); 577 578 return new_entry; 579} 580 581/************************************************************************ 582 Routine to add an entry to the smbpasswd file. 583*************************************************************************/ 584 585static BOOL add_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, struct smb_passwd *newpwd) 586{ 587 const char *pfile = smbpasswd_state->smbpasswd_file; 588 struct smb_passwd *pwd = NULL; 589 FILE *fp = NULL; 590 int wr_len; 591 int fd; 592 size_t new_entry_length; 593 char *new_entry; 594 SMB_OFF_T offpos; 595 uint32 max_found_uid = 0; 596 597 /* Open the smbpassword file - for update. */ 598 fp = startsmbfilepwent(pfile, PWF_UPDATE, &smbpasswd_state->pw_file_lock_depth); 599 600 if (fp == NULL && errno == ENOENT) { 601 /* Try again - create. */ 602 fp = startsmbfilepwent(pfile, PWF_CREATE, &smbpasswd_state->pw_file_lock_depth); 603 } 604 605 if (fp == NULL) { 606 DEBUG(0, ("add_smbfilepwd_entry: unable to open file.\n")); 607 return False; 608 } 609 610 /* 611 * Scan the file, a line at a time and check if the name matches. 612 */ 613 614 while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) { 615 if (strequal(newpwd->smb_name, pwd->smb_name)) { 616 DEBUG(0, ("add_smbfilepwd_entry: entry with name %s already exists\n", pwd->smb_name)); 617 endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); 618 return False; 619 } 620 621 /* Look for a free uid for use in non-unix accounts */ 622 if (pwd->smb_userid > max_found_uid) { 623 max_found_uid = pwd->smb_userid; 624 } 625 } 626 627 /* Ok - entry doesn't exist. We can add it */ 628 629 /* Create a new smb passwd entry and set it to the given password. */ 630 /* 631 * The add user write needs to be atomic - so get the fd from 632 * the fp and do a raw write() call. 633 */ 634 fd = fileno(fp); 635 636 if((offpos = sys_lseek(fd, 0, SEEK_END)) == -1) { 637 DEBUG(0, ("add_smbfilepwd_entry(sys_lseek): Failed to add entry for user %s to file %s. \ 638Error was %s\n", newpwd->smb_name, pfile, strerror(errno))); 639 endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); 640 return False; 641 } 642 643 if((new_entry = format_new_smbpasswd_entry(newpwd)) == NULL) { 644 DEBUG(0, ("add_smbfilepwd_entry(malloc): Failed to add entry for user %s to file %s. \ 645Error was %s\n", newpwd->smb_name, pfile, strerror(errno))); 646 endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); 647 return False; 648 } 649 650 new_entry_length = strlen(new_entry); 651 652#ifdef DEBUG_PASSWORD 653 DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|", 654 fd, new_entry_length, new_entry)); 655#endif 656 657 if ((wr_len = write(fd, new_entry, new_entry_length)) != new_entry_length) { 658 DEBUG(0, ("add_smbfilepwd_entry(write): %d Failed to add entry for user %s to file %s. \ 659Error was %s\n", wr_len, newpwd->smb_name, pfile, strerror(errno))); 660 661 /* Remove the entry we just wrote. */ 662 if(sys_ftruncate(fd, offpos) == -1) { 663 DEBUG(0, ("add_smbfilepwd_entry: ERROR failed to ftruncate file %s. \ 664Error was %s. Password file may be corrupt ! Please examine by hand !\n", 665 newpwd->smb_name, strerror(errno))); 666 } 667 668 endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); 669 free(new_entry); 670 return False; 671 } 672 673 free(new_entry); 674 endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); 675 return True; 676} 677 678/************************************************************************ 679 Routine to search the smbpasswd file for an entry matching the username. 680 and then modify its password entry. We can't use the startsmbpwent()/ 681 getsmbpwent()/endsmbpwent() interfaces here as we depend on looking 682 in the actual file to decide how much room we have to write data. 683 override = False, normal 684 override = True, override XXXXXXXX'd out password or NO PASS 685************************************************************************/ 686 687static BOOL mod_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, const struct smb_passwd* pwd) 688{ 689 /* Static buffers we will return. */ 690 pstring user_name; 691 692 char linebuf[256]; 693 char readbuf[1024]; 694 unsigned char c; 695 fstring ascii_p16; 696 fstring encode_bits; 697 unsigned char *p = NULL; 698 size_t linebuf_len = 0; 699 FILE *fp; 700 int lockfd; 701 const char *pfile = smbpasswd_state->smbpasswd_file; 702 BOOL found_entry = False; 703 BOOL got_pass_last_set_time = False; 704 705 SMB_OFF_T pwd_seekpos = 0; 706 707 int i; 708 int wr_len; 709 int fd; 710 711 if (!*pfile) { 712 DEBUG(0, ("No SMB password file set\n")); 713 return False; 714 } 715 DEBUG(10, ("mod_smbfilepwd_entry: opening file %s\n", pfile)); 716 717 fp = sys_fopen(pfile, "r+"); 718 719 if (fp == NULL) { 720 DEBUG(0, ("mod_smbfilepwd_entry: unable to open file %s\n", pfile)); 721 return False; 722 } 723 /* Set a buffer to do more efficient reads */ 724 setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf)); 725 726 lockfd = fileno(fp); 727 728 if (!pw_file_lock(lockfd, F_WRLCK, 5, &smbpasswd_state->pw_file_lock_depth)) { 729 DEBUG(0, ("mod_smbfilepwd_entry: unable to lock file %s\n", pfile)); 730 fclose(fp); 731 return False; 732 } 733 734 /* Make sure it is only rw by the owner */ 735 chmod(pfile, 0600); 736 737 /* We have a write lock on the file. */ 738 /* 739 * Scan the file, a line at a time and check if the name matches. 740 */ 741 while (!feof(fp)) { 742 pwd_seekpos = sys_ftell(fp); 743 744 linebuf[0] = '\0'; 745 746 fgets(linebuf, sizeof(linebuf), fp); 747 if (ferror(fp)) { 748 pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth); 749 fclose(fp); 750 return False; 751 } 752 753 /* 754 * Check if the string is terminated with a newline - if not 755 * then we must keep reading and discard until we get one. 756 */ 757 linebuf_len = strlen(linebuf); 758 if (linebuf[linebuf_len - 1] != '\n') { 759 c = '\0'; 760 while (!ferror(fp) && !feof(fp)) { 761 c = fgetc(fp); 762 if (c == '\n') { 763 break; 764 } 765 } 766 } else { 767 linebuf[linebuf_len - 1] = '\0'; 768 } 769 770#ifdef DEBUG_PASSWORD 771 DEBUG(100, ("mod_smbfilepwd_entry: got line |%s|\n", linebuf)); 772#endif 773 774 if ((linebuf[0] == 0) && feof(fp)) { 775 DEBUG(4, ("mod_smbfilepwd_entry: end of file reached\n")); 776 break; 777 } 778 779 /* 780 * The line we have should be of the form :- 781 * 782 * username:uid:[32hex bytes]:....other flags presently 783 * ignored.... 784 * 785 * or, 786 * 787 * username:uid:[32hex bytes]:[32hex bytes]:[attributes]:LCT-XXXXXXXX:...ignored. 788 * 789 * if Windows NT compatible passwords are also present. 790 */ 791 792 if (linebuf[0] == '#' || linebuf[0] == '\0') { 793 DEBUG(6, ("mod_smbfilepwd_entry: skipping comment or blank line\n")); 794 continue; 795 } 796 797 p = (unsigned char *) strchr_m(linebuf, ':'); 798 799 if (p == NULL) { 800 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no :)\n")); 801 continue; 802 } 803 804 /* 805 * As 256 is shorter than a pstring we don't need to check 806 * length here - if this ever changes.... 807 */ 808 809 SMB_ASSERT(sizeof(user_name) > sizeof(linebuf)); 810 811 strncpy(user_name, linebuf, PTR_DIFF(p, linebuf)); 812 user_name[PTR_DIFF(p, linebuf)] = '\0'; 813 if (strequal(user_name, pwd->smb_name)) { 814 found_entry = True; 815 break; 816 } 817 } 818 819 if (!found_entry) { 820 pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth); 821 fclose(fp); 822 823 DEBUG(2, ("Cannot update entry for user %s, as they don't exist in the smbpasswd file!\n", 824 pwd->smb_name)); 825 return False; 826 } 827 828 DEBUG(6, ("mod_smbfilepwd_entry: entry exists for user %s\n", pwd->smb_name)); 829 830 /* User name matches - get uid and password */ 831 p++; /* Go past ':' */ 832 833 if (!isdigit(*p)) { 834 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (uid not number)\n", 835 pwd->smb_name)); 836 pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth); 837 fclose(fp); 838 return False; 839 } 840 841 while (*p && isdigit(*p)) { 842 p++; 843 } 844 if (*p != ':') { 845 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no : after uid)\n", 846 pwd->smb_name)); 847 pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth); 848 fclose(fp); 849 return False; 850 } 851 852 /* 853 * Now get the password value - this should be 32 hex digits 854 * which are the ascii representations of a 16 byte string. 855 * Get two at a time and put them into the password. 856 */ 857 p++; 858 859 /* Record exact password position */ 860 pwd_seekpos += PTR_DIFF(p, linebuf); 861 862 if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) { 863 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (passwd too short)\n", 864 pwd->smb_name)); 865 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); 866 fclose(fp); 867 return (False); 868 } 869 870 if (p[32] != ':') { 871 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no terminating :)\n", 872 pwd->smb_name)); 873 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); 874 fclose(fp); 875 return False; 876 } 877 878 /* Now check if the NT compatible password is available. */ 879 p += 33; /* Move to the first character of the line after the lanman password. */ 880 if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) { 881 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (passwd too short)\n", 882 pwd->smb_name)); 883 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); 884 fclose(fp); 885 return (False); 886 } 887 888 if (p[32] != ':') { 889 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no terminating :)\n", 890 pwd->smb_name)); 891 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); 892 fclose(fp); 893 return False; 894 } 895 896 /* 897 * Now check if the account info and the password last 898 * change time is available. 899 */ 900 p += 33; /* Move to the first character of the line after the NT password. */ 901 902 if (*p == '[') { 903 i = 0; 904 encode_bits[i++] = *p++; 905 while((linebuf_len > PTR_DIFF(p, linebuf)) && (*p != ']')) { 906 encode_bits[i++] = *p++; 907 } 908 909 encode_bits[i++] = ']'; 910 encode_bits[i++] = '\0'; 911 912 if(i == NEW_PW_FORMAT_SPACE_PADDED_LEN) { 913 /* 914 * We are using a new format, space padded 915 * acct ctrl field. Encode the given acct ctrl 916 * bits into it. 917 */ 918 fstrcpy(encode_bits, pdb_encode_acct_ctrl(pwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN)); 919 } else { 920 DEBUG(0,("mod_smbfilepwd_entry: Using old smbpasswd format for user %s. \ 921This is no longer supported.!\n", pwd->smb_name)); 922 DEBUG(0,("mod_smbfilepwd_entry: No changes made, failing.!\n")); 923 pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth); 924 fclose(fp); 925 return False; 926 } 927 928 /* Go past the ']' */ 929 if(linebuf_len > PTR_DIFF(p, linebuf)) { 930 p++; 931 } 932 933 if((linebuf_len > PTR_DIFF(p, linebuf)) && (*p == ':')) { 934 p++; 935 936 /* We should be pointing at the LCT entry. */ 937 if((linebuf_len > (PTR_DIFF(p, linebuf) + 13)) && (StrnCaseCmp((char *)p, "LCT-", 4) == 0)) { 938 p += 4; 939 for(i = 0; i < 8; i++) { 940 if(p[i] == '\0' || !isxdigit(p[i])) { 941 break; 942 } 943 } 944 if(i == 8) { 945 /* 946 * p points at 8 characters of hex digits - 947 * read into a time_t as the seconds since 948 * 1970 that the password was last changed. 949 */ 950 got_pass_last_set_time = True; 951 } /* i == 8 */ 952 } /* *p && StrnCaseCmp() */ 953 } /* p == ':' */ 954 } /* p == '[' */ 955 956 /* Entry is correctly formed. */ 957 958 /* Create the 32 byte representation of the new p16 */ 959 pdb_sethexpwd(ascii_p16, pwd->smb_passwd, pwd->acct_ctrl); 960 961 /* Add on the NT md4 hash */ 962 ascii_p16[32] = ':'; 963 wr_len = 66; 964 pdb_sethexpwd(ascii_p16+33, pwd->smb_nt_passwd, pwd->acct_ctrl); 965 ascii_p16[65] = ':'; 966 ascii_p16[66] = '\0'; /* null-terminate the string so that strlen works */ 967 968 /* Add on the account info bits and the time of last password change. */ 969 if(got_pass_last_set_time) { 970 slprintf(&ascii_p16[strlen(ascii_p16)], 971 sizeof(ascii_p16)-(strlen(ascii_p16)+1), 972 "%s:LCT-%08X:", 973 encode_bits, (uint32)pwd->pass_last_set_time ); 974 wr_len = strlen(ascii_p16); 975 } 976 977#ifdef DEBUG_PASSWORD 978 DEBUG(100,("mod_smbfilepwd_entry: ")); 979 dump_data(100, ascii_p16, wr_len); 980#endif 981 982 if(wr_len > sizeof(linebuf)) { 983 DEBUG(0, ("mod_smbfilepwd_entry: line to write (%d) is too long.\n", wr_len+1)); 984 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); 985 fclose(fp); 986 return (False); 987 } 988 989 /* 990 * Do an atomic write into the file at the position defined by 991 * seekpos. 992 */ 993 994 /* The mod user write needs to be atomic - so get the fd from 995 the fp and do a raw write() call. 996 */ 997 998 fd = fileno(fp); 999 1000 if (sys_lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1) { 1001 DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile)); 1002 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); 1003 fclose(fp); 1004 return False; 1005 } 1006 1007 /* Sanity check - ensure the areas we are writing are framed by ':' */ 1008 if (read(fd, linebuf, wr_len+1) != wr_len+1) { 1009 DEBUG(0, ("mod_smbfilepwd_entry: read fail on file %s.\n", pfile)); 1010 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); 1011 fclose(fp); 1012 return False; 1013 } 1014 1015 if ((linebuf[0] != ':') || (linebuf[wr_len] != ':')) { 1016 DEBUG(0, ("mod_smbfilepwd_entry: check on passwd file %s failed.\n", pfile)); 1017 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); 1018 fclose(fp); 1019 return False; 1020 } 1021 1022 if (sys_lseek(fd, pwd_seekpos, SEEK_SET) != pwd_seekpos) { 1023 DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile)); 1024 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); 1025 fclose(fp); 1026 return False; 1027 } 1028 1029 /************************************************************************ 1030 2007/09/10, zzz save data 1031 *************************************************************************/ 1032#if 0 1033 { 1034 char cmd[256]; 1035 1036 //uid always 0 1037 snprintf(cmd, 256, "/usr/sbin/nvram set smb_pass=\"%s:0:%s\"", user_name, ascii_p16); 1038 printf("cmd:%s\n", cmd); 1039 system(cmd); 1040 system("/usr/sbin/nvram commit"); 1041 } 1042#endif //zzz 1043 if (write(fd, ascii_p16, wr_len) != wr_len) { 1044 DEBUG(0, ("mod_smbfilepwd_entry: write failed in passwd file %s\n", pfile)); 1045 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); 1046 fclose(fp); 1047 return False; 1048 } 1049 1050 pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth); 1051 fclose(fp); 1052 return True; 1053} 1054 1055/************************************************************************ 1056 Routine to delete an entry in the smbpasswd file by name. 1057*************************************************************************/ 1058 1059static BOOL del_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, const char *name) 1060{ 1061 const char *pfile = smbpasswd_state->smbpasswd_file; 1062 pstring pfile2; 1063 struct smb_passwd *pwd = NULL; 1064 FILE *fp = NULL; 1065 FILE *fp_write = NULL; 1066 int pfile2_lockdepth = 0; 1067 1068 slprintf(pfile2, sizeof(pfile2)-1, "%s.%u", pfile, (unsigned)sys_getpid() ); 1069 1070 /* 1071 * Open the smbpassword file - for update. It needs to be update 1072 * as we need any other processes to wait until we have replaced 1073 * it. 1074 */ 1075 1076 if((fp = startsmbfilepwent(pfile, PWF_UPDATE, &smbpasswd_state->pw_file_lock_depth)) == NULL) { 1077 DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile)); 1078 return False; 1079 } 1080 1081 /* 1082 * Create the replacement password file. 1083 */ 1084 if((fp_write = startsmbfilepwent(pfile2, PWF_CREATE, &pfile2_lockdepth)) == NULL) { 1085 DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile)); 1086 endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); 1087 return False; 1088 } 1089 1090 /* 1091 * Scan the file, a line at a time and check if the name matches. 1092 */ 1093 1094 while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) { 1095 char *new_entry; 1096 size_t new_entry_length; 1097 1098 if (strequal(name, pwd->smb_name)) { 1099 DEBUG(10, ("add_smbfilepwd_entry: found entry with name %s - deleting it.\n", name)); 1100 continue; 1101 } 1102 1103 /* 1104 * We need to copy the entry out into the second file. 1105 */ 1106 1107 if((new_entry = format_new_smbpasswd_entry(pwd)) == NULL) { 1108 DEBUG(0, ("del_smbfilepwd_entry(malloc): Failed to copy entry for user %s to file %s. \ 1109Error was %s\n", pwd->smb_name, pfile2, strerror(errno))); 1110 unlink(pfile2); 1111 endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); 1112 endsmbfilepwent(fp_write, &pfile2_lockdepth); 1113 return False; 1114 } 1115 1116 new_entry_length = strlen(new_entry); 1117 1118 if(fwrite(new_entry, 1, new_entry_length, fp_write) != new_entry_length) { 1119 DEBUG(0, ("del_smbfilepwd_entry(write): Failed to copy entry for user %s to file %s. \ 1120Error was %s\n", pwd->smb_name, pfile2, strerror(errno))); 1121 unlink(pfile2); 1122 endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); 1123 endsmbfilepwent(fp_write, &pfile2_lockdepth); 1124 free(new_entry); 1125 return False; 1126 } 1127 1128 free(new_entry); 1129 } 1130 1131 /* 1132 * Ensure pfile2 is flushed before rename. 1133 */ 1134 1135 if(fflush(fp_write) != 0) { 1136 DEBUG(0, ("del_smbfilepwd_entry: Failed to flush file %s. Error was %s\n", pfile2, strerror(errno))); 1137 endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); 1138 endsmbfilepwent(fp_write,&pfile2_lockdepth); 1139 return False; 1140 } 1141 1142 /* 1143 * Do an atomic rename - then release the locks. 1144 */ 1145 1146 if(rename(pfile2,pfile) != 0) { 1147 unlink(pfile2); 1148 } 1149 1150 endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth); 1151 endsmbfilepwent(fp_write,&pfile2_lockdepth); 1152 return True; 1153} 1154 1155/********************************************************************* 1156 Create a smb_passwd struct from a SAM_ACCOUNT. 1157 We will not allocate any new memory. The smb_passwd struct 1158 should only stay around as long as the SAM_ACCOUNT does. 1159 ********************************************************************/ 1160 1161static BOOL build_smb_pass (struct smb_passwd *smb_pw, const SAM_ACCOUNT *sampass) 1162{ 1163 uint32 rid; 1164 1165 if (sampass == NULL) 1166 return False; 1167 ZERO_STRUCTP(smb_pw); 1168 1169 if (!IS_SAM_DEFAULT(sampass, PDB_USERSID)) { 1170 rid = pdb_get_user_rid(sampass); 1171 1172 /* If the user specified a RID, make sure its able to be both stored and retreived */ 1173 if (rid == DOMAIN_USER_RID_GUEST) { 1174 struct passwd *passwd = getpwnam_alloc(lp_guestaccount()); 1175 if (!passwd) { 1176 DEBUG(0, ("Could not find gest account via getpwnam()! (%s)\n", lp_guestaccount())); 1177 return False; 1178 } 1179 smb_pw->smb_userid=passwd->pw_uid; 1180 passwd_free(&passwd); 1181 1182 } else if (algorithmic_pdb_rid_is_user(rid)) { 1183 smb_pw->smb_userid=algorithmic_pdb_user_rid_to_uid(rid); 1184 } else { 1185 DEBUG(0,("build_sam_pass: Failing attempt to store user with non-uid based user RID. \n")); 1186 return False; 1187 } 1188 } 1189 1190 smb_pw->smb_name=(const char*)pdb_get_username(sampass); 1191 1192 smb_pw->smb_passwd=pdb_get_lanman_passwd(sampass); 1193 smb_pw->smb_nt_passwd=pdb_get_nt_passwd(sampass); 1194 1195 smb_pw->acct_ctrl=pdb_get_acct_ctrl(sampass); 1196 smb_pw->pass_last_set_time=pdb_get_pass_last_set_time(sampass); 1197 1198 return True; 1199} 1200 1201/********************************************************************* 1202 Create a SAM_ACCOUNT from a smb_passwd struct 1203 ********************************************************************/ 1204 1205static BOOL build_sam_account(struct smbpasswd_privates *smbpasswd_state, 1206 SAM_ACCOUNT *sam_pass, const struct smb_passwd *pw_buf) 1207{ 1208 struct passwd *pwfile; 1209 1210 if (sam_pass==NULL) { 1211 DEBUG(5,("build_sam_account: SAM_ACCOUNT is NULL\n")); 1212 return False; 1213 } 1214 1215 /* verify the user account exists */ 1216 1217 if ( !(pwfile = getpwnam_alloc(pw_buf->smb_name)) ) { 1218 DEBUG(0,("build_sam_account: smbpasswd database is corrupt! username %s with uid " 1219 "%u is not in unix passwd database!\n", pw_buf->smb_name, pw_buf->smb_userid)); 1220 return False; 1221 } 1222 1223 if (!NT_STATUS_IS_OK(pdb_fill_sam_pw(sam_pass, pwfile))) 1224 return False; 1225 1226 passwd_free(&pwfile); 1227 1228 /* set remaining fields */ 1229 1230 pdb_set_nt_passwd (sam_pass, pw_buf->smb_nt_passwd, PDB_SET); 1231 pdb_set_lanman_passwd (sam_pass, pw_buf->smb_passwd, PDB_SET); 1232 pdb_set_acct_ctrl (sam_pass, pw_buf->acct_ctrl, PDB_SET); 1233 pdb_set_pass_last_set_time (sam_pass, pw_buf->pass_last_set_time, PDB_SET); 1234 pdb_set_pass_can_change_time (sam_pass, pw_buf->pass_last_set_time, PDB_SET); 1235 1236 return True; 1237} 1238 1239/***************************************************************** 1240 Functions to be implemented by the new passdb API 1241 ****************************************************************/ 1242 1243static NTSTATUS smbpasswd_setsampwent (struct pdb_methods *my_methods, BOOL update, uint16 acb_mask) 1244{ 1245 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data; 1246 1247 smbpasswd_state->pw_file = startsmbfilepwent(smbpasswd_state->smbpasswd_file, 1248 update ? PWF_UPDATE : PWF_READ, 1249 &(smbpasswd_state->pw_file_lock_depth)); 1250 1251 /* did we fail? Should we try to create it? */ 1252 if (!smbpasswd_state->pw_file && update && errno == ENOENT) { 1253 FILE *fp; 1254 /* slprintf(msg_str,msg_str_len-1, 1255 "smbpasswd file did not exist - attempting to create it.\n"); */ 1256 DEBUG(0,("smbpasswd file did not exist - attempting to create it.\n")); 1257 fp = sys_fopen(smbpasswd_state->smbpasswd_file, "w"); 1258 if (fp) { 1259 fprintf(fp, "# Samba SMB password file\n"); 1260 fclose(fp); 1261 } 1262 1263 smbpasswd_state->pw_file = startsmbfilepwent(smbpasswd_state->smbpasswd_file, 1264 update ? PWF_UPDATE : PWF_READ, 1265 &(smbpasswd_state->pw_file_lock_depth)); 1266 } 1267 1268 if (smbpasswd_state->pw_file != NULL) 1269 return NT_STATUS_OK; 1270 else 1271 return NT_STATUS_UNSUCCESSFUL; 1272} 1273 1274static void smbpasswd_endsampwent (struct pdb_methods *my_methods) 1275{ 1276 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data; 1277 endsmbfilepwent(smbpasswd_state->pw_file, &(smbpasswd_state->pw_file_lock_depth)); 1278} 1279 1280/***************************************************************** 1281 ****************************************************************/ 1282 1283static NTSTATUS smbpasswd_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT *user) 1284{ 1285 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; 1286 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data; 1287 struct smb_passwd *pw_buf=NULL; 1288 BOOL done = False; 1289 DEBUG(5,("pdb_getsampwent\n")); 1290 1291 if (user==NULL) { 1292 DEBUG(5,("pdb_getsampwent (smbpasswd): user is NULL\n")); 1293#if 0 1294 smb_panic("NULL pointer passed to getsampwent (smbpasswd)\n"); 1295#endif 1296 return nt_status; 1297 } 1298 1299 while (!done) { 1300 /* do we have an entry? */ 1301 pw_buf = getsmbfilepwent(smbpasswd_state, smbpasswd_state->pw_file); 1302 if (pw_buf == NULL) 1303 return nt_status; 1304 1305 /* build the SAM_ACCOUNT entry from the smb_passwd struct. 1306 We loop in case the user in the pdb does not exist in 1307 the local system password file */ 1308 if (build_sam_account(smbpasswd_state, user, pw_buf)) 1309 done = True; 1310 } 1311 1312 DEBUG(5,("getsampwent (smbpasswd): done\n")); 1313 1314 /* success */ 1315 return NT_STATUS_OK; 1316} 1317 1318/**************************************************************** 1319 Search smbpasswd file by iterating over the entries. Do not 1320 call getpwnam() for unix account information until we have found 1321 the correct entry 1322 ***************************************************************/ 1323 1324static NTSTATUS smbpasswd_getsampwnam(struct pdb_methods *my_methods, 1325 SAM_ACCOUNT *sam_acct, const char *username) 1326{ 1327 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; 1328 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data; 1329 struct smb_passwd *smb_pw; 1330 void *fp = NULL; 1331 1332 DEBUG(10, ("getsampwnam (smbpasswd): search by name: %s\n", username)); 1333 1334 /* startsmbfilepwent() is used here as we don't want to lookup 1335 the UNIX account in the local system password file until 1336 we have a match. */ 1337 fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ, &(smbpasswd_state->pw_file_lock_depth)); 1338 1339 if (fp == NULL) { 1340 DEBUG(0, ("Unable to open passdb database.\n")); 1341 return nt_status; 1342 } 1343 1344 while ( ((smb_pw=getsmbfilepwent(smbpasswd_state, fp)) != NULL)&& (!strequal(smb_pw->smb_name, username)) ) 1345 /* do nothing....another loop */ ; 1346 1347 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth)); 1348 1349 1350 /* did we locate the username in smbpasswd */ 1351 if (smb_pw == NULL) 1352 return nt_status; 1353 1354 DEBUG(10, ("getsampwnam (smbpasswd): found by name: %s\n", smb_pw->smb_name)); 1355 1356 if (!sam_acct) { 1357 DEBUG(10,("getsampwnam (smbpasswd): SAM_ACCOUNT is NULL\n")); 1358#if 0 1359 smb_panic("NULL pointer passed to pdb_getsampwnam\n"); 1360#endif 1361 return nt_status; 1362 } 1363 1364 /* now build the SAM_ACCOUNT */ 1365 if (!build_sam_account(smbpasswd_state, sam_acct, smb_pw)) 1366 return nt_status; 1367 1368 /* success */ 1369 return NT_STATUS_OK; 1370} 1371 1372static NTSTATUS smbpasswd_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT *sam_acct, const DOM_SID *sid) 1373{ 1374 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; 1375 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data; 1376 struct smb_passwd *smb_pw; 1377 void *fp = NULL; 1378 fstring sid_str; 1379 uint32 rid; 1380 1381 DEBUG(10, ("smbpasswd_getsampwrid: search by sid: %s\n", sid_to_string(sid_str, sid))); 1382 1383 if (!sid_peek_check_rid(get_global_sam_sid(), sid, &rid)) 1384 return NT_STATUS_UNSUCCESSFUL; 1385 1386 /* More special case 'guest account' hacks... */ 1387 if (rid == DOMAIN_USER_RID_GUEST) { 1388 const char *guest_account = lp_guestaccount(); 1389 if (!(guest_account && *guest_account)) { 1390 DEBUG(1, ("Guest account not specfied!\n")); 1391 return nt_status; 1392 } 1393 return smbpasswd_getsampwnam(my_methods, sam_acct, guest_account); 1394 } 1395 1396 /* Open the sam password file - not for update. */ 1397 fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ, &(smbpasswd_state->pw_file_lock_depth)); 1398 1399 if (fp == NULL) { 1400 DEBUG(0, ("Unable to open passdb database.\n")); 1401 return nt_status; 1402 } 1403 1404 while ( ((smb_pw=getsmbfilepwent(smbpasswd_state, fp)) != NULL) && (algorithmic_pdb_uid_to_user_rid(smb_pw->smb_userid) != rid) ) 1405 /* do nothing */ ; 1406 1407 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth)); 1408 1409 1410 /* did we locate the username in smbpasswd */ 1411 if (smb_pw == NULL) 1412 return nt_status; 1413 1414 DEBUG(10, ("getsampwrid (smbpasswd): found by name: %s\n", smb_pw->smb_name)); 1415 1416 if (!sam_acct) { 1417 DEBUG(10,("getsampwrid: (smbpasswd) SAM_ACCOUNT is NULL\n")); 1418#if 0 1419 smb_panic("NULL pointer passed to pdb_getsampwrid\n"); 1420#endif 1421 return nt_status; 1422 } 1423 1424 /* now build the SAM_ACCOUNT */ 1425 if (!build_sam_account (smbpasswd_state, sam_acct, smb_pw)) 1426 return nt_status; 1427 1428 /* build_sam_account might change the SID on us, if the name was for the guest account */ 1429 if (NT_STATUS_IS_OK(nt_status) && !sid_equal(pdb_get_user_sid(sam_acct), sid)) { 1430 fstring sid_string1, sid_string2; 1431 DEBUG(1, ("looking for user with sid %s instead returned %s for account %s!?!\n", 1432 sid_to_string(sid_string1, sid), sid_to_string(sid_string2, pdb_get_user_sid(sam_acct)), pdb_get_username(sam_acct))); 1433 return NT_STATUS_NO_SUCH_USER; 1434 } 1435 1436 /* success */ 1437 return NT_STATUS_OK; 1438} 1439 1440static NTSTATUS smbpasswd_add_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT *sampass) 1441{ 1442 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data; 1443 struct smb_passwd smb_pw; 1444 1445 /* convert the SAM_ACCOUNT */ 1446 if (!build_smb_pass(&smb_pw, sampass)) { 1447 return NT_STATUS_UNSUCCESSFUL; 1448 } 1449 1450 /* add the entry */ 1451 if(!add_smbfilepwd_entry(smbpasswd_state, &smb_pw)) { 1452 return NT_STATUS_UNSUCCESSFUL; 1453 } 1454 1455 return NT_STATUS_OK; 1456} 1457 1458static NTSTATUS smbpasswd_update_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT *sampass) 1459{ 1460 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data; 1461 struct smb_passwd smb_pw; 1462 1463 /* convert the SAM_ACCOUNT */ 1464 if (!build_smb_pass(&smb_pw, sampass)) { 1465 DEBUG(0, ("smbpasswd_update_sam_account: build_smb_pass failed!\n")); 1466 return NT_STATUS_UNSUCCESSFUL; 1467 } 1468 1469 /* update the entry */ 1470 if(!mod_smbfilepwd_entry(smbpasswd_state, &smb_pw)) { 1471 DEBUG(0, ("smbpasswd_update_sam_account: mod_smbfilepwd_entry failed!\n")); 1472 return NT_STATUS_UNSUCCESSFUL; 1473 } 1474 1475 return NT_STATUS_OK; 1476} 1477 1478static NTSTATUS smbpasswd_delete_sam_account (struct pdb_methods *my_methods, SAM_ACCOUNT *sampass) 1479{ 1480 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data; 1481 1482 const char *username = pdb_get_username(sampass); 1483 1484 if (del_smbfilepwd_entry(smbpasswd_state, username)) 1485 return NT_STATUS_OK; 1486 1487 return NT_STATUS_UNSUCCESSFUL; 1488} 1489 1490static void free_private_data(void **vp) 1491{ 1492 struct smbpasswd_privates **privates = (struct smbpasswd_privates**)vp; 1493 1494 endsmbfilepwent((*privates)->pw_file, &((*privates)->pw_file_lock_depth)); 1495 1496 *privates = NULL; 1497 /* No need to free any further, as it is talloc()ed */ 1498} 1499 1500static NTSTATUS pdb_init_smbpasswd(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location) 1501{ 1502 NTSTATUS nt_status; 1503 struct smbpasswd_privates *privates; 1504 1505 if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) { 1506 return nt_status; 1507 } 1508 1509 (*pdb_method)->name = "smbpasswd"; 1510 1511 (*pdb_method)->setsampwent = smbpasswd_setsampwent; 1512 (*pdb_method)->endsampwent = smbpasswd_endsampwent; 1513 (*pdb_method)->getsampwent = smbpasswd_getsampwent; 1514 (*pdb_method)->getsampwnam = smbpasswd_getsampwnam; 1515 (*pdb_method)->getsampwsid = smbpasswd_getsampwsid; 1516 (*pdb_method)->add_sam_account = smbpasswd_add_sam_account; 1517 (*pdb_method)->update_sam_account = smbpasswd_update_sam_account; 1518 (*pdb_method)->delete_sam_account = smbpasswd_delete_sam_account; 1519 1520 /* Setup private data and free function */ 1521 1522 privates = TALLOC_ZERO_P(pdb_context->mem_ctx, struct smbpasswd_privates); 1523 1524 if (!privates) { 1525 DEBUG(0, ("talloc() failed for smbpasswd private_data!\n")); 1526 return NT_STATUS_NO_MEMORY; 1527 } 1528 1529 /* Store some config details */ 1530 1531 if (location) { 1532 privates->smbpasswd_file = talloc_strdup(pdb_context->mem_ctx, location); 1533 } else { 1534 privates->smbpasswd_file = talloc_strdup(pdb_context->mem_ctx, lp_smb_passwd_file()); 1535 } 1536 1537 if (!privates->smbpasswd_file) { 1538 DEBUG(0, ("talloc_strdp() failed for storing smbpasswd location!\n")); 1539 return NT_STATUS_NO_MEMORY; 1540 } 1541 1542 (*pdb_method)->private_data = privates; 1543 1544 (*pdb_method)->free_private_data = free_private_data; 1545 1546 return NT_STATUS_OK; 1547} 1548 1549NTSTATUS pdb_smbpasswd_init(void) 1550{ 1551 return smb_register_passdb(PASSDB_INTERFACE_VERSION, "smbpasswd", pdb_init_smbpasswd); 1552} 1553