summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
Diffstat (limited to 'source3')
-rw-r--r--source3/smbd/uid.c206
1 files changed, 205 insertions, 1 deletions
diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c
index e2cc26e0ae..e7c00ba456 100644
--- a/source3/smbd/uid.c
+++ b/source3/smbd/uid.c
@@ -532,6 +532,183 @@ BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE
}
/*****************************************************************
+ Id mapping cache. This is to avoid Winbind mappings already
+ seen by smbd to be queried too frequently, keeping winbindd
+ busy, and blocking smbd while winbindd is busy with other
+ stuff. Written by Michael Steffens <michael.steffens@hp.com>,
+ modified to use linked lists by jra.
+*****************************************************************/
+
+#define MAX_UID_SID_CACHE_SIZE 100
+#define TURNOVER_UID_SID_CACHE_SIZE 10
+#define MAX_GID_SID_CACHE_SIZE 100
+#define TURNOVER_GID_SID_CACHE_SIZE 10
+
+static size_t n_uid_sid_cache = 0;
+static size_t n_gid_sid_cache = 0;
+
+static struct uid_sid_cache {
+ struct uid_sid_cache *next, *prev;
+ uid_t uid;
+ DOM_SID sid;
+} *uid_sid_cache_head;
+
+static struct gid_sid_cache {
+ struct gid_sid_cache *next, *prev;
+ gid_t gid;
+ DOM_SID sid;
+} *gid_sid_cache_head;
+
+/*****************************************************************
+ Find a SID given a uid.
+*****************************************************************/
+
+static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
+{
+ struct uid_sid_cache *pc;
+
+ for (pc = uid_sid_cache_head; pc; pc = pc->next) {
+ if (pc->uid == uid) {
+ fstring sid;
+ *psid = pc->sid;
+ DEBUG(3,("fetch sid from uid cache %u -> %s\n",
+ (unsigned int)uid, sid_to_string(sid, psid)));
+ DLIST_PROMOTE(uid_sid_cache_head, pc);
+ return True;
+ }
+ }
+ return False;
+}
+
+/*****************************************************************
+ Find a uid given a SID.
+*****************************************************************/
+
+static BOOL fetch_uid_from_cache(uid_t *puid, const DOM_SID *psid)
+{
+ struct uid_sid_cache *pc;
+
+ for (pc = uid_sid_cache_head; pc; pc = pc->next) {
+ if (sid_compare(&pc->sid, psid) == 0) {
+ fstring sid;
+ *puid = pc->uid;
+ DEBUG(3,("fetch uid from cache %u -> %s\n",
+ (unsigned int)*puid, sid_to_string(sid, psid)));
+ DLIST_PROMOTE(uid_sid_cache_head, pc);
+ return True;
+ }
+ }
+ return False;
+}
+
+/*****************************************************************
+ Store uid to SID mapping in cache.
+*****************************************************************/
+
+static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
+{
+ struct uid_sid_cache *pc;
+
+ if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
+ /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
+ struct uid_sid_cache *pc_next;
+ size_t i;
+
+ for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
+ ;
+ for(; pc; pc = pc_next) {
+ pc_next = pc->next;
+ DLIST_REMOVE(uid_sid_cache_head,pc);
+ SAFE_FREE(pc);
+ n_uid_sid_cache--;
+ }
+ }
+
+ pc = (struct uid_sid_cache *)malloc(sizeof(struct uid_sid_cache));
+ if (!pc)
+ return;
+ pc->uid = uid;
+ sid_copy(&pc->sid, psid);
+ DLIST_ADD(uid_sid_cache_head, pc);
+ n_uid_sid_cache++;
+}
+
+/*****************************************************************
+ Find a SID given a gid.
+*****************************************************************/
+
+static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
+{
+ struct gid_sid_cache *pc;
+
+ for (pc = gid_sid_cache_head; pc; pc = pc->next) {
+ if (pc->gid == gid) {
+ fstring sid;
+ *psid = pc->sid;
+ DEBUG(3,("fetch sid from gid cache %u -> %s\n",
+ (unsigned int)gid, sid_to_string(sid, psid)));
+ DLIST_PROMOTE(gid_sid_cache_head, pc);
+ return True;
+ }
+ }
+ return False;
+}
+
+/*****************************************************************
+ Find a gid given a SID.
+*****************************************************************/
+
+static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
+{
+ struct gid_sid_cache *pc;
+
+ for (pc = gid_sid_cache_head; pc; pc = pc->next) {
+ if (sid_compare(&pc->sid, psid) == 0) {
+ fstring sid;
+ *pgid = pc->gid;
+ DEBUG(3,("fetch uid from cache %u -> %s\n",
+ (unsigned int)*pgid, sid_to_string(sid, psid)));
+ DLIST_PROMOTE(gid_sid_cache_head, pc);
+ return True;
+ }
+ }
+ return False;
+}
+
+/*****************************************************************
+ Store gid to SID mapping in cache.
+*****************************************************************/
+
+static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
+{
+ struct gid_sid_cache *pc;
+
+ if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
+ /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
+ struct gid_sid_cache *pc_next;
+ size_t i;
+
+ for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
+ ;
+ for(; pc; pc = pc_next) {
+ pc_next = pc->next;
+ DLIST_REMOVE(gid_sid_cache_head,pc);
+ SAFE_FREE(pc);
+ n_gid_sid_cache--;
+ }
+ }
+
+ pc = (struct gid_sid_cache *)malloc(sizeof(struct gid_sid_cache));
+ if (!pc)
+ return;
+ pc->gid = gid;
+ sid_copy(&pc->sid, psid);
+ DLIST_ADD(gid_sid_cache_head, pc);
+ n_gid_sid_cache++;
+}
+
+
+/*****************************************************************
*THE CANONICAL* convert uid_t to SID function.
Tries winbind first - then uses local lookup.
Returns SID pointer.
@@ -542,12 +719,17 @@ DOM_SID *uid_to_sid(DOM_SID *psid, uid_t uid)
uid_t low, high;
fstring sid;
+ if (fetch_sid_from_uid_cache(psid, uid))
+ return psid;
+
if (lp_winbind_uid(&low, &high) && uid >= low && uid <= high) {
if (winbind_uid_to_sid(psid, uid)) {
DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
(unsigned int)uid, sid_to_string(sid, psid)));
+ if (psid)
+ store_uid_sid_cache(psid, uid);
return psid;
}
}
@@ -558,6 +740,8 @@ DOM_SID *uid_to_sid(DOM_SID *psid, uid_t uid)
unbecome_root();
DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
+ if (psid)
+ store_uid_sid_cache(psid, uid);
return psid;
}
@@ -573,20 +757,26 @@ DOM_SID *gid_to_sid(DOM_SID *psid, gid_t gid)
gid_t low, high;
fstring sid;
+ if (fetch_sid_from_gid_cache(psid, gid))
+ return psid;
+
if (lp_winbind_gid(&low, &high) && gid >= low && gid <= high) {
if (winbind_gid_to_sid(psid, gid)) {
DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
(unsigned int)gid, sid_to_string(sid, psid)));
+ if (psid)
+ store_gid_sid_cache(psid, gid);
return psid;
}
}
/* Make sure we report failure, (when psid == NULL) */
psid = local_gid_to_sid(psid, gid);
-
DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
+ if (psid)
+ store_gid_sid_cache(psid, gid);
return psid;
}
@@ -602,12 +792,17 @@ BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid, enum SID_NAME_USE *sidtype)
{
fstring sid_str;
+ if (fetch_uid_from_cache(puid, psid))
+ return True;
+
/* if we know its local then don't try winbindd */
if (sid_compare_domain(get_global_sam_sid(), psid) == 0) {
BOOL result;
become_root();
result = local_sid_to_uid(puid, psid, sidtype);
unbecome_root();
+ if (result)
+ store_uid_sid_cache(psid, *puid);
return result;
}
@@ -657,6 +852,8 @@ BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid, enum SID_NAME_USE *sidtype)
become_root();
result = local_sid_to_uid(puid, psid, sidtype);
unbecome_root();
+ if (result)
+ store_uid_sid_cache(psid, *puid);
return result;
}
@@ -664,6 +861,7 @@ BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid, enum SID_NAME_USE *sidtype)
sid_to_string(sid_str, psid),
(unsigned int)*puid ));
+ store_uid_sid_cache(psid, *puid);
return True;
}
@@ -681,6 +879,9 @@ BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid, enum SID_NAME_USE *sidtype)
*sidtype = SID_NAME_UNKNOWN;
+ if (fetch_gid_from_cache(pgid, psid))
+ return True;
+
/*
* First we must look up the name and decide if this is a group sid.
*/
@@ -691,6 +892,8 @@ BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid, enum SID_NAME_USE *sidtype)
become_root();
result = local_sid_to_gid(pgid, psid, sidtype);
unbecome_root();
+ if (result)
+ store_gid_sid_cache(psid, *pgid);
return result;
}
@@ -729,6 +932,7 @@ BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid, enum SID_NAME_USE *sidtype)
sid_to_string(sid_str, psid),
(unsigned int)*pgid ));
+ store_gid_sid_cache(psid, *pgid);
return True;
}