root/source3/passdb/pdb_smbpasswd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gotalarm_sig
  2. do_file_lock
  3. pw_file_lock
  4. pw_file_unlock
  5. pdb_init_smb
  6. startsmbfilepwent
  7. endsmbfilepwent
  8. getsmbfilepwent
  9. format_new_smbpasswd_entry
  10. add_smbfilepwd_entry
  11. mod_smbfilepwd_entry
  12. del_smbfilepwd_entry
  13. build_smb_pass
  14. build_sam_account
  15. smbpasswd_getsampwnam
  16. smbpasswd_getsampwsid
  17. smbpasswd_add_sam_account
  18. smbpasswd_update_sam_account
  19. smbpasswd_delete_sam_account
  20. smbpasswd_rename_sam_account
  21. smbpasswd_rid_algorithm
  22. free_private_data
  23. smbpasswd_search_end
  24. smbpasswd_search_next_entry
  25. smbpasswd_search_users
  26. pdb_init_smbpasswd
  27. pdb_smbpasswd_init

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

/* [<][>][^][v][top][bottom][index][help] */