summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/idmap.h24
-rw-r--r--source3/sam/idmap.c134
-rw-r--r--source3/sam/idmap_tdb.c127
3 files changed, 207 insertions, 78 deletions
diff --git a/source3/include/idmap.h b/source3/include/idmap.h
index 5a1f4fafc3..fd7646a324 100644
--- a/source3/include/idmap.h
+++ b/source3/include/idmap.h
@@ -22,24 +22,30 @@
Boston, MA 02111-1307, USA.
*/
-#define ID_EMPTY 0
-#define ID_USERID 1
-#define ID_GROUPID 2
-#define ID_OTHER 3
+#define ID_EMPTY 0x00
+#define ID_USERID 0x01
+#define ID_GROUPID 0x02
+#define ID_OTHER 0x04
-typedef union id_t {
+#define ID_TYPEMASK 0x0f
+
+#define ID_NOMAP 0x10
+#define ID_CACHE 0x20
+
+typedef union unid_t {
uid_t uid;
gid_t gid;
-} id_t;
+} unid_t;
/* Filled out by IDMAP backends */
struct idmap_methods {
/* Called when backend is first loaded */
- NTSTATUS (*init)(void);
+ NTSTATUS (*init)(const char *init_str);
- NTSTATUS (*get_sid_from_id)(DOM_SID *sid, id_t id, int id_type);
- NTSTATUS (*get_id_from_sid)(id_t *id, int *id_type, DOM_SID *sid);
+ NTSTATUS (*get_sid_from_id)(DOM_SID *sid, unid_t id, int id_type);
+ NTSTATUS (*get_id_from_sid)(unid_t *id, int *id_type, DOM_SID *sid);
+ NTSTATUS (*set_mapping)(DOM_SID *sid, unid_t id, int id_type);
/* Called when backend is unloaded */
NTSTATUS (*close)(void);
diff --git a/source3/sam/idmap.c b/source3/sam/idmap.c
index 96638b4723..b18423a13b 100644
--- a/source3/sam/idmap.c
+++ b/source3/sam/idmap.c
@@ -21,7 +21,6 @@
*/
#include "includes.h"
-#include "idmap.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
@@ -32,48 +31,58 @@ static struct {
/* Function to create a member of the idmap_methods list */
NTSTATUS (*reg_meth)(struct idmap_methods **methods);
struct idmap_methods *methods;
-} builtin_idmap_functions[] = {
+
+} remote_idmap_functions[] = {
+
{ "tdb", idmap_reg_tdb, NULL },
/* { "ldap", idmap_reg_ldap, NULL },*/
{ NULL, NULL, NULL }
+
};
-/* singleton pattern: uberlazy evaluation */
-static struct idmap_methods *impl;
+static struct idmap_methods *local_cache;
+static struct idmap_methods *remote_repo;
-static struct idmap_methods *get_impl(const char *name)
+static struct idmap_methods *get_methods(const char *name)
{
int i = 0;
struct idmap_methods *ret = NULL;
- while (builtin_idmap_functions[i].name && strcmp(builtin_idmap_functions[i].name, name)) {
+ while (remote_idmap_functions[i].name && strcmp(remote_idmap_functions[i].name, name)) {
i++;
}
- if (builtin_idmap_functions[i].name) {
+ if (remote_idmap_functions[i].name) {
- if (!builtin_idmap_functions[i].methods) {
- builtin_idmap_functions[i].reg_meth(&builtin_idmap_functions[i].methods);
+ if (!remote_idmap_functions[i].methods) {
+ remote_idmap_functions[i].reg_meth(&remote_idmap_functions[i].methods);
}
- ret = builtin_idmap_functions[i].methods;
+ ret = remote_idmap_functions[i].methods;
}
return ret;
}
/* Load idmap backend functions */
-BOOL set_impl(void)
+BOOL load_methods(void)
{
- if (!impl) {
- DEBUG(3, ("idmap_init: using '%s' as backend\n", lp_idmap_backend()));
+ if (!local_cache) {
+ idmap_reg_tdb(&local_cache);
+ }
+
+ if (!remote_repo && lp_idmap_backend()) {
+ DEBUG(3, ("load_methods: using '%s' as remote backend\n", lp_idmap_backend()));
- impl = get_impl(lp_idmap_backend());
- if (!impl) {
- DEBUG(0, ("set_impl: could not load backend '%s'\n", lp_idmap_backend()));
+ remote_repo = get_methods(lp_idmap_backend());
+ if (!remote_repo) {
+ DEBUG(0, ("load_methods: could not load remote backend '%s'\n", lp_idmap_backend()));
return False;
}
}
+
+ idmap_init();
+
return True;
}
@@ -82,9 +91,7 @@ NTSTATUS idmap_init(void)
{
NTSTATUS ret;
- if (!set_impl()) return NT_STATUS_UNSUCCESSFUL;
-
- ret = impl->init();
+ ret = remote_repo->init("idmap.tdb");
if (NT_STATUS_IS_ERR(ret)) {
DEBUG(3, ("idmap_init: init failed!\n"));
}
@@ -92,47 +99,105 @@ NTSTATUS idmap_init(void)
return ret;
}
+static NTSTATUS idmap_set_mapping(DOM_SID *sid, unid_t id, int id_type)
+{
+ NTSTATUS ret;
+
+ if (!load_methods()) return NT_STATUS_UNSUCCESSFUL;
+
+ ret = local_cache->set_mapping(sid, id, id_type);
+ if (NT_STATUS_IS_ERR(ret)) {
+ DEBUG (0, ("idmap_set_mapping: Error, unable to modify local cache!\n"));
+ return ret;
+ }
+
+ /* Being able to update the remote cache is seldomly right.
+ Generally this is a forbidden operation. */
+ if (!(id_type & ID_CACHE) && (remote_repo != NULL)) {
+ remote_repo->set_mapping(sid, id, id_type);
+ if (NT_STATUS_IS_ERR(ret)) {
+ DEBUG (0, ("idmap_set_mapping: Error, unable to modify remote cache!\n"));
+ }
+ }
+
+ return ret;
+}
+
/* Get ID from SID */
-NTSTATUS idmap_get_id_from_sid(id_t *id, int *id_type, DOM_SID *sid)
+NTSTATUS idmap_get_id_from_sid(unid_t *id, int *id_type, DOM_SID *sid)
{
NTSTATUS ret;
+ int loc_type;
- if (!set_impl()) return NT_STATUS_UNSUCCESSFUL;
+ if (!load_methods()) return NT_STATUS_UNSUCCESSFUL;
- ret = impl->get_id_from_sid(id, id_type, sid);
+ loc_type = *id_type;
+ if (remote_repo) { /* We have a central remote idmap */
+ loc_type |= ID_NOMAP;
+ }
+ ret = local_cache->get_id_from_sid(id, &loc_type, sid);
if (NT_STATUS_IS_ERR(ret)) {
- DEBUG(3, ("idmap_get_id_from_sid: error fetching id!\n"));
+ if (remote_repo) {
+ ret = remote_repo->get_id_from_sid(id, id_type, sid);
+ if (NT_STATUS_IS_ERR(ret)) {
+ DEBUG(3, ("idmap_get_id_from_sid: error fetching id!\n"));
+ } else {
+ loc_type |= ID_CACHE;
+ idmap_set_mapping(sid, *id, loc_type);
+ }
+ }
+ } else {
+ *id_type = loc_type & ID_TYPEMASK;
}
return ret;
}
/* Get SID from ID */
-NTSTATUS idmap_get_sid_from_id(DOM_SID *sid, id_t id, int id_type)
+NTSTATUS idmap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
{
NTSTATUS ret;
+ int loc_type;
- if (!set_impl()) return NT_STATUS_UNSUCCESSFUL;
+ if (!load_methods()) return NT_STATUS_UNSUCCESSFUL;
- ret = impl->get_sid_from_id(sid, id, id_type);
+ loc_type = id_type;
+ if (remote_repo) {
+ loc_type = id_type | ID_NOMAP;
+ }
+ ret = local_cache->get_sid_from_id(sid, id, loc_type);
if (NT_STATUS_IS_ERR(ret)) {
- DEBUG(3, ("idmap_get_sid_from_id: error fetching sid!\n"));
+ if (remote_repo) {
+ ret = remote_repo->get_sid_from_id(sid, id, id_type);
+ if (NT_STATUS_IS_ERR(ret)) {
+ DEBUG(3, ("idmap_get_sid_from_id: unable to fetch sid!\n"));
+ } else {
+ loc_type |= ID_CACHE;
+ idmap_set_mapping(sid, id, loc_type);
+ }
+ }
}
return ret;
}
-
/* Close backend */
NTSTATUS idmap_close(void)
{
NTSTATUS ret;
- if (!set_impl()) return NT_STATUS_UNSUCCESSFUL;
+ if (!load_methods()) return NT_STATUS_UNSUCCESSFUL;
- ret = impl->close();
+ ret = local_cache->close();
if (NT_STATUS_IS_ERR(ret)) {
- DEBUG(3, ("idmap_close: close failed!\n"));
+ DEBUG(3, ("idmap_close: failed to close local cache!\n"));
+ }
+
+ if (remote_repo) {
+ ret = remote_repo->close();
+ if (NT_STATUS_IS_ERR(ret)) {
+ DEBUG(3, ("idmap_close: failed to close remote idmap repository!\n"));
+ }
}
return ret;
@@ -141,8 +206,9 @@ NTSTATUS idmap_close(void)
/* Dump backend status */
void idmap_status(void)
{
- if (!set_impl()) return;
-
- impl->status();
+ if (load_methods()) {
+ local_cache->status();
+ remote_repo->status();
+ }
}
diff --git a/source3/sam/idmap_tdb.c b/source3/sam/idmap_tdb.c
index 3aaab3ac42..4af46ac8d3 100644
--- a/source3/sam/idmap_tdb.c
+++ b/source3/sam/idmap_tdb.c
@@ -23,7 +23,6 @@
*/
#include "includes.h"
-#include "idmap.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
@@ -38,6 +37,15 @@
/* Globals */
static TDB_CONTEXT *idmap_tdb;
+struct idmap_state {
+
+ /* User and group id pool */
+
+ uid_t uid_low, uid_high; /* Range of uids to allocate */
+ gid_t gid_low, gid_high; /* Range of gids to allocate */
+} idmap_state;
+
+
/* FIXME: let handle conversions when all things work ok.
I think it is better to handle the conversion at
upgrade time and leave the old db intact.
@@ -175,25 +183,25 @@ static BOOL tdb_idmap_convert(const char *idmap_name)
#endif
/* Allocate either a user or group id from the pool */
-static NTSTATUS tdb_allocate_id(id_t *id, int id_type)
+static NTSTATUS tdb_allocate_id(unid_t *id, int id_type)
{
int hwm;
if (!id) return NT_STATUS_INVALID_PARAMETER;
/* Get current high water mark */
- switch (id_type) {
+ switch (id_type & ID_TYPEMASK) {
case ID_USERID:
if ((hwm = tdb_fetch_int32(idmap_tdb, HWM_USER)) == -1) {
return NT_STATUS_INTERNAL_DB_ERROR;
}
- if (hwm > server_state.uid_high) {
+ if (hwm > idmap_state.uid_high) {
DEBUG(0, ("idmap Fatal Error: UID range full!!\n"));
return NT_STATUS_UNSUCCESSFUL;
}
- *id.uid = hwm++;
+ (*id).uid = hwm++;
/* Store new high water mark */
tdb_store_int32(idmap_tdb, HWM_USER, hwm);
@@ -203,12 +211,12 @@ static NTSTATUS tdb_allocate_id(id_t *id, int id_type)
return NT_STATUS_INTERNAL_DB_ERROR;
}
- if (hwm > server_state.gid_high) {
+ if (hwm > idmap_state.gid_high) {
DEBUG(0, ("idmap Fatal Error: GID range full!!\n"));
return NT_STATUS_UNSUCCESSFUL;
}
- *id.gid = hwm++;
+ (*id).gid = hwm++;
/* Store new high water mark */
tdb_store_int32(idmap_tdb, HWM_GROUP, hwm);
@@ -221,7 +229,7 @@ static NTSTATUS tdb_allocate_id(id_t *id, int id_type)
}
/* Get a sid from an id */
-static NTSTATUS tdb_get_sid_from_id(DOM_SID *sid, id_t id, int id_type)
+static NTSTATUS tdb_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
{
TDB_DATA key, data;
fstring keystr;
@@ -229,7 +237,7 @@ static NTSTATUS tdb_get_sid_from_id(DOM_SID *sid, id_t id, int id_type)
if (!sid) return NT_STATUS_INVALID_PARAMETER;
- switch (id_type) {
+ switch (id_type & ID_TYPEMASK) {
case ID_USERID:
slprintf(keystr, sizeof(keystr), "UID %d", id.uid);
break;
@@ -256,7 +264,7 @@ static NTSTATUS tdb_get_sid_from_id(DOM_SID *sid, id_t id, int id_type)
}
/* Get an id from a sid */
-static NTSTATUS tdb_get_id_from_sid(id_t *id, int *id_type, DOM_SID *sid)
+static NTSTATUS tdb_get_id_from_sid(unid_t *id, int *id_type, DOM_SID *sid)
{
TDB_DATA data, key;
fstring keystr;
@@ -273,15 +281,16 @@ static NTSTATUS tdb_get_id_from_sid(id_t *id, int *id_type, DOM_SID *sid)
data = tdb_fetch(idmap_tdb, key);
if (data.dptr) {
+ int type = *id_type & ID_TYPEMASK;
fstring scanstr;
- if (*id_type == ID_EMPTY || *id_type == ID_USERID) {
+ if (type == ID_EMPTY || type == ID_USERID) {
/* Parse and return existing uid */
fstrcpy(scanstr, "UID %d");
- if (sscanf(data.dptr, scanstr, *id.uid) == 1) {
+ if (sscanf(data.dptr, scanstr, (*id).uid) == 1) {
/* uid ok? */
- if (*id_type == ID_EMPTY) {
+ if (type == ID_EMPTY) {
*id_type = ID_USERID;
}
ret = NT_STATUS_OK;
@@ -289,13 +298,13 @@ static NTSTATUS tdb_get_id_from_sid(id_t *id, int *id_type, DOM_SID *sid)
}
}
- if (*id_type == ID_EMPTY || *id_type == ID_GROUPID) {
+ if (type == ID_EMPTY || type == ID_GROUPID) {
/* Parse and return existing gid */
fstrcpy(scanstr, "GID %d");
- if (sscanf(data.dptr, scanstr, *id.gid) == 1) {
+ if (sscanf(data.dptr, scanstr, (*id).gid) == 1) {
/* gid ok? */
- if (*id_type == ID_EMPTY) {
+ if (type == ID_EMPTY) {
*id_type = ID_GROUPID;
}
ret = NT_STATUS_OK;
@@ -304,24 +313,33 @@ static NTSTATUS tdb_get_id_from_sid(id_t *id, int *id_type, DOM_SID *sid)
idok:
SAFE_FREE(data.dptr);
- } else if (*id_type == ID_USERID || *id_type == ID_GROUPID) {
+ } else if (!(*id_type & ID_NOMAP) &&
+ (((*id_type & ID_TYPEMASK) == ID_USERID)
+ || (*id_type & ID_TYPEMASK) == ID_GROUPID)) {
/* Allocate a new id for this sid */
- ret = tdb_allocate_id(id, id_type);
+ ret = tdb_allocate_id(id, *id_type);
if (NT_STATUS_IS_OK(ret)) {
fstring keystr2;
/* Store new id */
- slprintf(keystr2, sizeof(keystr2), "%s %d",
- *id_type ? "GID" : "UID", *id);
+ if (*id_type & ID_USERID) {
+ slprintf(keystr2, sizeof(keystr2), "UID %d", (*id).uid);
+ } else {
+ slprintf(keystr2, sizeof(keystr2), "GID %d", (*id).gid);
+ }
data.dptr = keystr2;
data.dsize = strlen(keystr2) + 1;
- if (tdb_store(idmap_tdb, key, data, TDB_INSERT) == -1)
+ if (tdb_store(idmap_tdb, key, data, TDB_INSERT) == -1) {
+ /* TODO: print tdb error !! */
return NT_STATUS_UNSUCCESSFUL;
- if (tdb_store(idmap_tdb, data, key, TDB_INSERT) == -1)
+ }
+ if (tdb_store(idmap_tdb, data, key, TDB_INSERT) == -1) {
+ /* TODO: print tdb error !! */
return NT_STATUS_UNSUCCESSFUL;
+ }
ret = NT_STATUS_OK;
}
@@ -330,13 +348,49 @@ idok:
return ret;
}
+static NTSTATUS tdb_set_mapping(DOM_SID *sid, unid_t id, int id_type)
+{
+ TDB_DATA ksid, kid;
+ fstring ksidstr;
+ fstring kidstr;
+
+ if (!sid) return NT_STATUS_INVALID_PARAMETER;
+
+ sid_to_string(ksidstr, sid);
+
+ ksid.dptr = ksidstr;
+ ksid.dsize = strlen(ksidstr) + 1;
+
+ id_type &= ID_TYPEMASK;
+ if (id_type & ID_USERID) {
+ slprintf(kidstr, sizeof(kidstr), "UID %d", id.uid);
+ } else if (id_type & ID_GROUPID) {
+ slprintf(kidstr, sizeof(kidstr), "GID %d", id.gid);
+ } else {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ kid.dptr = kidstr;
+ kid.dsize = strlen(kidstr) + 1;
+
+ if (tdb_store(idmap_tdb, ksid, kid, TDB_INSERT) == -1) {
+ /* TODO: print tdb error !! */
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ if (tdb_store(idmap_tdb, kid, ksid, TDB_INSERT) == -1) {
+ /* TODO: print tdb error !! */
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ return NT_STATUS_OK;
+}
+
/*****************************************************************************
Initialise idmap database.
*****************************************************************************/
-static NTSTATUS tdb_idmap_init(void)
+static NTSTATUS tdb_idmap_init(const char *db_name)
{
/* Open tdb cache */
- if (!(idmap_tdb = tdb_open_log(lock_path("idmap.tdb"), 0,
+ if (!(idmap_tdb = tdb_open_log(lock_path(db_name), 0,
TDB_DEFAULT, O_RDWR | O_CREAT,
0600))) {
DEBUG(0, ("idmap_init: Unable to open idmap database\n"));
@@ -354,14 +408,14 @@ static NTSTATUS tdb_idmap_init(void)
/* Create high water marks for group and user id */
if (tdb_fetch_int32(idmap_tdb, HWM_USER) == -1) {
- if (tdb_store_int32(idmap_tdb, HWM_USER, server_state.uid_low) == -1) {
+ if (tdb_store_int32(idmap_tdb, HWM_USER, idmap_state.uid_low) == -1) {
DEBUG(0, ("idmap_init: Unable to initialise user hwm in idmap database\n"));
return NT_STATUS_INTERNAL_DB_ERROR;
}
}
if (tdb_fetch_int32(idmap_tdb, HWM_GROUP) == -1) {
- if (tdb_store_int32(idmap_tdb, HWM_GROUP, server_state.gid_low) == -1) {
+ if (tdb_store_int32(idmap_tdb, HWM_GROUP, idmap_state.gid_low) == -1) {
DEBUG(0, ("idmap_init: Unable to initialise group hwm in idmap database\n"));
return NT_STATUS_INTERNAL_DB_ERROR;
}
@@ -373,11 +427,13 @@ static NTSTATUS tdb_idmap_init(void)
/* Close the tdb */
static NTSTATUS tdb_idmap_close(void)
{
- if (idmap_tdb)
- if (tdb_close(idmap_tdb) == 0)
+ if (idmap_tdb) {
+ if (tdb_close(idmap_tdb) == 0) {
return NT_STATUS_OK;
- else
- retrun NT_STATUS_UNSUCCESSFUL;
+ } else {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
return NT_STATUS_OK;
}
@@ -426,9 +482,9 @@ static void tdb_idmap_status(void)
/* Display percentage of id range already allocated. */
if (user_hwm != -1) {
- int num_users = user_hwm - server_state.uid_low;
+ int num_users = user_hwm - idmap_state.uid_low;
int total_users =
- server_state.uid_high - server_state.uid_low;
+ idmap_state.uid_high - idmap_state.uid_low;
DEBUG(DUMP_INFO,
("\tUser id range is %d%% full (%d of %d)\n",
@@ -437,9 +493,9 @@ static void tdb_idmap_status(void)
}
if (group_hwm != -1) {
- int num_groups = group_hwm - server_state.gid_low;
+ int num_groups = group_hwm - idmap_state.gid_low;
int total_groups =
- server_state.gid_high - server_state.gid_low;
+ idmap_state.gid_high - idmap_state.gid_low;
DEBUG(DUMP_INFO,
("\tGroup id range is %d%% full (%d of %d)\n",
@@ -455,6 +511,7 @@ struct idmap_methods tdb_idmap_methods = {
tdb_idmap_init,
tdb_get_sid_from_id,
tdb_get_id_from_sid,
+ tdb_set_mapping,
tdb_idmap_close,
tdb_idmap_status
@@ -464,6 +521,6 @@ NTSTATUS idmap_reg_tdb(struct idmap_methods **meth)
{
*meth = &tdb_idmap_methods;
- return NTSTATUS_OK;
+ return NT_STATUS_OK;
}