Changes from APPLIANCE_HEAD:
[ira/wip.git] / source3 / passdb / smbpassfile.c
index 0165d76488e2099d43f6a5b1ab3956826a25e711..f995d8fd4b668a468b1f19831f9f5618319f4c10 100644 (file)
  * Mass Ave, Cambridge, MA 02139, USA.
  */
 
+/*
+ * This file also contains migration code to move from an old
+ * trust account password file stored in the file :
+ * ${SAMBA_HOME}/private/{domain}.{netbiosname}.mac
+ * into a record stored in the tdb ${SAMBA_HOME}/private/secrets.tdb
+ * database. JRA.
+ */
+
 #include "includes.h"
 
 extern int DEBUGLEVEL;
+extern pstring global_myname;
 
 BOOL global_machine_password_needs_changing = False;
+
+
 static int mach_passwd_lock_depth;
 static FILE *mach_passwd_fp;
 
+/***************************************************************
+ Lock an fd. Abandon after waitsecs seconds.
+****************************************************************/
+
+static BOOL pw_file_lock(int fd, int type, int secs, int *plock_depth)
+{
+  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;
+    }
+  }
+
+  (*plock_depth)++;
+
+  return True;
+}
+
+/***************************************************************
+ Unlock an fd. Abandon after waitsecs seconds.
+****************************************************************/
+
+static BOOL pw_file_unlock(int fd, int *plock_depth)
+{
+  BOOL ret=True;
+
+  if(*plock_depth == 1)
+    ret = do_file_lock(fd, 5, F_UNLCK);
+
+  if (*plock_depth > 0)
+    (*plock_depth)--;
+
+  if(!ret)
+    DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n",
+                 strerror(errno)));
+  return ret;
+}
+
 /************************************************************************
- Routine to get the name for a trust account file.
+ Routine to get the name for an old trust account file.
 ************************************************************************/
 
 static void get_trust_account_file_name( char *domain, char *name, char *mac_file)
 {
   unsigned int mac_file_len;
-  char *p;
 
-  pstrcpy(mac_file, lp_smb_passwd_file());
-  p = strrchr(mac_file, '/');
-  if(p != NULL)
-    *++p = '\0';
+  pstrcpy(mac_file, lp_private_dir());
+  if (mac_file[strlen(mac_file)-1] != '/')
+       pstrcat (mac_file, "/");
 
   mac_file_len = strlen(mac_file);
 
@@ -55,34 +106,30 @@ static void get_trust_account_file_name( char *domain, char *name, char *mac_fil
 }
  
 /************************************************************************
- Routine to lock the trust account password file for a domain.
+ Routine to lock the old trust account password file for a domain.
+ As this is a function to migrate to the new secrets.tdb, we never
+ create the file here, only open it.
 ************************************************************************/
 
-BOOL trust_password_lock( char *domain, char *name, BOOL update)
+static BOOL trust_password_file_lock(char *domain, char *name)
 {
   pstring mac_file;
 
   if(mach_passwd_lock_depth == 0) {
+    int fd;
 
     get_trust_account_file_name( domain, name, mac_file);
 
-    if((mach_passwd_fp = sys_fopen(mac_file, "r+b")) == NULL) {
-      if(errno == ENOENT && update) {
-        mach_passwd_fp = sys_fopen(mac_file, "w+b");
-      }
+    if ((fd = sys_open(mac_file, O_RDWR, 0)) == -1)
+      return False;
 
-      if(mach_passwd_fp == NULL) {
+    if((mach_passwd_fp = fdopen(fd, "w+b")) == NULL) {
         DEBUG(0,("trust_password_lock: cannot open file %s - Error was %s.\n",
               mac_file, strerror(errno) ));
         return False;
-      }
     }
 
-    chmod(mac_file, 0600);
-
-    if(!file_lock(fileno(mach_passwd_fp), (update ? F_WRLCK : F_RDLCK), 
-                                      60, &mach_passwd_lock_depth))
-    {
+    if(!pw_file_lock(fileno(mach_passwd_fp), F_WRLCK, 60, &mach_passwd_lock_depth)) {
       DEBUG(0,("trust_password_lock: cannot lock file %s\n", mac_file));
       fclose(mach_passwd_fp);
       return False;
@@ -94,45 +141,69 @@ BOOL trust_password_lock( char *domain, char *name, BOOL update)
 }
 
 /************************************************************************
- Routine to unlock the trust account password file for a domain.
+ Routine to unlock the old trust account password file for a domain.
 ************************************************************************/
 
-BOOL trust_password_unlock(void)
+static BOOL trust_password_file_unlock(void)
 {
-  BOOL ret = file_unlock(fileno(mach_passwd_fp), &mach_passwd_lock_depth);
+  BOOL ret = pw_file_unlock(fileno(mach_passwd_fp), &mach_passwd_lock_depth);
   if(mach_passwd_lock_depth == 0)
     fclose(mach_passwd_fp);
   return ret;
 }
 
 /************************************************************************
- Routine to delete the trust account password file for a domain.
+ Routine to delete the old trust account password file for a domain.
+ Note that this file must be locked as it is truncated before the
+ delete. This is to ensure it only gets deleted by one smbd.
 ************************************************************************/
 
-BOOL trust_password_delete( char *domain, char *name )
+static BOOL trust_password_file_delete( char *domain, char *name )
 {
   pstring mac_file;
+  int ret;
 
   get_trust_account_file_name( domain, name, mac_file);
-  return (unlink( mac_file ) == 0);
+  if(sys_ftruncate(fileno(mach_passwd_fp),(SMB_OFF_T)0) == -1) {
+    DEBUG(0,("trust_password_file_delete: Failed to truncate file %s (%s)\n",
+        mac_file, strerror(errno) ));
+  }
+  ret = unlink( mac_file );
+  return (ret != -1);
 }
 
 /************************************************************************
- Routine to get the trust account password for a domain.
+ Routine to get the old trust account password for a domain - to convert
+ to the new secrets.tdb entry.
  The user of this function must have locked the trust password file.
 ************************************************************************/
 
-BOOL get_trust_account_password( unsigned char *ret_pwd, time_t *pass_last_set_time)
+static BOOL get_trust_account_password_from_file( unsigned char *ret_pwd, time_t *pass_last_set_time)
 {
   char linebuf[256];
   char *p;
   int i;
-
+  SMB_STRUCT_STAT st;
   linebuf[0] = '\0';
 
   *pass_last_set_time = (time_t)0;
   memset(ret_pwd, '\0', 16);
 
+  if(sys_fstat(fileno(mach_passwd_fp), &st) == -1) {
+    DEBUG(0,("get_trust_account_password: Failed to stat file. Error was %s.\n",
+              strerror(errno) )); 
+    return False;
+  }
+
+  /*
+   * If size is zero, another smbd has migrated this file
+   * to the secrets.tdb file, and we are in a race condition.
+   * Just ignore the file.
+   */
+
+  if (st.st_size == 0)
+    return False;
+
   if(sys_fseek( mach_passwd_fp, (SMB_OFF_T)0, SEEK_SET) == -1) {
     DEBUG(0,("get_trust_account_password: Failed to seek to start of file. Error was %s.\n",
               strerror(errno) ));
@@ -156,7 +227,7 @@ BOOL get_trust_account_password( unsigned char *ret_pwd, time_t *pass_last_set_t
 
   if(strlen(linebuf) != 45) {
     DEBUG(0,("get_trust_account_password: Malformed trust password file (wrong length \
-- was %d, should be 45).\n", strlen(linebuf)));
+- was %d, should be 45).\n", (int)strlen(linebuf)));
 #ifdef DEBUG_PASSWORD
     DEBUG(100,("get_trust_account_password: line = |%s|\n", linebuf));
 #endif
@@ -167,7 +238,7 @@ BOOL get_trust_account_password( unsigned char *ret_pwd, time_t *pass_last_set_t
    * Get the hex password.
    */
 
-  if (!pwdb_gethexpwd((char *)linebuf, (char *)ret_pwd, NULL) || linebuf[32] != ':' || 
+  if (!pdb_gethexpwd((char *)linebuf, ret_pwd) || linebuf[32] != ':' || 
          strncmp(&linebuf[33], "TLC-", 4)) {
     DEBUG(0,("get_trust_account_password: Malformed trust password file (incorrect format).\n"));
 #ifdef DEBUG_PASSWORD
@@ -203,66 +274,26 @@ BOOL get_trust_account_password( unsigned char *ret_pwd, time_t *pass_last_set_t
 }
 
 /************************************************************************
- Routine to get the trust account password for a domain.
- The user of this function must have locked the trust password file.
+ Migrate an old DOMAIN.MACINE.mac password file to the tdb secrets db.
 ************************************************************************/
 
-BOOL set_trust_account_password( unsigned char *md4_new_pwd)
-{
-  char linebuf[64];
-  int i;
-
-  if(sys_fseek( mach_passwd_fp, (SMB_OFF_T)0, SEEK_SET) == -1) {
-    DEBUG(0,("set_trust_account_password: Failed to seek to start of file. Error was %s.\n",
-              strerror(errno) ));
-    return False;
-  } 
-
-  for (i = 0; i < 16; i++)
-    slprintf(&linebuf[(i*2)], sizeof(linebuf) -  (i*2) - 1, "%02X", md4_new_pwd[i]);
-
-  slprintf(&linebuf[32], 32, ":TLC-%08X\n", (unsigned)time(NULL));
-
-  if(fwrite( linebuf, 1, 46, mach_passwd_fp)!= 46) {
-    DEBUG(0,("set_trust_account_password: Failed to write file. Warning - the trust \
-account is now invalid. Please recreate. Error was %s.\n", strerror(errno) ));
-    return False;
-  }
-
-  fflush(mach_passwd_fp);
-  return True;
-}
-
-BOOL trust_get_passwd( unsigned char trust_passwd[16], char *domain, char *myname)
+BOOL migrate_from_old_password_file(char *domain)
 {
-  time_t lct;
+       struct machine_acct_pass pass;
 
-  /*
-   * Get the trust account password.
-   */
-  if(!trust_password_lock( domain, myname, False)) {
-    DEBUG(0,("domain_client_validate: unable to open the trust account password file for \
-trust %s in domain %s.\n", myname, domain ));
-    return False;
-  }
+       if (!trust_password_file_lock(domain, global_myname))
+               return True;
 
-  if(get_trust_account_password( trust_passwd, &lct) == False) {
-    DEBUG(0,("domain_client_validate: unable to read the trust account password for \
-trust %s in domain %s.\n", myname, domain ));
-    trust_password_unlock();
-    return False;
-  }
+       if (!get_trust_account_password_from_file( pass.hash, &pass.mod_time)) {
+               trust_password_file_unlock();
+               return False;
+       }
 
-  trust_password_unlock();
+       if (!secrets_store(trust_keystr(domain), (void *)&pass, sizeof(pass)))
+               return False;
 
-  /* 
-   * Here we check the last change time to see if the trust
-   * password needs changing. JRA. 
-   */
+       trust_password_file_delete(domain, global_myname);
+       trust_password_file_unlock();
 
-  if(time(NULL) > lct + lp_machine_password_timeout())
-  {
-    global_machine_password_needs_changing = True;
-  }
-  return True;
+       return True;
 }