summaryrefslogtreecommitdiff
path: root/source3/nsswitch/idmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/nsswitch/idmap.c')
-rw-r--r--source3/nsswitch/idmap.c244
1 files changed, 144 insertions, 100 deletions
diff --git a/source3/nsswitch/idmap.c b/source3/nsswitch/idmap.c
index 885950830e..82b8f3d592 100644
--- a/source3/nsswitch/idmap.c
+++ b/source3/nsswitch/idmap.c
@@ -43,6 +43,12 @@ struct idmap_alloc_backend {
struct idmap_cache_ctx;
+struct idmap_alloc_context {
+ const char *params;
+ struct idmap_alloc_methods *methods;
+ BOOL initialized;
+};
+
static TALLOC_CTX *idmap_ctx = NULL;
static struct idmap_cache_ctx *idmap_cache;
@@ -53,9 +59,10 @@ static int pdb_dom_num = -1;
static int def_dom_num = -1;
static struct idmap_alloc_backend *alloc_backends = NULL;
-static struct idmap_alloc_methods *alloc_methods = NULL;
+static struct idmap_alloc_context *idmap_alloc_ctx = NULL;
#define IDMAP_CHECK_RET(ret) do { if ( ! NT_STATUS_IS_OK(ret)) { DEBUG(2, ("ERROR: NTSTATUS = 0x%08x\n", NT_STATUS_V(ret))); goto done; } } while(0)
+#define IDMAP_REPORT_RET(ret) do { if ( ! NT_STATUS_IS_OK(ret)) { DEBUG(2, ("ERROR: NTSTATUS = 0x%08x\n", NT_STATUS_V(ret))); } } while(0)
#define IDMAP_CHECK_ALLOC(mem) do { if (!mem) { DEBUG(0, ("Out of memory!\n")); ret = NT_STATUS_NO_MEMORY; goto done; } } while(0)
static struct idmap_methods *get_methods(struct idmap_backend *be, const char *name)
@@ -102,6 +109,12 @@ void set_idmap_in_own_child(void)
idmap_in_own_child = True;
}
+BOOL idmap_is_offline(void)
+{
+ return ( lp_winbind_offline_logon() &&
+ get_global_winbindd_state_offline() );
+}
+
/**********************************************************************
Allow a module to register itself as a method.
**********************************************************************/
@@ -221,9 +234,9 @@ static int close_domain_destructor(struct idmap_domain *dom)
NTSTATUS idmap_close(void)
{
/* close the alloc backend first before freeing idmap_ctx */
- if (alloc_methods) {
- alloc_methods->close_fn();
- alloc_methods = NULL;
+ if (idmap_alloc_ctx) {
+ idmap_alloc_ctx->methods->close_fn();
+ idmap_alloc_ctx->methods = NULL;
}
alloc_backends = NULL;
@@ -272,7 +285,7 @@ NTSTATUS idmap_init_cache(void)
NTSTATUS idmap_init(void)
{
NTSTATUS ret;
- static NTSTATUS backend_init_status = NT_STATUS_UNSUCCESSFUL;
+ static NTSTATUS idmap_init_status = NT_STATUS_UNSUCCESSFUL;
struct idmap_domain *dom;
char *compat_backend = NULL;
char *compat_params = NULL;
@@ -283,24 +296,12 @@ NTSTATUS idmap_init(void)
int compat = 0;
int i;
- /* Always initialize the cache. We'll have to delay initialization
- of backends if we are offline */
-
ret = idmap_init_cache();
if ( !NT_STATUS_IS_OK(ret) )
return ret;
- if ( NT_STATUS_IS_OK(backend_init_status) ) {
+ if (NT_STATUS_IS_OK(idmap_init_status))
return NT_STATUS_OK;
- }
-
- /* We can't reliably call intialization code here unless
- we are online */
-
- if ( get_global_winbindd_state_offline() ) {
- backend_init_status = NT_STATUS_FILE_IS_OFFLINE;
- return backend_init_status;
- }
static_init_idmap;
@@ -432,13 +433,18 @@ NTSTATUS idmap_init(void)
/* now that we have methods, set the destructor for this domain */
talloc_set_destructor(dom, close_domain_destructor);
+ if (compat_params) {
+ dom->params = talloc_strdup(dom, compat_params);
+ IDMAP_CHECK_ALLOC(dom->params);
+ } else {
+ dom->params = NULL;
+ }
+
/* Finally instance a backend copy for this domain */
- ret = dom->methods->init(dom, compat_params);
+ ret = dom->methods->init(dom);
if ( ! NT_STATUS_IS_OK(ret)) {
- DEBUG(0, ("ERROR: Initialization failed for backend %s (domain %s)\n",
+ DEBUG(0, ("ERROR: Initialization failed for backend %s (domain %s), deferred!\n",
parm_backend, dom->name));
- ret = NT_STATUS_UNSUCCESSFUL;
- goto done;
}
idmap_domains = talloc_realloc(idmap_ctx, idmap_domains, struct idmap_domain *, i+1);
if ( ! idmap_domains) {
@@ -489,8 +495,15 @@ NTSTATUS idmap_init(void)
/* now that we have methods, set the destructor for this domain */
talloc_set_destructor(dom, close_domain_destructor);
+ if (compat_params) {
+ dom->params = talloc_strdup(dom, compat_params);
+ IDMAP_CHECK_ALLOC(dom->params);
+ } else {
+ dom->params = NULL;
+ }
+
/* Finally instance a backend copy for this domain */
- ret = dom->methods->init(dom, compat_params);
+ ret = dom->methods->init(dom);
if ( ! NT_STATUS_IS_OK(ret)) {
DEBUG(0, ("ERROR: Initialization failed for idmap_nss ?!\n"));
ret = NT_STATUS_UNSUCCESSFUL;
@@ -533,8 +546,15 @@ NTSTATUS idmap_init(void)
/* now that we have methods, set the destructor for this domain */
talloc_set_destructor(dom, close_domain_destructor);
+ if (compat_params) {
+ dom->params = talloc_strdup(dom, compat_params);
+ IDMAP_CHECK_ALLOC(dom->params);
+ } else {
+ dom->params = NULL;
+ }
+
/* Finally instance a backend copy for this domain */
- ret = dom->methods->init(dom, compat_params);
+ ret = dom->methods->init(dom);
if ( ! NT_STATUS_IS_OK(ret)) {
DEBUG(0, ("ERROR: Initialization failed for idmap_passdb ?!\n"));
ret = NT_STATUS_UNSUCCESSFUL;
@@ -595,37 +615,50 @@ NTSTATUS idmap_init(void)
}
if ( alloc_backend ) {
+
+ idmap_alloc_ctx = talloc_zero(idmap_ctx, struct idmap_alloc_context);
+ IDMAP_CHECK_ALLOC(idmap_alloc_ctx);
- alloc_methods = get_alloc_methods(alloc_backends, alloc_backend);
- if ( ! alloc_methods) {
+ idmap_alloc_ctx->methods = get_alloc_methods(alloc_backends, alloc_backend);
+ if ( ! idmap_alloc_ctx->methods) {
ret = smb_probe_module("idmap", alloc_backend);
if (NT_STATUS_IS_OK(ret)) {
- alloc_methods = get_alloc_methods(alloc_backends, alloc_backend);
+ idmap_alloc_ctx->methods = get_alloc_methods(alloc_backends, alloc_backend);
}
}
- if ( alloc_methods) {
- ret = alloc_methods->init(compat_params);
+ if (idmap_alloc_ctx->methods) {
+
+ if (compat_params) {
+ idmap_alloc_ctx->params = talloc_strdup(idmap_alloc_ctx, compat_params);
+ IDMAP_CHECK_ALLOC(idmap_alloc_ctx->params);
+ } else {
+ idmap_alloc_ctx->params = NULL;
+ }
+
+ ret = idmap_alloc_ctx->methods->init(idmap_alloc_ctx->params);
if ( ! NT_STATUS_IS_OK(ret)) {
- DEBUG(0, ("idmap_init: Initialization failed for alloc "
- "backend %s\n", alloc_backend));
- ret = NT_STATUS_UNSUCCESSFUL;
- goto done;
- }
+ DEBUG(0, ("ERROR: Initialization failed for alloc "
+ "backend %s, deferred!\n", alloc_backend));
+ } else {
+ idmap_alloc_ctx->initialized = True;
+ }
} else {
DEBUG(2, ("idmap_init: Unable to get methods for alloc backend %s\n",
alloc_backend));
/* certain compat backends are just readonly */
- if ( compat )
+ if ( compat ) {
+ TALLOC_FREE(idmap_alloc_ctx);
ret = NT_STATUS_OK;
- else
+ } else {
ret = NT_STATUS_UNSUCCESSFUL;
+ }
}
}
/* cleanpu temporary strings */
TALLOC_FREE( compat_backend );
-
- backend_init_status = NT_STATUS_OK;
+
+ idmap_init_status = NT_STATUS_OK;
return ret;
@@ -633,12 +666,35 @@ done:
DEBUG(0, ("Aborting IDMAP Initialization ...\n"));
idmap_close();
- /* save the init status for later checks */
- backend_init_status = ret;
-
return ret;
}
+static NTSTATUS idmap_alloc_init(void)
+{
+ NTSTATUS ret;
+
+ if (! NT_STATUS_IS_OK(ret = idmap_init())) {
+ return ret;
+ }
+
+ if ( ! idmap_alloc_ctx) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ if ( ! idmap_alloc_ctx->initialized) {
+ ret = idmap_alloc_ctx->methods->init(idmap_alloc_ctx->params);
+ if ( ! NT_STATUS_IS_OK(ret)) {
+ DEBUG(0, ("ERROR: Initialization failed for alloc "
+ "backend, deferred!\n"));
+ return ret;
+ } else {
+ idmap_alloc_ctx->initialized = True;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
/**************************************************************************
idmap allocator interface functions
**************************************************************************/
@@ -647,60 +703,48 @@ NTSTATUS idmap_allocate_uid(struct unixid *id)
{
NTSTATUS ret;
- if (! NT_STATUS_IS_OK(ret = idmap_init())) {
+ if (! NT_STATUS_IS_OK(ret = idmap_alloc_init())) {
return ret;
}
- if ( !alloc_methods )
- return NT_STATUS_NOT_SUPPORTED;
-
id->type = ID_TYPE_UID;
- return alloc_methods->allocate_id(id);
+ return idmap_alloc_ctx->methods->allocate_id(id);
}
NTSTATUS idmap_allocate_gid(struct unixid *id)
{
NTSTATUS ret;
- if (! NT_STATUS_IS_OK(ret = idmap_init())) {
+ if (! NT_STATUS_IS_OK(ret = idmap_alloc_init())) {
return ret;
}
- if ( !alloc_methods )
- return NT_STATUS_NOT_SUPPORTED;
-
id->type = ID_TYPE_GID;
- return alloc_methods->allocate_id(id);
+ return idmap_alloc_ctx->methods->allocate_id(id);
}
NTSTATUS idmap_set_uid_hwm(struct unixid *id)
{
NTSTATUS ret;
- if (! NT_STATUS_IS_OK(ret = idmap_init())) {
+ if (! NT_STATUS_IS_OK(ret = idmap_alloc_init())) {
return ret;
}
- if ( !alloc_methods )
- return NT_STATUS_NOT_SUPPORTED;
-
id->type = ID_TYPE_UID;
- return alloc_methods->set_id_hwm(id);
+ return idmap_alloc_ctx->methods->set_id_hwm(id);
}
NTSTATUS idmap_set_gid_hwm(struct unixid *id)
{
NTSTATUS ret;
- if (! NT_STATUS_IS_OK(ret = idmap_init())) {
+ if (! NT_STATUS_IS_OK(ret = idmap_alloc_init())) {
return ret;
}
- if ( !alloc_methods )
- return NT_STATUS_NOT_SUPPORTED;
-
id->type = ID_TYPE_GID;
- return alloc_methods->set_id_hwm(id);
+ return idmap_alloc_ctx->methods->set_id_hwm(id);
}
/******************************************************************************
@@ -815,6 +859,11 @@ static NTSTATUS idmap_new_mapping(TALLOC_CTX *ctx, struct id_map *map)
enum lsa_SidType sid_type;
BOOL wbret;
+ /* If we are offline we cannot lookup SIDs, deny mapping */
+ if (idmap_is_offline()) {
+ return NT_STATUS_FILE_IS_OFFLINE;
+ }
+
ret = idmap_can_map(map, &dom);
if ( ! NT_STATUS_IS_OK(ret)) {
return NT_STATUS_NONE_MAPPED;
@@ -937,11 +986,6 @@ static NTSTATUS idmap_backends_unixids_to_sids(struct id_map **ids)
_ids = ids;
- /* make sure all maps are marked as in UNKNOWN status */
- for (i = 0; _ids[i]; i++) {
- _ids[i]->status = ID_UNKNOWN;
- }
-
unmapped = NULL;
for (n = num_domains-1; n >= 0; n--) { /* cycle backwards */
@@ -950,12 +994,12 @@ static NTSTATUS idmap_backends_unixids_to_sids(struct id_map **ids)
DEBUG(10, ("Query sids from domain %s\n", dom->name));
ret = dom->methods->unixids_to_sids(dom, _ids);
- IDMAP_CHECK_RET(ret);
+ IDMAP_REPORT_RET(ret);
unmapped = NULL;
for (i = 0, u = 0; _ids[i]; i++) {
- if (_ids[i]->status == ID_UNKNOWN || _ids[i]->status == ID_UNMAPPED) {
+ if (_ids[i]->status != ID_MAPPED) {
unmapped = talloc_realloc(ctx, unmapped, struct id_map *, u + 2);
IDMAP_CHECK_ALLOC(unmapped);
unmapped[u] = _ids[i];
@@ -975,7 +1019,9 @@ static NTSTATUS idmap_backends_unixids_to_sids(struct id_map **ids)
if (unmapped) {
/* there are still unmapped ids, map them to the unix users/groups domains */
+ /* except for expired entries, these will be returned as valid (offline mode) */
for (i = 0; unmapped[i]; i++) {
+ if (unmapped[i]->status == ID_EXPIRED) continue;
switch (unmapped[i]->xid.type) {
case ID_TYPE_UID:
uid_to_unix_users_sid((uid_t)unmapped[i]->xid.id, unmapped[i]->sid);
@@ -1025,11 +1071,8 @@ static NTSTATUS idmap_backends_sids_to_unixids(struct id_map **ids)
for (i = 0; ids[i]; i++) {
uint32 idx;
- /* make sure they are unknown to start off */
- ids[i]->status = ID_UNKNOWN;
-
if ( (dom = find_idmap_domain_from_sid( ids[i]->sid )) == NULL ) {
- /* no vailable idmap_domain. Move on */
+ /* no available idmap_domain. Move on */
continue;
}
@@ -1057,7 +1100,7 @@ static NTSTATUS idmap_backends_sids_to_unixids(struct id_map **ids)
dom = idmap_domains[i];
DEBUG(10, ("Query ids from domain %s\n", dom->name));
ret = dom->methods->sids_to_unixids(dom, dom_ids[i]);
- IDMAP_CHECK_RET(ret);
+ IDMAP_REPORT_RET(ret);
}
}
@@ -1065,6 +1108,8 @@ static NTSTATUS idmap_backends_sids_to_unixids(struct id_map **ids)
/* let's see if we have any unmapped SID left and act accordingly */
for (i = 0; ids[i]; i++) {
+ /* NOTE: this will NOT touch ID_EXPIRED entries that the backend
+ * was not able to confirm/deny (offline mode) */
if (ids[i]->status == ID_UNKNOWN || ids[i]->status == ID_UNMAPPED) {
/* ok this is an unmapped one, see if we can map it */
ret = idmap_new_mapping(ctx, ids[i]);
@@ -1075,7 +1120,8 @@ static NTSTATUS idmap_backends_sids_to_unixids(struct id_map **ids)
/* could not map it */
ids[i]->status = ID_UNMAPPED;
} else {
- /* Something very bad happened down there */
+ /* Something very bad happened down there
+ * OR we are offline */
ids[i]->status = ID_UNKNOWN;
}
}
@@ -1164,13 +1210,6 @@ NTSTATUS idmap_unixids_to_sids(struct id_map **ids)
/* let's see if there is any id mapping to be retieved from the backends */
if (bi) {
- /* Only do query if we are online */
- if ( lp_winbind_offline_logon() &&
- get_global_winbindd_state_offline() )
- {
- ret = NT_STATUS_FILE_IS_OFFLINE;
- goto done;
- }
ret = idmap_backends_unixids_to_sids(bids);
IDMAP_CHECK_RET(ret);
@@ -1179,11 +1218,17 @@ NTSTATUS idmap_unixids_to_sids(struct id_map **ids)
for (i = 0; i < bi; i++) {
if (bids[i]->status == ID_MAPPED) {
ret = idmap_cache_set(idmap_cache, bids[i]);
+ } else if (bids[i]->status == ID_EXPIRED) {
+ /* the cache returned an expired entry and the backend was
+ * was not able to clear the situation (offline).
+ * This handles a previous NT_STATUS_SYNCHRONIZATION_REQUIRED
+ * for disconnected mode, */
+ bids[i]->status = ID_MAPPED;
} else if (bids[i]->status == ID_UNKNOWN) {
- /* return an expired entry in the cache or an unknown */
- /* this handles a previous NT_STATUS_SYNCHRONIZATION_REQUIRED
- * for disconnected mode */
- idmap_cache_map_id(idmap_cache, ids[i]);
+ /* something bad here. We were not able to handle this for some
+ * reason, mark it as unmapped and hope next time things will
+ * settle down. */
+ bids[i]->status = ID_UNMAPPED;
} else { /* unmapped */
ret = idmap_cache_set_negative_id(idmap_cache, bids[i]);
}
@@ -1270,13 +1315,6 @@ NTSTATUS idmap_sids_to_unixids(struct id_map **ids)
/* let's see if there is any id mapping to be retieved from the backends */
if (bids) {
- /* Only do query if we are online */
- if ( lp_winbind_offline_logon() &&
- get_global_winbindd_state_offline() )
- {
- ret = NT_STATUS_FILE_IS_OFFLINE;
- goto done;
- }
ret = idmap_backends_sids_to_unixids(bids);
IDMAP_CHECK_RET(ret);
@@ -1285,12 +1323,18 @@ NTSTATUS idmap_sids_to_unixids(struct id_map **ids)
for (i = 0; bids[i]; i++) {
if (bids[i]->status == ID_MAPPED) {
ret = idmap_cache_set(idmap_cache, bids[i]);
+ } else if (bids[i]->status == ID_EXPIRED) {
+ /* the cache returned an expired entry and the backend was
+ * was not able to clear the situation (offline).
+ * This handles a previous NT_STATUS_SYNCHRONIZATION_REQUIRED
+ * for disconnected mode, */
+ bids[i]->status = ID_MAPPED;
} else if (bids[i]->status == ID_UNKNOWN) {
- /* return an expired entry in the cache or an unknown */
- /* this handles a previous NT_STATUS_SYNCHRONIZATION_REQUIRED
- * for disconnected mode */
- idmap_cache_map_id(idmap_cache, ids[i]);
- } else {
+ /* something bad here. We were not able to handle this for some
+ * reason, mark it as unmapped and hope next time things will
+ * settle down. */
+ bids[i]->status = ID_UNMAPPED;
+ } else { /* unmapped */
ret = idmap_cache_set_negative_sid(idmap_cache, bids[i]);
}
IDMAP_CHECK_RET(ret);
@@ -1362,15 +1406,15 @@ void idmap_dump_maps(char *logfile)
return;
}
- if ( alloc_methods ) {
+ if (NT_STATUS_IS_OK(ret = idmap_alloc_init())) {
allid.type = ID_TYPE_UID;
allid.id = 0;
- alloc_methods->get_id_hwm(&allid);
+ idmap_alloc_ctx->methods->get_id_hwm(&allid);
fprintf(dump, "USER HWM %lu\n", (unsigned long)allid.id);
allid.type = ID_TYPE_GID;
allid.id = 0;
- alloc_methods->get_id_hwm(&allid);
+ idmap_alloc_ctx->methods->get_id_hwm(&allid);
fprintf(dump, "GROUP HWM %lu\n", (unsigned long)allid.id);
}