winbindd: Use a remote RPC server when we are an RODC when needed
authorAndrew Bartlett <abartlet@samba.org>
Sun, 25 May 2014 23:58:38 +0000 (11:58 +1200)
committerAndrew Bartlett <abartlet@samba.org>
Fri, 4 Jul 2014 00:52:35 +0000 (02:52 +0200)
This allows us to operate against the local cache where possible, but
to forward some operations to the read-write DC.

Andrew Bartlett

Change-Id: Idc78ae379a402969381758919fcede17568f094e
Pair-programmed-with: Garming Sam <garming@catalyst.net.nz>
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Signed-off-by: Garming Sam <garming@catalyst.net.nz>
Reviewed-by: Nadezhda Ivanova <nivanova@samba.org>
source3/winbindd/winbindd.h
source3/winbindd/winbindd_cache.c
source3/winbindd/winbindd_cm.c
source3/winbindd/winbindd_msrpc.c
source3/winbindd/winbindd_pam.c
source3/winbindd/winbindd_proto.h
source3/winbindd/winbindd_util.c

index 07c87dbcf45ce65801ec7241886bfad08b8c495c..5b98928a25f47fcebcb651d1592a88d8e614c99f 100644 (file)
@@ -164,6 +164,7 @@ struct winbindd_domain {
        bool active_directory;                 /* is this a win2k active directory ? */
        bool primary;                          /* is this our primary domain ? */
        bool internal;                         /* BUILTIN and member SAM */
+       bool rodc;                             /* Are we an RODC for this AD domain? (do some operations locally) */
        bool online;                           /* is this domain available ? */
        time_t startup_time;                   /* When we set "startup" true. monotonic clock */
        bool startup;                          /* are we in the first 30 seconds after startup_time ? */
index dfad8f5c0891032ef29f913d62f1e69235e197df..bfd78daef537e45a1551536677f3b958059de72b 100644 (file)
@@ -132,7 +132,8 @@ static struct winbind_cache *get_cache(struct winbindd_domain *domain)
        }
 
        if ( !domain->initialized ) {
-               init_dc_connection( domain );
+               /* We do not need a connection to an RW DC for cache operation */
+               init_dc_connection(domain, false);
        }
 
        /* 
index a8ace52472edc17903f25d56de7a5d82f7eeb325..05205a7d48aac1d405040edda96bb6179392f6cc 100644 (file)
@@ -94,7 +94,7 @@ struct dc_name_ip {
 extern struct winbindd_methods reconnect_methods;
 extern bool override_logfile;
 
-static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain);
+static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain, bool need_rw_dc);
 static void set_dc_type_and_flags( struct winbindd_domain *domain );
 static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
                    struct dc_name_ip **dcs, int *num_dcs);
@@ -176,7 +176,7 @@ static void msg_try_to_go_online(struct messaging_context *msg,
                           the offline handler if false. Bypasses online
                           check so always does network calls. */
 
-                       init_dc_connection_network(domain);
+                       init_dc_connection_network(domain, true);
                        break;
                }
        }
@@ -1931,9 +1931,13 @@ static bool connection_ok(struct winbindd_domain *domain)
 /* Initialize a new connection up to the RPC BIND.
    Bypass online status check so always does network calls. */
 
-static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain)
+static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain, bool need_rw_dc)
 {
        NTSTATUS result;
+       bool skip_connection = domain->internal;
+       if (need_rw_dc && domain->rodc) {
+               skip_connection = false;
+       }
 
        /* Internal connections never use the network. */
        if (dom_sid_equal(&domain->sid, &global_sid_Builtin)) {
@@ -1941,7 +1945,7 @@ static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain)
        }
 
        /* Still ask the internal LSA and SAMR server about the local domain */
-       if (domain->internal || connection_ok(domain)) {
+       if (skip_connection || connection_ok(domain)) {
                if (!domain->initialized) {
                        set_dc_type_and_flags(domain);
                }
@@ -1959,7 +1963,7 @@ static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain)
        return result;
 }
 
-NTSTATUS init_dc_connection(struct winbindd_domain *domain)
+NTSTATUS init_dc_connection(struct winbindd_domain *domain, bool need_rw_dc)
 {
        if (dom_sid_equal(&domain->sid, &global_sid_Builtin)) {
                return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
@@ -1970,14 +1974,14 @@ NTSTATUS init_dc_connection(struct winbindd_domain *domain)
                return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
        }
 
-       return init_dc_connection_network(domain);
+       return init_dc_connection_network(domain, need_rw_dc);
 }
 
-static NTSTATUS init_dc_connection_rpc(struct winbindd_domain *domain)
+static NTSTATUS init_dc_connection_rpc(struct winbindd_domain *domain, bool need_rw_dc)
 {
        NTSTATUS status;
 
-       status = init_dc_connection(domain);
+       status = init_dc_connection(domain, need_rw_dc);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -2382,6 +2386,7 @@ static NTSTATUS cm_get_schannel_creds(struct winbindd_domain *domain,
 }
 
 NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
+                       bool need_rw_dc,
                        struct rpc_pipe_client **cli, struct policy_handle *sam_handle)
 {
        struct winbindd_cm_conn *conn;
@@ -2392,10 +2397,12 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
        const char *domain_name = NULL;
 
        if (sid_check_is_our_sam(&domain->sid)) {
-               return open_internal_samr_conn(mem_ctx, domain, cli, sam_handle);
+               if (domain->rodc == false || need_rw_dc == false) {
+                       return open_internal_samr_conn(mem_ctx, domain, cli, sam_handle);
+               }
        }
 
-       status = init_dc_connection_rpc(domain);
+       status = init_dc_connection_rpc(domain, need_rw_dc);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -2605,7 +2612,7 @@ NTSTATUS cm_connect_lsa_tcp(struct winbindd_domain *domain,
 
        DEBUG(10,("cm_connect_lsa_tcp\n"));
 
-       status = init_dc_connection_rpc(domain);
+       status = init_dc_connection_rpc(domain, false);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -2656,7 +2663,7 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
        struct netlogon_creds_cli_context *p_creds;
 
-       result = init_dc_connection_rpc(domain);
+       result = init_dc_connection_rpc(domain, false);
        if (!NT_STATUS_IS_OK(result))
                return result;
 
@@ -2829,7 +2836,7 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
 
        *cli = NULL;
 
-       result = init_dc_connection_rpc(domain);
+       result = init_dc_connection_rpc(domain, true);
        if (!NT_STATUS_IS_OK(result)) {
                return result;
        }
index 426d64cf1f930166f3cac5d85e596888d29c8abb..9aef7ccdff5f44b43a72ac885724e3df21f3a8c7 100644 (file)
@@ -76,7 +76,7 @@ static NTSTATUS msrpc_query_user_list(struct winbindd_domain *domain,
                goto done;
        }
 
-       status = cm_connect_sam(domain, tmp_ctx, &samr_pipe, &dom_pol);
+       status = cm_connect_sam(domain, tmp_ctx, false, &samr_pipe, &dom_pol);
        if (!NT_STATUS_IS_OK(status)) {
                goto done;
        }
@@ -135,7 +135,7 @@ static NTSTATUS msrpc_enum_dom_groups(struct winbindd_domain *domain,
                goto done;
        }
 
-       status = cm_connect_sam(domain, tmp_ctx, &samr_pipe, &dom_pol);
+       status = cm_connect_sam(domain, tmp_ctx, false, &samr_pipe, &dom_pol);
        if (!NT_STATUS_IS_OK(status)) {
                goto done;
        }
@@ -194,7 +194,7 @@ static NTSTATUS msrpc_enum_local_groups(struct winbindd_domain *domain,
                goto done;
        }
 
-       status = cm_connect_sam(domain, tmp_ctx, &samr_pipe, &dom_pol);
+       status = cm_connect_sam(domain, tmp_ctx, false, &samr_pipe, &dom_pol);
        if (!NT_STATUS_IS_OK(status)) {
                goto done;
        }
@@ -452,7 +452,7 @@ static NTSTATUS msrpc_query_user(struct winbindd_domain *domain,
        }
 
        /* no cache; hit the wire */
-       status = cm_connect_sam(domain, tmp_ctx, &samr_pipe, &dom_pol);
+       status = cm_connect_sam(domain, tmp_ctx, false, &samr_pipe, &dom_pol);
        if (!NT_STATUS_IS_OK(status)) {
                goto done;
        }
@@ -512,7 +512,7 @@ static NTSTATUS msrpc_lookup_usergroups(struct winbindd_domain *domain,
        }
 
        /* no cache; hit the wire */
-       status = cm_connect_sam(domain, tmp_ctx, &samr_pipe, &dom_pol);
+       status = cm_connect_sam(domain, tmp_ctx, false, &samr_pipe, &dom_pol);
        if (!NT_STATUS_IS_OK(status)) {
                goto done;
        }
@@ -575,7 +575,7 @@ static NTSTATUS msrpc_lookup_useraliases(struct winbindd_domain *domain,
                goto done;
        }
 
-       status = cm_connect_sam(domain, tmp_ctx, &samr_pipe, &dom_pol);
+       status = cm_connect_sam(domain, tmp_ctx, false, &samr_pipe, &dom_pol);
        if (!NT_STATUS_IS_OK(status)) {
                goto done;
        }
@@ -641,7 +641,7 @@ static NTSTATUS msrpc_lookup_groupmem(struct winbindd_domain *domain,
 
        *num_names = 0;
 
-       result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+       result = cm_connect_sam(domain, mem_ctx, false, &cli, &dom_pol);
        if (!NT_STATUS_IS_OK(result))
                return result;
 
@@ -903,7 +903,7 @@ static NTSTATUS msrpc_sequence_number(struct winbindd_domain *domain,
        }
 #endif /* HAVE_LDAP */
 
-       status = cm_connect_sam(domain, tmp_ctx, &samr_pipe, &dom_pol);
+       status = cm_connect_sam(domain, tmp_ctx, false, &samr_pipe, &dom_pol);
        if (!NT_STATUS_IS_OK(status)) {
                goto done;
        }
@@ -992,7 +992,7 @@ static NTSTATUS msrpc_lockout_policy(struct winbindd_domain *domain,
                return NT_STATUS_NOT_SUPPORTED;
        }
 
-       status = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+       status = cm_connect_sam(domain, mem_ctx, false, &cli, &dom_pol);
        if (!NT_STATUS_IS_OK(status)) {
                goto done;
        }
@@ -1042,7 +1042,7 @@ static NTSTATUS msrpc_password_policy(struct winbindd_domain *domain,
                return NT_STATUS_NOT_SUPPORTED;
        }
 
-       status = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+       status = cm_connect_sam(domain, mem_ctx, false, &cli, &dom_pol);
        if (!NT_STATUS_IS_OK(status)) {
                goto done;
        }
index dd8f442d3d6c0ce6420857bf4a87fac74c6a6ee0..8387bdc75848406fed41a895a2f78ad8c6a1efe8 100644 (file)
@@ -1185,7 +1185,7 @@ static NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
        }
 
        if (!contact_domain->initialized) {
-               init_dc_connection(contact_domain);
+               init_dc_connection(contact_domain, false);
        }
 
        if (!contact_domain->active_directory) {
@@ -1541,7 +1541,7 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(TALLOC_CTX *mem_ctx,
                uint32 acct_flags;
                struct dcerpc_binding_handle *b;
 
-               status_tmp = cm_connect_sam(domain, mem_ctx,
+               status_tmp = cm_connect_sam(domain, mem_ctx, false,
                                            &samr_pipe, &samr_domain_handle);
 
                if (!NT_STATUS_IS_OK(status_tmp)) {
@@ -1664,7 +1664,7 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
                                "request in startup mode.\n", domain->name ));
 
                        winbindd_flush_negative_conn_cache(domain);
-                       result = init_dc_connection(domain);
+                       result = init_dc_connection(domain, false);
                }
        }
 
@@ -2079,7 +2079,7 @@ enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact
 
        /* Get sam handle */
 
-       result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
+       result = cm_connect_sam(contact_domain, state->mem_ctx, true, &cli,
                                &dom_pol);
        if (!NT_STATUS_IS_OK(result)) {
                DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
@@ -2352,7 +2352,7 @@ enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domai
 
        /* Get sam handle */
 
-       result = cm_connect_sam(contact_domain, state->mem_ctx, &cli, &dom_pol);
+       result = cm_connect_sam(contact_domain, state->mem_ctx, true, &cli, &dom_pol);
        if (!NT_STATUS_IS_OK(result)) {
                DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
                goto done;
index dfd61621c6abae204f10693a58a017159748db2b..e1b32b77993fe35518244fd0f8bf06c89006fd5e 100644 (file)
@@ -171,8 +171,9 @@ NTSTATUS wb_open_internal_pipe(TALLOC_CTX *mem_ctx,
                               struct rpc_pipe_client **ret_pipe);
 void invalidate_cm_connection(struct winbindd_cm_conn *conn);
 void close_conns_after_fork(void);
-NTSTATUS init_dc_connection(struct winbindd_domain *domain);
+NTSTATUS init_dc_connection(struct winbindd_domain *domain, bool need_rw_dc);
 NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
+                       bool need_rw_dc,
                        struct rpc_pipe_client **cli, struct policy_handle *sam_handle);
 NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
                        struct rpc_pipe_client **cli, struct policy_handle *lsa_policy);
index 4e8ab92c00a242f52875ce754d5c4ce6c15d73fc..35cc524baef8f3808e9e33ef9aa7018c792b2e44 100644 (file)
@@ -26,6 +26,7 @@
 #include "../libcli/security/security.h"
 #include "../libcli/auth/pam_errors.h"
 #include "passdb/machine_sid.h"
+#include "passdb.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
@@ -576,7 +577,7 @@ enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domai
                fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
        }
 
-       init_dc_connection(domain);
+       init_dc_connection(domain, false);
 
        if (!domain->initialized) {
                /* If we return error here we can't do any cached authentication,
@@ -618,8 +619,34 @@ bool init_domain_list(void)
        /* Local SAM */
 
        if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
-               (void)add_trusted_domain(get_global_sam_name(), lp_dnsdomain(),
-                                        &cache_methods, get_global_sam_sid());
+               struct winbindd_domain *domain;
+               enum netr_SchannelType sec_chan_type;
+               const char *account_name;
+               struct samr_Password current_nt_hash;
+               bool ok;
+
+               domain = add_trusted_domain(get_global_sam_name(), lp_dnsdomain(),
+                                           &cache_methods, get_global_sam_sid());
+               if (domain == NULL) {
+                       DEBUG(0, ("Failed to add our own, local AD domain to winbindd's internal list\n"));
+                       return false;
+               }
+
+               /*
+                * We need to call this to find out if we are an RODC
+                */
+               ok = get_trust_pw_hash(domain->name,
+                                      current_nt_hash.hash,
+                                      &account_name,
+                                      &sec_chan_type);
+               if (!ok) {
+                       DEBUG(0, ("Failed to fetch our own, local AD domain join password for winbindd's internal use\n"));
+                       return false;
+               }
+               if (sec_chan_type == SEC_CHAN_RODC) {
+                       domain->rodc = true;
+               }
+
        } else {
                (void)add_trusted_domain(get_global_sam_name(), NULL,
                                         &cache_methods, get_global_sam_sid());
@@ -692,7 +719,7 @@ struct winbindd_domain *find_domain_from_name(const char *domain_name)
                return NULL;
 
        if (!domain->initialized)
-               init_dc_connection(domain);
+               init_dc_connection(domain, false);
 
        return domain;
 }
@@ -727,7 +754,7 @@ struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
                return NULL;
 
        if (!domain->initialized)
-               init_dc_connection(domain);
+               init_dc_connection(domain, false);
 
        return domain;
 }