From 3bb5b158017d5bad82bfb4a9e29187549e665446 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 8 Aug 2006 15:33:09 +0000 Subject: r17459: As by Jerry's word commit this without his review. This patch add some missing async functions to solve UID/GID -> SID requests not just out of the cache, but down the remote idmap if necessary. This patch solves the problem of servers not showing users/groups names for allocated UID/GIDs when joined to a group of servers that share a prepopulated idmap backend. Also correctly resolve UID/GIDs to SIDs when looking ACLs from the windows security tab on teh same situation. Simo. (This used to be commit b8578bfab6a04fcd65a2e65f507067459e326077) --- source3/nsswitch/winbindd_async.c | 110 ++++++++++++++++++++++++++++++++++++++ source3/nsswitch/winbindd_dual.c | 2 + source3/nsswitch/winbindd_group.c | 104 +++++++++++++++++++++-------------- source3/nsswitch/winbindd_nss.h | 2 + source3/nsswitch/winbindd_sid.c | 46 ++++++++++++++-- source3/nsswitch/winbindd_user.c | 32 ++++++++--- 6 files changed, 246 insertions(+), 50 deletions(-) diff --git a/source3/nsswitch/winbindd_async.c b/source3/nsswitch/winbindd_async.c index 808e73209d..4edf46dbee 100644 --- a/source3/nsswitch/winbindd_async.c +++ b/source3/nsswitch/winbindd_async.c @@ -1524,3 +1524,113 @@ void query_user_async(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain, do_async_domain(mem_ctx, domain, &request, query_user_recv, (void *)cont, private_data); } + +/* The following uid2sid/gid2sid functions has been contributed by + * Keith Reynolds */ + +static void winbindd_uid2sid_recv(TALLOC_CTX *mem_ctx, BOOL success, + struct winbindd_response *response, + void *c, void *private_data) +{ + void (*cont)(void *priv, BOOL succ, const char *sid) = c; + + if (!success) { + DEBUG(5, ("Could not trigger uid2sid\n")); + cont(private_data, False, NULL); + return; + } + + if (response->result != WINBINDD_OK) { + DEBUG(5, ("uid2sid returned an error\n")); + cont(private_data, False, NULL); + return; + } + + cont(private_data, True, response->data.sid.sid); +} + +void winbindd_uid2sid_async(TALLOC_CTX *mem_ctx, uid_t uid, + void (*cont)(void *private_data, BOOL success, const char *sid), + void *private_data) +{ + struct winbindd_request request; + + ZERO_STRUCT(request); + request.cmd = WINBINDD_DUAL_UID2SID; + request.data.uid = uid; + do_async(mem_ctx, idmap_child(), &request, winbindd_uid2sid_recv, cont, private_data); +} + +enum winbindd_result winbindd_dual_uid2sid(struct winbindd_domain *domain, + struct winbindd_cli_state *state) +{ + DOM_SID sid; + NTSTATUS result; + + DEBUG(3,("[%5lu]: uid to sid %lu\n", + (unsigned long)state->pid, + (unsigned long) state->request.data.uid)); + + /* Find sid for this uid and return it, possibly ask the slow remote idmap */ + result = idmap_uid_to_sid(&sid, state->request.data.uid, IDMAP_FLAG_NONE); + + if (NT_STATUS_IS_OK(result)) { + sid_to_string(state->response.data.sid.sid, &sid); + state->response.data.sid.type = SID_NAME_USER; + return WINBINDD_OK; + } + + return WINBINDD_ERROR; +} + +static void winbindd_gid2sid_recv(TALLOC_CTX *mem_ctx, BOOL success, + struct winbindd_response *response, + void *c, void *private_data) +{ + void (*cont)(void *priv, BOOL succ, const char *sid) = c; + + if (!success) { + DEBUG(5, ("Could not trigger gid2sid\n")); + cont(private_data, False, NULL); + return; + } + + cont(private_data, True, response->data.sid.sid); +} + +void winbindd_gid2sid_async(TALLOC_CTX *mem_ctx, gid_t gid, + void (*cont)(void *private_data, BOOL success, const char *sid), + void *private_data) +{ + struct winbindd_request request; + + ZERO_STRUCT(request); + request.cmd = WINBINDD_DUAL_GID2SID; + request.data.gid = gid; + do_async(mem_ctx, idmap_child(), &request, winbindd_gid2sid_recv, cont, private_data); +} + +enum winbindd_result winbindd_dual_gid2sid(struct winbindd_domain *domain, + struct winbindd_cli_state *state) +{ + DOM_SID sid; + NTSTATUS result; + + DEBUG(3,("[%5lu]: gid %lu to sid\n", + (unsigned long)state->pid, + (unsigned long) state->request.data.gid)); + + /* Find sid for this gid and return it, possibly ask the slow remote idmap */ + result = idmap_gid_to_sid(&sid, state->request.data.gid, IDMAP_FLAG_NONE); + + if (NT_STATUS_IS_OK(result)) { + sid_to_string(state->response.data.sid.sid, &sid); + DEBUG(10, ("[%5lu]: retrieved sid: %s\n", + (unsigned long)state->pid, + state->response.data.sid.sid)); + state->response.data.sid.type = SID_NAME_DOM_GRP; + return WINBINDD_OK; + } + + return WINBINDD_ERROR; +} diff --git a/source3/nsswitch/winbindd_dual.c b/source3/nsswitch/winbindd_dual.c index b4d4a794ae..874b480214 100644 --- a/source3/nsswitch/winbindd_dual.c +++ b/source3/nsswitch/winbindd_dual.c @@ -357,6 +357,8 @@ static struct winbindd_child_dispatch_table child_dispatch_table[] = { { WINBINDD_CHECK_MACHACC, winbindd_dual_check_machine_acct, "CHECK_MACHACC" }, { WINBINDD_DUAL_SID2UID, winbindd_dual_sid2uid, "DUAL_SID2UID" }, { WINBINDD_DUAL_SID2GID, winbindd_dual_sid2gid, "DUAL_SID2GID" }, + { WINBINDD_DUAL_UID2SID, winbindd_dual_uid2sid, "DUAL_UID2SID" }, + { WINBINDD_DUAL_GID2SID, winbindd_dual_gid2sid, "DUAL_GID2SID" }, { WINBINDD_DUAL_UID2NAME, winbindd_dual_uid2name, "DUAL_UID2NAME" }, { WINBINDD_DUAL_NAME2UID, winbindd_dual_name2uid, "DUAL_NAME2UID" }, { WINBINDD_DUAL_GID2NAME, winbindd_dual_gid2name, "DUAL_GID2NAME" }, diff --git a/source3/nsswitch/winbindd_group.c b/source3/nsswitch/winbindd_group.c index 5528b6c78e..5cab6eb663 100644 --- a/source3/nsswitch/winbindd_group.c +++ b/source3/nsswitch/winbindd_group.c @@ -329,54 +329,16 @@ void winbindd_getgrnam(struct winbindd_cli_state *state) request_ok(state); } -/* Return a group structure from a gid number */ - -void winbindd_getgrgid(struct winbindd_cli_state *state) +static void getgrgid_got_sid(struct winbindd_cli_state *state, DOM_SID group_sid) { struct winbindd_domain *domain; - DOM_SID group_sid; enum SID_NAME_USE name_type; fstring dom_name; fstring group_name; size_t gr_mem_len; size_t num_gr_mem; char *gr_mem; - NTSTATUS status; - - DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid, - (unsigned long)state->request.data.gid)); - - /* Bug out if the gid isn't in the winbind range */ - - if ((state->request.data.gid < server_state.gid_low) || - (state->request.data.gid > server_state.gid_high)) { - request_error(state); - return; - } - - /* Get sid from gid */ - - status = idmap_gid_to_sid(&group_sid, state->request.data.gid, 0); - if (NT_STATUS_IS_OK(status)) { - /* This is a remote one */ - goto got_sid; - } - /* Ok, this might be "ours", i.e. an alias */ - - if (pdb_gid_to_sid(state->request.data.gid, &group_sid) && - lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) && - (name_type == SID_NAME_ALIAS)) { - /* Hey, got an alias */ - goto got_sid; - } - - DEBUG(1, ("could not convert gid %lu to sid\n", - (unsigned long)state->request.data.gid)); - request_error(state); - return; - - got_sid: /* Get name from sid */ if (!winbindd_lookup_name_by_sid(state->mem_ctx, &group_sid, dom_name, @@ -423,9 +385,73 @@ void winbindd_getgrgid(struct winbindd_cli_state *state) state->response.length += gr_mem_len; state->response.extra_data.data = gr_mem; + request_ok(state); } +static void getgrgid_recv(void *private_data, BOOL success, const char *sid) +{ + struct winbindd_cli_state *state = talloc_get_type_abort(private_data, struct winbindd_cli_state); + enum SID_NAME_USE name_type; + DOM_SID group_sid; + + if (success) { + DEBUG(10,("getgrgid_recv: gid %lu has sid %s\n", + (unsigned long)(state->request.data.gid), sid)); + + string_to_sid(&group_sid, sid); + getgrgid_got_sid(state, group_sid); + return; + } + + /* Ok, this might be "ours", i.e. an alias */ + if (pdb_gid_to_sid(state->request.data.gid, &group_sid) && + lookup_sid(state->mem_ctx, &group_sid, NULL, NULL, &name_type) && + (name_type == SID_NAME_ALIAS)) { + /* Hey, got an alias */ + DEBUG(10,("getgrgid_recv: we have an alias with gid %lu and sid %s\n", + (unsigned long)(state->request.data.gid), sid)); + getgrgid_got_sid(state, group_sid); + return; + } + + DEBUG(1, ("could not convert gid %lu to sid\n", + (unsigned long)state->request.data.gid)); + request_error(state); +} + +/* Return a group structure from a gid number */ +void winbindd_getgrgid(struct winbindd_cli_state *state) +{ + DOM_SID group_sid; + NTSTATUS status; + + DEBUG(3, ("[%5lu]: getgrgid %lu\n", (unsigned long)state->pid, + (unsigned long)state->request.data.gid)); + + /* Bug out if the gid isn't in the winbind range */ + + if ((state->request.data.gid < server_state.gid_low) || + (state->request.data.gid > server_state.gid_high)) { + request_error(state); + return; + } + + /* Get sid from gid */ + + status = idmap_gid_to_sid(&group_sid, state->request.data.gid, IDMAP_FLAG_NONE); + if (NT_STATUS_IS_OK(status)) { + /* This is a remote one */ + getgrgid_got_sid(state, group_sid); + return; + } + + DEBUG(10,("winbindd_getgrgid: gid %lu not found in cache, try with the async interface\n", + (unsigned long)state->request.data.gid)); + + winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, getgrgid_recv, state); +} + /* * set/get/endgrent functions */ diff --git a/source3/nsswitch/winbindd_nss.h b/source3/nsswitch/winbindd_nss.h index b36c0147a7..4a95a3cf42 100644 --- a/source3/nsswitch/winbindd_nss.h +++ b/source3/nsswitch/winbindd_nss.h @@ -140,6 +140,8 @@ enum winbindd_cmd { * between parent and children */ WINBINDD_DUAL_SID2UID, WINBINDD_DUAL_SID2GID, + WINBINDD_DUAL_UID2SID, + WINBINDD_DUAL_GID2SID, WINBINDD_DUAL_IDMAPSET, /* Wrapper around possibly blocking unix nss calls */ diff --git a/source3/nsswitch/winbindd_sid.c b/source3/nsswitch/winbindd_sid.c index 4a9e17e4c7..7af6373167 100644 --- a/source3/nsswitch/winbindd_sid.c +++ b/source3/nsswitch/winbindd_sid.c @@ -297,11 +297,12 @@ static void uid2sid_lookupname_recv(void *private_data, BOOL success, enum SID_NAME_USE type); static void uid2sid_idmap_set_mapping_recv(void *private_data, BOOL success); +static void uid2sid_recv(void *private_data, BOOL success, const char *sid); + void winbindd_uid_to_sid(struct winbindd_cli_state *state) { DOM_SID sid; NTSTATUS status; - struct uid2sid_state *uid2sid_state; DEBUG(3, ("[%5lu]: uid to sid %lu\n", (unsigned long)state->pid, (unsigned long)state->request.data.uid)); @@ -322,6 +323,25 @@ void winbindd_uid_to_sid(struct winbindd_cli_state *state) return; } + winbindd_uid2sid_async(state->mem_ctx, state->request.data.uid, uid2sid_recv, state); +} + +static void uid2sid_recv(void *private_data, BOOL success, const char *sid) +{ + struct winbindd_cli_state *state = private_data; + struct uid2sid_state *uid2sid_state; + + if (success) { + DEBUG(10,("uid2sid: uid %lu has sid %s\n", + (unsigned long)(state->request.data.uid), sid)); + fstrcpy(state->response.data.sid.sid, sid); + state->response.data.sid.type = SID_NAME_USER; + request_ok(state); + return; + } + + /* preexisitng mapping not found go on */ + if (is_in_uid_range(state->request.data.uid)) { /* This is winbind's, so we should better have succeeded * above. */ @@ -337,9 +357,6 @@ void winbindd_uid_to_sid(struct winbindd_cli_state *state) return; } - /* The only chance that this is correct is that winbind trusted - * domains only = yes, and the user exists in nss and the domain. */ - uid2sid_state = TALLOC_ZERO_P(state->mem_ctx, struct uid2sid_state); if (uid2sid_state == NULL) { DEBUG(0, ("talloc failed\n")); @@ -424,6 +441,8 @@ static void gid2sid_lookupname_recv(void *private_data, BOOL success, enum SID_NAME_USE type); static void gid2sid_idmap_set_mapping_recv(void *private_data, BOOL success); +static void gid2sid_recv(void *private_data, BOOL success, const char *sid); + void winbindd_gid_to_sid(struct winbindd_cli_state *state) { DOM_SID sid; @@ -449,6 +468,25 @@ void winbindd_gid_to_sid(struct winbindd_cli_state *state) return; } + winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, gid2sid_recv, state); +} + +static void gid2sid_recv(void *private_data, BOOL success, const char *sid) +{ + struct winbindd_cli_state *state = private_data; + struct gid2sid_state *gid2sid_state; + + if (success) { + DEBUG(10,("gid2sid: gid %lu has sid %s\n", + (unsigned long)(state->request.data.gid), sid)); + fstrcpy(state->response.data.sid.sid, sid); + state->response.data.sid.type = SID_NAME_DOM_GRP; + request_ok(state); + return; + } + + /* preexisitng mapping not found go on */ + if (is_in_gid_range(state->request.data.gid)) { /* This is winbind's, so we should better have succeeded * above. */ diff --git a/source3/nsswitch/winbindd_user.c b/source3/nsswitch/winbindd_user.c index 8a0ebbafa5..f08efa044f 100644 --- a/source3/nsswitch/winbindd_user.c +++ b/source3/nsswitch/winbindd_user.c @@ -380,15 +380,32 @@ static void getpwnam_name2sid_recv(void *private_data, BOOL success, winbindd_getpwsid(state, sid); } -/* Return a password structure given a uid number */ +static void getpwuid_recv(void *private_data, BOOL success, const char *sid) +{ + struct winbindd_cli_state *state = private_data; + DOM_SID user_sid; + + if (!success) { + DEBUG(10,("uid2sid_recv: uid [%lu] to sid mapping failed\n.", + (unsigned long)(state->request.data.uid))); + request_error(state); + return; + } + + DEBUG(10,("uid2sid_recv: uid %lu has sid %s\n", + (unsigned long)(state->request.data.uid), sid)); + string_to_sid(&user_sid, sid); + winbindd_getpwsid(state, &user_sid); +} + +/* Return a password structure given a uid number */ void winbindd_getpwuid(struct winbindd_cli_state *state) { DOM_SID user_sid; NTSTATUS status; /* Bug out if the uid isn't in the winbind range */ - if ((state->request.data.uid < server_state.uid_low ) || (state->request.data.uid > server_state.uid_high)) { request_error(state); @@ -401,14 +418,15 @@ void winbindd_getpwuid(struct winbindd_cli_state *state) status = idmap_uid_to_sid(&user_sid, state->request.data.uid, IDMAP_FLAG_QUERY_ONLY | IDMAP_FLAG_CACHE_ONLY); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(5, ("Could not find SID for uid %lu\n", - (unsigned long)state->request.data.uid)); - request_error(state); + if (NT_STATUS_IS_OK(status)) { + winbindd_getpwsid(state, &user_sid); return; } - winbindd_getpwsid(state, &user_sid); + DEBUG(10,("Could not find SID for uid %lu in the cache. Querying idmap backend\n", + (unsigned long)state->request.data.uid)); + + winbindd_uid2sid_async(state->mem_ctx, state->request.data.uid, getpwuid_recv, state); } /* -- cgit