r23616: Fix bugzilla #4719: must change password is not set from usrmgr.exe.
authorJim McDonough <jmcd@samba.org>
Tue, 26 Jun 2007 20:09:41 +0000 (20:09 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:23:36 +0000 (12:23 -0500)
This was only affecting the newer versions of usrmgr.exe, because they
use a user_info_25 struct.  The password is getting set separately
inside that code, so the password last set time was getting set from the
password change logic.

We also were not parsing a number of fields (like logon hours) from the
user_info_25.  That should also be fixed.

source/include/rpc_samr.h
source/rpc_parse/parse_samr.c
source/rpc_server/srv_samr_nt.c
source/rpc_server/srv_samr_util.c

index 2d931e67fc827b8931e03b2bd0fd538edb8f9616..d34ecdb5fbb59e69ee6fc2d3f1e1c5237777637e 100644 (file)
@@ -262,7 +262,19 @@ typedef struct sam_user_info_25
        uint32 acb_info; /* account info (ACB_xxxx bit-mask) */
        uint32 fields_present;
 
-       uint32 unknown_5[5];
+       uint16 logon_divs; /* 0x0000 00a8 which is 168 which is num hrs in a week */
+       /* uint8 pad[2] */
+       uint32 ptr_logon_hrs; /* pointer to logon hours */
+
+       /* Was unknown_5. */
+       uint16 bad_password_count;
+       uint16 logon_count;
+
+       uint8 padding1[6];
+               
+       uint8 passmustchange; /* 0x00 must change = 0x01 */
+
+       uint8 padding2;
 
        uint8 pass[532];
 
@@ -276,6 +288,7 @@ typedef struct sam_user_info_25
        UNISTR2 uni_workstations; /* login from workstations unicode string */
        UNISTR2 uni_comment;
        UNISTR2 uni_munged_dial ; /* munged path name and dial-back tel no */
+       LOGON_HRS logon_hrs;
 } SAM_USER_INFO_25;
 
 /* SAM_USER_INFO_26 */
index e7726fbb26cb93455a7feddc1485c72b7f78c987..1a4048e54b3784d66dafeec2546d4c8c04b481ba 100644 (file)
@@ -6134,9 +6134,26 @@ static BOOL sam_io_user_info25(const char *desc, SAM_USER_INFO_25 * usr, prs_str
        if(!prs_uint32("fields_present ", ps, depth, &usr->fields_present))
                return False;
 
-       if(!prs_uint32s(False, "unknown_5      ", ps, depth, usr->unknown_5, 5))
+       if(!prs_uint16("logon_divs    ", ps, depth, &usr->logon_divs))  /* logon divisions per week */
+               return False;
+       if(!prs_align(ps))
+               return False;
+       if(!prs_uint32("ptr_logon_hrs ", ps, depth, &usr->ptr_logon_hrs))
+               return False;
+
+       if(!prs_uint16("bad_password_count     ", ps, depth, &usr->bad_password_count))
+               return False;
+       if(!prs_uint16("logon_count     ", ps, depth, &usr->logon_count))
                return False;
 
+       if(!prs_uint8s(False, "padding1      ", ps, depth, usr->padding1, sizeof(usr->padding1)))
+               return False;
+       if(!prs_uint8("passmustchange ", ps, depth, &usr->passmustchange))
+               return False;
+       if(!prs_uint8("padding2       ", ps, depth, &usr->padding2))
+               return False;
+
+
        if(!prs_uint8s(False, "password      ", ps, depth, usr->pass, sizeof(usr->pass)))
                return False;
 
@@ -6172,13 +6189,11 @@ static BOOL sam_io_user_info25(const char *desc, SAM_USER_INFO_25 * usr, prs_str
        if(!smb_io_unistr2("uni_munged_dial ", &usr->uni_munged_dial, usr->hdr_munged_dial.buffer, ps, depth))
                return False;
 
-#if 0 /* JRA - unknown... */
        /* ok, this is only guess-work (as usual) */
        if (usr->ptr_logon_hrs) {
                if(!sam_io_logon_hrs("logon_hrs", &usr->logon_hrs, ps, depth))
                        return False;
        } 
-#endif
 
        return True;
 }
index b392f289a80068b427780bb7bfed38461c29cc74..e28fc591369a89afb256ecdf1dc12d4ae8a14b7f 100644 (file)
@@ -3357,11 +3357,17 @@ static BOOL set_user_info_pw(uint8 *pass, struct samu *pwd)
        uint32 len;
        pstring plaintext_buf;
        uint32 acct_ctrl;
+       time_t last_set_time;
+       enum pdb_value_state last_set_state;
  
        DEBUG(5, ("Attempting administrator password change for user %s\n",
                  pdb_get_username(pwd)));
 
        acct_ctrl = pdb_get_acct_ctrl(pwd);
+       /* we need to know if it's expired, because this is an admin change, not a
+          user change, so it's still expired when we're done */
+       last_set_state = pdb_get_init_flags(pwd, PDB_PASSLASTSET);
+       last_set_time = pdb_get_pass_last_set_time(pwd);
 
        ZERO_STRUCT(plaintext_buf);
  
@@ -3404,6 +3410,9 @@ static BOOL set_user_info_pw(uint8 *pass, struct samu *pwd)
  
        ZERO_STRUCT(plaintext_buf);
  
+       /* restore last set time as this is an admin change, not a user pw change */
+       pdb_set_pass_last_set_time (pwd, last_set_time, last_set_state);
        DEBUG(5,("set_user_info_pw: pdb_update_pwd()\n"));
  
        /* update the SAMBA password */
index 8acc1785ef654ef4cab867f35a4c6b4ded1a21a4..42ad462ee77949c2bde1fd093b0e7a3208f17b6f 100644 (file)
@@ -670,4 +670,47 @@ void copy_id25_to_sam_passwd(struct samu *to, SAM_USER_INFO_25 *from)
                        pdb_set_acct_ctrl(to, from->acb_info, PDB_CHANGED);
                }
        }
+
+       if (from->fields_present & ACCT_LOGON_HOURS) {
+               DEBUG(15,("INFO_25 LOGON_DIVS: %08X -> %08X\n",pdb_get_logon_divs(to),from->logon_divs));
+               if (from->logon_divs != pdb_get_logon_divs(to)) {
+                       pdb_set_logon_divs(to, from->logon_divs, PDB_CHANGED);
+               }
+
+               DEBUG(15,("INFO_25 LOGON_HRS.LEN: %08X -> %08X\n",pdb_get_hours_len(to),from->logon_hrs.len));
+               if (from->logon_hrs.len != pdb_get_hours_len(to)) {
+                       pdb_set_hours_len(to, from->logon_hrs.len, PDB_CHANGED);
+               }
+
+               DEBUG(15,("INFO_25 LOGON_HRS.HOURS: %s -> %s\n",pdb_get_hours(to),from->logon_hrs.hours));
+               /* Fix me: only update if it changes --metze */
+               pdb_set_hours(to, from->logon_hrs.hours, PDB_CHANGED);
+       }
+
+       if (from->fields_present & ACCT_BAD_PWD_COUNT) {
+               DEBUG(10,("INFO_25 BAD_PASSWORD_COUNT: %08X -> %08X\n",pdb_get_bad_password_count(to),from->bad_password_count));
+               if (from->bad_password_count != pdb_get_bad_password_count(to)) {
+                       pdb_set_bad_password_count(to, from->bad_password_count, PDB_CHANGED);
+               }
+       }
+
+       if (from->fields_present & ACCT_NUM_LOGONS) {
+               DEBUG(10,("INFO_25 LOGON_COUNT: %08X -> %08X\n",pdb_get_logon_count(to),from->logon_count));
+               if (from->logon_count != pdb_get_logon_count(to)) {
+                       pdb_set_logon_count(to, from->logon_count, PDB_CHANGED);
+               }
+       }
+
+       /* If the must change flag is set, the last set time goes to zero.
+          the must change and can change fields also do, but they are 
+          calculated from policy, not set from the wire */
+
+       if (from->fields_present & ACCT_EXPIRED_FLAG) {
+               DEBUG(10,("INFO_25 PASS_MUST_CHANGE_AT_NEXT_LOGON: %02X\n",from->passmustchange));
+               if (from->passmustchange == PASS_MUST_CHANGE_AT_NEXT_LOGON) {
+                       pdb_set_pass_last_set_time(to, 0, PDB_CHANGED);         
+               } else {
+                       pdb_set_pass_last_set_time(to, time(NULL),PDB_CHANGED);
+               }
+       }
 }