]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s4:libnet: Move code using RC4 into its own function
authorAndreas Schneider <asn@samba.org>
Tue, 26 Jul 2022 13:13:08 +0000 (15:13 +0200)
committerAndreas Schneider <asn@cryptomilk.org>
Thu, 28 Jul 2022 11:51:29 +0000 (11:51 +0000)
Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
source4/libnet/libnet_passwd.c

index 4990f69bc49f4d40a8f12f11e8232654790e9579..027b15b2bc94b835eadc4026f250b9ca1b62adc0 100644 (file)
 #include <gnutls/gnutls.h>
 #include <gnutls/crypto.h>
 
-/*
- * do a password change using DCERPC/SAMR calls
- * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
- * 2. try samr_ChangePasswordUser3
- * 3. try samr_ChangePasswordUser2
- * 4. try samr_OemChangePasswordUser2
- */
-static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
+static NTSTATUS libnet_ChangePassword_samr_rc4(TALLOC_CTX *mem_ctx,
+                                              struct dcerpc_binding_handle *h,
+                                              struct lsa_String *server,
+                                              struct lsa_String *account,
+                                              const char *old_password,
+                                              const char *new_password,
+                                              const char **error_string)
 {
-        NTSTATUS status;
-       struct libnet_RpcConnect c;
        struct samr_OemChangePasswordUser2 oe2;
        struct samr_ChangePasswordUser2 pw2;
        struct samr_ChangePasswordUser3 pw3;
-       struct lsa_String server, account;
-       struct lsa_AsciiString a_server, a_account;
        struct samr_CryptPassword nt_pass, lm_pass;
-       struct samr_Password nt_verifier, lm_verifier;
        uint8_t old_nt_hash[16], new_nt_hash[16];
        uint8_t old_lm_hash[16], new_lm_hash[16];
-       struct samr_DomInfo1 *dominfo = NULL;
-       struct userPwdChangeFailureInformation *reject = NULL;
+       struct samr_Password nt_verifier, lm_verifier;
+       struct lsa_AsciiString a_server, a_account;
        gnutls_cipher_hd_t cipher_hnd = NULL;
        gnutls_datum_t nt_session_key = {
                .data = old_nt_hash,
@@ -61,37 +55,19 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT
                .data = old_lm_hash,
                .size = sizeof(old_lm_hash),
        };
+       struct samr_DomInfo1 *dominfo = NULL;
+       struct userPwdChangeFailureInformation *reject = NULL;
+       NTSTATUS status;
        int rc;
 
-       ZERO_STRUCT(c);
+       E_md4hash(old_password, old_nt_hash);
+       E_md4hash(new_password, new_nt_hash);
 
-       /* prepare connect to the SAMR pipe of the users domain PDC */
-       c.level                    = LIBNET_RPC_CONNECT_PDC;
-       c.in.name                  = r->samr.in.domain_name;
-       c.in.dcerpc_iface          = &ndr_table_samr;
-       c.in.dcerpc_flags          = DCERPC_ANON_FALLBACK;
-
-       /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
-       status = libnet_RpcConnect(ctx, mem_ctx, &c);
-       if (!NT_STATUS_IS_OK(status)) {
-               r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                               "Connection to SAMR pipe of PDC of domain '%s' failed: %s",
-                                               r->samr.in.domain_name, nt_errstr(status));
-               return status;
-       }
-
-       /* prepare password change for account */
-       server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.out.dcerpc_pipe));
-       account.string = r->samr.in.account_name;
-
-       E_md4hash(r->samr.in.oldpassword, old_nt_hash);
-       E_md4hash(r->samr.in.newpassword, new_nt_hash);
-
-       E_deshash(r->samr.in.oldpassword, old_lm_hash);
-       E_deshash(r->samr.in.newpassword, new_lm_hash);
+       E_deshash(old_password, old_lm_hash);
+       E_deshash(new_password, new_lm_hash);
 
        /* prepare samr_ChangePasswordUser3 */
-       encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_UNICODE);
+       encode_pw_buffer(lm_pass.data, new_password, STR_UNICODE);
 
        rc = gnutls_cipher_init(&cipher_hnd,
                                GNUTLS_CIPHER_ARCFOUR_128,
@@ -99,7 +75,7 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT
                                NULL);
        if (rc < 0) {
                status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
-               goto disconnect;
+               goto done;
        }
 
        rc = gnutls_cipher_encrypt(cipher_hnd,
@@ -108,16 +84,16 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT
        gnutls_cipher_deinit(cipher_hnd);
        if (rc < 0) {
                status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
-               goto disconnect;
+               goto done;
        }
 
        rc = E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
        if (rc != 0) {
                status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
-               goto disconnect;
+               goto done;
        }
 
-       encode_pw_buffer(nt_pass.data,  r->samr.in.newpassword, STR_UNICODE);
+       encode_pw_buffer(nt_pass.data, new_password, STR_UNICODE);
 
        rc = gnutls_cipher_init(&cipher_hnd,
                                GNUTLS_CIPHER_ARCFOUR_128,
@@ -125,7 +101,7 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT
                                NULL);
        if (rc < 0) {
                status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
-               goto disconnect;
+               goto done;
        }
 
        rc = gnutls_cipher_encrypt(cipher_hnd,
@@ -134,17 +110,17 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT
        gnutls_cipher_deinit(cipher_hnd);
        if (rc < 0) {
                status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
-               goto disconnect;
+               goto done;
        }
 
        rc = E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
        if (rc != 0) {
                status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
-               goto disconnect;
+               goto done;
        }
 
-       pw3.in.server = &server;
-       pw3.in.account = &account;
+       pw3.in.server = server;
+       pw3.in.account = account;
        pw3.in.nt_password = &nt_pass;
        pw3.in.nt_verifier = &nt_verifier;
        pw3.in.lm_change = 1;
@@ -155,25 +131,29 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT
        pw3.out.reject = &reject;
 
        /* 2. try samr_ChangePasswordUser3 */
-       status = dcerpc_samr_ChangePasswordUser3_r(c.out.dcerpc_pipe->binding_handle, mem_ctx, &pw3);
+       status = dcerpc_samr_ChangePasswordUser3_r(h, mem_ctx, &pw3);
        if (!NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
                if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(pw3.out.result)) {
                        status = pw3.out.result;
                }
                if (!NT_STATUS_IS_OK(status)) {
-                       r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                                                  "samr_ChangePasswordUser3 failed: %s",
-                                                                  nt_errstr(status));
-                       r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                                                  "samr_ChangePasswordUser3 for '%s\\%s' failed: %s",
-                                                                  r->samr.in.domain_name, r->samr.in.account_name,
-                                                                  nt_errstr(status));
+                       *error_string = talloc_asprintf(
+                               mem_ctx,
+                               "samr_ChangePasswordUser3 failed: %s",
+                               nt_errstr(status));
+                       *error_string =
+                               talloc_asprintf(mem_ctx,
+                                               "samr_ChangePasswordUser3 for "
+                                               "'%s\\%s' failed: %s",
+                                               server->string,
+                                               account->string,
+                                               nt_errstr(status));
                }
-               goto disconnect;
+               goto done;
        }
 
        /* prepare samr_ChangePasswordUser2 */
-       encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII|STR_TERMINATE);
+       encode_pw_buffer(lm_pass.data, new_password, STR_ASCII | STR_TERMINATE);
 
        rc = gnutls_cipher_init(&cipher_hnd,
                                GNUTLS_CIPHER_ARCFOUR_128,
@@ -181,7 +161,7 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT
                                NULL);
        if (rc < 0) {
                status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
-               goto disconnect;
+               goto done;
        }
 
        rc = gnutls_cipher_encrypt(cipher_hnd,
@@ -190,16 +170,16 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT
        gnutls_cipher_deinit(cipher_hnd);
        if (rc < 0) {
                status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
-               goto disconnect;
+               goto done;
        }
 
        rc = E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
        if (rc != 0) {
                status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
-               goto disconnect;
+               goto done;
        }
 
-       encode_pw_buffer(nt_pass.data, r->samr.in.newpassword, STR_UNICODE);
+       encode_pw_buffer(nt_pass.data, new_password, STR_UNICODE);
 
        rc = gnutls_cipher_init(&cipher_hnd,
                                GNUTLS_CIPHER_ARCFOUR_128,
@@ -207,7 +187,7 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT
                                NULL);
        if (rc < 0) {
                status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
-               goto disconnect;
+               goto done;
        }
        rc = gnutls_cipher_encrypt(cipher_hnd,
                                   nt_pass.data,
@@ -215,17 +195,17 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT
        gnutls_cipher_deinit(cipher_hnd);
        if (rc < 0) {
                status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
-               goto disconnect;
+               goto done;
        }
 
        rc = E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
        if (rc != 0) {
                status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
-               goto disconnect;
+               goto done;
        }
 
-       pw2.in.server = &server;
-       pw2.in.account = &account;
+       pw2.in.server = server;
+       pw2.in.account = account;
        pw2.in.nt_password = &nt_pass;
        pw2.in.nt_verifier = &nt_verifier;
        pw2.in.lm_change = 1;
@@ -233,26 +213,29 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT
        pw2.in.lm_verifier = &lm_verifier;
 
        /* 3. try samr_ChangePasswordUser2 */
-       status = dcerpc_samr_ChangePasswordUser2_r(c.out.dcerpc_pipe->binding_handle, mem_ctx, &pw2);
+       status = dcerpc_samr_ChangePasswordUser2_r(h, mem_ctx, &pw2);
        if (!NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
                if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(pw2.out.result)) {
                        status = pw2.out.result;
                }
                if (!NT_STATUS_IS_OK(status)) {
-                       r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                                                  "samr_ChangePasswordUser2 for '%s\\%s' failed: %s",
-                                                                  r->samr.in.domain_name, r->samr.in.account_name,
-                                                                  nt_errstr(status));
+                       *error_string =
+                               talloc_asprintf(mem_ctx,
+                                               "samr_ChangePasswordUser2 for "
+                                               "'%s\\%s' failed: %s",
+                                               server->string,
+                                               account->string,
+                                               nt_errstr(status));
                }
-               goto disconnect;
+               goto done;
        }
 
 
        /* prepare samr_OemChangePasswordUser2 */
-       a_server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.out.dcerpc_pipe));
-       a_account.string = r->samr.in.account_name;
+       a_server.string = server->string;
+       a_account.string = account->string;
 
-       encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII);
+       encode_pw_buffer(lm_pass.data, new_password, STR_ASCII);
 
        rc = gnutls_cipher_init(&cipher_hnd,
                                GNUTLS_CIPHER_ARCFOUR_128,
@@ -260,7 +243,7 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT
                                NULL);
        if (rc < 0) {
                status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
-               goto disconnect;
+               goto done;
        }
 
        rc = gnutls_cipher_encrypt(cipher_hnd,
@@ -269,13 +252,13 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT
        gnutls_cipher_deinit(cipher_hnd);
        if (rc < 0) {
                status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
-               goto disconnect;
+               goto done;
        }
 
        rc = E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
        if (rc != 0) {
                status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
-               goto disconnect;
+               goto done;
        }
 
        oe2.in.server = &a_server;
@@ -284,17 +267,71 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT
        oe2.in.hash = &lm_verifier;
 
        /* 4. try samr_OemChangePasswordUser2 */
-       status = dcerpc_samr_OemChangePasswordUser2_r(c.out.dcerpc_pipe->binding_handle, mem_ctx, &oe2);
+       status = dcerpc_samr_OemChangePasswordUser2_r(h, mem_ctx, &oe2);
        if (!NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
                if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(oe2.out.result)) {
                        status = oe2.out.result;
                }
                if (!NT_STATUS_IS_OK(oe2.out.result)) {
-                       r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                                                  "samr_OemChangePasswordUser2 for '%s\\%s' failed: %s",
-                                                                  r->samr.in.domain_name, r->samr.in.account_name,
-                                                                  nt_errstr(status));
+                       *error_string =
+                               talloc_asprintf(mem_ctx,
+                                               "samr_OemChangePasswordUser2 "
+                                               "for '%s\\%s' failed: %s",
+                                               server->string,
+                                               account->string,
+                                               nt_errstr(status));
                }
+               goto done;
+       }
+
+       status = NT_STATUS_OK;
+done:
+       return status;
+}
+
+/*
+ * do a password change using DCERPC/SAMR calls
+ * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
+ * 2. try samr_ChangePasswordUser3
+ * 3. try samr_ChangePasswordUser2
+ * 4. try samr_OemChangePasswordUser2
+ */
+static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
+{
+        NTSTATUS status;
+       struct libnet_RpcConnect c;
+       struct lsa_String server, account;
+
+       ZERO_STRUCT(c);
+
+       /* prepare connect to the SAMR pipe of the users domain PDC */
+       c.level                    = LIBNET_RPC_CONNECT_PDC;
+       c.in.name                  = r->samr.in.domain_name;
+       c.in.dcerpc_iface          = &ndr_table_samr;
+       c.in.dcerpc_flags          = DCERPC_ANON_FALLBACK;
+
+       /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
+       status = libnet_RpcConnect(ctx, mem_ctx, &c);
+       if (!NT_STATUS_IS_OK(status)) {
+               r->samr.out.error_string = talloc_asprintf(mem_ctx,
+                                               "Connection to SAMR pipe of PDC of domain '%s' failed: %s",
+                                               r->samr.in.domain_name, nt_errstr(status));
+               return status;
+       }
+
+       /* prepare password change for account */
+       server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.out.dcerpc_pipe));
+       account.string = r->samr.in.account_name;
+
+       status = libnet_ChangePassword_samr_rc4(
+               mem_ctx,
+               c.out.dcerpc_pipe->binding_handle,
+               &server,
+               &account,
+               r->samr.in.oldpassword,
+               r->samr.in.newpassword,
+               &(r->samr.out.error_string));
+       if (!NT_STATUS_IS_OK(status)) {
                goto disconnect;
        }