r25026: Move param/param.h out of includes.h
[kai/samba.git] / source4 / libnet / libnet_join.c
index ed9869980438aaae66d2c453dfe75204b332cea9..9404bc874d9077921a17152bd13e1fd3d1123de4 100644 (file)
@@ -7,7 +7,7 @@
  
    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
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -16,8 +16,7 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
@@ -32,6 +31,7 @@
 #include "auth/credentials/credentials.h"
 #include "auth/credentials/credentials_krb5.h"
 #include "librpc/gen_ndr/ndr_samr_c.h"
+#include "param/param.h"
 
 /*
  * complete a domain join, when joining to a AD domain:
@@ -70,12 +70,11 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
 
        int ret, rtn;
 
-       unsigned int kvno;
-       
        const char * const attrs[] = {
                "msDS-KeyVersionNumber",
                "servicePrincipalName",
                "dNSHostName",
+               "objectGUID",
                NULL,
        };
 
@@ -112,13 +111,13 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
        status = dcerpc_pipe_connect_b(tmp_ctx, 
                                       &drsuapi_pipe,
                                       drsuapi_binding,
-                                      &dcerpc_table_drsuapi,
+                                      &ndr_table_drsuapi,
                                       ctx->cred, 
                                       ctx->event_ctx);
        if (!NT_STATUS_IS_OK(status)) {
                r->out.error_string = talloc_asprintf(r,
                                        "Connection to DRSUAPI pipe of PDC of domain '%s' failed: %s",
-                                       r->in.domain_name,
+                                       r->out.domain_name,
                                        nt_errstr(status));
                talloc_free(tmp_ctx);
                return status;
@@ -161,8 +160,8 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
        ZERO_STRUCT(r_crack_names);
        r_crack_names.in.bind_handle            = &drsuapi_bind_handle;
        r_crack_names.in.level                  = 1;
-       r_crack_names.in.req.req1.unknown1      = 0x000004e4;
-       r_crack_names.in.req.req1.unknown2      = 0x00000407;
+       r_crack_names.in.req.req1.codepage      = 1252; /* western european */
+       r_crack_names.in.req.req1.language      = 0x00000407; /* german */
        r_crack_names.in.req.req1.count         = 1;
        r_crack_names.in.req.req1.names         = names;
        r_crack_names.in.req.req1.format_flags  = DRSUAPI_DS_NAME_FLAG_NO_FLAGS;
@@ -219,14 +218,6 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
        /* Store the DN of our machine account. */
        account_dn_str = r_crack_names.out.ctr.ctr1->array[0].result_name;
 
-       account_dn = ldb_dn_new(tmp_ctx, remote_ldb, account_dn_str);
-       if (! ldb_dn_validate(account_dn)) {
-               r->out.error_string = talloc_asprintf(r, "Invalid account dn: %s",
-                                                     account_dn_str);
-               talloc_free(tmp_ctx);
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
        /* Now we know the user's DN, open with LDAP, read and modify a few things */
 
        remote_ldb_url = talloc_asprintf(tmp_ctx, "ldap://%s", 
@@ -245,6 +236,14 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
                return NT_STATUS_UNSUCCESSFUL;
        }
 
+       account_dn = ldb_dn_new(tmp_ctx, remote_ldb, account_dn_str);
+       if (! ldb_dn_validate(account_dn)) {
+               r->out.error_string = talloc_asprintf(r, "Invalid account dn: %s",
+                                                     account_dn_str);
+               talloc_free(tmp_ctx);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
        /* search for the user's record */
        ret = ldb_search(remote_ldb, account_dn, LDB_SCOPE_BASE, 
                         NULL, attrs, &res);
@@ -264,9 +263,6 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
                return NT_STATUS_UNSUCCESSFUL;
        }
 
-       /* If we have a kvno recorded in AD, we need it locally as well */
-       kvno = ldb_msg_find_attr_as_uint(res->msgs[0], "msDS-KeyVersionNumber", 0);
-
        /* Prepare a new message, for the modify */
        msg = ldb_msg_new(tmp_ctx);
        if (!msg) {
@@ -383,7 +379,12 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
        r->out.domain_dn_str = r_crack_names.out.ctr.ctr1->array[0].result_name;
        talloc_steal(r, r_crack_names.out.ctr.ctr1->array[0].result_name);
 
-       r->out.kvno = kvno;
+       /* Store the KVNO of the account, critical for some kerberos
+        * operations */
+       r->out.kvno = ldb_msg_find_attr_as_uint(res->msgs[0], "msDS-KeyVersionNumber", 0);
+
+       /* Store the account GUID. */
+       r->out.account_guid = samdb_result_guid(res->msgs[0], "objectGUID");
 
        if (r->in.acct_type == ACB_SVRTRUST) {
                status = libnet_JoinSite(remote_ldb, r);
@@ -408,9 +409,9 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
  * - potentially delete and recreate the user
  * - assert the account is of the right type with samrQueryUserInfo
  * 
- * - call libnet_SetPassword_samr_handle to set the password
+ * - call libnet_SetPassword_samr_handle to set the password,
+ *   and pass a samr_UserInfo21 struct to set full_name and the account flags
  *
- * - do a samrSetUserInfo to set the account flags
  * - do some ADS specific things when we join as Domain Controller,
  *    look at libnet_joinADSDomain() for the details
  */
@@ -432,8 +433,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
        struct samr_CreateUser2 cu;
        struct policy_handle *u_handle = NULL;
        struct samr_QueryUserInfo qui;
-       struct samr_SetUserInfo sui;
-       union samr_UserInfo u_info;
+       struct samr_UserInfo21 u_info21;
        union libnet_SetPassword r2;
        struct samr_GetUserPwInfo pwp;
        struct lsa_String samr_account_name;
@@ -468,7 +468,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                return NT_STATUS_NO_MEMORY;
        }
 
-       /* prepare connect to the LSA pipe of PDC */
+       /* prepare connect to the SAMR pipe of PDC */
        if (r->in.level == LIBNET_JOINDOMAIN_AUTOMATIC) {
                connect_with_info->in.binding = NULL;
                connect_with_info->in.name    = r->in.domain_name;
@@ -477,11 +477,13 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                connect_with_info->in.name    = NULL;
        }
 
+       /* This level makes a connection to the LSA pipe on the way,
+        * to get some useful bits of information about the domain */
        connect_with_info->level              = LIBNET_RPC_CONNECT_DC_INFO;
-       connect_with_info->in.dcerpc_iface    = &dcerpc_table_samr;
+       connect_with_info->in.dcerpc_iface    = &ndr_table_samr;
 
        /*
-         establish a SAMR connection, on the same CIFS transport
+         establish the SAMR connection
        */
        status = libnet_RpcConnect(ctx, tmp_ctx, connect_with_info);
        if (!NT_STATUS_IS_OK(status)) {
@@ -502,7 +504,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
 
        status = dcerpc_pipe_auth(tmp_ctx, &samr_pipe,
                                  connect_with_info->out.dcerpc_pipe->binding, 
-                                 &dcerpc_table_samr, ctx->cred);
+                                 &ndr_table_samr, ctx->cred);
        if (!NT_STATUS_IS_OK(status)) {
                r->out.error_string = talloc_asprintf(mem_ctx,
                                                "SAMR bind failed: %s",
@@ -534,6 +536,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                } else {
                        /* Bugger, we just lost our way to automaticly find the domain name */
                        connect_with_info->out.domain_name = talloc_strdup(tmp_ctx, lp_workgroup());
+                       connect_with_info->out.realm = talloc_strdup(tmp_ctx, lp_realm());
                }
        }
 
@@ -756,7 +759,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                acct_flags = qui.out.info->info16.acct_flags;
        }
        
-       acct_flags = (acct_flags & ~ACB_DISABLED);
+       acct_flags = (acct_flags & ~(ACB_DISABLED|ACB_PWNOTREQ));
 
        /* Find out what password policy this user has */
        pwp.in.user_handle = u_handle;
@@ -770,11 +773,18 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
        
        password_str = generate_random_str(tmp_ctx, MAX(8, policy_min_pw_len)); 
 
+       /* set full_name and reset flags */
+       ZERO_STRUCT(u_info21);
+       u_info21.full_name.string       = r->in.account_name;
+       u_info21.acct_flags             = acct_flags;
+       u_info21.fields_present         = SAMR_FIELD_FULL_NAME | SAMR_FIELD_ACCT_FLAGS;
+
        r2.samr_handle.level            = LIBNET_SET_PASSWORD_SAMR_HANDLE;
        r2.samr_handle.in.account_name  = r->in.account_name;
        r2.samr_handle.in.newpassword   = password_str;
        r2.samr_handle.in.user_handle   = u_handle;
        r2.samr_handle.in.dcerpc_pipe   = samr_pipe;
+       r2.samr_handle.in.info21        = &u_info21;
 
        status = libnet_SetPassword(ctx, tmp_ctx, &r2); 
        if (!NT_STATUS_IS_OK(status)) {
@@ -783,26 +793,6 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                return status;
        }
 
-       /* reset flags (if required) */
-       if (acct_flags != qui.out.info->info16.acct_flags) {
-               ZERO_STRUCT(u_info);
-               u_info.info16.acct_flags = acct_flags;
-
-               sui.in.user_handle = u_handle;
-               sui.in.info = &u_info;
-               sui.in.level = 16;
-               
-               dcerpc_samr_SetUserInfo(samr_pipe, tmp_ctx, &sui);
-               if (!NT_STATUS_IS_OK(status)) {
-                       r->out.error_string = talloc_asprintf(mem_ctx,
-                                                       "samr_SetUserInfo for [%s] failed to remove ACB_DISABLED flag: %s",
-                                                       r->in.account_name,
-                                                       nt_errstr(status));
-                       talloc_free(tmp_ctx);
-                       return status;
-               }
-       }
-
        account_sid = dom_sid_add_rid(mem_ctx, connect_with_info->out.domain_sid, rid);
        if (!account_sid) {
                r->out.error_string = NULL;
@@ -870,7 +860,6 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
        uint32_t acct_type = 0;
        const char *account_name;
        const char *netbios_name;
-       char *filter;
        
        r->out.error_string = NULL;
 
@@ -1153,33 +1142,6 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
-       if (r2->out.realm) {
-               struct cli_credentials *creds;
-               /* Make a credentials structure from it */
-               creds = cli_credentials_init(mem_ctx);
-               if (!creds) {
-                       r->out.error_string = NULL;
-                       talloc_free(tmp_mem);
-                       return NT_STATUS_NO_MEMORY;
-               }
-               cli_credentials_set_conf(creds);
-               filter = talloc_asprintf(mem_ctx, "dn=%s", ldb_dn_get_linearized(msg->dn));
-               status = cli_credentials_set_secrets(creds, NULL, filter);
-               if (!NT_STATUS_IS_OK(status)) {
-                       r->out.error_string = talloc_asprintf(mem_ctx, "Failed to read secrets for keytab update for %s", 
-                                                             filter);
-                       talloc_free(tmp_mem);
-                       return status;
-               } 
-               ret = cli_credentials_update_keytab(creds);
-               if (ret != 0) {
-                       r->out.error_string = talloc_asprintf(mem_ctx, "Failed to update keytab for %s", 
-                                                             filter);
-                       talloc_free(tmp_mem);
-                       return NT_STATUS_UNSUCCESSFUL;
-               }
-       }
-
        /* move all out parameter to the callers TALLOC_CTX */
        r->out.error_string     = NULL;
        r->out.join_password    = r2->out.join_password;