diff options
-rw-r--r-- | source3/include/idmap.h | 24 | ||||
-rw-r--r-- | source3/sam/idmap.c | 134 | ||||
-rw-r--r-- | source3/sam/idmap_tdb.c | 127 |
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; } |