[RFC][WIP] cache-only name lookups in smbd

Uri Simchoni uri at samba.org
Mon Nov 28 07:42:08 UTC 2016


Hi,

I'm trying to allow smbd to serve files in the presence of short
interruptions in the connection to AD. One challenge is that shares
defined in smb.conf have user / group names in their access lists (read
list, write list, valid users, ...) and those names are converted to
SIDs on each tree connect. Sometimes this conversion causes a network
lookup. When a few minute outage occurs, the first user to try the
network lookup experience a Windows Explorer freeze, and that creates
support calls. Subsequent users find winbindd in a different mood
(offline) and get service.

One approach I've tried to handle this challenge is to:
a. constantly prime the winbindd cache
b. introduce a cache-only lookup (essentially equivalent to the lookup
in offline state - no check for expiration)
c. since the current and new approach represent different tradeoffs,
I've made it configurable.

This approach is in the attached patch - adding a "priming daemon" and
an API to winbindd to do cache-only lookups. The patch set is still
rough around the edges, doesn't handle SIGHUP, the primed restart (which
I've copied from notifyd) doesn't work reliably, but you can get the
general idea.

I'd appreciate feedback as to whether this approach is desirable at all
in samba. Some of my thoughts are:

1. An alternative approach is to use the RPC-managed share ACLs,
everything there is in SIDs, or pre-translate names to SIDs and put the
SIDs in smb.conf. From an appliance point of view, this shifts the added
complexity outside of Samba.

2. It complicates things, and having two modes of lookup is likely to
make one mode bit-rot, esp. since it's difficult to simulate network outage.

3. It can't possibly handle all parameter substitutions - another source
of conceptual complication (some lookups are cached and some aren't)

4. So far I haven't managed to avoid some code duplication between the
lazy evaluation code in share_access.c and primed. The netgroups kind of
make this hard.

Despite all of the above, in the cases where it works (no substitutions
and no configuration errors), this does make for more robust operation,
and may prove useful to others.

Thanks,
Uri.
-------------- next part --------------
From 7a23003437a70af0e40ecf3e1ebd396fab445e32 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Mon, 28 Nov 2016 08:40:50 +0200
Subject: [PATCH 1/9] s3-passdb - add LOOKUP_NAME_CACHE_ONLY lookup flag

This flag shall be used later by lookup_name() and
internally by winbindd

Signed-off-by: Uri Simchoni <uri at samba.org>
---
 source3/passdb/lookup_sid.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/source3/passdb/lookup_sid.h b/source3/passdb/lookup_sid.h
index 8b5edf6..bd46f2e 100644
--- a/source3/passdb/lookup_sid.h
+++ b/source3/passdb/lookup_sid.h
@@ -39,6 +39,7 @@ struct unixid;
 #define LOOKUP_NAME_BUILTIN		0x00000010 /* builtin names */
 #define LOOKUP_NAME_WKN			0x00000020 /* well known names */
 #define LOOKUP_NAME_DOMAIN		0x00000040 /* only lookup own domain */
+#define LOOKUP_NAME_CACHE_ONLY		0x00000080 /* only cache-based lookup */
 #define LOOKUP_NAME_LOCAL		(LOOKUP_NAME_ISOLATED\
 					|LOOKUP_NAME_BUILTIN\
 					|LOOKUP_NAME_WKN\
-- 
2.9.3


From ecaa5ccc9372a5dec9903b2f8db2020fbb5845e5 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Mon, 28 Nov 2016 08:42:20 +0200
Subject: [PATCH 2/9] wb-client: introduce wbcLookupNameEx()

This is an extended version of wbcLookupName(), with ability
to do a cache-only lookup.

Signed-off-by: Uri Simchoni <uri at samba.org>
---
 nsswitch/libwbclient/ABI/wbclient-0.14.sigs | 134 ++++++++++++++++++++++++++++
 nsswitch/libwbclient/wbc_sid.c              |  30 +++++--
 nsswitch/libwbclient/wbclient.h             |  44 ++++++++-
 nsswitch/libwbclient/wscript                |   2 +-
 nsswitch/winbind_struct_protocol.h          |   1 +
 source3/winbindd/winbindd_cache.c           |  86 ++++++++++--------
 source3/winbindd/winbindd_lookupname.c      |   8 +-
 source3/winbindd/winbindd_proto.h           |   1 +
 8 files changed, 263 insertions(+), 43 deletions(-)
 create mode 100644 nsswitch/libwbclient/ABI/wbclient-0.14.sigs

diff --git a/nsswitch/libwbclient/ABI/wbclient-0.14.sigs b/nsswitch/libwbclient/ABI/wbclient-0.14.sigs
new file mode 100644
index 0000000..42b9e1d
--- /dev/null
+++ b/nsswitch/libwbclient/ABI/wbclient-0.14.sigs
@@ -0,0 +1,134 @@
+wbcAddNamedBlob: wbcErr (size_t *, struct wbcNamedBlob **, const char *, uint32_t, uint8_t *, size_t)
+wbcAllocateGid: wbcErr (gid_t *)
+wbcAllocateMemory: void *(size_t, size_t, void (*)(void *))
+wbcAllocateStringArray: const char **(int)
+wbcAllocateUid: wbcErr (uid_t *)
+wbcAuthenticateUser: wbcErr (const char *, const char *)
+wbcAuthenticateUserEx: wbcErr (const struct wbcAuthUserParams *, struct wbcAuthUserInfo **, struct wbcAuthErrorInfo **)
+wbcChangeTrustCredentials: wbcErr (const char *, struct wbcAuthErrorInfo **)
+wbcChangeUserPassword: wbcErr (const char *, const char *, const char *)
+wbcChangeUserPasswordEx: wbcErr (const struct wbcChangePasswordParams *, struct wbcAuthErrorInfo **, enum wbcPasswordChangeRejectReason *, struct wbcUserPasswordPolicyInfo **)
+wbcCheckTrustCredentials: wbcErr (const char *, struct wbcAuthErrorInfo **)
+wbcCredentialCache: wbcErr (struct wbcCredentialCacheParams *, struct wbcCredentialCacheInfo **, struct wbcAuthErrorInfo **)
+wbcCredentialSave: wbcErr (const char *, const char *)
+wbcCtxAllocateGid: wbcErr (struct wbcContext *, gid_t *)
+wbcCtxAllocateUid: wbcErr (struct wbcContext *, uid_t *)
+wbcCtxAuthenticateUser: wbcErr (struct wbcContext *, const char *, const char *)
+wbcCtxAuthenticateUserEx: wbcErr (struct wbcContext *, const struct wbcAuthUserParams *, struct wbcAuthUserInfo **, struct wbcAuthErrorInfo **)
+wbcCtxChangeTrustCredentials: wbcErr (struct wbcContext *, const char *, struct wbcAuthErrorInfo **)
+wbcCtxChangeUserPassword: wbcErr (struct wbcContext *, const char *, const char *, const char *)
+wbcCtxChangeUserPasswordEx: wbcErr (struct wbcContext *, const struct wbcChangePasswordParams *, struct wbcAuthErrorInfo **, enum wbcPasswordChangeRejectReason *, struct wbcUserPasswordPolicyInfo **)
+wbcCtxCheckTrustCredentials: wbcErr (struct wbcContext *, const char *, struct wbcAuthErrorInfo **)
+wbcCtxCreate: struct wbcContext *(void)
+wbcCtxCredentialCache: wbcErr (struct wbcContext *, struct wbcCredentialCacheParams *, struct wbcCredentialCacheInfo **, struct wbcAuthErrorInfo **)
+wbcCtxCredentialSave: wbcErr (struct wbcContext *, const char *, const char *)
+wbcCtxDcInfo: wbcErr (struct wbcContext *, const char *, size_t *, const char ***, const char ***)
+wbcCtxDomainInfo: wbcErr (struct wbcContext *, const char *, struct wbcDomainInfo **)
+wbcCtxEndgrent: wbcErr (struct wbcContext *)
+wbcCtxEndpwent: wbcErr (struct wbcContext *)
+wbcCtxFree: void (struct wbcContext *)
+wbcCtxGetDisplayName: wbcErr (struct wbcContext *, const struct wbcDomainSid *, char **, char **, enum wbcSidType *)
+wbcCtxGetGroups: wbcErr (struct wbcContext *, const char *, uint32_t *, gid_t **)
+wbcCtxGetSidAliases: wbcErr (struct wbcContext *, const struct wbcDomainSid *, struct wbcDomainSid *, uint32_t, uint32_t **, uint32_t *)
+wbcCtxGetgrent: wbcErr (struct wbcContext *, struct group **)
+wbcCtxGetgrgid: wbcErr (struct wbcContext *, gid_t, struct group **)
+wbcCtxGetgrlist: wbcErr (struct wbcContext *, struct group **)
+wbcCtxGetgrnam: wbcErr (struct wbcContext *, const char *, struct group **)
+wbcCtxGetpwent: wbcErr (struct wbcContext *, struct passwd **)
+wbcCtxGetpwnam: wbcErr (struct wbcContext *, const char *, struct passwd **)
+wbcCtxGetpwsid: wbcErr (struct wbcContext *, struct wbcDomainSid *, struct passwd **)
+wbcCtxGetpwuid: wbcErr (struct wbcContext *, uid_t, struct passwd **)
+wbcCtxGidToSid: wbcErr (struct wbcContext *, gid_t, struct wbcDomainSid *)
+wbcCtxInterfaceDetails: wbcErr (struct wbcContext *, struct wbcInterfaceDetails **)
+wbcCtxListGroups: wbcErr (struct wbcContext *, const char *, uint32_t *, const char ***)
+wbcCtxListTrusts: wbcErr (struct wbcContext *, struct wbcDomainInfo **, size_t *)
+wbcCtxListUsers: wbcErr (struct wbcContext *, const char *, uint32_t *, const char ***)
+wbcCtxLogoffUser: wbcErr (struct wbcContext *, const char *, uid_t, const char *)
+wbcCtxLogoffUserEx: wbcErr (struct wbcContext *, const struct wbcLogoffUserParams *, struct wbcAuthErrorInfo **)
+wbcCtxLogonUser: wbcErr (struct wbcContext *, const struct wbcLogonUserParams *, struct wbcLogonUserInfo **, struct wbcAuthErrorInfo **, struct wbcUserPasswordPolicyInfo **)
+wbcCtxLookupDomainController: wbcErr (struct wbcContext *, const char *, uint32_t, struct wbcDomainControllerInfo **)
+wbcCtxLookupDomainControllerEx: wbcErr (struct wbcContext *, const char *, struct wbcGuid *, const char *, uint32_t, struct wbcDomainControllerInfoEx **)
+wbcCtxLookupName: wbcErr (struct wbcContext *, const char *, const char *, struct wbcDomainSid *, enum wbcSidType *)
+wbcCtxLookupNameEx: wbcErr (struct wbcContext *, const char *, const char *, struct wbcDomainSid *, enum wbcSidType *, uint32_t)
+wbcCtxLookupRids: wbcErr (struct wbcContext *, struct wbcDomainSid *, int, uint32_t *, const char **, const char ***, enum wbcSidType **)
+wbcCtxLookupSid: wbcErr (struct wbcContext *, const struct wbcDomainSid *, char **, char **, enum wbcSidType *)
+wbcCtxLookupSids: wbcErr (struct wbcContext *, const struct wbcDomainSid *, int, struct wbcDomainInfo **, int *, struct wbcTranslatedName **)
+wbcCtxLookupUserSids: wbcErr (struct wbcContext *, const struct wbcDomainSid *, bool, uint32_t *, struct wbcDomainSid **)
+wbcCtxPing: wbcErr (struct wbcContext *)
+wbcCtxPingDc: wbcErr (struct wbcContext *, const char *, struct wbcAuthErrorInfo **)
+wbcCtxPingDc2: wbcErr (struct wbcContext *, const char *, struct wbcAuthErrorInfo **, char **)
+wbcCtxResolveWinsByIP: wbcErr (struct wbcContext *, const char *, char **)
+wbcCtxResolveWinsByName: wbcErr (struct wbcContext *, const char *, char **)
+wbcCtxSetgrent: wbcErr (struct wbcContext *)
+wbcCtxSetpwent: wbcErr (struct wbcContext *)
+wbcCtxSidToGid: wbcErr (struct wbcContext *, const struct wbcDomainSid *, gid_t *)
+wbcCtxSidToUid: wbcErr (struct wbcContext *, const struct wbcDomainSid *, uid_t *)
+wbcCtxSidsToUnixIds: wbcErr (struct wbcContext *, const struct wbcDomainSid *, uint32_t, struct wbcUnixId *)
+wbcCtxUidToSid: wbcErr (struct wbcContext *, uid_t, struct wbcDomainSid *)
+wbcCtxUnixIdsToSids: wbcErr (struct wbcContext *, const struct wbcUnixId *, uint32_t, struct wbcDomainSid *)
+wbcDcInfo: wbcErr (const char *, size_t *, const char ***, const char ***)
+wbcDomainInfo: wbcErr (const char *, struct wbcDomainInfo **)
+wbcEndgrent: wbcErr (void)
+wbcEndpwent: wbcErr (void)
+wbcErrorString: const char *(wbcErr)
+wbcFreeMemory: void (void *)
+wbcGetDisplayName: wbcErr (const struct wbcDomainSid *, char **, char **, enum wbcSidType *)
+wbcGetGlobalCtx: struct wbcContext *(void)
+wbcGetGroups: wbcErr (const char *, uint32_t *, gid_t **)
+wbcGetSidAliases: wbcErr (const struct wbcDomainSid *, struct wbcDomainSid *, uint32_t, uint32_t **, uint32_t *)
+wbcGetgrent: wbcErr (struct group **)
+wbcGetgrgid: wbcErr (gid_t, struct group **)
+wbcGetgrlist: wbcErr (struct group **)
+wbcGetgrnam: wbcErr (const char *, struct group **)
+wbcGetpwent: wbcErr (struct passwd **)
+wbcGetpwnam: wbcErr (const char *, struct passwd **)
+wbcGetpwsid: wbcErr (struct wbcDomainSid *, struct passwd **)
+wbcGetpwuid: wbcErr (uid_t, struct passwd **)
+wbcGidToSid: wbcErr (gid_t, struct wbcDomainSid *)
+wbcGuidToString: wbcErr (const struct wbcGuid *, char **)
+wbcInterfaceDetails: wbcErr (struct wbcInterfaceDetails **)
+wbcLibraryDetails: wbcErr (struct wbcLibraryDetails **)
+wbcListGroups: wbcErr (const char *, uint32_t *, const char ***)
+wbcListTrusts: wbcErr (struct wbcDomainInfo **, size_t *)
+wbcListUsers: wbcErr (const char *, uint32_t *, const char ***)
+wbcLogoffUser: wbcErr (const char *, uid_t, const char *)
+wbcLogoffUserEx: wbcErr (const struct wbcLogoffUserParams *, struct wbcAuthErrorInfo **)
+wbcLogonUser: wbcErr (const struct wbcLogonUserParams *, struct wbcLogonUserInfo **, struct wbcAuthErrorInfo **, struct wbcUserPasswordPolicyInfo **)
+wbcLookupDomainController: wbcErr (const char *, uint32_t, struct wbcDomainControllerInfo **)
+wbcLookupDomainControllerEx: wbcErr (const char *, struct wbcGuid *, const char *, uint32_t, struct wbcDomainControllerInfoEx **)
+wbcLookupName: wbcErr (const char *, const char *, struct wbcDomainSid *, enum wbcSidType *)
+wbcLookupNameEx: wbcErr (const char *, const char *, struct wbcDomainSid *, enum wbcSidType *, uint32_t)
+wbcLookupRids: wbcErr (struct wbcDomainSid *, int, uint32_t *, const char **, const char ***, enum wbcSidType **)
+wbcLookupSid: wbcErr (const struct wbcDomainSid *, char **, char **, enum wbcSidType *)
+wbcLookupSids: wbcErr (const struct wbcDomainSid *, int, struct wbcDomainInfo **, int *, struct wbcTranslatedName **)
+wbcLookupUserSids: wbcErr (const struct wbcDomainSid *, bool, uint32_t *, struct wbcDomainSid **)
+wbcPing: wbcErr (void)
+wbcPingDc: wbcErr (const char *, struct wbcAuthErrorInfo **)
+wbcPingDc2: wbcErr (const char *, struct wbcAuthErrorInfo **, char **)
+wbcQueryGidToSid: wbcErr (gid_t, struct wbcDomainSid *)
+wbcQuerySidToGid: wbcErr (const struct wbcDomainSid *, gid_t *)
+wbcQuerySidToUid: wbcErr (const struct wbcDomainSid *, uid_t *)
+wbcQueryUidToSid: wbcErr (uid_t, struct wbcDomainSid *)
+wbcRemoveGidMapping: wbcErr (gid_t, const struct wbcDomainSid *)
+wbcRemoveUidMapping: wbcErr (uid_t, const struct wbcDomainSid *)
+wbcRequestResponse: wbcErr (struct wbcContext *, int, struct winbindd_request *, struct winbindd_response *)
+wbcRequestResponsePriv: wbcErr (struct wbcContext *, int, struct winbindd_request *, struct winbindd_response *)
+wbcResolveWinsByIP: wbcErr (const char *, char **)
+wbcResolveWinsByName: wbcErr (const char *, char **)
+wbcSetGidHwm: wbcErr (gid_t)
+wbcSetGidMapping: wbcErr (gid_t, const struct wbcDomainSid *)
+wbcSetUidHwm: wbcErr (uid_t)
+wbcSetUidMapping: wbcErr (uid_t, const struct wbcDomainSid *)
+wbcSetgrent: wbcErr (void)
+wbcSetpwent: wbcErr (void)
+wbcSidToGid: wbcErr (const struct wbcDomainSid *, gid_t *)
+wbcSidToString: wbcErr (const struct wbcDomainSid *, char **)
+wbcSidToStringBuf: int (const struct wbcDomainSid *, char *, int)
+wbcSidToUid: wbcErr (const struct wbcDomainSid *, uid_t *)
+wbcSidTypeString: const char *(enum wbcSidType)
+wbcSidsToUnixIds: wbcErr (const struct wbcDomainSid *, uint32_t, struct wbcUnixId *)
+wbcStrDup: char *(const char *)
+wbcStringToGuid: wbcErr (const char *, struct wbcGuid *)
+wbcStringToSid: wbcErr (const char *, struct wbcDomainSid *)
+wbcUidToSid: wbcErr (uid_t, struct wbcDomainSid *)
+wbcUnixIdsToSids: wbcErr (const struct wbcUnixId *, uint32_t, struct wbcDomainSid *)
diff --git a/nsswitch/libwbclient/wbc_sid.c b/nsswitch/libwbclient/wbc_sid.c
index cc71b9e..2e1ef2c 100644
--- a/nsswitch/libwbclient/wbc_sid.c
+++ b/nsswitch/libwbclient/wbc_sid.c
@@ -180,11 +180,12 @@ done:
 
 
 /* Convert a domain and name to SID */
-wbcErr wbcCtxLookupName(struct wbcContext *ctx,
-			const char *domain,
-			const char *name,
-			struct wbcDomainSid *sid,
-			enum wbcSidType *name_type)
+wbcErr wbcCtxLookupNameEx(struct wbcContext *ctx,
+			  const char *domain,
+			  const char *name,
+			  struct wbcDomainSid *sid,
+			  enum wbcSidType *name_type,
+			  uint32_t flags)
 {
 	struct winbindd_request request;
 	struct winbindd_response response;
@@ -206,6 +207,7 @@ wbcErr wbcCtxLookupName(struct wbcContext *ctx,
 		sizeof(request.data.name.dom_name)-1);
 	strncpy(request.data.name.name, name,
 		sizeof(request.data.name.name)-1);
+	request.data.name.flags = flags;
 
 	wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPNAME,
 					&request,
@@ -223,6 +225,24 @@ wbcErr wbcCtxLookupName(struct wbcContext *ctx,
 	return wbc_status;
 }
 
+wbcErr wbcLookupNameEx(const char *domain,
+		       const char *name,
+		       struct wbcDomainSid *sid,
+		       enum wbcSidType *name_type,
+		       uint32_t flags)
+{
+	return wbcCtxLookupNameEx(NULL, domain, name, sid, name_type, flags);
+}
+
+wbcErr wbcCtxLookupName(struct wbcContext *ctx,
+			const char *domain,
+			const char *name,
+			struct wbcDomainSid *sid,
+			enum wbcSidType *name_type)
+{
+	return wbcCtxLookupNameEx(ctx, domain, name, sid, name_type, 0);
+}
+
 wbcErr wbcLookupName(const char *domain,
 		     const char *name,
 		     struct wbcDomainSid *sid,
diff --git a/nsswitch/libwbclient/wbclient.h b/nsswitch/libwbclient/wbclient.h
index 8c1803b..1bc6bb7a 100644
--- a/nsswitch/libwbclient/wbclient.h
+++ b/nsswitch/libwbclient/wbclient.h
@@ -74,9 +74,10 @@ const char *wbcErrorString(wbcErr error);
  *  0.11: Extended wbcAuthenticateUserEx to provide PAC parsing
  *  0.12: Added wbcCtxCreate and friends
  *  0.13: Added wbcCtxUnixIdsToSids and wbcUnixIdsToSids
+ *  0.14: Added wbcCtxLookupNameEx and wbcLookupNameEx
  **/
 #define WBCLIENT_MAJOR_VERSION 0
-#define WBCLIENT_MINOR_VERSION 13
+#define WBCLIENT_MINOR_VERSION 14
 #define WBCLIENT_VENDOR_VERSION "Samba libwbclient"
 struct wbcLibraryDetails {
 	uint16_t major_version;
@@ -657,6 +658,47 @@ wbcErr wbcInterfaceDetails(struct wbcInterfaceDetails **details);
  **********************************************************/
 
 /**
+ * wbcCtxLookupNameEx flags
+ **/
+#define WBC_LOOKUP_NAME_CACHE_ONLY 0x00000001
+
+/**
+ * @brief Convert a domain and name to SID
+ *
+ * @param *ctx        wbclient Context
+ * @param dom_name    Domain name (possibly "")
+ * @param name        User or group name
+ * @param *sid        Pointer to the resolved domain SID
+ * @param *name_type  Pointer to the SID type
+ * @param flags       Flags to customize operation
+ *
+ * @return #wbcErr
+ **/
+wbcErr wbcCtxLookupNameEx(struct wbcContext *ctx,
+			  const char *dom_name,
+			  const char *name,
+			  struct wbcDomainSid *sid,
+			  enum wbcSidType *name_type,
+			  uint32_t flags);
+
+/**
+ * @brief Convert a domain and name to SID
+ *
+ * @param dom_name    Domain name (possibly "")
+ * @param name        User or group name
+ * @param *sid        Pointer to the resolved domain SID
+ * @param *name_type  Pointer to the SID type
+ * @param flags       Flags to customize operation
+ *
+ * @return #wbcErr
+ **/
+wbcErr wbcLookupNameEx(const char *dom_name,
+		       const char *name,
+		       struct wbcDomainSid *sid,
+		       enum wbcSidType *name_type,
+		       uint32_t flags);
+
+/**
  * @brief Convert a domain and name to SID
  *
  * @param *ctx        wbclient Context
diff --git a/nsswitch/libwbclient/wscript b/nsswitch/libwbclient/wscript
index 5c5002a..c5390b9 100644
--- a/nsswitch/libwbclient/wscript
+++ b/nsswitch/libwbclient/wscript
@@ -3,7 +3,7 @@
 import Options, Logs
 
 # Remember to also update wbclient.h
-VERSION="0.13"
+VERSION="0.14"
 
 # It may be useful at some point to allow Samba to build against a
 # system libwbclient, such as the one provided by Likewise.  To to
diff --git a/nsswitch/winbind_struct_protocol.h b/nsswitch/winbind_struct_protocol.h
index 84829d2..8284e4f 100644
--- a/nsswitch/winbind_struct_protocol.h
+++ b/nsswitch/winbind_struct_protocol.h
@@ -304,6 +304,7 @@ struct winbindd_request {
 		struct {
 			fstring dom_name;       /* lookupname */
 			fstring name;
+			uint32_t flags;
 		} name;
 		uint32_t num_entries;  /* getpwent, getgrent */
 		struct {
diff --git a/source3/winbindd/winbindd_cache.c b/source3/winbindd/winbindd_cache.c
index 4a9782a..be67bf6 100644
--- a/source3/winbindd/winbindd_cache.c
+++ b/source3/winbindd/winbindd_cache.c
@@ -34,6 +34,7 @@
 #include "../libcli/security/security.h"
 #include "passdb/machine_sid.h"
 #include "util_tdb.h"
+#include "passdb/lookup_sid.h" /* only for LOOKUP_NAME_CACHE_ONLY flag */
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
@@ -703,9 +704,11 @@ static bool is_builtin_domain(struct winbindd_domain *domain)
 */
 static struct cache_entry *wcache_fetch(struct winbind_cache *cache, 
 					struct winbindd_domain *domain,
-					const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+					bool validate,
+					const char *format, ...) PRINTF_ATTRIBUTE(4,5);
 static struct cache_entry *wcache_fetch(struct winbind_cache *cache, 
 					struct winbindd_domain *domain,
+					bool validate,
 					const char *format, ...)
 {
 	va_list ap;
@@ -718,7 +721,9 @@ static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
 		return NULL;
 	}
 
-	refresh_sequence_number(domain);
+	if (validate) {
+		refresh_sequence_number(domain);
+	}
 
 	va_start(ap, format);
 	smb_xvasprintf(&kstr, format, ap);
@@ -730,6 +735,10 @@ static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
 		return NULL;
 	}
 
+	if (!validate) {
+		goto ret;
+	}
+
 	if (centry_expired(domain, kstr, centry)) {
 
 		DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
@@ -740,6 +749,7 @@ static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
 		return NULL;
 	}
 
+ret:
 	DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
 		 kstr, domain->name ));
 
@@ -1150,7 +1160,7 @@ NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
 		return NT_STATUS_INVALID_PARAMETER;
 	}
 
-	centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
+	centry = wcache_fetch(cache, domain, true, "NSS/NA/%s", upper_name);
 
 	talloc_free(upper_name);
 
@@ -1230,7 +1240,7 @@ NTSTATUS resolve_alias_to_username( TALLOC_CTX *mem_ctx,
 		return NT_STATUS_INVALID_PARAMETER;
 	}
 
-	centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
+	centry = wcache_fetch(cache, domain, true, "NSS/AN/%s", upper_name);
 
 	talloc_free(upper_name);
 
@@ -1351,7 +1361,7 @@ NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
 	/* Try and get a salted cred first. If we can't
 	   fall back to an unsalted cred. */
 
-	centry = wcache_fetch(cache, domain, "CRED/%s",
+	centry = wcache_fetch(cache, domain, true, "CRED/%s",
 			      sid_to_fstring(tmp, sid));
 	if (!centry) {
 		DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n", 
@@ -1467,7 +1477,7 @@ NTSTATUS wb_cache_query_user_list(struct winbindd_domain *domain,
 	if (!cache->tdb)
 		goto do_query;
 
-	centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
+	centry = wcache_fetch(cache, domain, true, "UL/%s", domain->name);
 	if (!centry)
 		goto do_query;
 
@@ -1550,7 +1560,8 @@ do_query:
 			 * try to fetch from cache again.
 			 */
 			if (cache->tdb && !domain->online && !domain->internal && old_status) {
-				centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
+				centry = wcache_fetch(cache, domain, true,
+						      "UL/%s", domain->name);
 				/* partial response... */
 				if (!centry) {
 					goto skip_save;
@@ -1619,7 +1630,8 @@ NTSTATUS wb_cache_enum_dom_groups(struct winbindd_domain *domain,
 	if (!cache->tdb)
 		goto do_query;
 
-	centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
+	centry =
+	    wcache_fetch(cache, domain, true, "GL/%s/domain", domain->name);
 	if (!centry)
 		goto do_query;
 
@@ -1671,7 +1683,8 @@ do_query:
 			!domain->online &&
 			!domain->internal &&
 			old_status) {
-			centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
+			centry = wcache_fetch(cache, domain, true,
+					      "GL/%s/domain", domain->name);
 			if (centry) {
 				goto do_fetch_cache;
 			}
@@ -1714,7 +1727,7 @@ NTSTATUS wb_cache_enum_local_groups(struct winbindd_domain *domain,
 	if (!cache->tdb)
 		goto do_query;
 
-	centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
+	centry = wcache_fetch(cache, domain, true, "GL/%s/local", domain->name);
 	if (!centry)
 		goto do_query;
 
@@ -1776,7 +1789,8 @@ do_query:
 			!domain->internal &&
 			!domain->online &&
 			old_status) {
-			centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
+			centry = wcache_fetch(cache, domain, true,
+					      "GL/%s/local", domain->name);
 			if (centry) {
 				goto do_fetch_cache;
 			}
@@ -1806,6 +1820,7 @@ skip_save:
 NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
 			    const char *domain_name,
 			    const char *name,
+			    uint32_t flags,
 			    struct dom_sid *sid,
 			    enum lsa_SidType *type)
 {
@@ -1813,6 +1828,7 @@ NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
 	struct cache_entry *centry;
 	NTSTATUS status;
 	char *uname;
+	bool cache_only = ((flags & LOOKUP_NAME_CACHE_ONLY) != 0);
 
 	if (cache->tdb == NULL) {
 		return NT_STATUS_NOT_FOUND;
@@ -1827,7 +1843,8 @@ NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
 		domain_name = domain->name;
 	}
 
-	centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
+	centry = wcache_fetch(cache, domain, !cache_only, "NS/%s/%s",
+			      domain_name, uname);
 	TALLOC_FREE(uname);
 	if (centry == NULL) {
 		return NT_STATUS_NOT_FOUND;
@@ -1860,7 +1877,8 @@ NTSTATUS wb_cache_name_to_sid(struct winbindd_domain *domain,
 
 	old_status = domain->online;
 
-	status = wcache_name_to_sid(domain, domain_name, name, sid, type);
+	status =
+	    wcache_name_to_sid(domain, domain_name, name, flags, sid, type);
 	if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
 		return status;
 	}
@@ -1893,7 +1911,8 @@ NTSTATUS wb_cache_name_to_sid(struct winbindd_domain *domain,
 			!domain->online &&
 			old_status) {
 			NTSTATUS cache_status;
-			cache_status = wcache_name_to_sid(domain, domain_name, name, sid, type);
+			cache_status = wcache_name_to_sid(
+			    domain, domain_name, name, flags, sid, type);
 			return cache_status;
 		}
 	}
@@ -1938,7 +1957,7 @@ static NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	centry = wcache_fetch(cache, domain, "SN/%s", sid_string);
+	centry = wcache_fetch(cache, domain, true, "SN/%s", sid_string);
 	TALLOC_FREE(sid_string);
 	if (centry == NULL) {
 		return NT_STATUS_NOT_FOUND;
@@ -2073,7 +2092,7 @@ NTSTATUS wb_cache_rids_to_names(struct winbindd_domain *domain,
 			goto error;
 		}
 
-		centry = wcache_fetch(cache, domain, "SN/%s",
+		centry = wcache_fetch(cache, domain, true, "SN/%s",
 				      sid_to_fstring(tmp, &sid));
 		if (!centry) {
 			goto do_query;
@@ -2161,8 +2180,9 @@ NTSTATUS wb_cache_rids_to_names(struct winbindd_domain *domain,
 					goto error;
 				}
 
-				centry = wcache_fetch(cache, domain, "SN/%s",
-						      sid_to_fstring(tmp, &sid));
+				centry =
+				    wcache_fetch(cache, domain, true, "SN/%s",
+						 sid_to_fstring(tmp, &sid));
 				if (!centry) {
 					(*types)[i] = SID_NAME_UNKNOWN;
 					(*names)[i] = talloc_strdup(*names, "");
@@ -2282,7 +2302,7 @@ NTSTATUS wcache_query_user(struct winbindd_domain *domain,
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	centry = wcache_fetch(cache, domain, "U/%s", sid_string);
+	centry = wcache_fetch(cache, domain, true, "U/%s", sid_string);
 	TALLOC_FREE(sid_string);
 	if (centry == NULL) {
 		return NT_STATUS_NOT_FOUND;
@@ -2424,7 +2444,7 @@ NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain,
 		return NT_STATUS_NOT_FOUND;
 	}
 
-	centry = wcache_fetch(cache, domain, "UG/%s",
+	centry = wcache_fetch(cache, domain, true, "UG/%s",
 			      sid_to_fstring(sid_string, user_sid));
 	if (centry == NULL) {
 		return NT_STATUS_NOT_FOUND;
@@ -2589,7 +2609,7 @@ NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	centry = wcache_fetch(cache, domain, "UA%s", sidlist);
+	centry = wcache_fetch(cache, domain, true, "UA%s", sidlist);
 	TALLOC_FREE(sidlist);
 	if (centry == NULL) {
 		return NT_STATUS_NOT_FOUND;
@@ -2711,7 +2731,7 @@ NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	centry = wcache_fetch(cache, domain, "GM/%s", sid_string);
+	centry = wcache_fetch(cache, domain, true, "GM/%s", sid_string);
 	TALLOC_FREE(sid_string);
 	if (centry == NULL) {
 		return NT_STATUS_NOT_FOUND;
@@ -2964,7 +2984,7 @@ NTSTATUS wb_cache_lockout_policy(struct winbindd_domain *domain,
 	if (!cache->tdb)
 		goto do_query;
 
-	centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
+	centry = wcache_fetch(cache, domain, true, "LOC_POL/%s", domain->name);
 
 	if (!centry)
  		goto do_query;
@@ -3004,7 +3024,8 @@ do_query:
 			!domain->internal &&
 			!domain->online &&
 			old_status) {
-			centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
+			centry = wcache_fetch(cache, domain, true, "LOC_POL/%s",
+					      domain->name);
 			if (centry) {
 				goto do_fetch_cache;
 			}
@@ -3034,7 +3055,7 @@ NTSTATUS wb_cache_password_policy(struct winbindd_domain *domain,
 	if (!cache->tdb)
 		goto do_query;
 
-	centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
+	centry = wcache_fetch(cache, domain, true, "PWD_POL/%s", domain->name);
 
 	if (!centry)
 		goto do_query;
@@ -3076,7 +3097,8 @@ do_query:
 			!domain->internal &&
 			!domain->online &&
 			old_status) {
-			centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
+			centry = wcache_fetch(cache, domain, true, "PWD_POL/%s",
+					      domain->name);
 			if (centry) {
 				goto do_fetch_cache;
 			}
@@ -3326,20 +3348,14 @@ bool lookup_cached_name(const char *domain_name,
 {
 	struct winbindd_domain *domain;
 	NTSTATUS status;
-	bool original_online_state;
 
 	domain = find_lookup_domain_from_name(domain_name);
 	if (domain == NULL) {
 		return false;
 	}
 
-	/* If we are doing a cached logon, temporarily set the domain
-	   offline so the cache won't expire the entry */
-
-	original_online_state = domain->online;
-	domain->online = false;
-	status = wcache_name_to_sid(domain, domain_name, name, sid, type);
-	domain->online = original_online_state;
+	status = wcache_name_to_sid(domain, domain_name, name,
+				    LOOKUP_NAME_CACHE_ONLY, sid, type);
 
 	return NT_STATUS_IS_OK(status);
 }
@@ -4938,7 +4954,7 @@ NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
 	if (!cache->tdb)
 		goto do_query;
 
-	centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
+	centry = wcache_fetch(cache, domain, true, "NSS/PWINFO/%s",
 			      sid_to_fstring(tmp, user_sid));
 
 	if (!centry)
diff --git a/source3/winbindd/winbindd_lookupname.c b/source3/winbindd/winbindd_lookupname.c
index 1be29fd..9823d36 100644
--- a/source3/winbindd/winbindd_lookupname.c
+++ b/source3/winbindd/winbindd_lookupname.c
@@ -19,6 +19,7 @@
 
 #include "includes.h"
 #include "winbindd.h"
+#include "passdb/lookup_sid.h" /* only for LOOKUP_NAME_NO_NSS flag */
 
 struct winbindd_lookupname_state {
 	struct tevent_context *ev;
@@ -36,6 +37,7 @@ struct tevent_req *winbindd_lookupname_send(TALLOC_CTX *mem_ctx,
 	struct tevent_req *req, *subreq;
 	struct winbindd_lookupname_state *state;
 	char *domname, *name, *p;
+	uint32_t flags = 0;
 
 	req = tevent_req_create(mem_ctx, &state,
 				struct winbindd_lookupname_state);
@@ -65,10 +67,14 @@ struct tevent_req *winbindd_lookupname_send(TALLOC_CTX *mem_ctx,
 		name = request->data.name.name;
 	}
 
+	if (request->data.name.flags & WBC_LOOKUP_NAME_CACHE_ONLY) {
+		flags |= LOOKUP_NAME_CACHE_ONLY;
+	}
+
 	DEBUG(3, ("lookupname %s%s%s\n", domname, lp_winbind_separator(),
 		  name));
 
-	subreq = wb_lookupname_send(state, ev, domname, name, 0);
+	subreq = wb_lookupname_send(state, ev, domname, name, flags);
 	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, ev);
 	}
diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h
index 23900af..48fbfe1 100644
--- a/source3/winbindd/winbindd_proto.h
+++ b/source3/winbindd/winbindd_proto.h
@@ -165,6 +165,7 @@ void cache_name2sid(struct winbindd_domain *domain,
 NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
 			    const char *domain_name,
 			    const char *name,
+			    uint32_t flags,
 			    struct dom_sid *sid,
 			    enum lsa_SidType *type);
 NTSTATUS wcache_query_user(struct winbindd_domain *domain,
-- 
2.9.3


From 59253977d9cee5dab1da43c29f5e0a3aee5f7a76 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at ctera.com>
Date: Mon, 28 Nov 2016 00:14:59 +0200
Subject: [PATCH 3/9] param: add "cached share acl" parameter

This is a different mode of evaluating share access lists
based on smb.conf.

Trustees in smb.conf access lists need to be converted to SIDs. This
lookup is usually done lazily on a need basis. This lazy lookup
could cause bad user experience with a flaky DC connection, if the user
asking for a tree-connect is the first to encounter the disruption.

With this new mode, a new daemon "primed" periodically makes lookup
requests to trustees in all share ACLs, thus priming the winbindd
cache and avoiding lookup initiated by the SMB request.In addition,
smbd asks first for a cached result, without consideration of whether
the entry has expired.

Signed-off-by: Uri Simchoni <uri at samba.org>
---
 docs-xml/smbdotconf/misc/cachedshareacl.xml | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 docs-xml/smbdotconf/misc/cachedshareacl.xml

diff --git a/docs-xml/smbdotconf/misc/cachedshareacl.xml b/docs-xml/smbdotconf/misc/cachedshareacl.xml
new file mode 100644
index 0000000..1e1812a
--- /dev/null
+++ b/docs-xml/smbdotconf/misc/cachedshareacl.xml
@@ -0,0 +1,18 @@
+<samba:parameter name="cached share acls"
+                 context="G"
+                 type="boolean"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+	<para>
+	This boolean option tells <command moreinfo="none">smbd</command> whether to
+	prefer cached values when translating share ACL list members to Windows
+	security identifiers.
+	</para>
+
+	<para>
+	Fixme - explain some more...
+	</para>
+</description>
+
+<value type="default">no</value>
+</samba:parameter>
-- 
2.9.3


From bb96df4563f3a0cd96e44f8a8584542579c78c02 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at ctera.com>
Date: Sun, 27 Nov 2016 11:50:42 +0200
Subject: [PATCH 4/9] util: check for out-of-memory in str_list_unique()

Signed-off-by: Uri Simchoni <uri at samba.org>
---
 lib/util/util_strlist.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/lib/util/util_strlist.c b/lib/util/util_strlist.c
index 203a643..3e09cd8 100644
--- a/lib/util/util_strlist.c
+++ b/lib/util/util_strlist.c
@@ -396,6 +396,9 @@ _PUBLIC_ const char **str_list_unique(const char **list)
 	}
 	list2 = (const char **)talloc_memdup(list, list,
 					     sizeof(list[0])*(len+1));
+	if (!list2) {
+		return NULL;
+	}
 	TYPESAFE_QSORT(list2, len, list_cmp);
 	list[0] = list2[0];
 	for (i=j=1;i<len;i++) {
-- 
2.9.3


From 8712c0c2f69ebd0c013b20ac8c026080a670d92b Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at ctera.com>
Date: Sun, 27 Nov 2016 13:55:17 +0200
Subject: [PATCH 5/9] smbd: make do_group_check() public and rename it

Turn do_group_check(), a function that checks the syntax of
smb.conf access list principals and returns their type, into
a public function, and give it a proper public name.

Signed-off-by: Uri Simchoni <uri at samba.org>
---
 source3/smbd/proto.h        | 1 +
 source3/smbd/share_access.c | 4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index 352d28c..f0642dd 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -1078,6 +1078,7 @@ void reply_sesssetup_and_X(struct smb_request *req);
 
 /* The following definitions come from smbd/share_access.c  */
 
+bool smbconf_is_group_name(const char **name, const char **pattern);
 bool token_contains_name_in_list(const char *username,
 				 const char *domain,
 				 const char *sharename,
diff --git a/source3/smbd/share_access.c b/source3/smbd/share_access.c
index 3cbf7f3..0664609 100644
--- a/source3/smbd/share_access.c
+++ b/source3/smbd/share_access.c
@@ -32,7 +32,7 @@
  * + and & may be combined
  */
 
-static bool do_group_checks(const char **name, const char **pattern)
+bool smbconf_is_group_name(const char **name, const char **pattern)
 {
 	if ((*name)[0] == '@') {
 		*pattern = "&+";
@@ -96,7 +96,7 @@ static bool token_contains_name(TALLOC_CTX *mem_ctx,
 		return nt_token_check_sid( &sid, token );
 	}
 
-	if (!do_group_checks(&name, &prefix)) {
+	if (!smbconf_is_group_name(&name, &prefix)) {
 		if (!lookup_name_smbconf(mem_ctx, name, LOOKUP_NAME_ALL,
 				 NULL, NULL, &sid, &type)) {
 			DEBUG(5, ("lookup_name %s failed\n", name));
-- 
2.9.3


From c13e361d8975463696f420743524bb65dd658fe6 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at ctera.com>
Date: Sun, 27 Nov 2016 13:57:27 +0200
Subject: [PATCH 6/9] smbd: add primed

Add a cache priming damon. This daemon periodically queries winbindd
about names in smb.conf access lists, in order to avoid lazy lookup
as part of servicing a request.

Signed-off-by: Uri Simchoni <uri at samba.org>
---
 source3/smbd/server.c      | 189 +++++++++++++++++++++++++++++
 source3/smbd/smbd_primed.c | 297 +++++++++++++++++++++++++++++++++++++++++++++
 source3/smbd/smbd_primed.h |  32 +++++
 source3/wscript_build      |   3 +-
 4 files changed, 520 insertions(+), 1 deletion(-)
 create mode 100644 source3/smbd/smbd_primed.c
 create mode 100644 source3/smbd/smbd_primed.h

diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 3cbd089..4805198 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -52,6 +52,7 @@
 #include "smbd/smbd_cleanupd.h"
 #include "lib/util/sys_rw.h"
 #include "cleanupdb.h"
+#include "smbd/smbd_primed.h"
 
 #ifdef CLUSTER_SUPPORT
 #include "ctdb_protocol.h"
@@ -75,6 +76,7 @@ struct smbd_parent_context {
 
 	struct server_id cleanupd;
 	struct server_id notifyd;
+	struct server_id primed;
 
 	struct tevent_timer *cleanup_te;
 };
@@ -771,6 +773,171 @@ static void cleanupd_started(struct tevent_req *req)
 	}
 }
 
+static void primed_stopped(struct tevent_req *req);
+
+static struct tevent_req *primed_req(struct messaging_context *msg_ctx,
+				     struct tevent_context *ev)
+{
+	struct tevent_req *req;
+
+	req = smbd_primed_send(msg_ctx, ev, msg_ctx);
+	if (req == NULL) {
+		return NULL;
+	}
+	tevent_req_set_callback(req, primed_stopped, msg_ctx);
+
+	return req;
+}
+
+static void primed_stopped(struct tevent_req *req)
+{
+	NTSTATUS ret;
+
+	ret = smbd_primed_recv(req);
+	TALLOC_FREE(req);
+	DBG_WARNING("primed stopped: %s\n", nt_errstr(ret));
+}
+
+static bool smbd_primed_init(struct messaging_context *msg,
+			     bool interactive,
+			     struct server_id *ppid)
+{
+	struct tevent_context *ev = messaging_tevent_context(msg);
+	struct tevent_req *req;
+	pid_t pid;
+	NTSTATUS status;
+
+	if (!lp_cached_share_acls()) {
+		return true;
+	}
+
+	if (interactive) {
+		req = primed_req(msg, ev);
+		return (req != NULL);
+	}
+
+	pid = fork();
+	if (pid == -1) {
+		DBG_WARNING("fork failed: %s\n", strerror(errno));
+		return false;
+	}
+
+	if (pid != 0) {
+		if (am_parent != 0) {
+			add_child_pid(am_parent, pid);
+		}
+		*ppid = pid_to_procid(pid);
+		return true;
+	}
+
+	status = smbd_reinit_after_fork(msg, ev, true, "smbd-primed");
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_WARNING("reinit_after_fork failed: %s\n",
+			    nt_errstr(status));
+		exit(1);
+	}
+
+	req = primed_req(msg, ev);
+	if (req == NULL) {
+		exit(1);
+	}
+	tevent_req_set_callback(req, primed_stopped, msg);
+
+	return tevent_req_poll(req, ev);
+}
+
+static void primed_init_trigger(struct tevent_req *req);
+
+struct primed_init_state {
+	bool ok;
+	struct tevent_context *ev;
+	struct messaging_context *msg;
+	struct server_id *ppid;
+};
+
+static struct tevent_req *primed_init_send(struct tevent_context *ev,
+					   TALLOC_CTX *mem_ctx,
+					   struct messaging_context *msg,
+					   struct server_id *ppid)
+{
+	struct tevent_req *req = NULL;
+	struct tevent_req *subreq = NULL;
+	struct primed_init_state *state = NULL;
+
+	req = tevent_req_create(mem_ctx, &state, struct primed_init_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	*state = (struct primed_init_state){.msg = msg, .ev = ev, .ppid = ppid};
+
+	subreq =
+	    tevent_wakeup_send(state, ev, tevent_timeval_current_ofs(1, 0));
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	tevent_req_set_callback(subreq, primed_init_trigger, req);
+	return req;
+}
+
+static void primed_init_trigger(struct tevent_req *subreq)
+{
+	struct tevent_req *req =
+	    tevent_req_callback_data(subreq, struct tevent_req);
+	struct primed_init_state *state =
+	    tevent_req_data(req, struct primed_init_state);
+	bool ok;
+
+	DBG_NOTICE("Triggering primed startup\n");
+
+	ok = tevent_wakeup_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (!ok) {
+		tevent_req_error(req, ENOMEM);
+		return;
+	}
+
+	state->ok = smbd_primed_init(state->msg, false, state->ppid);
+	if (state->ok) {
+		DBG_WARNING("primed restarted\n");
+		tevent_req_done(req);
+		return;
+	}
+
+	DBG_NOTICE("primed startup failed, rescheduling\n");
+
+	subreq = tevent_wakeup_send(state, state->ev,
+				    tevent_timeval_current_ofs(1, 0));
+	if (tevent_req_nomem(subreq, req)) {
+		DBG_ERR("scheduling primed restart failed, giving up\n");
+		return;
+	}
+
+	tevent_req_set_callback(subreq, primed_init_trigger, req);
+	return;
+}
+
+static bool primed_init_recv(struct tevent_req *req)
+{
+	struct primed_init_state *state =
+	    tevent_req_data(req, struct primed_init_state);
+
+	return state->ok;
+}
+
+static void primed_started(struct tevent_req *req)
+{
+	bool ok;
+
+	ok = primed_init_recv(req);
+	TALLOC_FREE(req);
+	if (!ok) {
+		DBG_ERR("Failed to restart primed, giving up\n");
+		return;
+	}
+}
+
 static void remove_child_pid(struct smbd_parent_context *parent,
 			     pid_t pid,
 			     bool unclean_shutdown)
@@ -833,6 +1000,24 @@ static void remove_child_pid(struct smbd_parent_context *parent,
 		return;
 	}
 
+	if (pid == procid_to_pid(&parent->primed)) {
+		struct tevent_req *req;
+		struct tevent_context *ev =
+		    messaging_tevent_context(parent->msg_ctx);
+
+		server_id_set_disconnected(&parent->primed);
+
+		DBG_WARNING("Restarting primed\n");
+		req = primed_init_send(ev, parent, parent->msg_ctx,
+				       &parent->primed);
+		if (req == NULL) {
+			DBG_ERR("Failed to restart primed\n");
+			return;
+		}
+		tevent_req_set_callback(req, primed_started, parent);
+		return;
+	}
+
 	ok = cleanupdb_store_child(pid, unclean_shutdown);
 	if (!ok) {
 		DBG_ERR("cleanupdb_store_child failed\n");
@@ -1856,6 +2041,10 @@ extern void build_options(bool screen);
 		exit_daemon("Samba cannot init notification", EACCES);
 	}
 
+	if (!smbd_primed_init(msg_ctx, interactive, &parent->primed)) {
+		exit_daemon("Samba cannot init cache priming", EACCES);
+	}
+
 	if (!cleanupd_init(msg_ctx, interactive, &parent->cleanupd)) {
 		exit_daemon("Samba cannot init the cleanupd", EACCES);
 	}
diff --git a/source3/smbd/smbd_primed.c b/source3/smbd/smbd_primed.c
new file mode 100644
index 0000000..498b8e4
--- /dev/null
+++ b/source3/smbd/smbd_primed.c
@@ -0,0 +1,297 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Uri Simchoni 2016
+ *
+ * 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 <tevent.h>
+//#include "messages.h"
+//#include "lib/param/loadparm.h"
+//#include "passdb/lookup_sid.h"
+#include "smbd/smbd.h"
+#include "smbd_primed.h"
+#include "../libcli/security/security.h"
+#include "passdb/lookup_sid.h"
+#include "../lib/util/tevent_ntstatus.h"
+
+struct smbd_primed_state {
+	struct tevent_context *ev;
+	struct tevent_timer *tm;
+	const char **names;
+};
+
+static void smbd_primed_shutdown(struct messaging_context *msg,
+				 void *private_data,
+				 uint32_t msg_type,
+				 struct server_id server_id,
+				 DATA_BLOB *data);
+static void smbd_primed_conf_updated(struct messaging_context *msg,
+				     void *private_data,
+				     uint32_t msg_type,
+				     struct server_id server_id,
+				     DATA_BLOB *data);
+
+static NTSTATUS smbd_primed_restart(struct tevent_req *req);
+
+struct tevent_req *smbd_primed_send(TALLOC_CTX *mem_ctx,
+				    struct tevent_context *ev,
+				    struct messaging_context *msg)
+{
+	struct tevent_req *req;
+	struct smbd_primed_state *state;
+	NTSTATUS status;
+
+	req = tevent_req_create(mem_ctx, &state, struct smbd_primed_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	state->ev = ev;
+	state->tm = NULL;
+	state->names = NULL;
+
+	status =
+	    messaging_register(msg, req, MSG_SHUTDOWN, smbd_primed_shutdown);
+	if (tevent_req_nterror(req, status)) {
+		return tevent_req_post(req, ev);
+	}
+
+	status = messaging_register(msg, req, MSG_SMB_CONF_UPDATED,
+				    smbd_primed_conf_updated);
+	if (tevent_req_nterror(req, status)) {
+		return tevent_req_post(req, ev);
+	}
+
+	status = smbd_primed_restart(req);
+	if (tevent_req_nterror(req, status)) {
+		return tevent_req_post(req, ev);
+	}
+
+	return req;
+}
+
+NTSTATUS smbd_primed_recv(struct tevent_req *req)
+{
+	NTSTATUS status;
+
+	if (tevent_req_is_nterror(req, &status)) {
+		return status;
+	}
+
+	return NT_STATUS_OK;
+}
+
+static void smbd_primed_shutdown(struct messaging_context *msg,
+				 void *private_data,
+				 uint32_t msg_type,
+				 struct server_id server_id,
+				 DATA_BLOB *data)
+{
+	struct tevent_req *req =
+	    talloc_get_type_abort(private_data, struct tevent_req);
+	tevent_req_done(req);
+}
+
+static void smbd_primed_conf_updated(struct messaging_context *msg,
+				     void *private_data,
+				     uint32_t msg_type,
+				     struct server_id server_id,
+				     DATA_BLOB *data)
+{
+	struct tevent_req *req =
+	    talloc_get_type_abort(private_data, struct tevent_req);
+	NTSTATUS status;
+
+	DBG_DEBUG("reloading services\n");
+	reload_services(NULL, NULL, false);
+	status = smbd_primed_restart(req);
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+}
+
+static void add_name_to_list(const char ***lst1, const char *const *lst2)
+{
+	if (*lst1 == NULL) {
+		return;
+	}
+
+	if (lst2 == NULL) {
+		return;
+	}
+
+	*lst1 = str_list_append(*lst1, lst2);
+}
+
+typedef const char **(*share_conf_list_fn)(int);
+
+static void
+add_share_lists(const char ***final_list, int snum, share_conf_list_fn fns[])
+{
+	share_conf_list_fn *fn;
+	for (fn = fns; *fn; ++fn) {
+		const char *const *lst = (*fn)(snum);
+		add_name_to_list(final_list, lst);
+	}
+}
+
+static NTSTATUS smbd_primed_build_list(struct smbd_primed_state *state)
+{
+	int num_services = lp_numservices();
+	int snum;
+	static share_conf_list_fn fns[] = {
+	    lp_valid_users, lp_write_list, lp_read_list, NULL};
+
+	TALLOC_FREE(state->names);
+	state->names = (const char **)discard_const(str_list_make_empty(state));
+	if (!state->names) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	for (snum = 0; snum < num_services; snum++) {
+		add_share_lists(&state->names, snum, fns);
+	}
+
+	if (!state->names) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	if (!str_list_unique(state->names)) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	DBG_DEBUG("Final list of watched names:\n");
+	if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) {
+		str_list_show(state->names);
+	}
+
+	return NT_STATUS_OK;
+}
+
+static NTSTATUS smbd_primed_lookup_name(TALLOC_CTX *mem_ctx,
+					const char *sharename,
+					const char *name)
+{
+	const char *prefix;
+	struct dom_sid sid;
+	enum lsa_SidType type;
+
+	if (sharename != NULL) {
+		name = talloc_string_sub(mem_ctx, name, "%S", sharename);
+	}
+
+	if (name == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	DBG_DEBUG("looking up [%s]\n", name);
+
+	if (string_to_sid(&sid, name)) {
+		DBG_DEBUG("A SID\n");
+		return NT_STATUS_OK;
+	}
+
+	if (!smbconf_is_group_name(&name, &prefix)) {
+		if (!lookup_name_smbconf(mem_ctx, name, LOOKUP_NAME_ALL, NULL,
+					 NULL, &sid, &type)) {
+			DBG_INFO("lookup_name %s failed\n", name);
+		} else {
+			DBG_DEBUG("[%s] mapped to a %s\n", name,
+				  sid_type_lookup(type));
+		}
+		return NT_STATUS_OK;
+	}
+
+	for (/* initialized above */; *prefix != '\0'; prefix++) {
+		if (*prefix == '+') {
+			if (!lookup_name_smbconf(mem_ctx, name,
+						 LOOKUP_NAME_ALL |
+						     LOOKUP_NAME_GROUP,
+						 NULL, NULL, &sid, &type)) {
+				DBG_INFO("lookup_name %s failed\n", name);
+			} else {
+				DBG_DEBUG("[%s] mapped to a %s\n", name,
+					  sid_type_lookup(type));
+				return NT_STATUS_OK;
+			}
+		}
+	}
+	return NT_STATUS_OK;
+}
+
+static void smbd_primed_prime_lookup_cache(struct tevent_context *ev,
+					   struct tevent_timer *te,
+					   struct timeval current_time,
+					   void *private_data)
+{
+	struct tevent_req *req =
+	    talloc_get_type_abort(private_data, struct tevent_req);
+	struct smbd_primed_state *state =
+	    tevent_req_data(req, struct smbd_primed_state);
+	const char **name;
+	NTSTATUS status;
+	TALLOC_CTX *frame = NULL;
+	struct timeval next_time;
+
+	DBG_DEBUG("primed: looking up names\n");
+
+	TALLOC_FREE(state->tm);
+
+	frame = talloc_stackframe();
+	if (tevent_req_nomem(frame, req)) {
+		return;
+	}
+
+	for (name = state->names; *name; ++name) {
+		status = smbd_primed_lookup_name(frame, NULL, *name);
+		if (!NT_STATUS_IS_OK(status)) {
+			break;
+		}
+	}
+
+	TALLOC_FREE(frame);
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+
+	next_time = timeval_add(&current_time, lp_winbind_cache_time() / 2, 0);
+	state->tm = tevent_add_timer(ev, state, next_time,
+				     smbd_primed_prime_lookup_cache, req);
+
+	if (tevent_req_nomem(state->tm, req)) {
+		return;
+	}
+}
+
+static NTSTATUS smbd_primed_restart(struct tevent_req *req)
+{
+	NTSTATUS status;
+	struct smbd_primed_state *state =
+	    tevent_req_data(req, struct smbd_primed_state);
+
+	TALLOC_FREE(state->tm);
+	status = smbd_primed_build_list(state);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	state->tm = tevent_add_timer(state->ev, state, timeval_current(),
+				     smbd_primed_prime_lookup_cache, req);
+
+	if (!state->tm) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	return NT_STATUS_OK;
+}
diff --git a/source3/smbd/smbd_primed.h b/source3/smbd/smbd_primed.h
new file mode 100644
index 0000000..eb26ac4
--- /dev/null
+++ b/source3/smbd/smbd_primed.h
@@ -0,0 +1,32 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Uri Simchoni 2016
+ *
+ * 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/>.
+ */
+
+#ifndef __SMBD_PRIMED_H__
+#define __SMBD_PRIMED_H__
+
+#include "replace.h"
+#include <tevent.h>
+#include "messages.h"
+
+struct tevent_req *smbd_primed_send(TALLOC_CTX *mem_ctx,
+				    struct tevent_context *ev,
+				    struct messaging_context *msg);
+NTSTATUS smbd_primed_recv(struct tevent_req *req);
+
+#endif
diff --git a/source3/wscript_build b/source3/wscript_build
index d6d2be2..1ad2fbe 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -865,7 +865,8 @@ bld.SAMBA3_SUBSYSTEM('SPOOLSSD',
 ########################## BINARIES #################################
 
 bld.SAMBA3_BINARY('smbd/smbd',
-                 source='smbd/server.c smbd/smbd_cleanupd.c',
+                 source='''smbd/server.c smbd/smbd_cleanupd.c
+                 smbd/smbd_primed.c''',
                  deps='''
                       smbd_base
                       EPMD
-- 
2.9.3


From 1bd98bed894913310596eaaeeeb67b4c15424f71 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Mon, 28 Nov 2016 08:30:58 +0200
Subject: [PATCH 7/9] s3-passdb: add winbind_lookup_name_cache_only()

Add a utility function for name lookup based on
winbindd cache only

Signed-off-by: Uri Simchoni <uri at samba.org>
---
 source3/lib/winbind_util.c                  |  29 +++
 source3/lib/winbind_util.h                  |   5 +
 source3/passdb/ABI/samba-passdb-0.25.1.sigs | 313 ++++++++++++++++++++++++++++
 source3/wscript_build                       |   2 +-
 4 files changed, 348 insertions(+), 1 deletion(-)
 create mode 100644 source3/passdb/ABI/samba-passdb-0.25.1.sigs

diff --git a/source3/lib/winbind_util.c b/source3/lib/winbind_util.c
index b3ecac1..2914dc1 100644
--- a/source3/lib/winbind_util.c
+++ b/source3/lib/winbind_util.c
@@ -83,6 +83,35 @@ bool winbind_lookup_name(const char *dom_name, const char *name, struct dom_sid
 	return true;	
 }
 
+bool winbind_lookup_name_cache_only(const char *dom_name,
+				    const char *name,
+				    struct dom_sid *sid,
+				    enum lsa_SidType *name_type,
+				    bool *ret_wb_avail)
+{
+	struct wbcDomainSid dom_sid;
+	wbcErr result;
+	enum wbcSidType type;
+
+	if (ret_wb_avail) {
+		*ret_wb_avail = true;
+	}
+
+	result = wbcLookupNameEx(dom_name, name, &dom_sid, &type,
+				 WBC_LOOKUP_NAME_CACHE_ONLY);
+	if (result == WBC_ERR_WINBIND_NOT_AVAILABLE && ret_wb_avail) {
+		*ret_wb_avail = false;
+	}
+	if (result != WBC_ERR_SUCCESS) {
+		return false;
+	}
+
+	memcpy(sid, &dom_sid, sizeof(struct dom_sid));
+	*name_type = (enum lsa_SidType)type;
+
+	return true;
+}
+
 /* Call winbindd to convert sid to name */
 
 bool winbind_lookup_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
diff --git a/source3/lib/winbind_util.h b/source3/lib/winbind_util.h
index 2a90092..495c6ed 100644
--- a/source3/lib/winbind_util.h
+++ b/source3/lib/winbind_util.h
@@ -30,6 +30,11 @@
 
 bool winbind_lookup_name(const char *dom_name, const char *name, struct dom_sid *sid,
                          enum lsa_SidType *name_type);
+bool winbind_lookup_name_cache_only(const char *dom_name,
+				    const char *name,
+				    struct dom_sid *sid,
+				    enum lsa_SidType *name_type,
+				    bool *ret_wb_avail);
 bool winbind_lookup_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
 			const char **domain, const char **name,
                         enum lsa_SidType *name_type);
diff --git a/source3/passdb/ABI/samba-passdb-0.25.1.sigs b/source3/passdb/ABI/samba-passdb-0.25.1.sigs
new file mode 100644
index 0000000..2bc21af
--- /dev/null
+++ b/source3/passdb/ABI/samba-passdb-0.25.1.sigs
@@ -0,0 +1,313 @@
+PDB_secrets_clear_domain_protection: bool (const char *)
+PDB_secrets_fetch_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_fetch_domain_sid: bool (const char *, struct dom_sid *)
+PDB_secrets_mark_domain_protected: bool (const char *)
+PDB_secrets_store_domain_guid: bool (const char *, struct GUID *)
+PDB_secrets_store_domain_sid: bool (const char *, const struct dom_sid *)
+account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_default: bool (enum pdb_policy_type, uint32_t *)
+account_policy_get_desc: const char *(enum pdb_policy_type)
+account_policy_name_to_typenum: enum pdb_policy_type (const char *)
+account_policy_names_list: void (TALLOC_CTX *, const char ***, int *)
+account_policy_set: bool (enum pdb_policy_type, uint32_t)
+add_initial_entry: NTSTATUS (gid_t, const char *, enum lsa_SidType, const char *, const char *)
+algorithmic_pdb_gid_to_group_rid: uint32_t (gid_t)
+algorithmic_pdb_rid_is_user: bool (uint32_t)
+algorithmic_pdb_uid_to_user_rid: uint32_t (uid_t)
+algorithmic_pdb_user_rid_to_uid: uid_t (uint32_t)
+algorithmic_rid_base: int (void)
+builtin_domain_name: const char *(void)
+cache_account_policy_get: bool (enum pdb_policy_type, uint32_t *)
+cache_account_policy_set: bool (enum pdb_policy_type, uint32_t)
+create_builtin_administrators: NTSTATUS (const struct dom_sid *)
+create_builtin_users: NTSTATUS (const struct dom_sid *)
+decode_account_policy_name: const char *(enum pdb_policy_type)
+get_account_pol_db: struct db_context *(void)
+get_account_policy_attr: const char *(enum pdb_policy_type)
+get_domain_group_from_sid: bool (struct dom_sid, GROUP_MAP *)
+get_primary_group_sid: NTSTATUS (TALLOC_CTX *, const char *, struct passwd **, struct dom_sid **)
+get_privileges_for_sid_as_set: NTSTATUS (TALLOC_CTX *, PRIVILEGE_SET **, struct dom_sid *)
+get_privileges_for_sids: bool (uint64_t *, struct dom_sid *, int)
+get_trust_pw_clear: bool (const char *, char **, const char **, enum netr_SchannelType *)
+get_trust_pw_hash: bool (const char *, uint8_t *, const char **, enum netr_SchannelType *)
+gid_to_sid: void (struct dom_sid *, gid_t)
+gid_to_unix_groups_sid: void (gid_t, struct dom_sid *)
+grab_named_mutex: struct named_mutex *(TALLOC_CTX *, const char *, int)
+grant_all_privileges: bool (const struct dom_sid *)
+grant_privilege_by_name: bool (const struct dom_sid *, const char *)
+grant_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+groupdb_tdb_init: const struct mapping_backend *(void)
+init_account_policy: bool (void)
+init_buffer_from_samu: uint32_t (uint8_t **, struct samu *, bool)
+init_samu_from_buffer: bool (struct samu *, uint32_t, uint8_t *, uint32_t)
+initialize_password_db: bool (bool, struct tevent_context *)
+is_dc_trusted_domain_situation: bool (const char *)
+is_privileged_sid: bool (const struct dom_sid *)
+local_password_change: NTSTATUS (const char *, int, const char *, char **, char **)
+login_cache_delentry: bool (const struct samu *)
+login_cache_init: bool (void)
+login_cache_read: bool (struct samu *, struct login_cache *)
+login_cache_shutdown: bool (void)
+login_cache_write: bool (const struct samu *, const struct login_cache *)
+lookup_builtin_name: bool (const char *, uint32_t *)
+lookup_builtin_rid: bool (TALLOC_CTX *, uint32_t, const char **)
+lookup_global_sam_name: bool (const char *, int, uint32_t *, enum lsa_SidType *)
+lookup_name: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_name_smbconf: bool (TALLOC_CTX *, const char *, int, const char **, const char **, struct dom_sid *, enum lsa_SidType *)
+lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+lookup_sids: NTSTATUS (TALLOC_CTX *, int, const struct dom_sid **, int, struct lsa_dom_info **, struct lsa_name_info **)
+lookup_unix_group_name: bool (const char *, struct dom_sid *)
+lookup_unix_user_name: bool (const char *, struct dom_sid *)
+lookup_wellknown_name: bool (TALLOC_CTX *, const char *, struct dom_sid *, const char **)
+lookup_wellknown_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **)
+make_pdb_method: NTSTATUS (struct pdb_methods **)
+make_pdb_method_name: NTSTATUS (struct pdb_methods **, const char *)
+max_algorithmic_gid: gid_t (void)
+max_algorithmic_uid: uid_t (void)
+pdb_add_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_add_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_add_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_add_sam_account: NTSTATUS (struct samu *)
+pdb_build_fields_present: uint32_t (struct samu *)
+pdb_capabilities: uint32_t (void)
+pdb_copy_sam_account: bool (struct samu *, struct samu *)
+pdb_create_alias: NTSTATUS (const char *, uint32_t *)
+pdb_create_builtin: NTSTATUS (uint32_t)
+pdb_create_builtin_alias: NTSTATUS (uint32_t, gid_t)
+pdb_create_dom_group: NTSTATUS (TALLOC_CTX *, const char *, uint32_t *)
+pdb_create_user: NTSTATUS (TALLOC_CTX *, const char *, uint32_t, uint32_t *)
+pdb_decode_acct_ctrl: uint32_t (const char *)
+pdb_default_add_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_default_alias_memberships: NTSTATUS (struct pdb_methods *, TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_default_create_alias: NTSTATUS (struct pdb_methods *, const char *, uint32_t *)
+pdb_default_del_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, const struct dom_sid *)
+pdb_default_delete_alias: NTSTATUS (struct pdb_methods *, const struct dom_sid *)
+pdb_default_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_default_enum_aliasmem: NTSTATUS (struct pdb_methods *, const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_default_enum_group_mapping: NTSTATUS (struct pdb_methods *, const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_default_get_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_default_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_default_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_default_set_aliasinfo: NTSTATUS (struct pdb_methods *, const struct dom_sid *, struct acct_info *)
+pdb_default_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_del_aliasmem: NTSTATUS (const struct dom_sid *, const struct dom_sid *)
+pdb_del_groupmem: NTSTATUS (TALLOC_CTX *, uint32_t, uint32_t)
+pdb_del_trusted_domain: NTSTATUS (const char *)
+pdb_del_trusteddom_pw: bool (const char *)
+pdb_delete_alias: NTSTATUS (const struct dom_sid *)
+pdb_delete_dom_group: NTSTATUS (TALLOC_CTX *, uint32_t)
+pdb_delete_group_mapping_entry: NTSTATUS (struct dom_sid)
+pdb_delete_sam_account: NTSTATUS (struct samu *)
+pdb_delete_secret: NTSTATUS (const char *)
+pdb_delete_user: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_element_is_changed: bool (const struct samu *, enum pdb_elements)
+pdb_element_is_set_or_changed: bool (const struct samu *, enum pdb_elements)
+pdb_encode_acct_ctrl: char *(uint32_t, size_t)
+pdb_enum_alias_memberships: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+pdb_enum_aliasmem: NTSTATUS (const struct dom_sid *, TALLOC_CTX *, struct dom_sid **, size_t *)
+pdb_enum_group_mapping: bool (const struct dom_sid *, enum lsa_SidType, GROUP_MAP ***, size_t *, bool)
+pdb_enum_group_members: NTSTATUS (TALLOC_CTX *, const struct dom_sid *, uint32_t **, size_t *)
+pdb_enum_group_memberships: NTSTATUS (TALLOC_CTX *, struct samu *, struct dom_sid **, gid_t **, uint32_t *)
+pdb_enum_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct pdb_trusted_domain ***)
+pdb_enum_trusteddoms: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+pdb_enum_upn_suffixes: NTSTATUS (TALLOC_CTX *, uint32_t *, char ***)
+pdb_find_backend_entry: struct pdb_init_function_entry *(const char *)
+pdb_get_account_policy: bool (enum pdb_policy_type, uint32_t *)
+pdb_get_acct_ctrl: uint32_t (const struct samu *)
+pdb_get_acct_desc: const char *(const struct samu *)
+pdb_get_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_get_backend_private_data: void *(const struct samu *, const struct pdb_methods *)
+pdb_get_backends: const struct pdb_init_function_entry *(void)
+pdb_get_bad_password_count: uint16_t (const struct samu *)
+pdb_get_bad_password_time: time_t (const struct samu *)
+pdb_get_code_page: uint16_t (const struct samu *)
+pdb_get_comment: const char *(const struct samu *)
+pdb_get_country_code: uint16_t (const struct samu *)
+pdb_get_dir_drive: const char *(const struct samu *)
+pdb_get_domain: const char *(const struct samu *)
+pdb_get_domain_info: struct pdb_domain_info *(TALLOC_CTX *)
+pdb_get_fullname: const char *(const struct samu *)
+pdb_get_group_rid: uint32_t (struct samu *)
+pdb_get_group_sid: const struct dom_sid *(struct samu *)
+pdb_get_homedir: const char *(const struct samu *)
+pdb_get_hours: const uint8_t *(const struct samu *)
+pdb_get_hours_len: uint32_t (const struct samu *)
+pdb_get_init_flags: enum pdb_value_state (const struct samu *, enum pdb_elements)
+pdb_get_kickoff_time: time_t (const struct samu *)
+pdb_get_lanman_passwd: const uint8_t *(const struct samu *)
+pdb_get_logoff_time: time_t (const struct samu *)
+pdb_get_logon_count: uint16_t (const struct samu *)
+pdb_get_logon_divs: uint16_t (const struct samu *)
+pdb_get_logon_script: const char *(const struct samu *)
+pdb_get_logon_time: time_t (const struct samu *)
+pdb_get_munged_dial: const char *(const struct samu *)
+pdb_get_nt_passwd: const uint8_t *(const struct samu *)
+pdb_get_nt_username: const char *(const struct samu *)
+pdb_get_pass_can_change: bool (const struct samu *)
+pdb_get_pass_can_change_time: time_t (const struct samu *)
+pdb_get_pass_can_change_time_noncalc: time_t (const struct samu *)
+pdb_get_pass_last_set_time: time_t (const struct samu *)
+pdb_get_pass_must_change_time: time_t (const struct samu *)
+pdb_get_plaintext_passwd: const char *(const struct samu *)
+pdb_get_profile_path: const char *(const struct samu *)
+pdb_get_pw_history: const uint8_t *(const struct samu *, uint32_t *)
+pdb_get_secret: NTSTATUS (TALLOC_CTX *, const char *, DATA_BLOB *, NTTIME *, DATA_BLOB *, NTTIME *, struct security_descriptor **)
+pdb_get_seq_num: bool (time_t *)
+pdb_get_tevent_context: struct tevent_context *(void)
+pdb_get_trust_credentials: NTSTATUS (const char *, const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusted_domain: NTSTATUS (TALLOC_CTX *, const char *, struct pdb_trusted_domain **)
+pdb_get_trusted_domain_by_sid: NTSTATUS (TALLOC_CTX *, struct dom_sid *, struct pdb_trusted_domain **)
+pdb_get_trusteddom_creds: NTSTATUS (const char *, TALLOC_CTX *, struct cli_credentials **)
+pdb_get_trusteddom_pw: bool (const char *, char **, struct dom_sid *, time_t *)
+pdb_get_unknown_6: uint32_t (const struct samu *)
+pdb_get_user_rid: uint32_t (const struct samu *)
+pdb_get_user_sid: const struct dom_sid *(const struct samu *)
+pdb_get_username: const char *(const struct samu *)
+pdb_get_workstations: const char *(const struct samu *)
+pdb_getgrgid: bool (GROUP_MAP *, gid_t)
+pdb_getgrnam: bool (GROUP_MAP *, const char *)
+pdb_getgrsid: bool (GROUP_MAP *, struct dom_sid)
+pdb_gethexhours: bool (const char *, unsigned char *)
+pdb_gethexpwd: bool (const char *, unsigned char *)
+pdb_getsampwnam: bool (struct samu *, const char *)
+pdb_getsampwsid: bool (struct samu *, const struct dom_sid *)
+pdb_group_rid_to_gid: gid_t (uint32_t)
+pdb_id_to_sid: bool (struct unixid *, struct dom_sid *)
+pdb_increment_bad_password_count: bool (struct samu *)
+pdb_is_password_change_time_max: bool (time_t)
+pdb_is_responsible_for_builtin: bool (void)
+pdb_is_responsible_for_everything_else: bool (void)
+pdb_is_responsible_for_our_sam: bool (void)
+pdb_is_responsible_for_unix_groups: bool (void)
+pdb_is_responsible_for_unix_users: bool (void)
+pdb_is_responsible_for_wellknown: bool (void)
+pdb_lookup_rids: NTSTATUS (const struct dom_sid *, int, uint32_t *, const char **, enum lsa_SidType *)
+pdb_new_rid: bool (uint32_t *)
+pdb_nop_add_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_nop_delete_group_mapping_entry: NTSTATUS (struct pdb_methods *, struct dom_sid)
+pdb_nop_enum_group_mapping: NTSTATUS (struct pdb_methods *, enum lsa_SidType, GROUP_MAP **, size_t *, bool)
+pdb_nop_getgrgid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, gid_t)
+pdb_nop_getgrnam: NTSTATUS (struct pdb_methods *, GROUP_MAP *, const char *)
+pdb_nop_getgrsid: NTSTATUS (struct pdb_methods *, GROUP_MAP *, struct dom_sid)
+pdb_nop_update_group_mapping_entry: NTSTATUS (struct pdb_methods *, GROUP_MAP *)
+pdb_rename_sam_account: NTSTATUS (struct samu *, const char *)
+pdb_search_aliases: struct pdb_search *(TALLOC_CTX *, const struct dom_sid *)
+pdb_search_entries: uint32_t (struct pdb_search *, uint32_t, uint32_t, struct samr_displayentry **)
+pdb_search_groups: struct pdb_search *(TALLOC_CTX *)
+pdb_search_users: struct pdb_search *(TALLOC_CTX *, uint32_t)
+pdb_set_account_policy: bool (enum pdb_policy_type, uint32_t)
+pdb_set_acct_ctrl: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_acct_desc: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_aliasinfo: NTSTATUS (const struct dom_sid *, struct acct_info *)
+pdb_set_backend_private_data: bool (struct samu *, void *, void (*)(void **), const struct pdb_methods *, enum pdb_value_state)
+pdb_set_bad_password_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_bad_password_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_code_page: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_comment: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_country_code: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_dir_drive: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_domain: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_fullname: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_group_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_group_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_homedir: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_hours: bool (struct samu *, const uint8_t *, int, enum pdb_value_state)
+pdb_set_hours_len: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_init_flags: bool (struct samu *, enum pdb_elements, enum pdb_value_state)
+pdb_set_kickoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_lanman_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_logoff_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_logon_count: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_divs: bool (struct samu *, uint16_t, enum pdb_value_state)
+pdb_set_logon_script: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_logon_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_munged_dial: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_nt_passwd: bool (struct samu *, const uint8_t *, enum pdb_value_state)
+pdb_set_nt_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pass_can_change: bool (struct samu *, bool)
+pdb_set_pass_can_change_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_pass_last_set_time: bool (struct samu *, time_t, enum pdb_value_state)
+pdb_set_plaintext_passwd: bool (struct samu *, const char *)
+pdb_set_plaintext_pw_only: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_profile_path: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_pw_history: bool (struct samu *, const uint8_t *, uint32_t, enum pdb_value_state)
+pdb_set_secret: NTSTATUS (const char *, DATA_BLOB *, DATA_BLOB *, struct security_descriptor *)
+pdb_set_trusted_domain: NTSTATUS (const char *, const struct pdb_trusted_domain *)
+pdb_set_trusteddom_pw: bool (const char *, const char *, const struct dom_sid *)
+pdb_set_unix_primary_group: NTSTATUS (TALLOC_CTX *, struct samu *)
+pdb_set_unknown_6: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_upn_suffixes: NTSTATUS (uint32_t, const char **)
+pdb_set_user_sid: bool (struct samu *, const struct dom_sid *, enum pdb_value_state)
+pdb_set_user_sid_from_rid: bool (struct samu *, uint32_t, enum pdb_value_state)
+pdb_set_user_sid_from_string: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_username: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_set_workstations: bool (struct samu *, const char *, enum pdb_value_state)
+pdb_sethexhours: void (char *, const unsigned char *)
+pdb_sethexpwd: void (char *, const unsigned char *, uint32_t)
+pdb_sid_to_id: bool (const struct dom_sid *, struct unixid *)
+pdb_sid_to_id_unix_users_and_groups: bool (const struct dom_sid *, struct unixid *)
+pdb_update_autolock_flag: bool (struct samu *, bool *)
+pdb_update_bad_password_count: bool (struct samu *, bool *)
+pdb_update_group_mapping_entry: NTSTATUS (GROUP_MAP *)
+pdb_update_history: bool (struct samu *, const uint8_t *)
+pdb_update_login_attempts: NTSTATUS (struct samu *, bool)
+pdb_update_sam_account: NTSTATUS (struct samu *)
+privilege_create_account: NTSTATUS (const struct dom_sid *)
+privilege_delete_account: NTSTATUS (const struct dom_sid *)
+privilege_enum_sids: NTSTATUS (enum sec_privilege, TALLOC_CTX *, struct dom_sid **, int *)
+privilege_enumerate_accounts: NTSTATUS (struct dom_sid **, int *)
+revoke_all_privileges: bool (const struct dom_sid *)
+revoke_privilege_by_name: bool (const struct dom_sid *, const char *)
+revoke_privilege_set: bool (const struct dom_sid *, struct lsa_PrivilegeSet *)
+samu_alloc_rid_unix: NTSTATUS (struct pdb_methods *, struct samu *, const struct passwd *)
+samu_new: struct samu *(TALLOC_CTX *)
+samu_set_unix: NTSTATUS (struct samu *, const struct passwd *)
+secrets_trusted_domains: NTSTATUS (TALLOC_CTX *, uint32_t *, struct trustdom_info ***)
+sid_check_is_builtin: bool (const struct dom_sid *)
+sid_check_is_for_passdb: bool (const struct dom_sid *)
+sid_check_is_in_builtin: bool (const struct dom_sid *)
+sid_check_is_in_unix_groups: bool (const struct dom_sid *)
+sid_check_is_in_unix_users: bool (const struct dom_sid *)
+sid_check_is_in_wellknown_domain: bool (const struct dom_sid *)
+sid_check_is_unix_groups: bool (const struct dom_sid *)
+sid_check_is_unix_users: bool (const struct dom_sid *)
+sid_check_is_wellknown_builtin: bool (const struct dom_sid *)
+sid_check_is_wellknown_domain: bool (const struct dom_sid *, const char **)
+sid_check_object_is_for_passdb: bool (const struct dom_sid *)
+sid_to_gid: bool (const struct dom_sid *, gid_t *)
+sid_to_uid: bool (const struct dom_sid *, uid_t *)
+sids_to_unixids: bool (const struct dom_sid *, uint32_t, struct unixid *)
+smb_add_user_group: int (const char *, const char *)
+smb_create_group: int (const char *, gid_t *)
+smb_delete_group: int (const char *)
+smb_delete_user_group: int (const char *, const char *)
+smb_nscd_flush_group_cache: void (void)
+smb_nscd_flush_user_cache: void (void)
+smb_register_passdb: NTSTATUS (int, const char *, pdb_init_function)
+smb_set_primary_group: int (const char *, const char *)
+uid_to_sid: void (struct dom_sid *, uid_t)
+uid_to_unix_users_sid: void (uid_t, struct dom_sid *)
+unix_groups_domain_name: const char *(void)
+unix_users_domain_name: const char *(void)
+unixid_from_both: void (struct unixid *, uint32_t)
+unixid_from_gid: void (struct unixid *, uint32_t)
+unixid_from_uid: void (struct unixid *, uint32_t)
+wb_is_trusted_domain: wbcErr (const char *)
+winbind_allocate_gid: bool (gid_t *)
+winbind_allocate_uid: bool (uid_t *)
+winbind_get_groups: bool (TALLOC_CTX *, const char *, uint32_t *, gid_t **)
+winbind_get_sid_aliases: bool (TALLOC_CTX *, const struct dom_sid *, const struct dom_sid *, size_t, uint32_t **, size_t *)
+winbind_getpwnam: struct passwd *(const char *)
+winbind_getpwsid: struct passwd *(const struct dom_sid *)
+winbind_gid_to_sid: bool (struct dom_sid *, gid_t)
+winbind_lookup_name: bool (const char *, const char *, struct dom_sid *, enum lsa_SidType *)
+winbind_lookup_name_cache_only: bool (const char *, const char *, struct dom_sid *, enum lsa_SidType *, bool *)
+winbind_lookup_rids: bool (TALLOC_CTX *, const struct dom_sid *, int, uint32_t *, const char **, const char ***, enum lsa_SidType **)
+winbind_lookup_sid: bool (TALLOC_CTX *, const struct dom_sid *, const char **, const char **, enum lsa_SidType *)
+winbind_lookup_usersids: bool (TALLOC_CTX *, const struct dom_sid *, uint32_t *, struct dom_sid **)
+winbind_ping: bool (void)
+winbind_sid_to_gid: bool (gid_t *, const struct dom_sid *)
+winbind_sid_to_uid: bool (uid_t *, const struct dom_sid *)
+winbind_uid_to_sid: bool (struct dom_sid *, uid_t)
diff --git a/source3/wscript_build b/source3/wscript_build
index 1ad2fbe..fdbeeb0 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -134,7 +134,7 @@ bld.SAMBA3_LIBRARY('samba-passdb',
                    passdb/lookup_sid.h''',
                    abi_match=private_pdb_match,
                    abi_directory='passdb/ABI',
-                   vnum='0.25.0')
+                   vnum='0.25.1')
 
 bld.SAMBA3_SUBSYSTEM('pdb',
                    source='''passdb/pdb_get_set.c
-- 
2.9.3


From 71a6dd9309b9e0622a71458d86d8c7da98d3035e Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Mon, 28 Nov 2016 08:32:53 +0200
Subject: [PATCH 8/9] s3-passdb: implement LOOKUP_NAME_CACHE_ONLY flag in
 lookup_name()

Implement the LOOKUP_NAME_CACHE_ONLY flag by doing cached-based
lookup and falling back to regular lookup

Signed-off-by: Uri Simchoni <uri at samba.org>
---
 source3/passdb/lookup_sid.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c
index 110bdd3..75710de 100644
--- a/source3/passdb/lookup_sid.c
+++ b/source3/passdb/lookup_sid.c
@@ -50,12 +50,18 @@ bool lookup_name(TALLOC_CTX *mem_ctx,
 	struct dom_sid sid;
 	enum lsa_SidType type;
 	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+	bool prefer_cache = false;
 
 	if (tmp_ctx == NULL) {
 		DEBUG(0, ("talloc_new failed\n"));
 		return false;
 	}
 
+	if (flags & LOOKUP_NAME_CACHE_ONLY) {
+		prefer_cache = true;
+		flags &= ~LOOKUP_NAME_CACHE_ONLY;
+	}
+
 	p = strchr_m(full_name, '\\');
 
 	if (p != NULL) {
@@ -115,6 +121,23 @@ bool lookup_name(TALLOC_CTX *mem_ctx,
 	 * domain yet at this point yet. This comes later. */
 
 	if ((domain[0] != '\0') &&
+	    (flags & ~(LOOKUP_NAME_DOMAIN | LOOKUP_NAME_ISOLATED)) &&
+	    prefer_cache) {
+		bool wb_online = false;
+		if (winbind_lookup_name_cache_only(domain, name, &sid, &type,
+						   &wb_online)) {
+			goto ok;
+		}
+		/*
+		 * This could (?) legitimately fail even if someone is priming
+		 * the cache for us, if the lookup is not handled by winbind
+		 */
+		DBG_DEBUG("Cached lookup for [%s]\\[%s]] has failed"
+			  " (winbindd is %savailable\n",
+			  domain, name, wb_online ? "" : "un");
+	}
+
+	if ((domain[0] != '\0') &&
 	    (flags & ~(LOOKUP_NAME_DOMAIN|LOOKUP_NAME_ISOLATED)) &&
 	    (winbind_lookup_name(domain, name, &sid, &type))) {
 			goto ok;
-- 
2.9.3


From f129ce0a99cd55a13c951a143a1ac3fa0cc82fb3 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Mon, 28 Nov 2016 08:34:46 +0200
Subject: [PATCH 9/9] smbd: do cache-based share ACL lookups

Signed-off-by: Uri Simchoni <uri at samba.org>
---
 source3/smbd/share_access.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/source3/smbd/share_access.c b/source3/smbd/share_access.c
index 0664609..d59945c 100644
--- a/source3/smbd/share_access.c
+++ b/source3/smbd/share_access.c
@@ -77,6 +77,7 @@ static bool token_contains_name(TALLOC_CTX *mem_ctx,
 	const char *prefix;
 	struct dom_sid sid;
 	enum lsa_SidType type;
+	int flags = LOOKUP_NAME_ALL;
 
 	if (username != NULL) {
 		name = talloc_sub_basic(mem_ctx, username, domain, name);
@@ -96,9 +97,13 @@ static bool token_contains_name(TALLOC_CTX *mem_ctx,
 		return nt_token_check_sid( &sid, token );
 	}
 
+	if (lp_cached_share_acls()) {
+		flags |= LOOKUP_NAME_CACHE_ONLY;
+	}
+
 	if (!smbconf_is_group_name(&name, &prefix)) {
-		if (!lookup_name_smbconf(mem_ctx, name, LOOKUP_NAME_ALL,
-				 NULL, NULL, &sid, &type)) {
+		if (!lookup_name_smbconf(mem_ctx, name, flags, NULL, NULL, &sid,
+					 &type)) {
 			DEBUG(5, ("lookup_name %s failed\n", name));
 			return False;
 		}
@@ -110,11 +115,12 @@ static bool token_contains_name(TALLOC_CTX *mem_ctx,
 		return nt_token_check_sid(&sid, token);
 	}
 
+	flags |= LOOKUP_NAME_GROUP;
+
 	for (/* initialized above */ ; *prefix != '\0'; prefix++) {
 		if (*prefix == '+') {
-			if (!lookup_name_smbconf(mem_ctx, name,
-					 LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
-					 NULL, NULL, &sid, &type)) {
+			if (!lookup_name_smbconf(mem_ctx, name, flags, NULL,
+						 NULL, &sid, &type)) {
 				DEBUG(5, ("lookup_name %s failed\n", name));
 				return False;
 			}
-- 
2.9.3



More information about the samba-technical mailing list