r14380: Reduce the size of structs.h
[jelmer/samba4-debian.git] / source / libnet / libnet_passwd.c
index c20a7733a3b7a81b66bd629e57d41de8c91e5c3a..30012282e090aec66a18be82ec691681a7bd40d5 100644 (file)
@@ -2,6 +2,7 @@
    Unix SMB/CIFS implementation.
    
    Copyright (C) Stefan Metzmacher     2004
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
    
    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
 */
 
 #include "includes.h"
+#include "smb.h"
 #include "libnet/libnet.h"
-#include "librpc/gen_ndr/ndr_samr.h"
 #include "lib/crypto/crypto.h"
+#include "libcli/auth/libcli_auth.h"
 
 /*
  * do a password change using DCERPC/SAMR calls
@@ -34,7 +36,7 @@
 static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
 {
         NTSTATUS status;
-       union libnet_rpc_connect c;
+       struct libnet_RpcConnect c;
 #if 0
        struct policy_handle user_handle;
        struct samr_Password hash1, hash2, hash3, hash4, hash5, hash6;
@@ -43,22 +45,20 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT
        struct samr_OemChangePasswordUser2 oe2;
        struct samr_ChangePasswordUser2 pw2;
        struct samr_ChangePasswordUser3 pw3;
-       struct samr_Name server, account;
-       struct samr_AsciiName a_server, a_account;
+       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];
 
        /* prepare connect to the SAMR pipe of the users domain PDC */
-       c.pdc.level                     = LIBNET_RPC_CONNECT_PDC;
-       c.pdc.in.domain_name            = r->samr.in.domain_name;
-       c.pdc.in.dcerpc_iface_name      = DCERPC_SAMR_NAME;
-       c.pdc.in.dcerpc_iface_uuid      = DCERPC_SAMR_UUID;
-       c.pdc.in.dcerpc_iface_version   = DCERPC_SAMR_VERSION;
+       c.level                    = LIBNET_RPC_CONNECT_PDC;
+       c.in.name                  = r->samr.in.domain_name;
+       c.in.dcerpc_iface          = &dcerpc_table_samr;
 
        /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
-       status = libnet_rpc_connect(ctx, mem_ctx, &c);
+       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\n",
@@ -67,8 +67,8 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT
        }
 
        /* prepare password change for account */
-       server.name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.pdc.out.dcerpc_pipe));
-       account.name = r->samr.in.account_name;
+       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);
@@ -95,7 +95,7 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT
        pw3.in.password3 = NULL;
 
        /* 2. try samr_ChangePasswordUser3 */
-       status = dcerpc_samr_ChangePasswordUser3(c.pdc.out.dcerpc_pipe, mem_ctx, &pw3);
+       status = dcerpc_samr_ChangePasswordUser3(c.out.dcerpc_pipe, mem_ctx, &pw3);
        if (!NT_STATUS_IS_OK(status)) {
                r->samr.out.error_string = talloc_asprintf(mem_ctx,
                                                "samr_ChangePasswordUser3 failed: %s\n",
@@ -138,7 +138,7 @@ ChangePasswordUser2:
        pw2.in.lm_verifier = &lm_verifier;
 
        /* 3. try samr_ChangePasswordUser2 */
-       status = dcerpc_samr_ChangePasswordUser2(c.pdc.out.dcerpc_pipe, mem_ctx, &pw2);
+       status = dcerpc_samr_ChangePasswordUser2(c.out.dcerpc_pipe, mem_ctx, &pw2);
        if (!NT_STATUS_IS_OK(status)) {
                r->samr.out.error_string = talloc_asprintf(mem_ctx,
                                                "samr_ChangePasswordUser2 failed: %s\n",
@@ -163,8 +163,8 @@ ChangePasswordUser2:
 
 OemChangePasswordUser2:
        /* prepare samr_OemChangePasswordUser2 */
-       a_server.name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.pdc.out.dcerpc_pipe));
-       a_account.name = r->samr.in.account_name;
+       a_server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.out.dcerpc_pipe));
+       a_account.string = r->samr.in.account_name;
 
        encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII);
        arcfour_crypt(lm_pass.data, old_lm_hash, 516);
@@ -176,7 +176,7 @@ OemChangePasswordUser2:
        oe2.in.hash = &lm_verifier;
 
        /* 4. try samr_OemChangePasswordUser2 */
-       status = dcerpc_samr_OemChangePasswordUser2(c.pdc.out.dcerpc_pipe, mem_ctx, &oe2);
+       status = dcerpc_samr_OemChangePasswordUser2(c.out.dcerpc_pipe, mem_ctx, &oe2);
        if (!NT_STATUS_IS_OK(status)) {
                r->samr.out.error_string = talloc_asprintf(mem_ctx,
                                                "samr_OemChangePasswordUser2 failed: %s\n",
@@ -246,7 +246,7 @@ ChangePasswordUser:
 #endif
 disconnect:
        /* close connection */
-       dcerpc_pipe_close(c.pdc.out.dcerpc_pipe);
+       talloc_free(c.out.dcerpc_pipe);
 
        return status;
 }
@@ -287,6 +287,209 @@ NTSTATUS libnet_ChangePassword(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
        return NT_STATUS_INVALID_LEVEL;
 }
 
+static NTSTATUS libnet_SetPassword_samr_handle_26(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
+{
+       NTSTATUS status;
+       struct samr_SetUserInfo sui;
+       union samr_UserInfo u_info;
+       DATA_BLOB session_key;
+       DATA_BLOB confounded_session_key = data_blob_talloc(mem_ctx, NULL, 16);
+       uint8_t confounder[16]; 
+       struct MD5Context md5;
+
+       /* prepare samr_SetUserInfo level 26 */
+       ZERO_STRUCT(u_info);
+       encode_pw_buffer(u_info.info26.password.data, r->samr_handle.in.newpassword, STR_UNICODE);
+       u_info.info26.pw_len = strlen(r->samr_handle.in.newpassword);
+       
+       status = dcerpc_fetch_session_key(r->samr_handle.in.dcerpc_pipe, &session_key);
+       if (!NT_STATUS_IS_OK(status)) {
+               r->samr_handle.out.error_string = talloc_asprintf(mem_ctx,
+                                                                 "dcerpc_fetch_session_key failed: %s\n",
+                                                                 nt_errstr(status));
+               return status;
+       }
+       
+       generate_random_buffer((uint8_t *)confounder, 16);
+       
+       MD5Init(&md5);
+       MD5Update(&md5, confounder, 16);
+       MD5Update(&md5, session_key.data, session_key.length);
+       MD5Final(confounded_session_key.data, &md5);
+       
+       arcfour_crypt_blob(u_info.info26.password.data, 516, &confounded_session_key);
+       memcpy(&u_info.info26.password.data[516], confounder, 16);
+       
+       sui.in.user_handle = r->samr_handle.in.user_handle;
+       sui.in.info = &u_info;
+       sui.in.level = 26;
+       
+       /* 7. try samr_SetUserInfo level 26 to set the password */
+       status = dcerpc_samr_SetUserInfo(r->samr_handle.in.dcerpc_pipe, mem_ctx, &sui);
+       /* check result of samr_SetUserInfo level 26 */
+       if (!NT_STATUS_IS_OK(status)) {
+               r->samr_handle.out.error_string
+                       = talloc_asprintf(mem_ctx,
+                                         "SetUserInfo level 26 for [%s] failed: %s\n",
+                                         r->samr_handle.in.account_name, nt_errstr(status));
+       }
+       return status;
+}
+
+static NTSTATUS libnet_SetPassword_samr_handle_25(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
+{
+       NTSTATUS status;
+       struct samr_SetUserInfo sui;
+       union samr_UserInfo u_info;
+       DATA_BLOB session_key;
+       DATA_BLOB confounded_session_key = data_blob_talloc(mem_ctx, NULL, 16);
+       uint8_t confounder[16]; 
+       struct MD5Context md5;
+
+       /* prepare samr_SetUserInfo level 25 */
+       ZERO_STRUCT(u_info);
+       u_info.info25.info.fields_present = SAMR_FIELD_PASSWORD;
+       encode_pw_buffer(u_info.info25.password.data, r->samr_handle.in.newpassword, STR_UNICODE);
+
+       status = dcerpc_fetch_session_key(r->samr_handle.in.dcerpc_pipe, &session_key);
+       if (!NT_STATUS_IS_OK(status)) {
+               r->samr_handle.out.error_string = talloc_asprintf(mem_ctx,
+                                               "dcerpc_fetch_session_key failed: %s\n",
+                                               nt_errstr(status));
+               return status;
+       }
+
+       generate_random_buffer((uint8_t *)confounder, 16);
+
+       MD5Init(&md5);
+       MD5Update(&md5, confounder, 16);
+       MD5Update(&md5, session_key.data, session_key.length);
+       MD5Final(confounded_session_key.data, &md5);
+
+       arcfour_crypt_blob(u_info.info25.password.data, 516, &confounded_session_key);
+       memcpy(&u_info.info25.password.data[516], confounder, 16);
+
+       sui.in.user_handle = r->samr_handle.in.user_handle;
+       sui.in.info = &u_info;
+       sui.in.level = 25;
+
+       /* 8. try samr_SetUserInfo level 25 to set the password */
+       status = dcerpc_samr_SetUserInfo(r->samr_handle.in.dcerpc_pipe, mem_ctx, &sui);
+       if (!NT_STATUS_IS_OK(status)) {
+               r->samr_handle.out.error_string
+                       = talloc_asprintf(mem_ctx,
+                                         "SetUserInfo level 25 for [%s] failed: %s\n",
+                                         r->samr_handle.in.account_name, nt_errstr(status));
+       }
+       return status;
+}
+
+static NTSTATUS libnet_SetPassword_samr_handle_24(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
+{
+       NTSTATUS status;
+       struct samr_SetUserInfo sui;
+       union samr_UserInfo u_info;
+       DATA_BLOB session_key;
+
+       /* prepare samr_SetUserInfo level 24 */
+       ZERO_STRUCT(u_info);
+       encode_pw_buffer(u_info.info24.password.data, r->samr_handle.in.newpassword, STR_UNICODE);
+       /* w2k3 ignores this length */
+       u_info.info24.pw_len = strlen_m(r->samr_handle.in.newpassword)*2;
+
+       status = dcerpc_fetch_session_key(r->samr_handle.in.dcerpc_pipe, &session_key);
+       if (!NT_STATUS_IS_OK(status)) {
+               r->samr_handle.out.error_string = talloc_asprintf(mem_ctx,
+                                               "dcerpc_fetch_session_key failed: %s\n",
+                                               nt_errstr(status));
+               return status;
+       }
+
+       arcfour_crypt_blob(u_info.info24.password.data, 516, &session_key);
+
+       sui.in.user_handle = r->samr_handle.in.user_handle;
+       sui.in.info = &u_info;
+       sui.in.level = 24;
+
+       /* 9. try samr_SetUserInfo level 24 to set the password */
+       status = dcerpc_samr_SetUserInfo(r->samr_handle.in.dcerpc_pipe, mem_ctx, &sui);
+       if (!NT_STATUS_IS_OK(status)) {
+               r->samr_handle.out.error_string
+                       = talloc_asprintf(mem_ctx,
+                                         "SetUserInfo level 24 for [%s] failed: %s\n",
+                                         r->samr_handle.in.account_name, nt_errstr(status));
+       }
+       return status;
+}
+
+static NTSTATUS libnet_SetPassword_samr_handle_23(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
+{
+       NTSTATUS status;
+       struct samr_SetUserInfo sui;
+       union samr_UserInfo u_info;
+       DATA_BLOB session_key;
+
+       /* prepare samr_SetUserInfo level 23 */
+       ZERO_STRUCT(u_info);
+       u_info.info23.info.fields_present = SAMR_FIELD_PASSWORD;
+       encode_pw_buffer(u_info.info23.password.data, r->samr_handle.in.newpassword, STR_UNICODE);
+
+       status = dcerpc_fetch_session_key(r->samr_handle.in.dcerpc_pipe, &session_key);
+       if (!NT_STATUS_IS_OK(status)) {
+               r->samr_handle.out.error_string
+                       = talloc_asprintf(mem_ctx,
+                                         "dcerpc_fetch_session_key failed: %s\n",
+                                         nt_errstr(status));
+               return status;
+       }
+
+       arcfour_crypt_blob(u_info.info23.password.data, 516, &session_key);
+
+       sui.in.user_handle = r->samr_handle.in.user_handle;
+       sui.in.info = &u_info;
+       sui.in.level = 23;
+
+       /* 10. try samr_SetUserInfo level 23 to set the password */
+       status = dcerpc_samr_SetUserInfo(r->samr_handle.in.dcerpc_pipe, mem_ctx, &sui);
+       if (!NT_STATUS_IS_OK(status)) {
+               r->samr_handle.out.error_string
+                       = talloc_asprintf(mem_ctx,
+                                         "SetUserInfo level 23 for [%s] failed: %s\n",
+                                         r->samr_handle.in.account_name, nt_errstr(status));
+       }
+       return status;
+}
+
+/*
+ * 1. try samr_SetUserInfo level 26 to set the password
+ * 2. try samr_SetUserInfo level 25 to set the password
+ * 3. try samr_SetUserInfo level 24 to set the password
+ * 4. try samr_SetUserInfo level 23 to set the password
+*/
+static NTSTATUS libnet_SetPassword_samr_handle(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
+{
+       NTSTATUS status;
+       enum libnet_SetPassword_level levels[] = {
+               LIBNET_SET_PASSWORD_SAMR_HANDLE_26,
+               LIBNET_SET_PASSWORD_SAMR_HANDLE_25,
+               LIBNET_SET_PASSWORD_SAMR_HANDLE_24,
+               LIBNET_SET_PASSWORD_SAMR_HANDLE_23,
+       };
+       int i;
+       
+       for (i=0; i < ARRAY_SIZE(levels); i++) {
+               r->generic.level = levels[i];
+               status = libnet_SetPassword(ctx, mem_ctx, r);
+               if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)
+                   || NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
+                       /* Try another password set mechanism */
+                       continue;
+               }
+               break;
+       }
+       
+       return status;
+}
 /*
  * set a password with DCERPC/SAMR calls
  * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
@@ -296,55 +499,45 @@ NTSTATUS libnet_ChangePassword(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
  * 4. do a samr_OpenDomain to get a domain handle
  * 5. do a samr_LookupNames to get the users rid
  * 6. do a samr_OpenUser to get a user handle
- * 7. try samr_SetUserInfo level 26 to set the password
- * 8. try samr_SetUserInfo level 25 to set the password
- * 8. try samr_SetUserInfo level 24 to set the password
- *10. try samr_SetUserInfo level 23 to set the password
+ * 7  call libnet_SetPassword_samr_handle to set the password
  */
 static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
 {
        NTSTATUS status;
-       union libnet_rpc_connect c;
+       struct libnet_RpcConnect c;
        struct samr_Connect sc;
        struct policy_handle p_handle;
        struct samr_LookupDomain ld;
-       struct samr_Name d_name;
+       struct lsa_String d_name;
        struct samr_OpenDomain od;
        struct policy_handle d_handle;
        struct samr_LookupNames ln;
        struct samr_OpenUser ou;
        struct policy_handle u_handle;
-       struct samr_SetUserInfo sui;
-       union samr_UserInfo u_info;
-       DATA_BLOB session_key;
-       DATA_BLOB confounded_session_key = data_blob_talloc(mem_ctx, NULL, 16);
-       uint8_t confounder[16]; 
-       struct MD5Context md5;
+       union libnet_SetPassword r2;
 
        /* prepare connect to the SAMR pipe of users domain PDC */
-       c.pdc.level                     = LIBNET_RPC_CONNECT_PDC;
-       c.pdc.in.domain_name            = r->samr.in.domain_name;
-       c.pdc.in.dcerpc_iface_name      = DCERPC_SAMR_NAME;
-       c.pdc.in.dcerpc_iface_uuid      = DCERPC_SAMR_UUID;
-       c.pdc.in.dcerpc_iface_version   = DCERPC_SAMR_VERSION;
+       c.level               = LIBNET_RPC_CONNECT_PDC;
+       c.in.name             = r->samr.in.domain_name;
+       c.in.dcerpc_iface     = &dcerpc_table_samr;
 
        /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
-       status = libnet_rpc_connect(ctx, mem_ctx, &c);
+       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\n",
-                                               r->samr.in.domain_name, nt_errstr(status));
+                                                          "Connection to SAMR pipe of PDC of domain '%s' failed: %s\n",
+                                                          r->samr.in.domain_name, nt_errstr(status));
                return status;
        }
 
        /* prepare samr_Connect */
        ZERO_STRUCT(p_handle);
        sc.in.system_name = NULL;
-       sc.in.access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
+       sc.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
        sc.out.connect_handle = &p_handle;
 
        /* 2. do a samr_Connect to get a policy handle */
-       status = dcerpc_samr_Connect(c.pdc.out.dcerpc_pipe, mem_ctx, &sc);
+       status = dcerpc_samr_Connect(c.out.dcerpc_pipe, mem_ctx, &sc);
        if (!NT_STATUS_IS_OK(status)) {
                r->samr.out.error_string = talloc_asprintf(mem_ctx,
                                                "samr_Connect failed: %s\n",
@@ -352,22 +545,13 @@ static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX *
                goto disconnect;
        }
 
-       /* check result of samr_Connect */
-       if (!NT_STATUS_IS_OK(sc.out.result)) {
-               r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                               "samr_Connect failed: %s\n", 
-                                               nt_errstr(sc.out.result));
-               status = sc.out.result;
-               goto disconnect;
-       }
-
        /* prepare samr_LookupDomain */
-       d_name.name = r->samr.in.domain_name;
+       d_name.string = r->samr.in.domain_name;
        ld.in.connect_handle = &p_handle;
-       ld.in.domain = &d_name;
+       ld.in.domain_name = &d_name;
 
        /* 3. do a samr_LookupDomain to get the domain sid */
-       status = dcerpc_samr_LookupDomain(c.pdc.out.dcerpc_pipe, mem_ctx, &ld);
+       status = dcerpc_samr_LookupDomain(c.out.dcerpc_pipe, mem_ctx, &ld);
        if (!NT_STATUS_IS_OK(status)) {
                r->samr.out.error_string = talloc_asprintf(mem_ctx,
                                                "samr_LookupDomain for [%s] failed: %s\n",
@@ -375,24 +559,15 @@ static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX *
                goto disconnect;
        }
 
-       /* check result of samr_LookupDomain */
-       if (!NT_STATUS_IS_OK(ld.out.result)) {
-               r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                               "samr_LookupDomain for [%s] failed: %s\n",
-                                               r->samr.in.domain_name, nt_errstr(ld.out.result));
-               status = ld.out.result;
-               goto disconnect;
-       }
-
        /* prepare samr_OpenDomain */
        ZERO_STRUCT(d_handle);
        od.in.connect_handle = &p_handle;
-       od.in.access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
+       od.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
        od.in.sid = ld.out.sid;
        od.out.domain_handle = &d_handle;
 
        /* 4. do a samr_OpenDomain to get a domain handle */
-       status = dcerpc_samr_OpenDomain(c.pdc.out.dcerpc_pipe, mem_ctx, &od);
+       status = dcerpc_samr_OpenDomain(c.out.dcerpc_pipe, mem_ctx, &od);
        if (!NT_STATUS_IS_OK(status)) {
                r->samr.out.error_string = talloc_asprintf(mem_ctx,
                                                "samr_OpenDomain for [%s] failed: %s\n",
@@ -400,27 +575,18 @@ static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX *
                goto disconnect;
        }
 
-       /* check result of samr_OpenDomain */
-       if (!NT_STATUS_IS_OK(od.out.result)) {
-               r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                               "samr_OpenDomain for [%s] failed: %s\n",
-                                               r->samr.in.domain_name, nt_errstr(od.out.result));
-               status = od.out.result;
-               goto disconnect;
-       }
-
        /* prepare samr_LookupNames */
        ln.in.domain_handle = &d_handle;
        ln.in.num_names = 1;
-       ln.in.names = talloc_array_p(mem_ctx, struct samr_Name, 1);
+       ln.in.names = talloc_array(mem_ctx, struct lsa_String, 1);
        if (!ln.in.names) {
                r->samr.out.error_string = "Out of Memory";
                return NT_STATUS_NO_MEMORY;
        }
-       ln.in.names[0].name = r->samr.in.account_name;
+       ln.in.names[0].string = r->samr.in.account_name;
 
        /* 5. do a samr_LookupNames to get the users rid */
-       status = dcerpc_samr_LookupNames(c.pdc.out.dcerpc_pipe, mem_ctx, &ln);
+       status = dcerpc_samr_LookupNames(c.out.dcerpc_pipe, mem_ctx, &ln);
        if (!NT_STATUS_IS_OK(status)) {
                r->samr.out.error_string = talloc_asprintf(mem_ctx,
                                                "samr_LookupNames for [%s] failed: %s\n",
@@ -428,15 +594,6 @@ static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX *
                goto disconnect;
        }
 
-       /* check result of samr_LookupNames */
-       if (!NT_STATUS_IS_OK(ln.out.result)) {
-               r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                               "samr_LookupNames for [%s] failed: %s\n",
-                                               r->samr.in.account_name, nt_errstr(ln.out.result));
-               status = ln.out.result;
-               goto disconnect;
-       }
-
        /* check if we got one RID for the user */
        if (ln.out.rids.count != 1) {
                r->samr.out.error_string = talloc_asprintf(mem_ctx,
@@ -449,12 +606,12 @@ static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX *
        /* prepare samr_OpenUser */
        ZERO_STRUCT(u_handle);
        ou.in.domain_handle = &d_handle;
-       ou.in.access_mask = SEC_RIGHTS_MAXIMUM_ALLOWED;
+       ou.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
        ou.in.rid = ln.out.rids.ids[0];
        ou.out.user_handle = &u_handle;
 
        /* 6. do a samr_OpenUser to get a user handle */
-       status = dcerpc_samr_OpenUser(c.pdc.out.dcerpc_pipe, mem_ctx, &ou);
+       status = dcerpc_samr_OpenUser(c.out.dcerpc_pipe, mem_ctx, &ou);
        if (!NT_STATUS_IS_OK(status)) {
                r->samr.out.error_string = talloc_asprintf(mem_ctx,
                                                "samr_OpenUser for [%s] failed: %s\n",
@@ -462,206 +619,19 @@ static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX *
                goto disconnect;
        }
 
-       /* check result of samr_OpenUser */
-       if (!NT_STATUS_IS_OK(ou.out.result)) {
-               r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                               "samr_OpenUser for [%s] failed: %s\n",
-                                               r->samr.in.account_name, nt_errstr(ou.out.result));
-               status = ou.out.result;
-               goto disconnect;
-       }
-
-       /* prepare samr_SetUserInfo level 26 */
-       ZERO_STRUCT(u_info);
-       encode_pw_buffer(u_info.info26.password.data, r->samr.in.newpassword, STR_UNICODE);
-       u_info.info26.pw_len = strlen(r->samr.in.newpassword);
-
-       status = dcerpc_fetch_session_key(c.pdc.out.dcerpc_pipe, &session_key);
-       if (!NT_STATUS_IS_OK(status)) {
-               r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                               "dcerpc_fetch_session_key failed: %s\n",
-                                               nt_errstr(status));
-               goto disconnect;
-       }
-
-       generate_random_buffer((uint8_t *)confounder, 16);
-
-       MD5Init(&md5);
-       MD5Update(&md5, confounder, 16);
-       MD5Update(&md5, session_key.data, session_key.length);
-       MD5Final(confounded_session_key.data, &md5);
-
-       arcfour_crypt_blob(u_info.info26.password.data, 516, &confounded_session_key);
-       memcpy(&u_info.info26.password.data[516], confounder, 16);
-
-       sui.in.user_handle = &u_handle;
-       sui.in.info = &u_info;
-       sui.in.level = 26;
-
-       /* 7. try samr_SetUserInfo level 26 to set the password */
-       status = dcerpc_samr_SetUserInfo(c.pdc.out.dcerpc_pipe, mem_ctx, &sui);
-       if (!NT_STATUS_IS_OK(status)) {
-               r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                               "SetUserInfo level 26 for [%s] failed: %s\n",
-                                               r->samr.in.account_name, nt_errstr(status));
-               goto UserInfo25;
-       }
-
-       /* check result of samr_SetUserInfo level 26 */
-       if (!NT_STATUS_IS_OK(sui.out.result)) {
-               r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                               "SetUserInfo level 26 for [%s] failed: %s\n",
-                                               r->samr.in.account_name, nt_errstr(sui.out.result));
-               if (NT_STATUS_EQUAL(sui.out.result, NT_STATUS_WRONG_PASSWORD)) {
-                       status = sui.out.result;
-                       goto disconnect;
-               }
-               goto UserInfo25;
-       }
-
-       goto disconnect;
-
-UserInfo25:
-       /* prepare samr_SetUserInfo level 25 */
-       ZERO_STRUCT(u_info);
-       u_info.info25.info.fields_present = SAMR_FIELD_PASSWORD;
-       encode_pw_buffer(u_info.info25.password.data, r->samr.in.newpassword, STR_UNICODE);
-
-       status = dcerpc_fetch_session_key(c.pdc.out.dcerpc_pipe, &session_key);
-       if (!NT_STATUS_IS_OK(status)) {
-               r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                               "dcerpc_fetch_session_key failed: %s\n",
-                                               nt_errstr(status));
-               goto disconnect;
-       }
-
-       generate_random_buffer((uint8_t *)confounder, 16);
-
-       MD5Init(&md5);
-       MD5Update(&md5, confounder, 16);
-       MD5Update(&md5, session_key.data, session_key.length);
-       MD5Final(confounded_session_key.data, &md5);
-
-       arcfour_crypt_blob(u_info.info25.password.data, 516, &confounded_session_key);
-       memcpy(&u_info.info25.password.data[516], confounder, 16);
-
-       sui.in.user_handle = &u_handle;
-       sui.in.info = &u_info;
-       sui.in.level = 25;
-
-       /* 8. try samr_SetUserInfo level 25 to set the password */
-       status = dcerpc_samr_SetUserInfo(c.pdc.out.dcerpc_pipe, mem_ctx, &sui);
-       if (!NT_STATUS_IS_OK(status)) {
-               r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                               "SetUserInfo level 25 for [%s] failed: %s\n",
-                                               r->samr.in.account_name, nt_errstr(status));
-               goto UserInfo24;
-       }
-
-       /* check result of samr_SetUserInfo level 25 */
-       if (!NT_STATUS_IS_OK(sui.out.result)) {
-               r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                               "SetUserInfo level 25 for [%s] failed: %s\n",
-                                               r->samr.in.account_name, nt_errstr(sui.out.result));
-               if (NT_STATUS_EQUAL(sui.out.result, NT_STATUS_WRONG_PASSWORD)) {
-                       status = sui.out.result;
-                       goto disconnect;
-               }
-               goto UserInfo24;
-       }
-
-       goto disconnect;
-
-UserInfo24:
-       /* prepare samr_SetUserInfo level 24 */
-       ZERO_STRUCT(u_info);
-       encode_pw_buffer(u_info.info24.password.data, r->samr.in.newpassword, STR_UNICODE);
-       /* w2k3 ignores this length */
-       u_info.info24.pw_len = strlen_m(r->samr.in.newpassword)*2;
-
-       status = dcerpc_fetch_session_key(c.pdc.out.dcerpc_pipe, &session_key);
-       if (!NT_STATUS_IS_OK(status)) {
-               r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                               "dcerpc_fetch_session_key failed: %s\n",
-                                               nt_errstr(status));
-               goto disconnect;
-       }
-
-       arcfour_crypt_blob(u_info.info24.password.data, 516, &session_key);
-
-       sui.in.user_handle = &u_handle;
-       sui.in.info = &u_info;
-       sui.in.level = 24;
+       r2.samr_handle.level            = LIBNET_SET_PASSWORD_SAMR_HANDLE;
+       r2.samr_handle.in.account_name  = r->samr.in.account_name;
+       r2.samr_handle.in.newpassword   = r->samr.in.newpassword;
+       r2.samr_handle.in.user_handle   = &u_handle;
+       r2.samr_handle.in.dcerpc_pipe   = c.out.dcerpc_pipe;
 
-       /* 9. try samr_SetUserInfo level 24 to set the password */
-       status = dcerpc_samr_SetUserInfo(c.pdc.out.dcerpc_pipe, mem_ctx, &sui);
-       if (!NT_STATUS_IS_OK(status)) {
-               r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                               "SetUserInfo level 24 for [%s] failed: %s\n",
-                                               r->samr.in.account_name, nt_errstr(status));
-               goto UserInfo23;
-       }
-
-       /* check result of samr_SetUserInfo level 24 */
-       if (!NT_STATUS_IS_OK(sui.out.result)) {
-               r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                               "SetUserInfo level 24 for [%s] failed: %s\n",
-                                               r->samr.in.account_name, nt_errstr(sui.out.result));
-               if (NT_STATUS_EQUAL(sui.out.result, NT_STATUS_WRONG_PASSWORD)) {
-                       status = sui.out.result;
-                       goto disconnect;
-               }
-               goto UserInfo23;
-       }
-
-       goto disconnect;
-
-UserInfo23:
-       /* prepare samr_SetUserInfo level 23 */
-       ZERO_STRUCT(u_info);
-       u_info.info23.info.fields_present = SAMR_FIELD_PASSWORD;
-       encode_pw_buffer(u_info.info23.password.data, r->samr.in.newpassword, STR_UNICODE);
-
-       status = dcerpc_fetch_session_key(c.pdc.out.dcerpc_pipe, &session_key);
-       if (!NT_STATUS_IS_OK(status)) {
-               r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                               "dcerpc_fetch_session_key failed: %s\n",
-                                               nt_errstr(status));
-               goto disconnect;
-       }
-
-       arcfour_crypt_blob(u_info.info23.password.data, 516, &session_key);
-
-       sui.in.user_handle = &u_handle;
-       sui.in.info = &u_info;
-       sui.in.level = 23;
-
-       /* 10. try samr_SetUserInfo level 23 to set the password */
-       status = dcerpc_samr_SetUserInfo(c.pdc.out.dcerpc_pipe, mem_ctx, &sui);
-       if (!NT_STATUS_IS_OK(status)) {
-               r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                               "SetUserInfo level 23 for [%s] failed: %s\n",
-                                               r->samr.in.account_name, nt_errstr(status));
-               goto disconnect;
-       }
-
-       /* check result of samr_SetUserInfo level 23 */
-       if (!NT_STATUS_IS_OK(sui.out.result)) {
-               r->samr.out.error_string = talloc_asprintf(mem_ctx,
-                                               "SetUserInfo level 23 for [%s] failed: %s\n",
-                                               r->samr.in.account_name, nt_errstr(sui.out.result));
-               if (NT_STATUS_EQUAL(sui.out.result, NT_STATUS_WRONG_PASSWORD)) {
-                       status = sui.out.result;
-                       goto disconnect;
-               }
-               goto disconnect;
-       }
+       status = libnet_SetPassword(ctx, mem_ctx, &r2);
 
-       goto disconnect;
+       r->generic.out.error_string = r2.samr_handle.out.error_string;
 
 disconnect:
        /* close connection */
-       dcerpc_pipe_close(c.pdc.out.dcerpc_pipe);
+       talloc_free(c.out.dcerpc_pipe);
 
        return status;
 }
@@ -676,6 +646,7 @@ static NTSTATUS libnet_SetPassword_generic(struct libnet_context *ctx, TALLOC_CT
        r2.samr.in.domain_name  = r->generic.in.domain_name;
        r2.samr.in.newpassword  = r->generic.in.newpassword;
 
+       r->generic.out.error_string = "Unknown Error";
        status = libnet_SetPassword(ctx, mem_ctx, &r2);
 
        r->generic.out.error_string = r2.samr.out.error_string;
@@ -690,6 +661,16 @@ NTSTATUS libnet_SetPassword(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, uni
                        return libnet_SetPassword_generic(ctx, mem_ctx, r);
                case LIBNET_SET_PASSWORD_SAMR:
                        return libnet_SetPassword_samr(ctx, mem_ctx, r);
+               case LIBNET_SET_PASSWORD_SAMR_HANDLE:
+                       return libnet_SetPassword_samr_handle(ctx, mem_ctx, r);
+               case LIBNET_SET_PASSWORD_SAMR_HANDLE_26:
+                       return libnet_SetPassword_samr_handle_26(ctx, mem_ctx, r);
+               case LIBNET_SET_PASSWORD_SAMR_HANDLE_25:
+                       return libnet_SetPassword_samr_handle_25(ctx, mem_ctx, r);
+               case LIBNET_SET_PASSWORD_SAMR_HANDLE_24:
+                       return libnet_SetPassword_samr_handle_24(ctx, mem_ctx, r);
+               case LIBNET_SET_PASSWORD_SAMR_HANDLE_23:
+                       return libnet_SetPassword_samr_handle_23(ctx, mem_ctx, r);
                case LIBNET_SET_PASSWORD_KRB5:
                        return NT_STATUS_NOT_IMPLEMENTED;
                case LIBNET_SET_PASSWORD_LDAP: