winbindd: Add retry also for ADS method calls
authorChristof Schmitt <cs@samba.org>
Tue, 5 Jan 2016 21:37:30 +0000 (14:37 -0700)
committerJeremy Allison <jra@samba.org>
Tue, 12 Jan 2016 23:26:16 +0000 (00:26 +0100)
RPC calls can return IO_DEVICE_ERROR on expired SMB2 sessions. Retrying
on a new connection avoids surfacing this error to winbindd clients.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11670

Signed-off-by: Christof Schmitt <cs@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/winbindd/winbindd_cache.c
source3/winbindd/winbindd_ndr.c
source3/winbindd/winbindd_proto.h
source3/winbindd/winbindd_reconnect.c
source3/winbindd/winbindd_reconnect_ads.c [new file with mode: 0644]
source3/wscript_build

index ae9d11f732200b69474bc875b988920924ef74fa..cf3ed713e097baecb88f0aafbc1ef3fab75d8b10 100644 (file)
@@ -46,7 +46,7 @@
 
 extern struct winbindd_methods reconnect_methods;
 #ifdef HAVE_ADS
-extern struct winbindd_methods ads_methods;
+extern struct winbindd_methods reconnect_ads_methods;
 #endif
 extern struct winbindd_methods builtin_passdb_methods;
 extern struct winbindd_methods sam_passdb_methods;
@@ -168,7 +168,7 @@ static struct winbind_cache *get_cache(struct winbindd_domain *domain)
                    && domain->active_directory
                    && !lp_winbind_rpc_only()) {
                        DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name));
-                       domain->backend = &ads_methods;
+                       domain->backend = &reconnect_ads_methods;
                } else {
 #endif /* HAVE_ADS */
                        DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name));
index 37b7e02c359de67bc4d319a1b2cf424a0929072e..029e883b1cefb556443a2035dc8189550d697166 100644 (file)
@@ -75,6 +75,7 @@ void ndr_print_winbindd_cm_conn(struct ndr_print *ndr,
 
 #ifdef HAVE_ADS
 extern struct winbindd_methods ads_methods;
+extern struct winbindd_methods reconnect_ads_methods;
 #endif
 extern struct winbindd_methods msrpc_methods;
 extern struct winbindd_methods builtin_passdb_methods;
@@ -100,6 +101,8 @@ void ndr_print_winbindd_methods(struct ndr_print *ndr,
 #ifdef HAVE_ADS
        } else if (r == &ads_methods) {
                ndr_print_string(ndr, name, "ads_methods");
+       } else if (r == &reconnect_ads_methods) {
+               ndr_print_string(ndr, name, "reconnect_ads_methods");
 #endif
        } else if (r == &builtin_passdb_methods) {
                ndr_print_string(ndr, name, "builtin_passdb_methods");
index 9920a3f3e7adeb6ad9d7c272b8e7c46dd734e3b4..6e5071803bcc450dc410ea1e852dd7ba75a53994 100644 (file)
@@ -933,4 +933,8 @@ ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name);
 
 /* The following definitions come from winbindd/winbindd_irpc.c  */
 NTSTATUS wb_irpc_register(void);
+
+/* The following definitions come from winbindd/winbindd_reconnect.c  */
+bool reconnect_need_retry(NTSTATUS status, struct winbindd_domain *domain);
+
 #endif /*  _WINBINDD_PROTO_H_  */
index 9442f340419b28a423aa25a642883fe36d25eca1..f7dd8053f2e0e9aa43ca70c72df7883f9bc10829 100644 (file)
@@ -27,8 +27,7 @@
 
 extern struct winbindd_methods msrpc_methods;
 
-static bool reconnect_need_retry(NTSTATUS status,
-                                struct winbindd_domain *domain)
+bool reconnect_need_retry(NTSTATUS status, struct winbindd_domain *domain)
 {
        if (NT_STATUS_IS_OK(status)) {
                return false;
diff --git a/source3/winbindd/winbindd_reconnect_ads.c b/source3/winbindd/winbindd_reconnect_ads.c
new file mode 100644 (file)
index 0000000..7ea8298
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Wrapper around winbindd_ads.c to centralize retry logic.
+   Copyright (C) Christof Schmitt 2016
+
+   Based on winbindd_reconnect.c
+   Copyright (C) Volker Lendecke 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
+   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,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#ifdef HAVE_ADS
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+extern struct winbindd_methods ads_methods;
+
+/* List all users */
+static NTSTATUS query_user_list(struct winbindd_domain *domain,
+                               TALLOC_CTX *mem_ctx,
+                               uint32_t *num_entries,
+                               struct wbint_userinfo **info)
+{
+       NTSTATUS result;
+
+       result = ads_methods.query_user_list(domain, mem_ctx,
+                                            num_entries, info);
+
+       if (reconnect_need_retry(result, domain)) {
+               result = ads_methods.query_user_list(domain, mem_ctx,
+                                                    num_entries, info);
+       }
+
+       return result;
+}
+
+/* list all domain groups */
+static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
+                               TALLOC_CTX *mem_ctx,
+                               uint32_t *num_entries,
+                               struct wb_acct_info **info)
+{
+       NTSTATUS result;
+
+       result = ads_methods.enum_dom_groups(domain, mem_ctx,
+                                            num_entries, info);
+
+       if (reconnect_need_retry(result, domain)) {
+               result = ads_methods.enum_dom_groups(domain, mem_ctx,
+                                                    num_entries, info);
+       }
+
+       return result;
+}
+
+/* List all domain groups */
+static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
+                                 TALLOC_CTX *mem_ctx,
+                                 uint32_t *num_entries,
+                                 struct wb_acct_info **info)
+{
+       NTSTATUS result;
+
+       result = ads_methods.enum_local_groups(domain, mem_ctx,
+                                              num_entries, info);
+
+       if (reconnect_need_retry(result, domain)) {
+               result = ads_methods.enum_local_groups(domain, mem_ctx,
+                                                      num_entries, info);
+       }
+
+       return result;
+}
+
+/* convert a single name to a sid in a domain */
+static NTSTATUS name_to_sid(struct winbindd_domain *domain,
+                           TALLOC_CTX *mem_ctx,
+                           const char *domain_name,
+                           const char *name,
+                           uint32_t flags,
+                           struct dom_sid *sid,
+                           enum lsa_SidType *type)
+{
+       NTSTATUS result;
+
+       result = ads_methods.name_to_sid(domain, mem_ctx, domain_name, name,
+                                        flags, sid, type);
+
+       if (reconnect_need_retry(result, domain)) {
+               result = ads_methods.name_to_sid(domain, mem_ctx,
+                                                domain_name, name, flags,
+                                                sid, type);
+       }
+
+       return result;
+}
+
+/*
+  convert a domain SID to a user or group name
+*/
+static NTSTATUS sid_to_name(struct winbindd_domain *domain,
+                           TALLOC_CTX *mem_ctx,
+                           const struct dom_sid *sid,
+                           char **domain_name,
+                           char **name,
+                           enum lsa_SidType *type)
+{
+       NTSTATUS result;
+
+       result = ads_methods.sid_to_name(domain, mem_ctx, sid,
+                                        domain_name, name, type);
+
+       if (reconnect_need_retry(result, domain))
+               result = ads_methods.sid_to_name(domain, mem_ctx, sid,
+                                                domain_name, name, type);
+
+       return result;
+}
+
+static NTSTATUS rids_to_names(struct winbindd_domain *domain,
+                             TALLOC_CTX *mem_ctx,
+                             const struct dom_sid *sid,
+                             uint32_t *rids,
+                             size_t num_rids,
+                             char **domain_name,
+                             char ***names,
+                             enum lsa_SidType **types)
+{
+       NTSTATUS result;
+
+       result = ads_methods.rids_to_names(domain, mem_ctx, sid,
+                                          rids, num_rids,
+                                          domain_name, names, types);
+       if (reconnect_need_retry(result, domain)) {
+               result = ads_methods.rids_to_names(domain, mem_ctx, sid,
+                                                  rids, num_rids, domain_name,
+                                                  names, types);
+       }
+
+       return result;
+}
+
+/* Lookup user information from a rid or username. */
+static NTSTATUS query_user(struct winbindd_domain *domain,
+                          TALLOC_CTX *mem_ctx,
+                          const struct dom_sid *user_sid,
+                          struct wbint_userinfo *user_info)
+{
+       NTSTATUS result;
+
+       result = ads_methods.query_user(domain, mem_ctx, user_sid, user_info);
+
+       if (reconnect_need_retry(result, domain)) {
+               result = ads_methods.query_user(domain, mem_ctx, user_sid,
+                                               user_info);
+       }
+
+       return result;
+}
+
+/* Lookup groups a user is a member of.  I wish Unix had a call like this! */
+static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
+                                 TALLOC_CTX *mem_ctx,
+                                 const struct dom_sid *user_sid,
+                                 uint32_t *num_groups,
+                                 struct dom_sid **user_gids)
+{
+       NTSTATUS result;
+
+       result = ads_methods.lookup_usergroups(domain, mem_ctx, user_sid,
+                                              num_groups, user_gids);
+
+       if (reconnect_need_retry(result, domain)) {
+               result = ads_methods.lookup_usergroups(domain, mem_ctx,
+                                                      user_sid, num_groups,
+                                                      user_gids);
+       }
+
+       return result;
+}
+
+static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
+                                  TALLOC_CTX *mem_ctx,
+                                  uint32_t num_sids,
+                                  const struct dom_sid *sids,
+                                  uint32_t *num_aliases, uint32_t **alias_rids)
+{
+       NTSTATUS result;
+
+       result = ads_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids,
+                                               num_aliases, alias_rids);
+
+       if (reconnect_need_retry(result, domain)) {
+               result = ads_methods.lookup_useraliases(domain, mem_ctx,
+                                                       num_sids, sids,
+                                                       num_aliases,
+                                                       alias_rids);
+       }
+
+       return result;
+}
+
+/* Lookup group membership given a rid.   */
+static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
+                               TALLOC_CTX *mem_ctx,
+                               const struct dom_sid *group_sid,
+                               enum lsa_SidType type,
+                               uint32_t *num_names,
+                               struct dom_sid **sid_mem, char ***names,
+                               uint32_t **name_types)
+{
+       NTSTATUS result;
+
+       result = ads_methods.lookup_groupmem(domain, mem_ctx, group_sid, type,
+                                            num_names, sid_mem, names,
+                                            name_types);
+
+       if (reconnect_need_retry(result, domain)) {
+               result = ads_methods.lookup_groupmem(domain, mem_ctx, group_sid,
+                                                    type, num_names, sid_mem,
+                                                    names, name_types);
+       }
+
+       return result;
+}
+
+/* find the sequence number for a domain */
+static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq)
+{
+       NTSTATUS result;
+
+       result = ads_methods.sequence_number(domain, seq);
+
+       if (reconnect_need_retry(result, domain)) {
+               result = ads_methods.sequence_number(domain, seq);
+       }
+
+       return result;
+}
+
+/* find the lockout policy of a domain */
+static NTSTATUS lockout_policy(struct winbindd_domain *domain,
+                              TALLOC_CTX *mem_ctx,
+                              struct samr_DomInfo12 *policy)
+{
+       NTSTATUS result;
+
+       result = ads_methods.lockout_policy(domain, mem_ctx, policy);
+
+       if (reconnect_need_retry(result, domain)) {
+               result = ads_methods.lockout_policy(domain, mem_ctx, policy);
+       }
+
+       return result;
+}
+
+/* find the password policy of a domain */
+static NTSTATUS password_policy(struct winbindd_domain *domain,
+                               TALLOC_CTX *mem_ctx,
+                               struct samr_DomInfo1 *policy)
+{
+       NTSTATUS result;
+
+       result = ads_methods.password_policy(domain, mem_ctx, policy);
+
+       if (reconnect_need_retry(result, domain)) {
+               result = ads_methods.password_policy(domain, mem_ctx, policy);
+       }
+
+       return result;
+}
+
+/* get a list of trusted domains */
+static NTSTATUS trusted_domains(struct winbindd_domain *domain,
+                               TALLOC_CTX *mem_ctx,
+                               struct netr_DomainTrustList *trusts)
+{
+       NTSTATUS result;
+
+       result = ads_methods.trusted_domains(domain, mem_ctx, trusts);
+
+       if (reconnect_need_retry(result, domain)) {
+               result = ads_methods.trusted_domains(domain, mem_ctx, trusts);
+       }
+
+       return result;
+}
+
+/* the rpc backend methods are exposed via this structure */
+struct winbindd_methods reconnect_ads_methods = {
+       true,
+       query_user_list,
+       enum_dom_groups,
+       enum_local_groups,
+       name_to_sid,
+       sid_to_name,
+       rids_to_names,
+       query_user,
+       lookup_usergroups,
+       lookup_useraliases,
+       lookup_groupmem,
+       sequence_number,
+       lockout_policy,
+       password_policy,
+       trusted_domains,
+};
+
+#endif
index d40dd7edd3f9e450b2e84cc130fba053a040c4ef..87b09106d419b083097a923a5317efb9bb7e8c28 100755 (executable)
@@ -904,6 +904,7 @@ bld.SAMBA3_BINARY('winbindd/winbindd',
                  winbindd/winbindd_msrpc.c
                  winbindd/winbindd_rpc.c
                  winbindd/winbindd_reconnect.c
+                 winbindd/winbindd_reconnect_ads.c
                  winbindd/winbindd_ads.c
                  winbindd/winbindd_samr.c
                  winbindd/winbindd_dual.c