Fix immediate bug where the idmap can't tell the difference between an entry
[ira/wip.git] / source3 / nsswitch / winbindd_idmap.c
index 6361cbc70a71c7ce0f38076c9be15b6233d4b415..3b23089200fd9a33824b00366e7126518ebd970e 100644 (file)
@@ -1,20 +1,19 @@
 /* 
    Unix SMB/CIFS implementation.
-
-   Winbind daemon - user related function
-
+   Winbind ID Mapping
    Copyright (C) Tim Potter 2000
-   
+   Copyright (C) Anthony Liguori <aliguor@us.ibm.com>  2003
+
    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 2 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, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 #include "winbindd.h"
 
-/* High water mark keys */
-
-#define HWM_GROUP  "GROUP HWM"
-#define HWM_USER   "USER HWM"
-
-/* idmap version determines auto-conversion */
-#define IDMAP_VERSION 2
-
-/* Globals */
+static struct {
+  const char *name;
+  /* Function to create a member of the idmap_methods list */
+  BOOL (*reg_meth)(struct winbindd_idmap_methods **methods);
+  struct winbindd_idmap_methods *methods;
+} builtin_winbindd_idmap_functions[] = {
+  { "tdb", winbind_idmap_reg_tdb, NULL },
+  { NULL, NULL, NULL }
+};
 
-static TDB_CONTEXT *idmap_tdb;
+/* singleton pattern: uberlazy evaluation */
+static struct winbindd_idmap_methods *impl;
 
-/* Allocate either a user or group id from the pool */
-
-static BOOL allocate_id(uid_t *id, BOOL isgroup)
+static struct winbindd_idmap_methods *get_impl(const char *name)
 {
-    int hwm;
-
-    /* Get current high water mark */
-
-    if ((hwm = tdb_fetch_int(idmap_tdb, 
-                             isgroup ? HWM_GROUP : HWM_USER)) == -1) {
-        return False;
-    }
+  int i = 0;
+  struct winbindd_idmap_methods *ret = NULL;
 
-    /* Return next available uid in list */
+  while (builtin_winbindd_idmap_functions[i].name && 
+         strcmp(builtin_winbindd_idmap_functions[i].name, name)) {
+    i++;
+  }
 
-    if ((isgroup && (hwm > server_state.gid_high)) ||
-        (!isgroup && (hwm > server_state.uid_high))) {
-        DEBUG(0, ("winbind %sid range full!\n", isgroup ? "g" : "u"));
-        return False;
+  if (builtin_winbindd_idmap_functions[i].name) {
+    if (!builtin_winbindd_idmap_functions[i].methods) {
+      builtin_winbindd_idmap_functions[i].reg_meth(&builtin_winbindd_idmap_functions[i].methods);
     }
 
-    if (id) {
-        *id = hwm;
-    }
-
-    hwm++;
-
-    /* Store new high water mark */
+    ret = builtin_winbindd_idmap_functions[i].methods;
+  }
 
-    tdb_store_int(idmap_tdb, isgroup ? HWM_GROUP : HWM_USER, hwm);
-
-    return True;
+  return ret;
 }
 
-/* Get an id from a rid */
-static BOOL get_id_from_sid(DOM_SID *sid, uid_t *id, BOOL isgroup)
+/* Initialize backend */
+BOOL winbindd_idmap_init(void)
 {
-    TDB_DATA data, key;
-    fstring keystr;
-    BOOL result = False;
-
-    /* Check if sid is present in database */
-    sid_to_string(keystr, sid);
-    
-    key.dptr = keystr;
-    key.dsize = strlen(keystr) + 1;
-
-    data = tdb_fetch(idmap_tdb, key);
-
-    if (data.dptr) {
-        fstring scanstr;
-        int the_id;
-
-        /* Parse and return existing uid */
-        fstrcpy(scanstr, isgroup ? "GID" : "UID");
-        fstrcat(scanstr, " %d");
-
-        if (sscanf(data.dptr, scanstr, &the_id) == 1) {
-            /* Store uid */
-            if (id) {
-                   *id = the_id;
-            }
+  BOOL ret = False;
 
-            result = True;
-        }
+  DEBUG(3, ("winbindd_idmap_init: using '%s' as backend\n", 
+            lp_winbind_backend()));
 
-        SAFE_FREE(data.dptr);
-    } else {
-
-        /* Allocate a new id for this sid */
-
-        if (id && allocate_id(id, isgroup)) {
-            fstring keystr2;
-
-            /* Store new id */
-            
-            slprintf(keystr2, sizeof(keystr2), "%s %d", isgroup ? "GID" : "UID", *id);
-
-            data.dptr = keystr2;
-            data.dsize = strlen(keystr2) + 1;
-
-            tdb_store(idmap_tdb, key, data, TDB_REPLACE);
-            tdb_store(idmap_tdb, data, key, TDB_REPLACE);
-
-            result = True;
-        }
+  if (!impl) {
+    impl = get_impl(lp_winbind_backend());
+    if (!impl) {
+      DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n",
+                lp_winbind_backend()));
     }
+  }
 
-    return result;
-}
+  if (impl) {
+    ret = impl->init();
+  }
 
-/* Get a uid from a user sid */
-BOOL winbindd_idmap_get_uid_from_sid(DOM_SID *sid, uid_t *uid)
-{
-    return get_id_from_sid(sid, uid, False);
-}
+  DEBUG(3, ("winbind_idmap_init: returning %s\n", ret ? "true" : "false"));
 
-/* Get a gid from a group sid */
-BOOL winbindd_idmap_get_gid_from_sid(DOM_SID *sid, gid_t *gid)
-{
-    return get_id_from_sid(sid, gid, True);
+  return ret;
 }
 
-/* Get a uid from a user rid */
-BOOL winbindd_idmap_get_uid_from_rid(const char *dom_name, uint32 rid, uid_t *uid)
+/* Get UID from SID */
+BOOL winbindd_idmap_get_uid_from_sid(DOM_SID *sid, uid_t *uid)
 {
-       struct winbindd_domain *domain;
-       DOM_SID sid;
+  BOOL ret = False;
 
-       if (!(domain = find_domain_from_name(dom_name))) {
-               return False;
-       }
+  if (!impl) {
+    impl = get_impl(lp_winbind_backend());
+    if (!impl) {
+      DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n",
+                lp_winbind_backend()));
+    }
+  }
 
-       sid_copy(&sid, &domain->sid);
-       sid_append_rid(&sid, rid);
+  if (impl) {
+    ret = impl->get_uid_from_sid(sid, uid);
+  }
 
-       return get_id_from_sid(&sid, uid, False);
+  return ret;
 }
 
-/* Get a gid from a group rid */
-BOOL winbindd_idmap_get_gid_from_rid(const char *dom_name, uint32 rid, gid_t *gid)
+/* Get GID from SID */
+BOOL winbindd_idmap_get_gid_from_sid(DOM_SID *sid, gid_t *gid)
 {
-       struct winbindd_domain *domain;
-       DOM_SID sid;
+  BOOL ret = False;
 
-       if (!(domain = find_domain_from_name(dom_name))) {
-               return False;
-       }
+  if (!impl) {
+    impl = get_impl(lp_winbind_backend());
+    if (!impl) {
+      DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n",
+                lp_winbind_backend()));
+    }
+  }
 
-       sid_copy(&sid, &domain->sid);
-       sid_append_rid(&sid, rid);
+  if (impl) {
+    ret = impl->get_gid_from_sid(sid, gid);
+  }
 
-       return get_id_from_sid(&sid, gid, True);
+  return ret;
 }
 
-
-BOOL get_sid_from_id(int id, DOM_SID *sid, BOOL isgroup)
+/* Get SID from UID */
+BOOL winbindd_idmap_get_sid_from_uid(uid_t uid, DOM_SID *sid)
 {
-    TDB_DATA key, data;
-    fstring keystr;
-    BOOL result = False;
-
-    slprintf(keystr, sizeof(keystr), "%s %d", isgroup ? "GID" : "UID", id);
-
-    key.dptr = keystr;
-    key.dsize = strlen(keystr) + 1;
-
-    data = tdb_fetch(idmap_tdb, key);
+  BOOL ret = False;
 
-    if (data.dptr) {
-           result = string_to_sid(sid, data.dptr);
-           SAFE_FREE(data.dptr);
+  if (!impl) {
+    impl = get_impl(lp_winbind_backend());
+    if (!impl) {
+      DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n",
+                lp_winbind_backend()));
     }
+  }
 
-    return result;
-}
+  if (impl) {
+    ret = impl->get_sid_from_uid(uid, sid);
+  }
 
-/* Get a sid from a uid */
-BOOL winbindd_idmap_get_sid_from_uid(uid_t uid, DOM_SID *sid)
-{
-       return get_sid_from_id((int)uid, sid, False);
+  return ret;
 }
 
-/* Get a sid from a gid */
+/* Get SID from GID */
 BOOL winbindd_idmap_get_sid_from_gid(gid_t gid, DOM_SID *sid)
 {
-       return get_sid_from_id((int)gid, sid, True);
-}
-
-/* Get a user rid from a uid */
-BOOL winbindd_idmap_get_rid_from_uid(uid_t uid, uint32 *user_rid,
-                                     struct winbindd_domain **domain)
-{
-       DOM_SID sid;
-
-       if (!get_sid_from_id((int)uid, &sid, False)) {
-               return False;
-       }
-
-       *domain = find_domain_from_sid(&sid);
-       if (! *domain) return False;
-
-       sid_split_rid(&sid, user_rid);
-
-       return True;
-}
-
-/* Get a group rid from a gid */
-
-BOOL winbindd_idmap_get_rid_from_gid(gid_t gid, uint32 *group_rid, 
-                                     struct winbindd_domain **domain)
-{
-       DOM_SID sid;
+  BOOL ret = False;
 
-       if (!get_sid_from_id((int)gid, &sid, True)) {
-               return False;
-       }
+  if (!impl) {
+    impl = get_impl(lp_winbind_backend());
+  }
 
-       *domain = find_domain_from_sid(&sid);
-       if (! *domain) return False;
+  if (impl) {
+    ret = impl->get_sid_from_gid(gid, sid);
+  } else {
+    DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n",
+              lp_winbind_backend()));
+  }
 
-       sid_split_rid(&sid, group_rid);
-
-       return True;
-}
-
-/* convert one record to the new format */
-static int convert_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA data, void *ignored)
-{
-       struct winbindd_domain *domain;
-       char *p, *dom_name;
-       DOM_SID sid;
-       uint32 rid;
-       fstring keystr;
-       TDB_DATA key2;
-
-       p = strchr(key.dptr, '/');
-       if (!p) return 0;
-
-       *p++ = 0;
-       dom_name = key.dptr;
-
-       domain = find_domain_from_name(dom_name);
-       if (!domain) {
-               /* what do we do about this?? */
-               return 0;
-       }
-
-       rid = atoi(p);
-
-       sid_copy(&sid, &domain->sid);
-       sid_append_rid(&sid, rid);
-
-       sid_to_string(keystr, &sid);
-       key2.dptr = keystr;
-       key2.dsize = strlen(keystr) + 1;
-
-       if (tdb_store(idmap_tdb, key2, data, TDB_INSERT) != 0) {
-               /* not good! */
-               return 0;
-       }
-
-       if (tdb_store(idmap_tdb, data, key2, TDB_REPLACE) != 0) {
-               /* not good! */
-               return 0;
-       }
-
-       tdb_delete(idmap_tdb, key);
-
-       return 0;
-}
-
-/* convert the idmap database from an older version */
-static BOOL idmap_convert(void)
-{
-       if (tdb_fetch_int(idmap_tdb, "IDMAP_VERSION") == IDMAP_VERSION) {
-               return True;
-       }
-
-       /* the old format stored as DOMAIN/rid - now we store the SID direct */
-       tdb_traverse(idmap_tdb, convert_fn, NULL);
-
-        if (tdb_store_int(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION) == -1) {
-               return False;
-       }
-
-       return True;
-}
-
-
-/* Initialise idmap database */
-
-BOOL winbindd_idmap_init(void)
-{
-    /* Open tdb cache */
-
-    if (!(idmap_tdb = tdb_open_log(lock_path("winbindd_idmap.tdb"), 0,
-                                  TDB_DEFAULT, O_RDWR | O_CREAT, 0600))) {
-        DEBUG(0, ("Unable to open idmap database\n"));
-        return False;
-    }
-
-    /* possibly convert from an earlier version */
-    if (!idmap_convert()) {
-           return False;
-    }
-
-     /* Create high water marks for group and user id */
-
-    if (tdb_fetch_int(idmap_tdb, HWM_USER) == -1) {
-        if (tdb_store_int(idmap_tdb, HWM_USER, server_state.uid_low) == -1) {
-            DEBUG(0, ("Unable to initialise user hwm in idmap database\n"));
-            return False;
-        }
-    }
-
-    if (tdb_fetch_int(idmap_tdb, HWM_GROUP) == -1) {
-        if (tdb_store_int(idmap_tdb, HWM_GROUP, server_state.gid_low) == -1) {
-            DEBUG(0, ("Unable to initialise group hwm in idmap database\n"));
-            return False;
-        }
-    }
-
-    return True;   
+  return ret;
 }
 
+/* Close backend */
 BOOL winbindd_idmap_close(void)
 {
-       if (idmap_tdb)
-               return (tdb_close(idmap_tdb) == 0);
-       return True;
-}
+  BOOL ret = False;
 
-/* Dump status information to log file.  Display different stuff based on
-   the debug level:
+  if (!impl) {
+    impl = get_impl(lp_winbind_backend());
+  }
 
-   Debug Level        Information Displayed
-   =================================================================
-   0                  Percentage of [ug]id range allocated
-   0                  High water marks (next allocated ids)
-*/
+  if (impl) {
+    ret = impl->close();
+  } else {
+    DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n",
+              lp_winbind_backend()));
+  }
 
-#define DUMP_INFO 0
+  return ret;
+}
 
+/* Dump backend status */
 void winbindd_idmap_status(void)
 {
-    int user_hwm, group_hwm;
-
-    DEBUG(0, ("winbindd idmap status:\n"));
-
-    /* Get current high water marks */
-
-    if ((user_hwm = tdb_fetch_int(idmap_tdb, HWM_USER)) == -1) {
-        DEBUG(DUMP_INFO, ("\tCould not get userid high water mark!\n"));
-    }
-
-    if ((group_hwm = tdb_fetch_int(idmap_tdb, HWM_GROUP)) == -1) {
-        DEBUG(DUMP_INFO, ("\tCould not get groupid high water mark!\n"));
-    }
-
-    /* Display next ids to allocate */
-
-    if (user_hwm != -1) {
-        DEBUG(DUMP_INFO, ("\tNext userid to allocate is %d\n", user_hwm));
-    }
-
-    if (group_hwm != -1) {
-        DEBUG(DUMP_INFO, ("\tNext groupid to allocate is %d\n", group_hwm));
-    }
-
-    /* Display percentage of id range already allocated. */
-
-    if (user_hwm != -1) {
-        int num_users = user_hwm - server_state.uid_low;
-        int total_users = server_state.uid_high - server_state.uid_low;
-
-        DEBUG(DUMP_INFO, ("\tUser id range is %d%% full (%d of %d)\n", 
-                          num_users * 100 / total_users, num_users,
-                          total_users));
-    }
-
-    if (group_hwm != -1) {
-        int num_groups = group_hwm - server_state.gid_low;
-        int total_groups = server_state.gid_high - server_state.gid_low;
-
-        DEBUG(DUMP_INFO, ("\tGroup id range is %d%% full (%d of %d)\n",
-                          num_groups * 100 / total_groups, num_groups,
-                          total_groups));
-    }
+  if (!impl) {
+    impl = get_impl(lp_winbind_backend());
+  }
 
-    /* Display complete mapping of users and groups to rids */
+  if (impl) {
+    impl->status();
+  } else {
+    DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n",
+              lp_winbind_backend()));
+  }
 }