s3-passdb: Remove obsolete signal type cast.
[samba.git] / source3 / passdb / pdb_smbpasswd.c
index 0e7dd77b405c5c5dec056287cca8a0db7e115efc..a327da4cacc5eab59e5f684dca7f2ccaab78043d 100644 (file)
@@ -1,14 +1,14 @@
 /*
  * Unix SMB/CIFS implementation. 
  * SMB parameters and setup
- * Copyright (C) Andrew Tridgell 1992-1998 
- * Modified by Jeremy Allison 1995.
- * Modified by Gerald (Jerry) Carter 2000-2001
- * Modified by Andrew Bartlett 2002.
+ * Copyright (C) Andrew Tridgell       1992-1998 
+ * Modified by Jeremy Allison          1995.
+ * Modified by Gerald (Jerry) Carter   2000-2001,2003
+ * Modified by Andrew Bartlett         2002.
  * 
  * This program is free software; you can redistribute it and/or modify it under
  * the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
+ * Software Foundation; either version 3 of the License, or (at your option)
  * any later version.
  * 
  * This program is distributed in the hope that it will be useful, but WITHOUT
@@ -17,8 +17,7 @@
  * more details.
  * 
  * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 675
- * Mass Ave, Cambridge, MA 02139, USA.
+ * this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "includes.h"
    else.  However, smb_passwd is limited to the information
    stored by an smbpasswd entry 
  */
+
 struct smb_passwd
 {
-        BOOL smb_userid_set;     /* this is actually the unix uid_t */
-        uint32 smb_userid;     /* this is actually the unix uid_t */
+        uint32 smb_userid;        /* this is actually the unix uid_t */
         const char *smb_name;     /* username string */
 
-        const unsigned char *smb_passwd; /* Null if no password */
+        const unsigned char *smb_passwd;    /* Null if no password */
         const unsigned char *smb_nt_passwd; /* Null if no password */
 
-        uint16 acct_ctrl; /* account info (ACB_xxxx bit-mask) */
+        uint16 acct_ctrl;             /* account info (ACB_xxxx bit-mask) */
         time_t pass_last_set_time;    /* password last set time */
 };
 
@@ -49,75 +47,118 @@ struct smbpasswd_privates
 {
        /* used for maintain locks on the smbpasswd file */
        int     pw_file_lock_depth;
-       
+
        /* Global File pointer */
        FILE    *pw_file;
-       
+
        /* formerly static variables */
        struct smb_passwd pw_buf;
-       pstring  user_name;
+       fstring user_name;
        unsigned char smbpwd[16];
        unsigned char smbntpwd[16];
 
        /* retrive-once info */
        const char *smbpasswd_file;
+};
 
-       BOOL permit_non_unix_accounts;
+enum pwf_access_type { PWF_READ, PWF_UPDATE, PWF_CREATE };
 
-       uid_t low_nua_userid; 
-       uid_t high_nua_userid; 
+static SIG_ATOMIC_T gotalarm;
 
-};
+/***************************************************************
+ Signal function to tell us we timed out.
+****************************************************************/
 
-enum pwf_access_type { PWF_READ, PWF_UPDATE, PWF_CREATE };
+static void gotalarm_sig(int signum)
+{
+       gotalarm = 1;
+}
+
+/***************************************************************
+ Lock or unlock a fd for a known lock type. Abandon after waitsecs 
+ seconds.
+****************************************************************/
+
+static bool do_file_lock(int fd, int waitsecs, int type)
+{
+       SMB_STRUCT_FLOCK lock;
+       int             ret;
+       void (*oldsig_handler)(int);
+
+       gotalarm = 0;
+       oldsig_handler = CatchSignal(SIGALRM, gotalarm_sig);
+
+       lock.l_type = type;
+       lock.l_whence = SEEK_SET;
+       lock.l_start = 0;
+       lock.l_len = 1;
+       lock.l_pid = 0;
+
+       alarm(waitsecs);
+       /* Note we must *NOT* use sys_fcntl here ! JRA */
+       ret = fcntl(fd, SMB_F_SETLKW, &lock);
+       alarm(0);
+       CatchSignal(SIGALRM, oldsig_handler);
+
+       if (gotalarm && ret == -1) {
+               DEBUG(0, ("do_file_lock: failed to %s file.\n",
+                       type == F_UNLCK ? "unlock" : "lock"));
+               return False;
+       }
+
+       return (ret == 0);
+}
 
 /***************************************************************
  Lock an fd. Abandon after waitsecs seconds.
 ****************************************************************/
 
-static BOOL pw_file_lock(int fd, int type, int secs, int *plock_depth)
+static bool pw_file_lock(int fd, int type, int secs, int *plock_depth)
 {
-  if (fd < 0)
-    return False;
+       if (fd < 0) {
+               return False;
+       }
 
-  if(*plock_depth == 0) {
-    if (!do_file_lock(fd, secs, type)) {
-      DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n",
-                 strerror(errno)));
-      return False;
-    }
-  }
+       if(*plock_depth == 0) {
+               if (!do_file_lock(fd, secs, type)) {
+                       DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n",
+                               strerror(errno)));
+                       return False;
+               }
+       }
 
-  (*plock_depth)++;
+       (*plock_depth)++;
 
-  return True;
+       return True;
 }
 
 /***************************************************************
  Unlock an fd. Abandon after waitsecs seconds.
 ****************************************************************/
 
-static BOOL pw_file_unlock(int fd, int *plock_depth)
+static bool pw_file_unlock(int fd, int *plock_depth)
 {
-  BOOL ret=True;
+       bool ret=True;
 
-  if (fd == 0 || *plock_depth == 0) {
-         return True;
-  }
+       if (fd == 0 || *plock_depth == 0) {
+               return True;
+       }
 
-  if(*plock_depth == 1)
-    ret = do_file_lock(fd, 5, F_UNLCK);
+       if(*plock_depth == 1) {
+               ret = do_file_lock(fd, 5, F_UNLCK);
+       }
 
-  if (*plock_depth > 0)
-    (*plock_depth)--;
+       if (*plock_depth > 0) {
+               (*plock_depth)--;
+       }
 
-  if(!ret)
-    DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n",
-                 strerror(errno)));
-  return ret;
+       if(!ret) {
+               DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n",
+                       strerror(errno)));
+       }
+       return ret;
 }
 
-
 /**************************************************************
  Intialize a smb_passwd struct
  *************************************************************/
@@ -127,7 +168,7 @@ static void pdb_init_smb(struct smb_passwd *user)
        if (user == NULL) 
                return;
        ZERO_STRUCTP (user);
-       
+
        user->pass_last_set_time = (time_t)0;
 }
 
@@ -140,132 +181,160 @@ static void pdb_init_smb(struct smb_passwd *user)
 
 static FILE *startsmbfilepwent(const char *pfile, enum pwf_access_type type, int *lock_depth)
 {
-  FILE *fp = NULL;
-  const char *open_mode = NULL;
-  int race_loop = 0;
-  int lock_type = F_RDLCK;
-
-  if (!*pfile) {
-    DEBUG(0, ("startsmbfilepwent: No SMB password file set\n"));
-    return (NULL);
-  }
-
-  switch(type) {
-  case PWF_READ:
-    open_mode = "rb";
-    lock_type = F_RDLCK;
-    break;
-  case PWF_UPDATE:
-    open_mode = "r+b";
-    lock_type = F_WRLCK;
-    break;
-  case PWF_CREATE:
-    /*
-     * Ensure atomic file creation.
-     */
-    {
-      int i, fd = -1;
-
-      for(i = 0; i < 5; i++) {
-        if((fd = sys_open(pfile, O_CREAT|O_TRUNC|O_EXCL|O_RDWR, 0600))!=-1)
-          break;
-        sys_usleep(200); /* Spin, spin... */
-      }
-      if(fd == -1) {
-        DEBUG(0,("startsmbfilepwent_internal: too many race conditions creating file %s\n", pfile));
-        return NULL;
-      }
-      close(fd);
-      open_mode = "r+b";
-      lock_type = F_WRLCK;
-      break;
-    }
-  }
-                      
-  for(race_loop = 0; race_loop < 5; race_loop++) {
-    DEBUG(10, ("startsmbfilepwent_internal: opening file %s\n", pfile));
-
-    if((fp = sys_fopen(pfile, open_mode)) == NULL) {
-      DEBUG(0, ("startsmbfilepwent_internal: unable to open file %s. Error was %s\n", pfile, strerror(errno) ));
-      return NULL;
-    }
-
-    if (!pw_file_lock(fileno(fp), lock_type, 5, lock_depth)) {
-      DEBUG(0, ("startsmbfilepwent_internal: unable to lock file %s. Error was %s\n", pfile, strerror(errno) ));
-      fclose(fp);
-      return NULL;
-    }
-
-    /*
-     * Only check for replacement races on update or create.
-     * For read we don't mind if the data is one record out of date.
-     */
-
-    if(type == PWF_READ) {
-      break;
-    } else {
-      SMB_STRUCT_STAT sbuf1, sbuf2;
-
-      /*
-       * Avoid the potential race condition between the open and the lock
-       * by doing a stat on the filename and an fstat on the fd. If the
-       * two inodes differ then someone did a rename between the open and
-       * the lock. Back off and try the open again. Only do this 5 times to
-       * prevent infinate loops. JRA.
-       */
-
-      if (sys_stat(pfile,&sbuf1) != 0) {
-        DEBUG(0, ("startsmbfilepwent_internal: unable to stat file %s. Error was %s\n", pfile, strerror(errno)));
-        pw_file_unlock(fileno(fp), lock_depth);
-        fclose(fp);
-        return NULL;
-      }
-
-      if (sys_fstat(fileno(fp),&sbuf2) != 0) {
-        DEBUG(0, ("startsmbfilepwent_internal: unable to fstat file %s. Error was %s\n", pfile, strerror(errno)));
-        pw_file_unlock(fileno(fp), lock_depth);
-        fclose(fp);
-        return NULL;
-      }
-
-      if( sbuf1.st_ino == sbuf2.st_ino) {
-        /* No race. */
-        break;
-      }
-
-      /*
-       * Race occurred - back off and try again...
-       */
-
-      pw_file_unlock(fileno(fp), lock_depth);
-      fclose(fp);
-    }
-  }
-
-  if(race_loop == 5) {
-    DEBUG(0, ("startsmbfilepwent_internal: too many race conditions opening file %s\n", pfile));
-    return NULL;
-  }
-
-  /* Set a buffer to do more efficient reads */
-  setvbuf(fp, (char *)NULL, _IOFBF, 1024);
-
-  /* Make sure it is only rw by the owner */
-  if(fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) {
-    DEBUG(0, ("startsmbfilepwent_internal: failed to set 0600 permissions on password file %s. \
+       FILE *fp = NULL;
+       const char *open_mode = NULL;
+       int race_loop = 0;
+       int lock_type = F_RDLCK;
+
+       if (!*pfile) {
+               DEBUG(0, ("startsmbfilepwent: No SMB password file set\n"));
+               return (NULL);
+       }
+
+       switch(type) {
+               case PWF_READ:
+                       open_mode = "rb";
+                       lock_type = F_RDLCK;
+                       break;
+               case PWF_UPDATE:
+                       open_mode = "r+b";
+                       lock_type = F_WRLCK;
+                       break;
+               case PWF_CREATE:
+                       /*
+                        * Ensure atomic file creation.
+                        */
+                       {
+                               int i, fd = -1;
+
+                               for(i = 0; i < 5; i++) {
+                                       if((fd = sys_open(pfile, O_CREAT|O_TRUNC|O_EXCL|O_RDWR, 0600))!=-1) {
+                                               break;
+                                       }
+                                       sys_usleep(200); /* Spin, spin... */
+                               }
+                               if(fd == -1) {
+                                       DEBUG(0,("startsmbfilepwent_internal: too many race conditions \
+creating file %s\n", pfile));
+                                       return NULL;
+                               }
+                               close(fd);
+                               open_mode = "r+b";
+                               lock_type = F_WRLCK;
+                               break;
+                       }
+       }
+
+       for(race_loop = 0; race_loop < 5; race_loop++) {
+               DEBUG(10, ("startsmbfilepwent_internal: opening file %s\n", pfile));
+
+               if((fp = sys_fopen(pfile, open_mode)) == NULL) {
+
+                       /*
+                        * If smbpasswd file doesn't exist, then create new one. This helps to avoid
+                        * confusing error msg when adding user account first time.
+                        */
+                       if (errno == ENOENT) {
+                               if ((fp = sys_fopen(pfile, "a+")) != NULL) {
+                                       DEBUG(0, ("startsmbfilepwent_internal: file %s did not \
+exist. File successfully created.\n", pfile));
+                               } else {
+                                       DEBUG(0, ("startsmbfilepwent_internal: file %s did not \
+exist. Couldn't create new one. Error was: %s",
+                                       pfile, strerror(errno)));
+                                       return NULL;
+                               }
+                       } else {
+                               DEBUG(0, ("startsmbfilepwent_internal: unable to open file %s. \
+Error was: %s\n", pfile, strerror(errno)));
+                               return NULL;
+                       }
+               }
+
+               if (!pw_file_lock(fileno(fp), lock_type, 5, lock_depth)) {
+                       DEBUG(0, ("startsmbfilepwent_internal: unable to lock file %s. \
+Error was %s\n", pfile, strerror(errno) ));
+                       fclose(fp);
+                       return NULL;
+               }
+
+               /*
+                * Only check for replacement races on update or create.
+                * For read we don't mind if the data is one record out of date.
+                */
+
+               if(type == PWF_READ) {
+                       break;
+               } else {
+                       SMB_STRUCT_STAT sbuf1, sbuf2;
+
+                       /*
+                        * Avoid the potential race condition between the open and the lock
+                        * by doing a stat on the filename and an fstat on the fd. If the
+                        * two inodes differ then someone did a rename between the open and
+                        * the lock. Back off and try the open again. Only do this 5 times to
+                        * prevent infinate loops. JRA.
+                        */
+
+                       if (sys_stat(pfile, &sbuf1, false) != 0) {
+                               DEBUG(0, ("startsmbfilepwent_internal: unable to stat file %s. \
+Error was %s\n", pfile, strerror(errno)));
+                               pw_file_unlock(fileno(fp), lock_depth);
+                               fclose(fp);
+                               return NULL;
+                       }
+
+                       if (sys_fstat(fileno(fp), &sbuf2, false) != 0) {
+                               DEBUG(0, ("startsmbfilepwent_internal: unable to fstat file %s. \
+Error was %s\n", pfile, strerror(errno)));
+                               pw_file_unlock(fileno(fp), lock_depth);
+                               fclose(fp);
+                               return NULL;
+                       }
+
+                       if( sbuf1.st_ex_ino == sbuf2.st_ex_ino) {
+                               /* No race. */
+                               break;
+                       }
+
+                       /*
+                        * Race occurred - back off and try again...
+                        */
+
+                       pw_file_unlock(fileno(fp), lock_depth);
+                       fclose(fp);
+               }
+       }
+
+       if(race_loop == 5) {
+               DEBUG(0, ("startsmbfilepwent_internal: too many race conditions opening file %s\n", pfile));
+               return NULL;
+       }
+
+       /* Set a buffer to do more efficient reads */
+       setvbuf(fp, (char *)NULL, _IOFBF, 1024);
+
+       /* Make sure it is only rw by the owner */
+#ifdef HAVE_FCHMOD
+       if(fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) {
+#else
+       if(chmod(pfile, S_IRUSR|S_IWUSR) == -1) {
+#endif
+               DEBUG(0, ("startsmbfilepwent_internal: failed to set 0600 permissions on password file %s. \
 Error was %s\n.", pfile, strerror(errno) ));
-    pw_file_unlock(fileno(fp), lock_depth);
-    fclose(fp);
-    return NULL;
-  }
+               pw_file_unlock(fileno(fp), lock_depth);
+               fclose(fp);
+               return NULL;
+       }
 
-  /* We have a lock on the file. */
-  return fp;
+       /* We have a lock on the file. */
+       return fp;
 }
 
 /***************************************************************
  End enumeration of the smbpasswd list.
 ****************************************************************/
+
 static void endsmbfilepwent(FILE *fp, int *lock_depth)
 {
        if (!fp) {
@@ -283,225 +352,231 @@ static void endsmbfilepwent(FILE *fp, int *lock_depth)
 
 static struct smb_passwd *getsmbfilepwent(struct smbpasswd_privates *smbpasswd_state, FILE *fp)
 {
-  /* Static buffers we will return. */
-  struct smb_passwd *pw_buf = &smbpasswd_state->pw_buf;
-  char  *user_name = smbpasswd_state->user_name;
-  unsigned char *smbpwd = smbpasswd_state->smbpwd;
-  unsigned char *smbntpwd = smbpasswd_state->smbntpwd;
-  char            linebuf[256];
-  unsigned char   c;
-  unsigned char  *p;
-  long            uidval;
-  size_t            linebuf_len;
-
-  if(fp == NULL) {
-    DEBUG(0,("getsmbfilepwent: Bad password file pointer.\n"));
-    return NULL;
-  }
-
-  pdb_init_smb(pw_buf);
-
-  pw_buf->acct_ctrl = ACB_NORMAL;  
-
-  /*
-   * Scan the file, a line at a time and check if the name matches.
-   */
-  while (!feof(fp)) {
-    linebuf[0] = '\0';
-
-    fgets(linebuf, 256, fp);
-    if (ferror(fp)) {
-      return NULL;
-    }
-
-    /*
-     * Check if the string is terminated with a newline - if not
-     * then we must keep reading and discard until we get one.
-     */
-    if ((linebuf_len = strlen(linebuf)) == 0)
-               continue;
-
-    if (linebuf[linebuf_len - 1] != '\n') {
-      c = '\0';
-      while (!ferror(fp) && !feof(fp)) {
-        c = fgetc(fp);
-        if (c == '\n')
-          break;
-      }
-    } else
-      linebuf[linebuf_len - 1] = '\0';
+       /* Static buffers we will return. */
+       struct smb_passwd *pw_buf = &smbpasswd_state->pw_buf;
+       char  *user_name = smbpasswd_state->user_name;
+       unsigned char *smbpwd = smbpasswd_state->smbpwd;
+       unsigned char *smbntpwd = smbpasswd_state->smbntpwd;
+       char linebuf[256];
+       int c;
+       unsigned char *p;
+       long uidval;
+       size_t linebuf_len;
+       char *status;
+
+       if(fp == NULL) {
+               DEBUG(0,("getsmbfilepwent: Bad password file pointer.\n"));
+               return NULL;
+       }
+
+       pdb_init_smb(pw_buf);
+       pw_buf->acct_ctrl = ACB_NORMAL;  
+
+       /*
+        * Scan the file, a line at a time and check if the name matches.
+        */
+       status = linebuf;
+       while (status && !feof(fp)) {
+               linebuf[0] = '\0';
+
+               status = fgets(linebuf, 256, fp);
+               if (status == NULL && ferror(fp)) {
+                       return NULL;
+               }
+
+               /*
+                * Check if the string is terminated with a newline - if not
+                * then we must keep reading and discard until we get one.
+                */
+               if ((linebuf_len = strlen(linebuf)) == 0) {
+                       continue;
+               }
+
+               if (linebuf[linebuf_len - 1] != '\n') {
+                       c = '\0';
+                       while (!ferror(fp) && !feof(fp)) {
+                               c = fgetc(fp);
+                               if (c == '\n') {
+                                       break;
+                               }
+                       }
+               } else {
+                       linebuf[linebuf_len - 1] = '\0';
+               }
 
 #ifdef DEBUG_PASSWORD
-    DEBUG(100, ("getsmbfilepwent: got line |%s|\n", linebuf));
+               DEBUG(100, ("getsmbfilepwent: got line |%s|\n", linebuf));
 #endif
-    if ((linebuf[0] == 0) && feof(fp)) {
-      DEBUG(4, ("getsmbfilepwent: end of file reached\n"));
-      break;
-    }
-    /*
-     * The line we have should be of the form :-
-     * 
-     * username:uid:32hex bytes:[Account type]:LCT-12345678....other flags presently
-     * ignored....
-     * 
-     * or,
-     *
-     * username:uid:32hex bytes:32hex bytes:[Account type]:LCT-12345678....ignored....
-     *
-     * if Windows NT compatible passwords are also present.
-     * [Account type] is an ascii encoding of the type of account.
-     * LCT-(8 hex digits) is the time_t value of the last change time.
-     */
-
-    if (linebuf[0] == '#' || linebuf[0] == '\0') {
-      DEBUG(6, ("getsmbfilepwent: skipping comment or blank line\n"));
-      continue;
-    }
-    p = (unsigned char *) strchr_m(linebuf, ':');
-    if (p == NULL) {
-      DEBUG(0, ("getsmbfilepwent: malformed password entry (no :)\n"));
-      continue;
-    }
-    /*
-     * As 256 is shorter than a pstring we don't need to check
-     * length here - if this ever changes....
-     */
-    SMB_ASSERT(sizeof(pstring) > sizeof(linebuf));
-
-    strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
-    user_name[PTR_DIFF(p, linebuf)] = '\0';
-
-    /* Get smb uid. */
-
-    p++;               /* Go past ':' */
-
-    if(*p == '-') {
-      DEBUG(0, ("getsmbfilepwent: uids in the smbpasswd file must not be negative.\n"));
-      continue;
-    }
-
-    if (!isdigit(*p)) {
-      DEBUG(0, ("getsmbfilepwent: malformed password entry (uid not number)\n"));
-      continue;
-    }
-
-    uidval = atoi((char *) p);
-
-    while (*p && isdigit(*p))
-      p++;
-
-    if (*p != ':') {
-      DEBUG(0, ("getsmbfilepwent: malformed password entry (no : after uid)\n"));
-      continue;
-    }
-
-    pw_buf->smb_name = user_name;
-    pw_buf->smb_userid = uidval;
-
-    /*
-     * Now get the password value - this should be 32 hex digits
-     * which are the ascii representations of a 16 byte string.
-     * Get two at a time and put them into the password.
-     */
-
-    /* Skip the ':' */
-    p++;
-
-    if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
-      DEBUG(0, ("getsmbfilepwent: malformed password entry (passwd too short)\n"));
-      continue;
-    }
-
-    if (p[32] != ':') {
-      DEBUG(0, ("getsmbfilepwent: malformed password entry (no terminating :)\n"));
-      continue;
-    }
-
-    if (!strncasecmp((char *) p, "NO PASSWORD", 11)) {
-      pw_buf->smb_passwd = NULL;
-      pw_buf->acct_ctrl |= ACB_PWNOTREQ;
-    } else {
-           if (*p == '*' || *p == 'X') {
-                   /* NULL LM password */
-                   pw_buf->smb_passwd = NULL;
-                   DEBUG(10, ("getsmbfilepwent: LM password for user %s invalidated\n", user_name));
-           } else if (pdb_gethexpwd((char *)p, smbpwd)) {
-                   pw_buf->smb_passwd = smbpwd;
-           } else {
-                   pw_buf->smb_passwd = NULL;
-                   DEBUG(0, ("getsmbfilepwent: Malformed Lanman password entry (non hex chars)\n"));
-           }
-    }
-
-    /* 
-     * Now check if the NT compatible password is
-     * available.
-     */
-    pw_buf->smb_nt_passwd = NULL;
-
-    p += 33; /* Move to the first character of the line after
-                the lanman password. */
-    if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
-      if (*p != '*' && *p != 'X') {
-        if(pdb_gethexpwd((char *)p,smbntpwd))
-          pw_buf->smb_nt_passwd = smbntpwd;
-      }
-      p += 33; /* Move to the first character of the line after
-                  the NT password. */
-    }
-
-    DEBUG(5,("getsmbfilepwent: returning passwd entry for user %s, uid %ld\n",
-            user_name, uidval));
-
-    if (*p == '[')
-       {
-      unsigned char *end_p = (unsigned char *)strchr_m((char *)p, ']');
-      pw_buf->acct_ctrl = pdb_decode_acct_ctrl((char*)p);
-
-      /* Must have some account type set. */
-      if(pw_buf->acct_ctrl == 0)
-        pw_buf->acct_ctrl = ACB_NORMAL;
-
-      /* Now try and get the last change time. */
-      if(end_p)
-        p = end_p + 1;
-      if(*p == ':') {
-        p++;
-        if(*p && (StrnCaseCmp((char *)p, "LCT-", 4)==0)) {
-          int i;
-          p += 4;
-          for(i = 0; i < 8; i++) {
-            if(p[i] == '\0' || !isxdigit(p[i]))
-              break;
-          }
-          if(i == 8) {
-            /*
-             * p points at 8 characters of hex digits - 
-             * read into a time_t as the seconds since
-             * 1970 that the password was last changed.
-             */
-            pw_buf->pass_last_set_time = (time_t)strtol((char *)p, NULL, 16);
-          }
-        }
-      }
-    } else {
-      /* 'Old' style file. Fake up based on user name. */
-      /*
-       * Currently trust accounts are kept in the same
-       * password file as 'normal accounts'. If this changes
-       * we will have to fix this code. JRA.
-       */
-      if(pw_buf->smb_name[strlen(pw_buf->smb_name) - 1] == '$') {
-        pw_buf->acct_ctrl &= ~ACB_NORMAL;
-        pw_buf->acct_ctrl |= ACB_WSTRUST;
-      }
-    }
-
-    return pw_buf;
-  }
-
-  DEBUG(5,("getsmbfilepwent: end of file reached.\n"));
-  return NULL;
+               if ((linebuf[0] == 0) && feof(fp)) {
+                       DEBUG(4, ("getsmbfilepwent: end of file reached\n"));
+                       break;
+               }
+
+               /*
+                * The line we have should be of the form :-
+                * 
+                * username:uid:32hex bytes:[Account type]:LCT-12345678....other flags presently
+                * ignored....
+                * 
+                * or,
+                *
+                * username:uid:32hex bytes:32hex bytes:[Account type]:LCT-12345678....ignored....
+                *
+                * if Windows NT compatible passwords are also present.
+                * [Account type] is an ascii encoding of the type of account.
+                * LCT-(8 hex digits) is the time_t value of the last change time.
+                */
+
+               if (linebuf[0] == '#' || linebuf[0] == '\0') {
+                       DEBUG(6, ("getsmbfilepwent: skipping comment or blank line\n"));
+                       continue;
+               }
+               p = (unsigned char *) strchr_m(linebuf, ':');
+               if (p == NULL) {
+                       DEBUG(0, ("getsmbfilepwent: malformed password entry (no :)\n"));
+                       continue;
+               }
+
+               strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
+               user_name[PTR_DIFF(p, linebuf)] = '\0';
+
+               /* Get smb uid. */
+
+               p++; /* Go past ':' */
+
+               if(*p == '-') {
+                       DEBUG(0, ("getsmbfilepwent: user name %s has a negative uid.\n", user_name));
+                       continue;
+               }
+
+               if (!isdigit(*p)) {
+                       DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (uid not number)\n",
+                               user_name));
+                       continue;
+               }
+
+               uidval = atoi((char *) p);
+
+               while (*p && isdigit(*p)) {
+                       p++;
+               }
+
+               if (*p != ':') {
+                       DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (no : after uid)\n",
+                               user_name));
+                       continue;
+               }
+
+               pw_buf->smb_name = user_name;
+               pw_buf->smb_userid = uidval;
+
+               /*
+                * Now get the password value - this should be 32 hex digits
+                * which are the ascii representations of a 16 byte string.
+                * Get two at a time and put them into the password.
+                */
+
+               /* Skip the ':' */
+               p++;
+
+               if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
+                       DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (passwd too short)\n",
+                               user_name ));
+                       continue;
+               }
+
+               if (p[32] != ':') {
+                       DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (no terminating :)\n",
+                               user_name));
+                       continue;
+               }
+
+               if (strnequal((char *) p, "NO PASSWORD", 11)) {
+                       pw_buf->smb_passwd = NULL;
+                       pw_buf->acct_ctrl |= ACB_PWNOTREQ;
+               } else {
+                       if (*p == '*' || *p == 'X') {
+                               /* NULL LM password */
+                               pw_buf->smb_passwd = NULL;
+                               DEBUG(10, ("getsmbfilepwent: LM password for user %s invalidated\n", user_name));
+                       } else if (pdb_gethexpwd((char *)p, smbpwd)) {
+                               pw_buf->smb_passwd = smbpwd;
+                       } else {
+                               pw_buf->smb_passwd = NULL;
+                               DEBUG(0, ("getsmbfilepwent: Malformed Lanman password entry for user %s \
+(non hex chars)\n", user_name));
+                       }
+               }
+
+               /* 
+                * Now check if the NT compatible password is
+                * available.
+                */
+               pw_buf->smb_nt_passwd = NULL;
+               p += 33; /* Move to the first character of the line after the lanman password. */
+               if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
+                       if (*p != '*' && *p != 'X') {
+                               if(pdb_gethexpwd((char *)p,smbntpwd)) {
+                                       pw_buf->smb_nt_passwd = smbntpwd;
+                               }
+                       }
+                       p += 33; /* Move to the first character of the line after the NT password. */
+               }
+
+               DEBUG(5,("getsmbfilepwent: returning passwd entry for user %s, uid %ld\n",
+                       user_name, uidval));
+
+               if (*p == '[') {
+                       unsigned char *end_p = (unsigned char *)strchr_m((char *)p, ']');
+                       pw_buf->acct_ctrl = pdb_decode_acct_ctrl((char*)p);
+
+                       /* Must have some account type set. */
+                       if(pw_buf->acct_ctrl == 0) {
+                               pw_buf->acct_ctrl = ACB_NORMAL;
+                       }
+
+                       /* Now try and get the last change time. */
+                       if(end_p) {
+                               p = end_p + 1;
+                       }
+                       if(*p == ':') {
+                               p++;
+                               if(*p && (StrnCaseCmp((char *)p, "LCT-", 4)==0)) {
+                                       int i;
+                                       p += 4;
+                                       for(i = 0; i < 8; i++) {
+                                               if(p[i] == '\0' || !isxdigit(p[i])) {
+                                                       break;
+                                               }
+                                       }
+                                       if(i == 8) {
+                                               /*
+                                                * p points at 8 characters of hex digits - 
+                                                * read into a time_t as the seconds since
+                                                * 1970 that the password was last changed.
+                                                */
+                                               pw_buf->pass_last_set_time = (time_t)strtol((char *)p, NULL, 16);
+                                       }
+                               }
+                       }
+               } else {
+                       /* 'Old' style file. Fake up based on user name. */
+                       /*
+                        * Currently trust accounts are kept in the same
+                        * password file as 'normal accounts'. If this changes
+                        * we will have to fix this code. JRA.
+                        */
+                       if(pw_buf->smb_name[strlen(pw_buf->smb_name) - 1] == '$') {
+                               pw_buf->acct_ctrl &= ~ACB_NORMAL;
+                               pw_buf->acct_ctrl |= ACB_WSTRUST;
+                       }
+               }
+
+               return pw_buf;
+       }
+
+       DEBUG(5,("getsmbfilepwent: end of file reached.\n"));
+       return NULL;
 }
 
 /************************************************************************
@@ -510,160 +585,132 @@ static struct smb_passwd *getsmbfilepwent(struct smbpasswd_privates *smbpasswd_s
 
 static char *format_new_smbpasswd_entry(const struct smb_passwd *newpwd)
 {
-  int new_entry_length;
-  char *new_entry;
-  char *p;
-
-  new_entry_length = strlen(newpwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + NEW_PW_FORMAT_SPACE_PADDED_LEN + 1 + 13 + 2;
+       int new_entry_length;
+       char *new_entry;
+       char *p;
 
-  if((new_entry = (char *)malloc( new_entry_length )) == NULL) {
-    DEBUG(0, ("format_new_smbpasswd_entry: Malloc failed adding entry for user %s.\n", newpwd->smb_name ));
-    return NULL;
-  }
+       new_entry_length = strlen(newpwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + 
+                               NEW_PW_FORMAT_SPACE_PADDED_LEN + 1 + 13 + 2;
 
-  slprintf(new_entry, new_entry_length - 1, "%s:%u:", newpwd->smb_name, (unsigned)newpwd->smb_userid);
-
-  p = new_entry+strlen(new_entry);
-  
-  pdb_sethexpwd(p, newpwd->smb_passwd, newpwd->acct_ctrl);
+       if((new_entry = (char *)SMB_MALLOC( new_entry_length )) == NULL) {
+               DEBUG(0, ("format_new_smbpasswd_entry: Malloc failed adding entry for user %s.\n",
+                       newpwd->smb_name ));
+               return NULL;
+       }
 
-  p+=strlen(p); *p = ':'; p++;
+       slprintf(new_entry, new_entry_length - 1, "%s:%u:", newpwd->smb_name, (unsigned)newpwd->smb_userid);
 
-  pdb_sethexpwd(p, newpwd->smb_nt_passwd, newpwd->acct_ctrl);
+       p = new_entry+strlen(new_entry);
+       pdb_sethexpwd(p, newpwd->smb_passwd, newpwd->acct_ctrl);
+       p+=strlen(p);
+       *p = ':';
+       p++;
 
-  p+=strlen(p); *p = ':'; p++;
+       pdb_sethexpwd(p, newpwd->smb_nt_passwd, newpwd->acct_ctrl);
+       p+=strlen(p);
+       *p = ':';
+       p++;
 
-  /* Add the account encoding and the last change time. */
-  slprintf((char *)p, new_entry_length - 1 - (p - new_entry),  "%s:LCT-%08X:\n",
-           pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN),
-           (uint32)newpwd->pass_last_set_time);
+       /* Add the account encoding and the last change time. */
+       slprintf((char *)p, new_entry_length - 1 - (p - new_entry),  "%s:LCT-%08X:\n",
+               pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN),
+               (uint32)newpwd->pass_last_set_time);
 
-  return new_entry;
+       return new_entry;
 }
 
 /************************************************************************
  Routine to add an entry to the smbpasswd file.
 *************************************************************************/
 
-static BOOL add_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, struct smb_passwd *newpwd)
+static NTSTATUS add_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state,
+                                    struct smb_passwd *newpwd)
 {
-  const char *pfile = smbpasswd_state->smbpasswd_file;
-  struct smb_passwd *pwd = NULL;
-  FILE *fp = NULL;
-  int wr_len;
-  int fd;
-  size_t new_entry_length;
-  char *new_entry;
-  SMB_OFF_T offpos;
-  uint32 max_found_uid = 0;
+       const char *pfile = smbpasswd_state->smbpasswd_file;
+       struct smb_passwd *pwd = NULL;
+       FILE *fp = NULL;
+       int wr_len;
+       int fd;
+       size_t new_entry_length;
+       char *new_entry;
+       SMB_OFF_T offpos;
  
-  /* Open the smbpassword file - for update. */
-  fp = startsmbfilepwent(pfile, PWF_UPDATE, &(smbpasswd_state->pw_file_lock_depth));
-
-  if (fp == NULL && errno == ENOENT) {
-       /* Try again - create. */
-       fp = startsmbfilepwent(pfile, PWF_CREATE, &(smbpasswd_state->pw_file_lock_depth));
-  }
-
-  if (fp == NULL) {
-    DEBUG(0, ("add_smbfilepwd_entry: unable to open file.\n"));
-    return False;
-  }
-
-  /*
-   * Scan the file, a line at a time and check if the name matches.
-   */
-
-  while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) 
-  {
-    if (strequal(newpwd->smb_name, pwd->smb_name)) 
-    {
-       DEBUG(0, ("add_smbfilepwd_entry: entry with name %s already exists\n", pwd->smb_name));
-       endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
-       return False;
-    }
-    
-    /* Look for a free uid for use in non-unix accounts */
-    if (pwd->smb_userid > max_found_uid) {
-           max_found_uid = pwd->smb_userid;
-    }
-   }
-
-  /* Ok - entry doesn't exist. We can add it */
-
-  /* Account not in /etc/passwd hack!!! */
-  if (!newpwd->smb_userid_set) {
-         if (!smbpasswd_state->permit_non_unix_accounts) {
-                 DEBUG(0, ("add_smbfilepwd_entry: cannot add account %s without unix identity\n", newpwd->smb_name));
-                 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
-                 return False;
-         }
-
-         if (max_found_uid < smbpasswd_state->low_nua_userid) {
-                 newpwd->smb_userid = smbpasswd_state->low_nua_userid;
-                 newpwd->smb_userid_set = True;
-         } else if (max_found_uid >= smbpasswd_state->high_nua_userid) {
-                 DEBUG(0, ("add_smbfilepwd_entry: cannot add machine %s, no uids are free! \n", newpwd->smb_name));
-                 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
-                 return False;           
-         } else {
-                 newpwd->smb_userid = max_found_uid + 1;
-                 newpwd->smb_userid_set = True;
-         }
-  }
-
-
-  /* Create a new smb passwd entry and set it to the given password. */
-  /* 
-   * The add user write needs to be atomic - so get the fd from 
-   * the fp and do a raw write() call.
-   */
-  fd = fileno(fp);
-
-  if((offpos = sys_lseek(fd, 0, SEEK_END)) == -1) 
-  {
-       DEBUG(0, ("add_smbfilepwd_entry(sys_lseek): Failed to add entry for user %s to file %s. \
+       /* Open the smbpassword file - for update. */
+       fp = startsmbfilepwent(pfile, PWF_UPDATE, &smbpasswd_state->pw_file_lock_depth);
+
+       if (fp == NULL && errno == ENOENT) {
+               /* Try again - create. */
+               fp = startsmbfilepwent(pfile, PWF_CREATE, &smbpasswd_state->pw_file_lock_depth);
+       }
+
+       if (fp == NULL) {
+               DEBUG(0, ("add_smbfilepwd_entry: unable to open file.\n"));
+               return map_nt_error_from_unix(errno);
+       }
+
+       /*
+        * Scan the file, a line at a time and check if the name matches.
+        */
+
+       while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) {
+               if (strequal(newpwd->smb_name, pwd->smb_name)) {
+                       DEBUG(0, ("add_smbfilepwd_entry: entry with name %s already exists\n", pwd->smb_name));
+                       endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+                       return NT_STATUS_USER_EXISTS;
+               }
+       }
+
+       /* Ok - entry doesn't exist. We can add it */
+
+       /* Create a new smb passwd entry and set it to the given password. */
+       /* 
+        * The add user write needs to be atomic - so get the fd from 
+        * the fp and do a raw write() call.
+        */
+       fd = fileno(fp);
+
+       if((offpos = sys_lseek(fd, 0, SEEK_END)) == -1) {
+               NTSTATUS result = map_nt_error_from_unix(errno);
+               DEBUG(0, ("add_smbfilepwd_entry(sys_lseek): Failed to add entry for user %s to file %s. \
 Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
-       endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
-       return False;
-  }
+               endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+               return result;
+       }
 
-  if((new_entry = format_new_smbpasswd_entry(newpwd)) == NULL) 
-  {
-       DEBUG(0, ("add_smbfilepwd_entry(malloc): Failed to add entry for user %s to file %s. \
+       if((new_entry = format_new_smbpasswd_entry(newpwd)) == NULL) {
+               DEBUG(0, ("add_smbfilepwd_entry(malloc): Failed to add entry for user %s to file %s. \
 Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
-       endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
-       return False;
-  }
+               endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+               return NT_STATUS_NO_MEMORY;
+       }
 
-  new_entry_length = strlen(new_entry);
+       new_entry_length = strlen(new_entry);
 
 #ifdef DEBUG_PASSWORD
-  DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|", 
-                            fd, new_entry_length, new_entry));
+       DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|", 
+                       fd, (int)new_entry_length, new_entry));
 #endif
 
-  if ((wr_len = write(fd, new_entry, new_entry_length)) != new_entry_length) 
-  {
-       DEBUG(0, ("add_smbfilepwd_entry(write): %d Failed to add entry for user %s to file %s. \
+       if ((wr_len = write(fd, new_entry, new_entry_length)) != new_entry_length) {
+               NTSTATUS result = map_nt_error_from_unix(errno);
+               DEBUG(0, ("add_smbfilepwd_entry(write): %d Failed to add entry for user %s to file %s. \
 Error was %s\n", wr_len, newpwd->smb_name, pfile, strerror(errno)));
 
-       /* Remove the entry we just wrote. */
-       if(sys_ftruncate(fd, offpos) == -1) 
-       {
-               DEBUG(0, ("add_smbfilepwd_entry: ERROR failed to ftruncate file %s. \
+               /* Remove the entry we just wrote. */
+               if(sys_ftruncate(fd, offpos) == -1) {
+                       DEBUG(0, ("add_smbfilepwd_entry: ERROR failed to ftruncate file %s. \
 Error was %s. Password file may be corrupt ! Please examine by hand !\n", 
-               newpwd->smb_name, strerror(errno)));
-       }
+                               newpwd->smb_name, strerror(errno)));
+               }
 
-       endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
-       free(new_entry);
-       return False;
-  }
+               endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+               free(new_entry);
+               return result;
+       }
 
-  free(new_entry);
-  endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
-  return True;
+       free(new_entry);
+       endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+       return NT_STATUS_OK;
 }
 
 /************************************************************************
@@ -675,463 +722,468 @@ Error was %s. Password file may be corrupt ! Please examine by hand !\n",
  override = True, override XXXXXXXX'd out password or NO PASS
 ************************************************************************/
 
-static BOOL mod_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, const struct smb_passwd* pwd)
+static bool mod_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, const struct smb_passwd* pwd)
 {
-  /* Static buffers we will return. */
-       pstring user_name;
-
-  char            linebuf[256];
-  char            readbuf[1024];
-  unsigned char   c;
-  fstring         ascii_p16;
-  fstring         encode_bits;
-  unsigned char  *p = NULL;
-  size_t            linebuf_len = 0;
-  FILE           *fp;
-  int             lockfd;
-  const char     *pfile = smbpasswd_state->smbpasswd_file;
-  BOOL found_entry = False;
-  BOOL got_pass_last_set_time = False;
-
-  SMB_OFF_T pwd_seekpos = 0;
-
-  int i;
-  int wr_len;
-  int fd;
-
-  if (!*pfile) {
-    DEBUG(0, ("No SMB password file set\n"));
-    return False;
-  }
-  DEBUG(10, ("mod_smbfilepwd_entry: opening file %s\n", pfile));
-
-  fp = sys_fopen(pfile, "r+");
-
-  if (fp == NULL) {
-    DEBUG(0, ("mod_smbfilepwd_entry: unable to open file %s\n", pfile));
-    return False;
-  }
-  /* Set a buffer to do more efficient reads */
-  setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
-
-  lockfd = fileno(fp);
-
-  if (!pw_file_lock(lockfd, F_WRLCK, 5, &(smbpasswd_state->pw_file_lock_depth))) {
-    DEBUG(0, ("mod_smbfilepwd_entry: unable to lock file %s\n", pfile));
-    fclose(fp);
-    return False;
-  }
-
-  /* Make sure it is only rw by the owner */
-  chmod(pfile, 0600);
-
-  /* We have a write lock on the file. */
-  /*
-   * Scan the file, a line at a time and check if the name matches.
-   */
-  while (!feof(fp)) {
-    pwd_seekpos = sys_ftell(fp);
-
-    linebuf[0] = '\0';
-
-    fgets(linebuf, sizeof(linebuf), fp);
-    if (ferror(fp)) {
-      pw_file_unlock(lockfd, &(smbpasswd_state->pw_file_lock_depth));
-      fclose(fp);
-      return False;
-    }
-
-    /*
-     * Check if the string is terminated with a newline - if not
-     * then we must keep reading and discard until we get one.
-     */
-    linebuf_len = strlen(linebuf);
-    if (linebuf[linebuf_len - 1] != '\n') {
-      c = '\0';
-      while (!ferror(fp) && !feof(fp)) {
-        c = fgetc(fp);
-        if (c == '\n') {
-          break;
-        }
-      }
-    } else {
-      linebuf[linebuf_len - 1] = '\0';
-    }
+       /* Static buffers we will return. */
+       fstring user_name;
+
+       char *status;
+       char linebuf[256];
+       char readbuf[1024];
+       int c;
+       fstring ascii_p16;
+       fstring encode_bits;
+       unsigned char *p = NULL;
+       size_t linebuf_len = 0;
+       FILE *fp;
+       int lockfd;
+       const char *pfile = smbpasswd_state->smbpasswd_file;
+       bool found_entry = False;
+       bool got_pass_last_set_time = False;
+
+       SMB_OFF_T pwd_seekpos = 0;
+
+       int i;
+       int wr_len;
+       int fd;
+
+       if (!*pfile) {
+               DEBUG(0, ("No SMB password file set\n"));
+               return False;
+       }
+       DEBUG(10, ("mod_smbfilepwd_entry: opening file %s\n", pfile));
+
+       fp = sys_fopen(pfile, "r+");
+
+       if (fp == NULL) {
+               DEBUG(0, ("mod_smbfilepwd_entry: unable to open file %s\n", pfile));
+               return False;
+       }
+       /* Set a buffer to do more efficient reads */
+       setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
+
+       lockfd = fileno(fp);
+
+       if (!pw_file_lock(lockfd, F_WRLCK, 5, &smbpasswd_state->pw_file_lock_depth)) {
+               DEBUG(0, ("mod_smbfilepwd_entry: unable to lock file %s\n", pfile));
+               fclose(fp);
+               return False;
+       }
+
+       /* Make sure it is only rw by the owner */
+       chmod(pfile, 0600);
+
+       /* We have a write lock on the file. */
+       /*
+        * Scan the file, a line at a time and check if the name matches.
+        */
+       status = linebuf;
+       while (status && !feof(fp)) {
+               pwd_seekpos = sys_ftell(fp);
+
+               linebuf[0] = '\0';
+
+               status = fgets(linebuf, sizeof(linebuf), fp);
+               if (status == NULL && ferror(fp)) {
+                       pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
+                       fclose(fp);
+                       return False;
+               }
+
+               /*
+                * Check if the string is terminated with a newline - if not
+                * then we must keep reading and discard until we get one.
+                */
+               linebuf_len = strlen(linebuf);
+               if (linebuf[linebuf_len - 1] != '\n') {
+                       c = '\0';
+                       while (!ferror(fp) && !feof(fp)) {
+                               c = fgetc(fp);
+                               if (c == '\n') {
+                                       break;
+                               }
+                       }
+               } else {
+                       linebuf[linebuf_len - 1] = '\0';
+               }
 
 #ifdef DEBUG_PASSWORD
-    DEBUG(100, ("mod_smbfilepwd_entry: got line |%s|\n", linebuf));
+               DEBUG(100, ("mod_smbfilepwd_entry: got line |%s|\n", linebuf));
 #endif
 
-    if ((linebuf[0] == 0) && feof(fp)) {
-      DEBUG(4, ("mod_smbfilepwd_entry: end of file reached\n"));
-      break;
-    }
-
-    /*
-     * The line we have should be of the form :-
-     * 
-     * username:uid:[32hex bytes]:....other flags presently
-     * ignored....
-     * 
-     * or,
-     *
-     * username:uid:[32hex bytes]:[32hex bytes]:[attributes]:LCT-XXXXXXXX:...ignored.
-     *
-     * if Windows NT compatible passwords are also present.
-     */
-
-    if (linebuf[0] == '#' || linebuf[0] == '\0') {
-      DEBUG(6, ("mod_smbfilepwd_entry: skipping comment or blank line\n"));
-      continue;
-    }
-
-    p = (unsigned char *) strchr_m(linebuf, ':');
-
-    if (p == NULL) {
-      DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no :)\n"));
-      continue;
-    }
-
-    /*
-     * As 256 is shorter than a pstring we don't need to check
-     * length here - if this ever changes....
-     */
-
-    SMB_ASSERT(sizeof(user_name) > sizeof(linebuf));
-
-    strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
-    user_name[PTR_DIFF(p, linebuf)] = '\0';
-    if (strequal(user_name, pwd->smb_name)) {
-      found_entry = True;
-      break;
-    }
-  }
-
-  if (!found_entry) {
-    pw_file_unlock(lockfd, &(smbpasswd_state->pw_file_lock_depth));
-    fclose(fp);
-
-    DEBUG(2, ("Cannot update entry for user %s, as they don't exist in the smbpasswd file!\n",
-             pwd->smb_name));
-    return False;
-  }
-
-  DEBUG(6, ("mod_smbfilepwd_entry: entry exists\n"));
-
-  /* User name matches - get uid and password */
-  p++;         /* Go past ':' */
-
-  if (!isdigit(*p)) {
-    DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (uid not number)\n"));
-    pw_file_unlock(lockfd, &(smbpasswd_state->pw_file_lock_depth));
-    fclose(fp);
-    return False;
-  }
-
-  while (*p && isdigit(*p))
-    p++;
-  if (*p != ':') {
-    DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no : after uid)\n"));
-    pw_file_unlock(lockfd, &(smbpasswd_state->pw_file_lock_depth));
-    fclose(fp);
-    return False;
-  }
-
-  /*
-   * Now get the password value - this should be 32 hex digits
-   * which are the ascii representations of a 16 byte string.
-   * Get two at a time and put them into the password.
-   */
-  p++;
-
-  /* Record exact password position */
-  pwd_seekpos += PTR_DIFF(p, linebuf);
-
-  if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
-    DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
-    pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
-    fclose(fp);
-    return (False);
-  }
-
-  if (p[32] != ':') {
-    DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n"));
-    pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
-    fclose(fp);
-    return False;
-  }
-
-  /* Now check if the NT compatible password is
-     available. */
-  p += 33; /* Move to the first character of the line after
-              the lanman password. */
-  if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
-    DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
-    pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
-    fclose(fp);
-    return (False);
-  }
-
-  if (p[32] != ':') {
-    DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n"));
-    pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
-    fclose(fp);
-    return False;
-  }
-
-  /* 
-   * Now check if the account info and the password last
-   * change time is available.
-   */
-  p += 33; /* Move to the first character of the line after
-              the NT password. */
-
-  if (*p == '[') {
-
-    i = 0;
-    encode_bits[i++] = *p++;
-    while((linebuf_len > PTR_DIFF(p, linebuf)) && (*p != ']'))
-      encode_bits[i++] = *p++;
-
-    encode_bits[i++] = ']';
-    encode_bits[i++] = '\0';
-
-    if(i == NEW_PW_FORMAT_SPACE_PADDED_LEN) {
-      /*
-       * We are using a new format, space padded
-       * acct ctrl field. Encode the given acct ctrl
-       * bits into it.
-       */
-      fstrcpy(encode_bits, pdb_encode_acct_ctrl(pwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN));
-    } else {
-           DEBUG(0,("mod_smbfilepwd_entry:  Using old smbpasswd format.  This is no longer supported.!\n"));
-           DEBUG(0,("mod_smbfilepwd_entry:  No changes made, failing.!\n"));
-           return False;
-    }
-
-    /* Go past the ']' */
-    if(linebuf_len > PTR_DIFF(p, linebuf))
-      p++;
-
-    if((linebuf_len > PTR_DIFF(p, linebuf)) && (*p == ':')) {
-      p++;
-
-      /* We should be pointing at the LCT entry. */
-      if((linebuf_len > (PTR_DIFF(p, linebuf) + 13)) && (StrnCaseCmp((char *)p, "LCT-", 4) == 0)) {
-
-        p += 4;
-        for(i = 0; i < 8; i++) {
-          if(p[i] == '\0' || !isxdigit(p[i]))
-            break;
-        }
-        if(i == 8) {
-          /*
-           * p points at 8 characters of hex digits -
-           * read into a time_t as the seconds since
-           * 1970 that the password was last changed.
-           */
-          got_pass_last_set_time = True;
-        } /* i == 8 */
-      } /* *p && StrnCaseCmp() */
-    } /* p == ':' */
-  } /* p == '[' */
-
-  /* Entry is correctly formed. */
-
-  /* Create the 32 byte representation of the new p16 */
-  pdb_sethexpwd(ascii_p16, pwd->smb_passwd, pwd->acct_ctrl);
-
-  /* Add on the NT md4 hash */
-  ascii_p16[32] = ':';
-  wr_len = 66;
-  pdb_sethexpwd(ascii_p16+33, pwd->smb_nt_passwd, pwd->acct_ctrl);
-  ascii_p16[65] = ':';
-  ascii_p16[66] = '\0'; /* null-terminate the string so that strlen works */
-
-  /* Add on the account info bits and the time of last
-     password change. */
-
-  if(got_pass_last_set_time) {
-    slprintf(&ascii_p16[strlen(ascii_p16)], 
-            sizeof(ascii_p16)-(strlen(ascii_p16)+1),
-            "%s:LCT-%08X:", 
-                     encode_bits, (uint32)pwd->pass_last_set_time );
-    wr_len = strlen(ascii_p16);
-  }
+               if ((linebuf[0] == 0) && feof(fp)) {
+                       DEBUG(4, ("mod_smbfilepwd_entry: end of file reached\n"));
+                       break;
+               }
+
+               /*
+                * The line we have should be of the form :-
+                * 
+                * username:uid:[32hex bytes]:....other flags presently
+                * ignored....
+                * 
+                * or,
+                *
+                * username:uid:[32hex bytes]:[32hex bytes]:[attributes]:LCT-XXXXXXXX:...ignored.
+                *
+                * if Windows NT compatible passwords are also present.
+                */
+
+               if (linebuf[0] == '#' || linebuf[0] == '\0') {
+                       DEBUG(6, ("mod_smbfilepwd_entry: skipping comment or blank line\n"));
+                       continue;
+               }
+
+               p = (unsigned char *) strchr_m(linebuf, ':');
+
+               if (p == NULL) {
+                       DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no :)\n"));
+                       continue;
+               }
+
+               strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
+               user_name[PTR_DIFF(p, linebuf)] = '\0';
+               if (strequal(user_name, pwd->smb_name)) {
+                       found_entry = True;
+                       break;
+               }
+       }
+
+       if (!found_entry) {
+               pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
+               fclose(fp);
+
+               DEBUG(2, ("Cannot update entry for user %s, as they don't exist in the smbpasswd file!\n",
+                       pwd->smb_name));
+               return False;
+       }
+
+       DEBUG(6, ("mod_smbfilepwd_entry: entry exists for user %s\n", pwd->smb_name));
+
+       /* User name matches - get uid and password */
+       p++; /* Go past ':' */
+
+       if (!isdigit(*p)) {
+               DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (uid not number)\n",
+                       pwd->smb_name));
+               pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
+               fclose(fp);
+               return False;
+       }
+
+       while (*p && isdigit(*p)) {
+               p++;
+       }
+       if (*p != ':') {
+               DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no : after uid)\n",
+                       pwd->smb_name));
+               pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
+               fclose(fp);
+               return False;
+       }
+
+       /*
+        * Now get the password value - this should be 32 hex digits
+        * which are the ascii representations of a 16 byte string.
+        * Get two at a time and put them into the password.
+        */
+       p++;
+
+       /* Record exact password position */
+       pwd_seekpos += PTR_DIFF(p, linebuf);
+
+       if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
+               DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (passwd too short)\n",
+                       pwd->smb_name));
+               pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+               fclose(fp);
+               return (False);
+       }
+
+       if (p[32] != ':') {
+               DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no terminating :)\n",
+                       pwd->smb_name));
+               pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+               fclose(fp);
+               return False;
+       }
+
+       /* Now check if the NT compatible password is available. */
+       p += 33; /* Move to the first character of the line after the lanman password. */
+       if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
+               DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (passwd too short)\n",
+                       pwd->smb_name));
+               pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+               fclose(fp);
+               return (False);
+       }
+
+       if (p[32] != ':') {
+               DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no terminating :)\n",
+                       pwd->smb_name));
+               pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+               fclose(fp);
+               return False;
+       }
+
+       /* 
+        * Now check if the account info and the password last
+        * change time is available.
+        */
+       p += 33; /* Move to the first character of the line after the NT password. */
+
+       if (*p == '[') {
+               i = 0;
+               encode_bits[i++] = *p++;
+               while((linebuf_len > PTR_DIFF(p, linebuf)) && (*p != ']')) {
+                       encode_bits[i++] = *p++;
+               }
+
+               encode_bits[i++] = ']';
+               encode_bits[i++] = '\0';
+
+               if(i == NEW_PW_FORMAT_SPACE_PADDED_LEN) {
+                       /*
+                        * We are using a new format, space padded
+                        * acct ctrl field. Encode the given acct ctrl
+                        * bits into it.
+                        */
+                       fstrcpy(encode_bits, pdb_encode_acct_ctrl(pwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN));
+               } else {
+                       DEBUG(0,("mod_smbfilepwd_entry:  Using old smbpasswd format for user %s. \
+This is no longer supported.!\n", pwd->smb_name));
+                       DEBUG(0,("mod_smbfilepwd_entry:  No changes made, failing.!\n"));
+                       pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
+                       fclose(fp);
+                       return False;
+               }
+
+               /* Go past the ']' */
+               if(linebuf_len > PTR_DIFF(p, linebuf)) {
+                       p++;
+               }
+
+               if((linebuf_len > PTR_DIFF(p, linebuf)) && (*p == ':')) {
+                       p++;
+
+                       /* We should be pointing at the LCT entry. */
+                       if((linebuf_len > (PTR_DIFF(p, linebuf) + 13)) && (StrnCaseCmp((char *)p, "LCT-", 4) == 0)) {
+                               p += 4;
+                               for(i = 0; i < 8; i++) {
+                                       if(p[i] == '\0' || !isxdigit(p[i])) {
+                                               break;
+                                       }
+                               }
+                               if(i == 8) {
+                                       /*
+                                        * p points at 8 characters of hex digits -
+                                        * read into a time_t as the seconds since
+                                        * 1970 that the password was last changed.
+                                        */
+                                       got_pass_last_set_time = True;
+                               } /* i == 8 */
+                       } /* *p && StrnCaseCmp() */
+               } /* p == ':' */
+       } /* p == '[' */
+
+       /* Entry is correctly formed. */
+
+       /* Create the 32 byte representation of the new p16 */
+       pdb_sethexpwd(ascii_p16, pwd->smb_passwd, pwd->acct_ctrl);
+
+       /* Add on the NT md4 hash */
+       ascii_p16[32] = ':';
+       wr_len = 66;
+       pdb_sethexpwd(ascii_p16+33, pwd->smb_nt_passwd, pwd->acct_ctrl);
+       ascii_p16[65] = ':';
+       ascii_p16[66] = '\0'; /* null-terminate the string so that strlen works */
+
+       /* Add on the account info bits and the time of last password change. */
+       if(got_pass_last_set_time) {
+               slprintf(&ascii_p16[strlen(ascii_p16)], 
+                       sizeof(ascii_p16)-(strlen(ascii_p16)+1),
+                       "%s:LCT-%08X:", 
+                       encode_bits, (uint32)pwd->pass_last_set_time );
+               wr_len = strlen(ascii_p16);
+       }
 
 #ifdef DEBUG_PASSWORD
-  DEBUG(100,("mod_smbfilepwd_entry: "));
-  dump_data(100, ascii_p16, wr_len);
+       DEBUG(100,("mod_smbfilepwd_entry: "));
+       dump_data(100, (uint8 *)ascii_p16, wr_len);
 #endif
 
-  if(wr_len > sizeof(linebuf)) {
-    DEBUG(0, ("mod_smbfilepwd_entry: line to write (%d) is too long.\n", wr_len+1));
-    pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
-    fclose(fp);
-    return (False);
-  }
-
-  /*
-   * Do an atomic write into the file at the position defined by
-   * seekpos.
-   */
-
-  /* The mod user write needs to be atomic - so get the fd from 
-     the fp and do a raw write() call.
-   */
-
-  fd = fileno(fp);
-
-  if (sys_lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1) {
-    DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
-    pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
-    fclose(fp);
-    return False;
-  }
-
-  /* Sanity check - ensure the areas we are writing are framed by ':' */
-  if (read(fd, linebuf, wr_len+1) != wr_len+1) {
-    DEBUG(0, ("mod_smbfilepwd_entry: read fail on file %s.\n", pfile));
-    pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
-    fclose(fp);
-    return False;
-  }
-
-  if ((linebuf[0] != ':') || (linebuf[wr_len] != ':')) {
-    DEBUG(0, ("mod_smbfilepwd_entry: check on passwd file %s failed.\n", pfile));
-    pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
-    fclose(fp);
-    return False;
-  }
+       if(wr_len > sizeof(linebuf)) {
+               DEBUG(0, ("mod_smbfilepwd_entry: line to write (%d) is too long.\n", wr_len+1));
+               pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+               fclose(fp);
+               return (False);
+       }
+
+       /*
+        * Do an atomic write into the file at the position defined by
+        * seekpos.
+        */
+
+       /* The mod user write needs to be atomic - so get the fd from 
+               the fp and do a raw write() call.
+        */
+
+       fd = fileno(fp);
+
+       if (sys_lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1) {
+               DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
+               pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+               fclose(fp);
+               return False;
+       }
+
+       /* Sanity check - ensure the areas we are writing are framed by ':' */
+       if (read(fd, linebuf, wr_len+1) != wr_len+1) {
+               DEBUG(0, ("mod_smbfilepwd_entry: read fail on file %s.\n", pfile));
+               pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+               fclose(fp);
+               return False;
+       }
+
+       if ((linebuf[0] != ':') || (linebuf[wr_len] != ':'))    {
+               DEBUG(0, ("mod_smbfilepwd_entry: check on passwd file %s failed.\n", pfile));
+               pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+               fclose(fp);
+               return False;
+       }
  
-  if (sys_lseek(fd, pwd_seekpos, SEEK_SET) != pwd_seekpos) {
-    DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
-    pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
-    fclose(fp);
-    return False;
-  }
-
-  if (write(fd, ascii_p16, wr_len) != wr_len) {
-    DEBUG(0, ("mod_smbfilepwd_entry: write failed in passwd file %s\n", pfile));
-    pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
-    fclose(fp);
-    return False;
-  }
-
-  pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
-  fclose(fp);
-  return True;
+       if (sys_lseek(fd, pwd_seekpos, SEEK_SET) != pwd_seekpos) {
+               DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
+               pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+               fclose(fp);
+               return False;
+       }
+
+       if (write(fd, ascii_p16, wr_len) != wr_len) {
+               DEBUG(0, ("mod_smbfilepwd_entry: write failed in passwd file %s\n", pfile));
+               pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+               fclose(fp);
+               return False;
+       }
+
+       pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
+       fclose(fp);
+       return True;
 }
 
 /************************************************************************
  Routine to delete an entry in the smbpasswd file by name.
 *************************************************************************/
 
-static BOOL del_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, const char *name)
+static bool del_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, const char *name)
 {
        const char *pfile = smbpasswd_state->smbpasswd_file;
-  pstring pfile2;
-  struct smb_passwd *pwd = NULL;
-  FILE *fp = NULL;
-  FILE *fp_write = NULL;
-  int pfile2_lockdepth = 0;
-
-  slprintf(pfile2, sizeof(pfile2)-1, "%s.%u", pfile, (unsigned)sys_getpid() );
-
-  /*
-   * Open the smbpassword file - for update. It needs to be update
-   * as we need any other processes to wait until we have replaced
-   * it.
-   */
-
-  if((fp = startsmbfilepwent(pfile, PWF_UPDATE, &(smbpasswd_state->pw_file_lock_depth))) == NULL) {
-    DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
-    return False;
-  }
-
-  /*
-   * Create the replacement password file.
-   */
-  if((fp_write = startsmbfilepwent(pfile2, PWF_CREATE, &pfile2_lockdepth)) == NULL) {
-    DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
-    endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
-    return False;
-  }
-
-  /*
-   * Scan the file, a line at a time and check if the name matches.
-   */
-
-  while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) {
-    char *new_entry;
-    size_t new_entry_length;
-
-    if (strequal(name, pwd->smb_name)) {
-      DEBUG(10, ("add_smbfilepwd_entry: found entry with name %s - deleting it.\n", name));
-      continue;
-    }
-
-    /*
-     * We need to copy the entry out into the second file.
-     */
-
-    if((new_entry = format_new_smbpasswd_entry(pwd)) == NULL) 
-    {
-       DEBUG(0, ("del_smbfilepwd_entry(malloc): Failed to copy entry for user %s to file %s. \
+       char *pfile2 = NULL;
+       struct smb_passwd *pwd = NULL;
+       FILE *fp = NULL;
+       FILE *fp_write = NULL;
+       int pfile2_lockdepth = 0;
+
+       pfile2 = talloc_asprintf(talloc_tos(),
+                       "%s.%u",
+                       pfile, (unsigned)sys_getpid());
+       if (!pfile2) {
+               return false;
+       }
+
+       /*
+        * Open the smbpassword file - for update. It needs to be update
+        * as we need any other processes to wait until we have replaced
+        * it.
+        */
+
+       if((fp = startsmbfilepwent(pfile, PWF_UPDATE, &smbpasswd_state->pw_file_lock_depth)) == NULL) {
+               DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
+               return False;
+       }
+
+       /*
+        * Create the replacement password file.
+        */
+       if((fp_write = startsmbfilepwent(pfile2, PWF_CREATE, &pfile2_lockdepth)) == NULL) {
+               DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
+               endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+               return False;
+       }
+
+       /*
+        * Scan the file, a line at a time and check if the name matches.
+        */
+
+       while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) {
+               char *new_entry;
+               size_t new_entry_length;
+
+               if (strequal(name, pwd->smb_name)) {
+                       DEBUG(10, ("del_smbfilepwd_entry: found entry with "
+                                  "name %s - deleting it.\n", name));
+                       continue;
+               }
+
+               /*
+                * We need to copy the entry out into the second file.
+                */
+
+               if((new_entry = format_new_smbpasswd_entry(pwd)) == NULL) {
+                       DEBUG(0, ("del_smbfilepwd_entry(malloc): Failed to copy entry for user %s to file %s. \
 Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
-       unlink(pfile2);
-       endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
-       endsmbfilepwent(fp_write, &pfile2_lockdepth);
-       return False;
-    }
+                       unlink(pfile2);
+                       endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+                       endsmbfilepwent(fp_write, &pfile2_lockdepth);
+                       return False;
+               }
 
-    new_entry_length = strlen(new_entry);
+               new_entry_length = strlen(new_entry);
 
-    if(fwrite(new_entry, 1, new_entry_length, fp_write) != new_entry_length) 
-    {
-       DEBUG(0, ("del_smbfilepwd_entry(write): Failed to copy entry for user %s to file %s. \
+               if(fwrite(new_entry, 1, new_entry_length, fp_write) != new_entry_length) {
+                       DEBUG(0, ("del_smbfilepwd_entry(write): Failed to copy entry for user %s to file %s. \
 Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
-       unlink(pfile2);
-       endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
-       endsmbfilepwent(fp_write, &pfile2_lockdepth);
-       free(new_entry);
-       return False;
-    }
+                       unlink(pfile2);
+                       endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+                       endsmbfilepwent(fp_write, &pfile2_lockdepth);
+                       free(new_entry);
+                       return False;
+               }
+
+               free(new_entry);
+       }
 
-    free(new_entry);
-  }
+       /*
+        * Ensure pfile2 is flushed before rename.
+        */
 
-  /*
-   * Ensure pfile2 is flushed before rename.
-   */
+       if(fflush(fp_write) != 0) {
+               DEBUG(0, ("del_smbfilepwd_entry: Failed to flush file %s. Error was %s\n", pfile2, strerror(errno)));
+               endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
+               endsmbfilepwent(fp_write,&pfile2_lockdepth);
+               return False;
+       }
 
-  if(fflush(fp_write) != 0) 
-  {
-       DEBUG(0, ("del_smbfilepwd_entry: Failed to flush file %s. Error was %s\n", pfile2, strerror(errno)));
-       endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+       /*
+        * Do an atomic rename - then release the locks.
+        */
+
+       if(rename(pfile2,pfile) != 0) {
+               unlink(pfile2);
+       }
+
+       endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
        endsmbfilepwent(fp_write,&pfile2_lockdepth);
-       return False;
-  }
-
-  /*
-   * Do an atomic rename - then release the locks.
-   */
-
-  if(rename(pfile2,pfile) != 0) {
-    unlink(pfile2);
-  }
-  
-  endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
-  endsmbfilepwent(fp_write,&pfile2_lockdepth);
-  return True;
+       return True;
 }
 
 /*********************************************************************
- Create a smb_passwd struct from a SAM_ACCOUNT.
+ Create a smb_passwd struct from a struct samu.
  We will not allocate any new memory.  The smb_passwd struct
- should only stay around as long as the SAM_ACCOUNT does.
+ should only stay around as long as the struct samu does.
  ********************************************************************/
-static BOOL build_smb_pass (struct smb_passwd *smb_pw, const SAM_ACCOUNT *sampass)
+
+static bool build_smb_pass (struct smb_passwd *smb_pw, const struct samu *sampass)
 {
        uint32 rid;
 
@@ -1141,21 +1193,18 @@ static BOOL build_smb_pass (struct smb_passwd *smb_pw, const SAM_ACCOUNT *sampas
 
        if (!IS_SAM_DEFAULT(sampass, PDB_USERSID)) {
                rid = pdb_get_user_rid(sampass);
-               
+
                /* If the user specified a RID, make sure its able to be both stored and retreived */
                if (rid == DOMAIN_USER_RID_GUEST) {
-                       struct passwd *passwd = getpwnam_alloc(lp_guestaccount());
+                       struct passwd *passwd = getpwnam_alloc(NULL, lp_guestaccount());
                        if (!passwd) {
-                               DEBUG(0, ("Could not find gest account via getpwnam()! (%s)\n", lp_guestaccount()));
+                               DEBUG(0, ("Could not find guest account via getpwnam()! (%s)\n", lp_guestaccount()));
                                return False;
                        }
-                       smb_pw->smb_userid_set = True;
                        smb_pw->smb_userid=passwd->pw_uid;
-                       passwd_free(&passwd);
-
-               } else if (fallback_pdb_rid_is_user(rid)) {
-                       smb_pw->smb_userid_set = True;
-                       smb_pw->smb_userid=fallback_pdb_user_rid_to_uid(rid);
+                       TALLOC_FREE(passwd);
+               } else if (algorithmic_pdb_rid_is_user(rid)) {
+                       smb_pw->smb_userid=algorithmic_pdb_user_rid_to_uid(rid);
                } else {
                        DEBUG(0,("build_sam_pass: Failing attempt to store user with non-uid based user RID. \n"));
                        return False;
@@ -1170,179 +1219,66 @@ static BOOL build_smb_pass (struct smb_passwd *smb_pw, const SAM_ACCOUNT *sampas
        smb_pw->acct_ctrl=pdb_get_acct_ctrl(sampass);
        smb_pw->pass_last_set_time=pdb_get_pass_last_set_time(sampass);
 
-#if 0
-       /*
-        * ifdef'out by JFM on 11/29/2001.
-        * this assertion is no longer valid
-        * and I don't understand the goal 
-        * and doing the same thing with the group mapping code
-        * is hairy !
-        *
-        * We just have the RID, in which SID is it valid ?
-        * our domain SID ? well known SID ? local SID ?
-        */
-
-       if (gid != pdb_group_rid_to_gid(pdb_get_group_rid(sampass))) {
-               DEBUG(0,("build_sam_pass: Failing attempt to store user with non-gid based primary group RID. \n"));
-               DEBUG(0,("build_sam_pass: %d %d %d. \n", *gid, pdb_group_rid_to_gid(pdb_get_group_rid(sampass)), pdb_get_group_rid(sampass)));
-               return False;
-       }
-#endif
-
        return True;
 }      
 
 /*********************************************************************
- Create a SAM_ACCOUNT from a smb_passwd struct
+ Create a struct samu from a smb_passwd struct
  ********************************************************************/
-static BOOL build_sam_account(struct smbpasswd_privates *smbpasswd_state, 
-                             SAM_ACCOUNT *sam_pass, const struct smb_passwd *pw_buf)
+
+static bool build_sam_account(struct smbpasswd_privates *smbpasswd_state, 
+                             struct samu *sam_pass, const struct smb_passwd *pw_buf)
 {
        struct passwd *pwfile;
-       
-       if (sam_pass==NULL) {
-               DEBUG(5,("build_sam_account: SAM_ACCOUNT is NULL\n"));
+
+       if ( !sam_pass ) {
+               DEBUG(5,("build_sam_account: struct samu is NULL\n"));
                return False;
        }
-               
-       pwfile = getpwnam_alloc(pw_buf->smb_name);
-       if (pwfile == NULL) {
-               if ((smbpasswd_state->permit_non_unix_accounts) 
-                   && (pw_buf->smb_userid >= smbpasswd_state->low_nua_userid) 
-                   && (pw_buf->smb_userid <= smbpasswd_state->high_nua_userid)) {
-
-                       pdb_set_user_sid_from_rid(sam_pass, fallback_pdb_uid_to_user_rid (pw_buf->smb_userid), PDB_SET);
-                       
-                       /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. 
-                          
-                       This was down the bottom for machines, but it looks pretty good as
-                       a general default for non-unix users. --abartlet 2002-01-08
-                       */
-                       pdb_set_group_sid_from_rid (sam_pass, DOMAIN_GROUP_RID_USERS, PDB_SET); 
-                       pdb_set_username (sam_pass, pw_buf->smb_name, PDB_SET);
-                       pdb_set_domain (sam_pass, get_global_sam_name(), PDB_DEFAULT);
-                       
-               } else {
-                       DEBUG(0,("build_sam_account: smbpasswd database is corrupt!  username %s with uid %u is not in unix passwd database!\n", pw_buf->smb_name, pw_buf->smb_userid));
-                       return False;
-               }
-       } else {
-               if (!NT_STATUS_IS_OK(pdb_fill_sam_pw(sam_pass, pwfile))) {
+
+       /* verify the user account exists */
+
+       if ( !(pwfile = Get_Pwnam_alloc(NULL, pw_buf->smb_name )) ) {
+               DEBUG(0,("build_sam_account: smbpasswd database is corrupt!  username %s with uid "
+               "%u is not in unix passwd database!\n", pw_buf->smb_name, pw_buf->smb_userid));
                        return False;
-               }
-               
-               passwd_free(&pwfile);
        }
-       
-       pdb_set_nt_passwd (sam_pass, pw_buf->smb_nt_passwd, PDB_SET);
-       pdb_set_lanman_passwd (sam_pass, pw_buf->smb_passwd, PDB_SET);                  
+
+       if ( !NT_STATUS_IS_OK( samu_set_unix(sam_pass, pwfile )) )
+               return False;
+
+       TALLOC_FREE(pwfile);
+
+       /* set remaining fields */
+
+       if (!pdb_set_nt_passwd (sam_pass, pw_buf->smb_nt_passwd, PDB_SET))
+               return False;
+       if (!pdb_set_lanman_passwd (sam_pass, pw_buf->smb_passwd, PDB_SET))
+               return False;
        pdb_set_acct_ctrl (sam_pass, pw_buf->acct_ctrl, PDB_SET);
        pdb_set_pass_last_set_time (sam_pass, pw_buf->pass_last_set_time, PDB_SET);
        pdb_set_pass_can_change_time (sam_pass, pw_buf->pass_last_set_time, PDB_SET);
-       
-#if 0  /* JERRY */
-       /* the smbpasswd format doesn't have a must change time field, so
-          we can't get this right. The best we can do is to set this to 
-          some time in the future. 21 days seems as reasonable as any other value :) 
-       */
-       pdb_set_pass_must_change_time (sam_pass, pw_buf->pass_last_set_time + MAX_PASSWORD_AGE, PDB_DEFAULT);
-#endif
+
        return True;
 }
 
 /*****************************************************************
  Functions to be implemented by the new passdb API 
  ****************************************************************/
-static NTSTATUS smbpasswd_setsampwent (struct pdb_methods *my_methods, BOOL update)
-{
-       struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
-       
-       smbpasswd_state->pw_file = startsmbfilepwent(smbpasswd_state->smbpasswd_file, 
-                                                      update ? PWF_UPDATE : PWF_READ, 
-                                                      &(smbpasswd_state->pw_file_lock_depth));
-                                  
-       /* did we fail?  Should we try to create it? */
-       if (!smbpasswd_state->pw_file && update && errno == ENOENT) 
-       {
-               FILE *fp;
-               /* slprintf(msg_str,msg_str_len-1,
-                  "smbpasswd file did not exist - attempting to create it.\n"); */
-               DEBUG(0,("smbpasswd file did not exist - attempting to create it.\n"));
-               fp = sys_fopen(smbpasswd_state->smbpasswd_file, "w");
-               if (fp) 
-               {
-                       fprintf(fp, "# Samba SMB password file\n");
-                       fclose(fp);
-               }
-               
-               smbpasswd_state->pw_file = startsmbfilepwent(smbpasswd_state->smbpasswd_file, 
-                                                            update ? PWF_UPDATE : PWF_READ, 
-                                                            &(smbpasswd_state->pw_file_lock_depth));
-       }
-       
-       if (smbpasswd_state->pw_file != NULL)
-               return NT_STATUS_OK;
-       else
-               return NT_STATUS_UNSUCCESSFUL;  
-}
-
-static void smbpasswd_endsampwent (struct pdb_methods *my_methods)
-{
-       struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
-       endsmbfilepwent(smbpasswd_state->pw_file, &(smbpasswd_state->pw_file_lock_depth));
-}
-/*****************************************************************
- ****************************************************************/
-static NTSTATUS smbpasswd_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT *user)
-{
-       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
-       struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
-       struct smb_passwd *pw_buf=NULL;
-       BOOL done = False;
-       DEBUG(5,("pdb_getsampwent\n"));
-
-       if (user==NULL) {
-               DEBUG(5,("pdb_getsampwent (smbpasswd): user is NULL\n"));
-#if 0
-               smb_panic("NULL pointer passed to getsampwent (smbpasswd)\n");
-#endif
-               return nt_status;
-       }
-
-       while (!done)
-       {
-               /* do we have an entry? */
-               pw_buf = getsmbfilepwent(smbpasswd_state, smbpasswd_state->pw_file);
-               if (pw_buf == NULL) 
-                       return nt_status;
-
-               /* build the SAM_ACCOUNT entry from the smb_passwd struct. 
-                  We loop in case the user in the pdb does not exist in 
-                  the local system password file */
-               if (build_sam_account(smbpasswd_state, user, pw_buf))
-                       done = True;
-       }
-
-       DEBUG(5,("getsampwent (smbpasswd): done\n"));
-
-       /* success */
-       return NT_STATUS_OK;
-}
-
 
 /****************************************************************
  Search smbpasswd file by iterating over the entries.  Do not
  call getpwnam() for unix account information until we have found
  the correct entry
  ***************************************************************/
+
 static NTSTATUS smbpasswd_getsampwnam(struct pdb_methods *my_methods, 
-                                 SAM_ACCOUNT *sam_acct, const char *username)
+                                 struct samu *sam_acct, const char *username)
 {
        NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
        struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
        struct smb_passwd *smb_pw;
-       void *fp = NULL;
+       FILE *fp = NULL;
 
        DEBUG(10, ("getsampwnam (smbpasswd): search by name: %s\n", username));
 
@@ -1358,25 +1294,22 @@ static NTSTATUS smbpasswd_getsampwnam(struct pdb_methods *my_methods,
 
        while ( ((smb_pw=getsmbfilepwent(smbpasswd_state, fp)) != NULL)&& (!strequal(smb_pw->smb_name, username)) )
                /* do nothing....another loop */ ;
-       
+
        endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
 
 
        /* did we locate the username in smbpasswd  */
        if (smb_pw == NULL)
                return nt_status;
-       
+
        DEBUG(10, ("getsampwnam (smbpasswd): found by name: %s\n", smb_pw->smb_name));
 
        if (!sam_acct) {
-               DEBUG(10,("getsampwnam (smbpasswd): SAM_ACCOUNT is NULL\n"));
-#if 0
-               smb_panic("NULL pointer passed to pdb_getsampwnam\n");
-#endif
+               DEBUG(10,("getsampwnam (smbpasswd): struct samu is NULL\n"));
                return nt_status;
        }
-               
-       /* now build the SAM_ACCOUNT */
+
+       /* now build the struct samu */
        if (!build_sam_account(smbpasswd_state, sam_acct, smb_pw))
                return nt_status;
 
@@ -1384,16 +1317,16 @@ static NTSTATUS smbpasswd_getsampwnam(struct pdb_methods *my_methods,
        return NT_STATUS_OK;
 }
 
-static NTSTATUS smbpasswd_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT *sam_acct, const DOM_SID *sid)
+static NTSTATUS smbpasswd_getsampwsid(struct pdb_methods *my_methods, struct samu *sam_acct, const DOM_SID *sid)
 {
        NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
        struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
        struct smb_passwd *smb_pw;
-       void *fp = NULL;
-       fstring sid_str;
+       FILE *fp = NULL;
        uint32 rid;
-       
-       DEBUG(10, ("smbpasswd_getsampwrid: search by sid: %s\n", sid_to_string(sid_str, sid)));
+
+       DEBUG(10, ("smbpasswd_getsampwrid: search by sid: %s\n",
+                  sid_string_dbg(sid)));
 
        if (!sid_peek_check_rid(get_global_sam_sid(), sid, &rid))
                return NT_STATUS_UNSUCCESSFUL;
@@ -1416,7 +1349,7 @@ static NTSTATUS smbpasswd_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUN
                return nt_status;
        }
 
-       while ( ((smb_pw=getsmbfilepwent(smbpasswd_state, fp)) != NULL) && (fallback_pdb_uid_to_user_rid(smb_pw->smb_userid) != rid) )
+       while ( ((smb_pw=getsmbfilepwent(smbpasswd_state, fp)) != NULL) && (algorithmic_pdb_uid_to_user_rid(smb_pw->smb_userid) != rid) )
                /* do nothing */ ;
 
        endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
@@ -1425,26 +1358,24 @@ static NTSTATUS smbpasswd_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUN
        /* did we locate the username in smbpasswd  */
        if (smb_pw == NULL)
                return nt_status;
-       
+
        DEBUG(10, ("getsampwrid (smbpasswd): found by name: %s\n", smb_pw->smb_name));
-               
+
        if (!sam_acct) {
-               DEBUG(10,("getsampwrid: (smbpasswd) SAM_ACCOUNT is NULL\n"));
-#if 0
-               smb_panic("NULL pointer passed to pdb_getsampwrid\n");
-#endif
+               DEBUG(10,("getsampwrid: (smbpasswd) struct samu is NULL\n"));
                return nt_status;
        }
 
-       /* now build the SAM_ACCOUNT */
+       /* now build the struct samu */
        if (!build_sam_account (smbpasswd_state, sam_acct, smb_pw))
                return nt_status;
 
        /* build_sam_account might change the SID on us, if the name was for the guest account */
        if (NT_STATUS_IS_OK(nt_status) && !sid_equal(pdb_get_user_sid(sam_acct), sid)) {
-               fstring sid_string1, sid_string2;
-               DEBUG(1, ("looking for user with sid %s instead returned %s for account %s!?!\n",
-                         sid_to_string(sid_string1, sid), sid_to_string(sid_string2, pdb_get_user_sid(sam_acct)), pdb_get_username(sam_acct)));
+               DEBUG(1, ("looking for user with sid %s instead returned %s "
+                         "for account %s!?!\n", sid_string_dbg(sid),
+                         sid_string_dbg(pdb_get_user_sid(sam_acct)),
+                         pdb_get_username(sam_acct)));
                return NT_STATUS_NO_SUCH_USER;
        }
 
@@ -1452,45 +1383,41 @@ static NTSTATUS smbpasswd_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUN
        return NT_STATUS_OK;
 }
 
-static NTSTATUS smbpasswd_add_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT *sampass)
+static NTSTATUS smbpasswd_add_sam_account(struct pdb_methods *my_methods, struct samu *sampass)
 {
        struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
        struct smb_passwd smb_pw;
-       
-       /* convert the SAM_ACCOUNT */
+
+       /* convert the struct samu */
        if (!build_smb_pass(&smb_pw, sampass)) {
                return NT_STATUS_UNSUCCESSFUL;
        }
-       
+
        /* add the entry */
-       if(!add_smbfilepwd_entry(smbpasswd_state, &smb_pw)) {
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-       
-       return NT_STATUS_OK;
+       return add_smbfilepwd_entry(smbpasswd_state, &smb_pw);
 }
 
-static NTSTATUS smbpasswd_update_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT *sampass)
+static NTSTATUS smbpasswd_update_sam_account(struct pdb_methods *my_methods, struct samu *sampass)
 {
        struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
        struct smb_passwd smb_pw;
-       
-       /* convert the SAM_ACCOUNT */
+
+       /* convert the struct samu */
        if (!build_smb_pass(&smb_pw, sampass)) {
                DEBUG(0, ("smbpasswd_update_sam_account: build_smb_pass failed!\n"));
                return NT_STATUS_UNSUCCESSFUL;
        }
-       
+
        /* update the entry */
        if(!mod_smbfilepwd_entry(smbpasswd_state, &smb_pw)) {
                DEBUG(0, ("smbpasswd_update_sam_account: mod_smbfilepwd_entry failed!\n"));
                return NT_STATUS_UNSUCCESSFUL;
        }
-       
+
        return NT_STATUS_OK;
 }
 
-static NTSTATUS smbpasswd_delete_sam_account (struct pdb_methods *my_methods, SAM_ACCOUNT *sampass)
+static NTSTATUS smbpasswd_delete_sam_account (struct pdb_methods *my_methods, struct samu *sampass)
 {
        struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
 
@@ -1502,41 +1429,264 @@ static NTSTATUS smbpasswd_delete_sam_account (struct pdb_methods *my_methods, SA
        return NT_STATUS_UNSUCCESSFUL;
 }
 
+static NTSTATUS smbpasswd_rename_sam_account (struct pdb_methods *my_methods, 
+                                             struct samu *old_acct,
+                                             const char *newname)
+{
+       char *rename_script = NULL;
+       struct samu *new_acct = NULL;
+       bool interim_account = False;
+       TALLOC_CTX *ctx = talloc_tos();
+       NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+       if (!*(lp_renameuser_script()))
+               goto done;
+
+       if ( !(new_acct = samu_new( NULL )) ) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if ( !pdb_copy_sam_account( new_acct, old_acct ) 
+               || !pdb_set_username(new_acct, newname, PDB_CHANGED)) 
+       {
+               goto done;
+       }
+
+       ret = smbpasswd_add_sam_account(my_methods, new_acct);
+       if (!NT_STATUS_IS_OK(ret))
+               goto done;
+
+       interim_account = True;
+
+       /* rename the posix user */
+       rename_script = talloc_strdup(ctx,
+                               lp_renameuser_script());
+       if (!rename_script) {
+               ret = NT_STATUS_NO_MEMORY;
+               goto done;
+       }
+
+       if (*rename_script) {
+               int rename_ret;
+
+               rename_script = talloc_string_sub2(ctx,
+                                       rename_script,
+                                       "%unew",
+                                       newname,
+                                       true,
+                                       false,
+                                       true);
+               if (!rename_script) {
+                       ret = NT_STATUS_NO_MEMORY;
+                       goto done;
+               }
+               rename_script = talloc_string_sub2(ctx,
+                                       rename_script,
+                                       "%uold",
+                                       pdb_get_username(old_acct),
+                                       true,
+                                       false,
+                                       true);
+               if (!rename_script) {
+                       ret = NT_STATUS_NO_MEMORY;
+                       goto done;
+               }
+
+               rename_ret = smbrun(rename_script, NULL);
+
+               DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n", rename_script, rename_ret));
+
+               if (rename_ret == 0) {
+                       smb_nscd_flush_user_cache();
+               }
+
+               if (rename_ret)
+                       goto done;
+        } else {
+               goto done;
+       }
+
+       smbpasswd_delete_sam_account(my_methods, old_acct);
+       interim_account = False;
+
+done:
+       /* cleanup */
+       if (interim_account)
+               smbpasswd_delete_sam_account(my_methods, new_acct);
+
+       if (new_acct)
+               TALLOC_FREE(new_acct);
+
+       return (ret);   
+}
+
+static uint32_t smbpasswd_capabilities(struct pdb_methods *methods)
+{
+       return 0;
+}
+
 static void free_private_data(void **vp) 
 {
        struct smbpasswd_privates **privates = (struct smbpasswd_privates**)vp;
-       
+
        endsmbfilepwent((*privates)->pw_file, &((*privates)->pw_file_lock_depth));
-       
+
        *privates = NULL;
        /* No need to free any further, as it is talloc()ed */
 }
 
-static NTSTATUS pdb_init_smbpasswd(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
+struct smbpasswd_search_state {
+       uint32_t acct_flags;
+
+       struct samr_displayentry *entries;
+       uint32_t num_entries;
+       ssize_t array_size;
+       uint32_t current;
+};
+
+static void smbpasswd_search_end(struct pdb_search *search)
+{
+       struct smbpasswd_search_state *state = talloc_get_type_abort(
+               search->private_data, struct smbpasswd_search_state);
+       TALLOC_FREE(state);
+}
+
+static bool smbpasswd_search_next_entry(struct pdb_search *search,
+                                       struct samr_displayentry *entry)
+{
+       struct smbpasswd_search_state *state = talloc_get_type_abort(
+               search->private_data, struct smbpasswd_search_state);
+
+       if (state->current == state->num_entries) {
+               return false;
+       }
+
+       entry->idx = state->entries[state->current].idx;
+       entry->rid = state->entries[state->current].rid;
+       entry->acct_flags = state->entries[state->current].acct_flags;
+
+       entry->account_name = talloc_strdup(
+               search, state->entries[state->current].account_name);
+       entry->fullname = talloc_strdup(
+               search, state->entries[state->current].fullname);
+       entry->description = talloc_strdup(
+               search, state->entries[state->current].description);
+
+       if ((entry->account_name == NULL) || (entry->fullname == NULL)
+           || (entry->description == NULL)) {
+               DEBUG(0, ("talloc_strdup failed\n"));
+               return false;
+       }
+
+       state->current += 1;
+       return true;
+}
+
+static bool smbpasswd_search_users(struct pdb_methods *methods,
+                                  struct pdb_search *search,
+                                  uint32_t acct_flags)
+{
+       struct smbpasswd_privates *smbpasswd_state =
+               (struct smbpasswd_privates*)methods->private_data;
+
+       struct smbpasswd_search_state *search_state;
+       struct smb_passwd *pwd;
+       FILE *fp;
+
+       search_state = talloc_zero(search, struct smbpasswd_search_state);
+       if (search_state == NULL) {
+               DEBUG(0, ("talloc failed\n"));
+               return false;
+       }
+       search_state->acct_flags = acct_flags;
+
+       fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ,
+                              &smbpasswd_state->pw_file_lock_depth);
+
+       if (fp == NULL) {
+               DEBUG(10, ("Unable to open smbpasswd file.\n"));
+               TALLOC_FREE(search_state);
+               return false;
+       }
+
+       while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) {
+               struct samr_displayentry entry;
+               struct samu *user;
+
+               if ((acct_flags != 0)
+                   && ((acct_flags & pwd->acct_ctrl) == 0)) {
+                       continue;
+               }
+
+               user = samu_new(talloc_tos());
+               if (user == NULL) {
+                       DEBUG(0, ("samu_new failed\n"));
+                       break;
+               }
+
+               if (!build_sam_account(smbpasswd_state, user, pwd)) {
+                       /* Already got debug msgs... */
+                       break;
+               }
+
+               ZERO_STRUCT(entry);
+
+               entry.acct_flags = pdb_get_acct_ctrl(user);
+               sid_peek_rid(pdb_get_user_sid(user), &entry.rid);
+               entry.account_name = talloc_strdup(
+                       search_state, pdb_get_username(user));
+               entry.fullname = talloc_strdup(
+                       search_state, pdb_get_fullname(user));
+               entry.description = talloc_strdup(
+                       search_state, pdb_get_acct_desc(user));
+
+               TALLOC_FREE(user);
+
+               if ((entry.account_name == NULL) || (entry.fullname == NULL)
+                   || (entry.description == NULL)) {
+                       DEBUG(0, ("talloc_strdup failed\n"));
+                       break;
+               }
+
+               ADD_TO_LARGE_ARRAY(search_state, struct samr_displayentry,
+                                  entry, &search_state->entries,
+                                  &search_state->num_entries,
+                                  &search_state->array_size);
+       }
+
+       endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
+
+       search->private_data = search_state;
+       search->next_entry = smbpasswd_search_next_entry;
+       search->search_end = smbpasswd_search_end;
+
+       return true;
+}
+
+static NTSTATUS pdb_init_smbpasswd( struct pdb_methods **pdb_method, const char *location )
 {
        NTSTATUS nt_status;
        struct smbpasswd_privates *privates;
 
-       if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
+       if ( !NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method )) ) {
                return nt_status;
        }
 
        (*pdb_method)->name = "smbpasswd";
 
-       (*pdb_method)->setsampwent = smbpasswd_setsampwent;
-       (*pdb_method)->endsampwent = smbpasswd_endsampwent;
-       (*pdb_method)->getsampwent = smbpasswd_getsampwent;
        (*pdb_method)->getsampwnam = smbpasswd_getsampwnam;
        (*pdb_method)->getsampwsid = smbpasswd_getsampwsid;
        (*pdb_method)->add_sam_account = smbpasswd_add_sam_account;
        (*pdb_method)->update_sam_account = smbpasswd_update_sam_account;
        (*pdb_method)->delete_sam_account = smbpasswd_delete_sam_account;
+       (*pdb_method)->rename_sam_account = smbpasswd_rename_sam_account;
+       (*pdb_method)->search_users = smbpasswd_search_users;
 
-       /* Setup private data and free function */
+       (*pdb_method)->capabilities = smbpasswd_capabilities;
 
-       privates = talloc_zero(pdb_context->mem_ctx, sizeof(struct smbpasswd_privates));
+       /* Setup private data and free function */
 
-       if (!privates) {
+       if ( !(privates = TALLOC_ZERO_P( *pdb_method, struct smbpasswd_privates )) ) {
                DEBUG(0, ("talloc() failed for smbpasswd private_data!\n"));
                return NT_STATUS_NO_MEMORY;
        }
@@ -1544,11 +1694,11 @@ static NTSTATUS pdb_init_smbpasswd(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_m
        /* Store some config details */
 
        if (location) {
-               privates->smbpasswd_file = talloc_strdup(pdb_context->mem_ctx, location);
+               privates->smbpasswd_file = talloc_strdup(*pdb_method, location);
        } else {
-               privates->smbpasswd_file = talloc_strdup(pdb_context->mem_ctx, lp_smb_passwd_file());
+               privates->smbpasswd_file = talloc_strdup(*pdb_method, lp_smb_passwd_file());
        }
-       
+
        if (!privates->smbpasswd_file) {
                DEBUG(0, ("talloc_strdp() failed for storing smbpasswd location!\n"));
                return NT_STATUS_NO_MEMORY;
@@ -1558,11 +1708,6 @@ static NTSTATUS pdb_init_smbpasswd(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_m
 
        (*pdb_method)->free_private_data = free_private_data;
 
-       if (lp_idmap_uid(&privates->low_nua_userid, &privates->high_nua_userid)) {
-               DEBUG(3, ("idmap uid range defined, non unix accounts enabled\n"));
-               privates->permit_non_unix_accounts = True;
-       }
-
        return NT_STATUS_OK;
 }