summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
Diffstat (limited to 'source3')
-rw-r--r--source3/winbindd/idmap_cache.c80
-rw-r--r--source3/winbindd/winbindd.h2
-rw-r--r--source3/winbindd/winbindd_sid.c97
3 files changed, 160 insertions, 19 deletions
diff --git a/source3/winbindd/idmap_cache.c b/source3/winbindd/idmap_cache.c
index f7e1d4e6d1..027ce3b619 100644
--- a/source3/winbindd/idmap_cache.c
+++ b/source3/winbindd/idmap_cache.c
@@ -521,3 +521,83 @@ done:
return ret;
}
+bool idmap_cache_find_sid2uid(const struct dom_sid *sid, uid_t *puid,
+ bool *expired)
+{
+ fstring sidstr;
+ char *key;
+ char *value;
+ char *endptr;
+ time_t timeout;
+ uid_t uid;
+ bool ret;
+
+ key = talloc_asprintf(talloc_tos(), "IDMAP/SID2UID/%s",
+ sid_to_fstring(sidstr, sid));
+ if (key == NULL) {
+ return false;
+ }
+ ret = gencache_get(key, &value, &timeout);
+ TALLOC_FREE(key);
+ if (!ret) {
+ return false;
+ }
+ uid = strtol(value, &endptr, 10);
+ ret = (*endptr == '\0');
+ SAFE_FREE(value);
+ if (ret) {
+ *puid = uid;
+ *expired = (timeout <= time(NULL));
+ }
+ return ret;
+}
+
+bool idmap_cache_find_uid2sid(uid_t uid, struct dom_sid *sid, bool *expired)
+{
+ char *key;
+ char *value;
+ time_t timeout;
+ bool ret;
+
+ key = talloc_asprintf(talloc_tos(), "IDMAP/UID2SID/%d", (int)uid);
+ if (key == NULL) {
+ return false;
+ }
+ ret = gencache_get(key, &value, &timeout);
+ TALLOC_FREE(key);
+ if (!ret) {
+ return false;
+ }
+ ZERO_STRUCTP(sid);
+ ret = string_to_sid(sid, value);
+ SAFE_FREE(value);
+ if (ret) {
+ *expired = (timeout <= time(NULL));
+ }
+ return ret;
+}
+
+void idmap_cache_set_sid2uid(const struct dom_sid *sid, uid_t uid)
+{
+ time_t now = time(NULL);
+ time_t timeout;
+ fstring sidstr, key, value;
+
+ if (!is_null_sid(sid)) {
+ fstr_sprintf(key, "IDMAP/SID2UID/%s",
+ sid_to_fstring(sidstr, sid));
+ fstr_sprintf(value, "%d", (int)uid);
+ timeout = (uid == -1)
+ ? lp_idmap_negative_cache_time()
+ : lp_idmap_cache_time();
+ gencache_set(key, value, now + timeout);
+ }
+ if (uid != -1) {
+ fstr_sprintf(key, "IDMAP/UID2SID/%d", (int)uid);
+ sid_to_fstring(value, sid);
+ timeout = is_null_sid(sid)
+ ? lp_idmap_negative_cache_time()
+ : lp_idmap_cache_time();
+ gencache_set(key, value, now + timeout);
+ }
+}
diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h
index b2fe8b67e7..f6f269ee6d 100644
--- a/source3/winbindd/winbindd.h
+++ b/source3/winbindd/winbindd.h
@@ -379,4 +379,6 @@ enum ent_type {
#define IS_DOMAIN_OFFLINE(x) ( lp_winbind_offline_logon() && \
( get_global_winbindd_state_offline() \
|| !(x)->online ) )
+#define IS_DOMAIN_ONLINE(x) (!IS_DOMAIN_OFFLINE(x))
+
#endif /* _WINBINDD_H */
diff --git a/source3/winbindd/winbindd_sid.c b/source3/winbindd/winbindd_sid.c
index 0e8e6ca00b..ce34dadf4c 100644
--- a/source3/winbindd/winbindd_sid.c
+++ b/source3/winbindd/winbindd_sid.c
@@ -159,14 +159,19 @@ static void sid2uid_recv(void *private_data, bool success, uid_t uid)
{
struct winbindd_cli_state *state =
talloc_get_type_abort(private_data, struct winbindd_cli_state);
+ struct dom_sid sid;
+
+ string_to_sid(&sid, state->request.data.sid);
if (!success) {
DEBUG(5, ("Could not convert sid %s\n",
state->request.data.sid));
+ idmap_cache_set_sid2uid(&sid, -1);
request_error(state);
return;
}
+ idmap_cache_set_sid2uid(&sid, uid);
state->response.data.uid = uid;
request_ok(state);
}
@@ -180,34 +185,40 @@ static void sid2uid_lookupsid_recv( void *private_data, bool success,
talloc_get_type_abort(private_data, struct winbindd_cli_state);
DOM_SID sid;
+ if (!string_to_sid(&sid, state->request.data.sid)) {
+ DEBUG(1, ("sid2uid_lookupsid_recv: Could not get convert sid "
+ "%s from string\n", state->request.data.sid));
+ request_error(state);
+ return;
+ }
+
if (!success) {
DEBUG(5, ("sid2uid_lookupsid_recv Could not convert get sid type for %s\n",
state->request.data.sid));
- request_error(state);
- return;
+ goto fail;
}
if ( (type!=SID_NAME_USER) && (type!=SID_NAME_COMPUTER) ) {
DEBUG(5,("sid2uid_lookupsid_recv: Sid %s is not a user or a computer.\n",
state->request.data.sid));
- request_error(state);
- return;
+ goto fail;
}
- if (!string_to_sid(&sid, state->request.data.sid)) {
- DEBUG(1, ("sid2uid_lookupsid_recv: Could not get convert sid %s from string\n",
- state->request.data.sid));
- request_error(state);
- return;
- }
-
/* always use the async interface (may block) */
winbindd_sid2uid_async(state->mem_ctx, &sid, sid2uid_recv, state);
+ return;
+
+ fail:
+ idmap_cache_set_sid2uid(&sid, -1);
+ request_error(state);
+ return;
}
void winbindd_sid_to_uid(struct winbindd_cli_state *state)
{
DOM_SID sid;
+ uid_t uid;
+ bool expired;
/* Ensure null termination */
state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
@@ -222,10 +233,29 @@ void winbindd_sid_to_uid(struct winbindd_cli_state *state)
return;
}
+ if (idmap_cache_find_sid2uid(&sid, &uid, &expired)) {
+ DEBUG(10, ("idmap_cache_find_sid2uid found %d%s\n",
+ (int)uid, expired ? " (expired)": ""));
+ if (expired && IS_DOMAIN_ONLINE(find_our_domain())) {
+ DEBUG(10, ("revalidating expired entry\n"));
+ goto backend;
+ }
+ if (uid == -1) {
+ DEBUG(10, ("Returning negative cache entry\n"));
+ request_error(state);
+ return;
+ }
+ DEBUG(10, ("Returning positive cache entry\n"));
+ state->response.data.uid = uid;
+ request_ok(state);
+ return;
+ }
+
/* Validate the SID as a user. Hopefully this will hit cache.
Needed to prevent DoS by exhausting the uid allocation
range from random SIDs. */
+ backend:
winbindd_lookupsid_async( state->mem_ctx, &sid, sid2uid_lookupsid_recv, state );
}
@@ -411,30 +441,59 @@ void winbindd_set_hwm(struct winbindd_cli_state *state)
/* Convert a uid to a sid */
-static void uid2sid_recv(void *private_data, bool success, const char *sid)
+static void uid2sid_recv(void *private_data, bool success, const char *sidstr)
{
struct winbindd_cli_state *state =
(struct winbindd_cli_state *)private_data;
+ struct dom_sid sid;
- if (success) {
- DEBUG(10,("uid2sid: uid %lu has sid %s\n",
- (unsigned long)(state->request.data.uid), sid));
- fstrcpy(state->response.data.sid.sid, sid);
- state->response.data.sid.type = SID_NAME_USER;
- request_ok(state);
+ if (!success || !string_to_sid(&sid, sidstr)) {
+ ZERO_STRUCT(sid);
+ idmap_cache_set_sid2uid(&sid, state->request.data.uid);
+ request_error(state);
return;
}
- request_error(state);
+ DEBUG(10,("uid2sid: uid %lu has sid %s\n",
+ (unsigned long)(state->request.data.uid), sidstr));
+
+ idmap_cache_set_sid2uid(&sid, state->request.data.uid);
+ fstrcpy(state->response.data.sid.sid, sidstr);
+ state->response.data.sid.type = SID_NAME_USER;
+ request_ok(state);
return;
}
void winbindd_uid_to_sid(struct winbindd_cli_state *state)
{
+ struct dom_sid sid;
+ bool expired;
+
DEBUG(3, ("[%5lu]: uid to sid %lu\n", (unsigned long)state->pid,
(unsigned long)state->request.data.uid));
+ if (idmap_cache_find_uid2sid(state->request.data.uid, &sid,
+ &expired)) {
+ DEBUG(10, ("idmap_cache_find_uid2sid found %d%s\n",
+ (int)state->request.data.uid,
+ expired ? " (expired)": ""));
+ if (expired && IS_DOMAIN_ONLINE(find_our_domain())) {
+ DEBUG(10, ("revalidating expired entry\n"));
+ goto backend;
+ }
+ if (is_null_sid(&sid)) {
+ DEBUG(10, ("Returning negative cache entry\n"));
+ request_error(state);
+ return;
+ }
+ DEBUG(10, ("Returning positive cache entry\n"));
+ sid_to_fstring(state->response.data.sid.sid, &sid);
+ request_ok(state);
+ return;
+ }
+
/* always go via the async interface (may block) */
+ backend:
winbindd_uid2sid_async(state->mem_ctx, state->request.data.uid, uid2sid_recv, state);
}