diff options
-rw-r--r-- | source3/lib/util_str.c | 64 | ||||
-rw-r--r-- | source3/libsmb/smbencrypt.c | 36 | ||||
-rw-r--r-- | source3/rpc_server/srv_samr_nt.c | 58 | ||||
-rw-r--r-- | source3/smbd/chgpasswd.c | 157 |
4 files changed, 191 insertions, 124 deletions
diff --git a/source3/lib/util_str.c b/source3/lib/util_str.c index f1078c6383..6d429e3719 100644 --- a/source3/lib/util_str.c +++ b/source3/lib/util_str.c @@ -1254,22 +1254,27 @@ char *realloc_string_sub(char *string, const char *pattern, return string; } -/* Same as string_sub, but returns a talloc'ed string */ +/* + * Internal guts of talloc_string_sub and talloc_all_string_sub. + * 'filter' differentiates between them. + */ -char *talloc_string_sub(TALLOC_CTX *mem_ctx, const char *src, - const char *pattern, const char *insert) +static char *talloc_string_sub_internal(TALLOC_CTX *mem_ctx, const char *src, + const char *pattern, const char *insert, bool filter) { char *p, *in; char *s; char *string; ssize_t ls,lp,li,ld, i; - if (!insert || !pattern || !*pattern || !src || !*src) + if (!insert || !pattern || !*pattern || !src || !*src) { return NULL; + } string = talloc_strdup(mem_ctx, src); if (string == NULL) { - DEBUG(0, ("talloc_strdup failed\n")); + DEBUG(0, ("talloc_string_sub_internal: " + "talloc_strdup failed\n")); return NULL; } @@ -1277,27 +1282,30 @@ char *talloc_string_sub(TALLOC_CTX *mem_ctx, const char *src, in = SMB_STRDUP(insert); if (!in) { - DEBUG(0, ("talloc_string_sub: out of memory!\n")); + DEBUG(0, ("talloc_string_sub_internal: ENOMEM\n")); return NULL; } ls = (ssize_t)strlen(s); lp = (ssize_t)strlen(pattern); li = (ssize_t)strlen(insert); ld = li - lp; - for (i=0;i<li;i++) { - switch (in[i]) { - case '`': - case '"': - case '\'': - case ';': - case '$': - case '%': - case '\r': - case '\n': - in[i] = '_'; - default: - /* ok */ - break; + + if (filter) { + for (i=0;i<li;i++) { + switch (in[i]) { + case '`': + case '"': + case '\'': + case ';': + case '$': + case '%': + case '\r': + case '\n': + in[i] = '_'; + default: + /* ok */ + break; + } } } @@ -1325,6 +1333,14 @@ char *talloc_string_sub(TALLOC_CTX *mem_ctx, const char *src, return string; } +/* Same as string_sub, but returns a talloc'ed string */ + +char *talloc_string_sub(TALLOC_CTX *mem_ctx, const char *src, + const char *pattern, const char *insert) +{ + return talloc_string_sub_internal(mem_ctx, src, pattern, insert, true); +} + /** Similar to string_sub() but allows for any character to be substituted. Use with caution! @@ -1367,6 +1383,14 @@ void all_string_sub(char *s,const char *pattern,const char *insert, size_t len) } } +char *talloc_all_string_sub(TALLOC_CTX *ctx, + const char *src, + const char *pattern, + const char *insert) +{ + return talloc_string_sub_internal(ctx, src, pattern, insert, false); +} + /** Similar to all_string_sub but for unicode strings. Return a new allocated unicode string. diff --git a/source3/libsmb/smbencrypt.c b/source3/libsmb/smbencrypt.c index 20eddff722..77ff063cb9 100644 --- a/source3/libsmb/smbencrypt.c +++ b/source3/libsmb/smbencrypt.c @@ -522,12 +522,17 @@ bool encode_pw_buffer(uint8 buffer[516], const char *password, int string_flags) returned password including termination. ************************************************************/ -bool decode_pw_buffer(uint8 in_buffer[516], char *new_pwrd, - int new_pwrd_size, uint32 *new_pw_len, - int string_flags) +bool decode_pw_buffer(TALLOC_CTX *ctx, + uint8 in_buffer[516], + char **pp_new_pwrd, + uint32 *new_pw_len, + int string_flags) { int byte_len=0; + *pp_new_pwrd = NULL; + *new_pw_len = 0; + /* the incoming buffer can be any alignment. */ string_flags |= STR_NOALIGN; @@ -550,22 +555,31 @@ bool decode_pw_buffer(uint8 in_buffer[516], char *new_pwrd, if ( (byte_len < 0) || (byte_len > 512)) { DEBUG(0, ("decode_pw_buffer: incorrect password length (%d).\n", byte_len)); DEBUG(0, ("decode_pw_buffer: check that 'encrypt passwords = yes'\n")); - return False; + return false; } - /* decode into the return buffer. Buffer length supplied */ - *new_pw_len = pull_string(NULL, 0, new_pwrd, - &in_buffer[512 - byte_len], new_pwrd_size, - byte_len, string_flags); + /* decode into the return buffer. */ + *new_pw_len = pull_string_talloc(ctx, + NULL, + 0, + pp_new_pwrd, + &in_buffer[512 - byte_len], + byte_len, + string_flags); + + if (!*pp_new_pwrd || *new_pw_len == 0) { + DEBUG(0, ("decode_pw_buffer: pull_string_talloc failed\n")); + return false; + } #ifdef DEBUG_PASSWORD DEBUG(100,("decode_pw_buffer: new_pwrd: ")); - dump_data(100, (uint8 *)new_pwrd, *new_pw_len); + dump_data(100, (uint8 *)*pp_new_pwrd, *new_pw_len); DEBUG(100,("multibyte len:%d\n", *new_pw_len)); DEBUG(100,("original char len:%d\n", byte_len/2)); #endif - - return True; + + return true; } /*********************************************************** diff --git a/source3/rpc_server/srv_samr_nt.c b/source3/rpc_server/srv_samr_nt.c index 9aabaf08ca..3cc8f01d2c 100644 --- a/source3/rpc_server/srv_samr_nt.c +++ b/source3/rpc_server/srv_samr_nt.c @@ -3275,33 +3275,37 @@ static NTSTATUS set_user_info_21(TALLOC_CTX *mem_ctx, SAM_USER_INFO_21 *id21, static NTSTATUS set_user_info_23(TALLOC_CTX *mem_ctx, SAM_USER_INFO_23 *id23, struct samu *pwd) { - pstring plaintext_buf; - uint32 len; + char *plaintext_buf = NULL; + uint32 len = 0; uint16 acct_ctrl; NTSTATUS status; - + if (id23 == NULL) { DEBUG(5, ("set_user_info_23: NULL id23\n")); return NT_STATUS_INVALID_PARAMETER; } - + DEBUG(5, ("Attempting administrator password change (level 23) for user %s\n", pdb_get_username(pwd))); acct_ctrl = pdb_get_acct_ctrl(pwd); - if (!decode_pw_buffer(id23->pass, plaintext_buf, 256, &len, STR_UNICODE)) { + if (!decode_pw_buffer(mem_ctx, + id23->pass, + &plaintext_buf, + &len, + STR_UNICODE)) { TALLOC_FREE(pwd); return NT_STATUS_INVALID_PARAMETER; } - + if (!pdb_set_plaintext_passwd (pwd, plaintext_buf)) { TALLOC_FREE(pwd); return NT_STATUS_ACCESS_DENIED; } - + copy_id23_to_sam_passwd(pwd, id23); - + /* if it's a trust account, don't update /etc/passwd */ if ( ( (acct_ctrl & ACB_DOMTRUST) == ACB_DOMTRUST ) || ( (acct_ctrl & ACB_WSTRUST) == ACB_WSTRUST) || @@ -3320,16 +3324,16 @@ static NTSTATUS set_user_info_23(TALLOC_CTX *mem_ctx, SAM_USER_INFO_23 *id23, if ((passwd = Get_Pwnam(pdb_get_username(pwd))) == NULL) { DEBUG(1, ("chgpasswd: Username does not exist in system !?!\n")); } - + if(!chgpasswd(pdb_get_username(pwd), passwd, "", plaintext_buf, True)) { TALLOC_FREE(pwd); return NT_STATUS_ACCESS_DENIED; } } } - - ZERO_STRUCT(plaintext_buf); - + + memset(plaintext_buf, '\0', strlen(plaintext_buf)); + if (IS_SAM_CHANGED(pwd, PDB_GROUPSID) && (!NT_STATUS_IS_OK(status = pdb_set_unix_primary_group(mem_ctx, pwd)))) { @@ -3341,7 +3345,7 @@ static NTSTATUS set_user_info_23(TALLOC_CTX *mem_ctx, SAM_USER_INFO_23 *id23, TALLOC_FREE(pwd); return status; } - + TALLOC_FREE(pwd); return NT_STATUS_OK; @@ -3353,12 +3357,12 @@ static NTSTATUS set_user_info_23(TALLOC_CTX *mem_ctx, SAM_USER_INFO_23 *id23, static bool set_user_info_pw(uint8 *pass, struct samu *pwd) { - uint32 len; - pstring plaintext_buf; + uint32 len = 0; + char *plaintext_buf = NULL; 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))); @@ -3368,9 +3372,11 @@ static bool set_user_info_pw(uint8 *pass, struct samu *pwd) last_set_state = pdb_get_init_flags(pwd, PDB_PASSLASTSET); last_set_time = pdb_get_pass_last_set_time(pwd); - ZERO_STRUCT(plaintext_buf); - - if (!decode_pw_buffer(pass, plaintext_buf, 256, &len, STR_UNICODE)) { + if (!decode_pw_buffer(talloc_tos(), + pass, + &plaintext_buf, + &len, + STR_UNICODE)) { TALLOC_FREE(pwd); return False; } @@ -3379,7 +3385,7 @@ static bool set_user_info_pw(uint8 *pass, struct samu *pwd) TALLOC_FREE(pwd); return False; } - + /* if it's a trust account, don't update /etc/passwd */ if ( ( (acct_ctrl & ACB_DOMTRUST) == ACB_DOMTRUST ) || ( (acct_ctrl & ACB_WSTRUST) == ACB_WSTRUST) || @@ -3399,21 +3405,21 @@ static bool set_user_info_pw(uint8 *pass, struct samu *pwd) if ((passwd = Get_Pwnam(pdb_get_username(pwd))) == NULL) { DEBUG(1, ("chgpasswd: Username does not exist in system !?!\n")); } - + if(!chgpasswd(pdb_get_username(pwd), passwd, "", plaintext_buf, True)) { TALLOC_FREE(pwd); return False; } } } - - ZERO_STRUCT(plaintext_buf); - + + memset(plaintext_buf, '\0', strlen(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 */ if(!NT_STATUS_IS_OK(pdb_update_sam_account(pwd))) { TALLOC_FREE(pwd); diff --git a/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c index 6e7ef208c1..aef5adb72f 100644 --- a/source3/smbd/chgpasswd.c +++ b/source3/smbd/chgpasswd.c @@ -25,7 +25,7 @@ * user who is attempting to change the password. */ -/* +/* * This code was copied/borrowed and stolen from various sources. * The primary source was the poppasswd.c from the authors of POPMail. This software * was included as a client to change passwords using the 'passwd' program @@ -50,12 +50,12 @@ extern struct passdb_ops pdb_ops; static NTSTATUS check_oem_password(const char *user, - uchar password_encrypted_with_lm_hash[516], + uchar password_encrypted_with_lm_hash[516], const uchar old_lm_hash_encrypted[16], - uchar password_encrypted_with_nt_hash[516], + uchar password_encrypted_with_nt_hash[516], const uchar old_nt_hash_encrypted[16], - struct samu **hnd, char *new_passwd, - int new_passwd_size); + struct samu **hnd, + char **pp_new_passwd); #if ALLOW_CHANGE_PASSWORD @@ -231,7 +231,7 @@ static int dochild(int master, const char *slavedev, const struct passwd *pass, static int expect(int master, char *issue, char *expected) { - pstring buffer; + char buffer[1024]; int attempts, timeout, nread, len; bool match = False; @@ -450,13 +450,14 @@ while we were waiting\n", WTERMSIG(wstat))); return (chstat); } -bool chgpasswd(const char *name, const struct passwd *pass, +bool chgpasswd(const char *name, const struct passwd *pass, const char *oldpass, const char *newpass, bool as_root) { - pstring passwordprogram; - pstring chatsequence; + char *passwordprogram = NULL; + char *chatsequence = NULL; size_t i; size_t len; + TALLOC_CTX *ctx = talloc_tos(); if (!oldpass) { oldpass = ""; @@ -477,7 +478,7 @@ bool chgpasswd(const char *name, const struct passwd *pass, return (False); /* inform the user */ } - /* + /* * Check the old and new passwords don't contain any control * characters. */ @@ -497,7 +498,7 @@ bool chgpasswd(const char *name, const struct passwd *pass, return False; } } - + #ifdef WITH_PAM if (lp_pam_password_change()) { bool ret; @@ -510,7 +511,7 @@ bool chgpasswd(const char *name, const struct passwd *pass, } else { ret = smb_pam_passchange(name, oldpass, newpass); } - + if (as_root) unbecome_root(); @@ -522,20 +523,18 @@ bool chgpasswd(const char *name, const struct passwd *pass, if (pass == NULL) { DEBUG(0, ("chgpasswd: user %s doesn't exist in the UNIX password database.\n", name)); - return False; + return false; } - pstrcpy(passwordprogram, lp_passwd_program()); - pstrcpy(chatsequence, lp_passwd_chat()); - - if (!*chatsequence) { - DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n")); - return (False); - } - - if (!*passwordprogram) { + passwordprogram = talloc_strdup(ctx, lp_passwd_program()); + if (!passwordprogram || !*passwordprogram) { DEBUG(2, ("chgpasswd: Null password program - no password changing\n")); - return (False); + return false; + } + chatsequence = talloc_strdup(ctx, lp_passwd_chat()); + if (!chatsequence || !*chatsequence) { + DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n")); + return false; } if (as_root) { @@ -543,20 +542,38 @@ bool chgpasswd(const char *name, const struct passwd *pass, if (strstr_m(passwordprogram, "%u") == NULL) { DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \ the string %%u, and the given string %s does not.\n", passwordprogram )); - return False; + return false; } } - pstring_sub(passwordprogram, "%u", name); + passwordprogram = talloc_string_sub(ctx, passwordprogram, "%u", name); + if (!passwordprogram) { + return false; + } + /* note that we do NOT substitute the %o and %n in the password program as this would open up a security hole where the user could use a new password containing shell escape characters */ - pstring_sub(chatsequence, "%u", name); - all_string_sub(chatsequence, "%o", oldpass, sizeof(pstring)); - all_string_sub(chatsequence, "%n", newpass, sizeof(pstring)); - return (chat_with_program - (passwordprogram, pass, chatsequence, as_root)); + chatsequence = talloc_string_sub(ctx, chatsequence, "%u", name); + if (!chatsequence) { + return false; + } + chatsequence = talloc_all_string_sub(ctx, + chatsequence, + "%o", + oldpass); + if (!chatsequence) { + return false; + } + chatsequence = talloc_all_string_sub(ctx, + chatsequence, + "%n", + newpass); + return chat_with_program(passwordprogram, + pass, + chatsequence, + as_root); } #else /* ALLOW_CHANGE_PASSWORD */ @@ -695,9 +712,9 @@ bool change_lanman_password(struct samu *sampass, uchar *pass2) if (!pdb_set_pass_last_set_time (sampass, time(NULL), PDB_CHANGED)) { TALLOC_FREE(sampass); /* Not quite sure what this one qualifies as, but this will do */ - return False; + return False; } - + /* Now flush the sam_passwd struct to persistent storage */ ret = NT_STATUS_IS_OK(pdb_update_sam_account (sampass)); @@ -709,29 +726,32 @@ bool change_lanman_password(struct samu *sampass, uchar *pass2) ************************************************************/ NTSTATUS pass_oem_change(char *user, - uchar password_encrypted_with_lm_hash[516], + uchar password_encrypted_with_lm_hash[516], const uchar old_lm_hash_encrypted[16], - uchar password_encrypted_with_nt_hash[516], + uchar password_encrypted_with_nt_hash[516], const uchar old_nt_hash_encrypted[16], uint32 *reject_reason) { - pstring new_passwd; + char *new_passwd = NULL; struct samu *sampass = NULL; - NTSTATUS nt_status = check_oem_password(user, password_encrypted_with_lm_hash, - old_lm_hash_encrypted, - password_encrypted_with_nt_hash, + NTSTATUS nt_status = check_oem_password(user, + password_encrypted_with_lm_hash, + old_lm_hash_encrypted, + password_encrypted_with_nt_hash, old_nt_hash_encrypted, - &sampass, new_passwd, sizeof(new_passwd)); - - if (!NT_STATUS_IS_OK(nt_status)) + &sampass, + &new_passwd); + + if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; + } /* We've already checked the old password here.... */ become_root(); nt_status = change_oem_password(sampass, NULL, new_passwd, True, reject_reason); unbecome_root(); - memset(new_passwd, 0, sizeof(new_passwd)); + memset(new_passwd, 0, strlen(new_passwd)); TALLOC_FREE(sampass); @@ -739,24 +759,24 @@ NTSTATUS pass_oem_change(char *user, } /*********************************************************** - Decrypt and verify a user password change. + Decrypt and verify a user password change. - The 516 byte long buffers are encrypted with the old NT and - old LM passwords, and if the NT passwords are present, both + The 516 byte long buffers are encrypted with the old NT and + old LM passwords, and if the NT passwords are present, both buffers contain a unicode string. After decrypting the buffers, check the password is correct by matching the old hashed passwords with the passwords in the passdb. - + ************************************************************/ static NTSTATUS check_oem_password(const char *user, - uchar password_encrypted_with_lm_hash[516], + uchar password_encrypted_with_lm_hash[516], const uchar old_lm_hash_encrypted[16], - uchar password_encrypted_with_nt_hash[516], + uchar password_encrypted_with_nt_hash[516], const uchar old_nt_hash_encrypted[16], - struct samu **hnd, char *new_passwd, - int new_passwd_size) + struct samu **hnd, + char **pp_new_passwd) { static uchar null_pw[16]; static uchar null_ntpw[16]; @@ -788,11 +808,11 @@ static NTSTATUS check_oem_password(const char *user, if (ret == False) { DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n")); TALLOC_FREE(sampass); - return NT_STATUS_NO_SUCH_USER; + return NT_STATUS_NO_SUCH_USER; } acct_ctrl = pdb_get_acct_ctrl(sampass); - + if (acct_ctrl & ACB_DISABLED) { DEBUG(2,("check_lanman_password: account %s disabled.\n", user)); TALLOC_FREE(sampass); @@ -819,7 +839,7 @@ static NTSTATUS check_oem_password(const char *user, if (nt_pw && nt_pass_set) { /* IDEAL Case: passwords are in unicode, and we can - * read use the password encrypted with the NT hash + * read use the password encrypted with the NT hash */ password_encrypted = password_encrypted_with_nt_hash; encryption_key = nt_pw; @@ -831,7 +851,7 @@ static NTSTATUS check_oem_password(const char *user, DEBUG(1, ("NT password change supplied for user %s, but we have no NT password to check it with\n", user)); TALLOC_FREE(sampass); - return NT_STATUS_WRONG_PASSWORD; + return NT_STATUS_WRONG_PASSWORD; } else if (lm_pass_set) { if (lp_lanman_auth()) { DEBUG(1, ("LM password change supplied for user %s, but we have no LanMan password to check it with\n", @@ -849,13 +869,16 @@ static NTSTATUS check_oem_password(const char *user, return NT_STATUS_WRONG_PASSWORD; } - /* - * Decrypt the password with the key + /* + * Decrypt the password with the key */ SamOEMhash( password_encrypted, encryption_key, 516); - if ( !decode_pw_buffer(password_encrypted, new_passwd, new_passwd_size, &new_pw_len, - nt_pass_set ? STR_UNICODE : STR_ASCII)) { + if (!decode_pw_buffer(talloc_tos(), + password_encrypted, + pp_new_passwd, + &new_pw_len, + nt_pass_set ? STR_UNICODE : STR_ASCII)) { TALLOC_FREE(sampass); return NT_STATUS_WRONG_PASSWORD; } @@ -867,10 +890,10 @@ static NTSTATUS check_oem_password(const char *user, if (nt_pass_set) { /* NT passwords, verify the NT hash. */ - + /* Calculate the MD4 hash (NT compatible) of the password */ memset(new_nt_hash, '\0', 16); - E_md4hash(new_passwd, new_nt_hash); + E_md4hash(*pp_new_passwd, new_nt_hash); if (nt_pw) { /* @@ -882,7 +905,7 @@ static NTSTATUS check_oem_password(const char *user, TALLOC_FREE(sampass); return NT_STATUS_WRONG_PASSWORD; } - + /* We could check the LM password here, but there is * little point, we already know the password is * correct, and the LM password might not even be @@ -894,12 +917,12 @@ static NTSTATUS check_oem_password(const char *user, * change */ #ifdef DEBUG_PASSWORD DEBUG(100, - ("check_oem_password: password %s ok\n", new_passwd)); + ("check_oem_password: password %s ok\n", *pp_new_passwd)); #endif *hnd = sampass; return NT_STATUS_OK; } - + if (lanman_pw) { /* * check the lm verifier @@ -912,7 +935,7 @@ static NTSTATUS check_oem_password(const char *user, } #ifdef DEBUG_PASSWORD DEBUG(100, - ("check_oem_password: password %s ok\n", new_passwd)); + ("check_oem_password: password %s ok\n", *pp_new_passwd)); #endif *hnd = sampass; return NT_STATUS_OK; @@ -921,7 +944,7 @@ static NTSTATUS check_oem_password(const char *user, if (lanman_pw && lm_pass_set) { - E_deshash(new_passwd, new_lm_hash); + E_deshash(*pp_new_passwd, new_lm_hash); /* * check the lm verifier @@ -932,10 +955,10 @@ static NTSTATUS check_oem_password(const char *user, TALLOC_FREE(sampass); return NT_STATUS_WRONG_PASSWORD; } - + #ifdef DEBUG_PASSWORD DEBUG(100, - ("check_oem_password: password %s ok\n", new_passwd)); + ("check_oem_password: password %s ok\n", *pp_new_passwd)); #endif *hnd = sampass; return NT_STATUS_OK; |