diff options
Diffstat (limited to 'source3/winbindd')
38 files changed, 3898 insertions, 1240 deletions
diff --git a/source3/winbindd/wb_getpwsid.c b/source3/winbindd/wb_getpwsid.c new file mode 100644 index 0000000000..fc696cb9a1 --- /dev/null +++ b/source3/winbindd/wb_getpwsid.c @@ -0,0 +1,223 @@ +/* + Unix SMB/CIFS implementation. + async getpwsid + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" +#include "librpc/gen_ndr/cli_wbint.h" + +struct wb_getpwsid_state { + struct winbindd_domain *user_domain; + struct tevent_context *ev; + struct dom_sid sid; + struct winbind_userinfo *userinfo; + struct winbindd_pw *pw; +}; + +static void wb_getpwsid_queryuser_done(struct tevent_req *subreq); +static void wb_getpwsid_lookupsid_done(struct tevent_req *subreq); +static void wb_getpwsid_sid2uid_done(struct tevent_req *subreq); +static void wb_getpwsid_sid2gid_done(struct tevent_req *subreq); + +struct tevent_req *wb_getpwsid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const struct dom_sid *user_sid, + struct winbindd_pw *pw) +{ + struct tevent_req *req, *subreq; + struct wb_getpwsid_state *state; + + req = tevent_req_create(mem_ctx, &state, struct wb_getpwsid_state); + if (req == NULL) { + return NULL; + } + sid_copy(&state->sid, user_sid); + state->ev = ev; + state->pw = pw; + + state->user_domain = find_domain_from_sid_noinit(user_sid); + if (state->user_domain == NULL) { + tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER); + return tevent_req_post(req, ev); + } + + subreq = wb_queryuser_send(state, ev, &state->sid); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_getpwsid_queryuser_done, req); + return req; +} + +static void wb_getpwsid_queryuser_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_getpwsid_state *state = tevent_req_data( + req, struct wb_getpwsid_state); + NTSTATUS status; + + status = wb_queryuser_recv(subreq, state, &state->userinfo); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + + if ((state->userinfo->acct_name != NULL) + && (state->userinfo->acct_name[0] != '\0')) { + /* + * QueryUser got us a name, let's got directly to the + * sid2uid step + */ + subreq = wb_sid2uid_send(state, state->ev, + &state->userinfo->user_sid); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wb_getpwsid_sid2uid_done, req); + return; + } + + /* + * QueryUser didn't get us a name, do it via LSA. + */ + subreq = wb_lookupsid_send(state, state->ev, + &state->userinfo->user_sid); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wb_getpwsid_lookupsid_done, req); +} + +static void wb_getpwsid_lookupsid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_getpwsid_state *state = tevent_req_data( + req, struct wb_getpwsid_state); + NTSTATUS status; + enum lsa_SidType type; + const char *domain; + + status = wb_lookupsid_recv(subreq, state->userinfo, &type, &domain, + &state->userinfo->acct_name); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + subreq = wb_sid2uid_send(state, state->ev, &state->userinfo->user_sid); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wb_getpwsid_sid2uid_done, req); +} + +static void wb_getpwsid_sid2uid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_getpwsid_state *state = tevent_req_data( + req, struct wb_getpwsid_state); + NTSTATUS status; + + status = wb_sid2uid_recv(subreq, &state->pw->pw_uid); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + subreq = wb_sid2gid_send(state, state->ev, + &state->userinfo->group_sid); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wb_getpwsid_sid2gid_done, req); +} + +static void wb_getpwsid_sid2gid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_getpwsid_state *state = tevent_req_data( + req, struct wb_getpwsid_state); + NTSTATUS status; + char *username; + char *mapped_name; + + status = wb_sid2gid_recv(subreq, &state->pw->pw_gid); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + + username = talloc_strdup_lower(state, state->userinfo->acct_name); + if (tevent_req_nomem(username, req)) { + return; + } + + status = normalize_name_map(state, state->user_domain, username, + &mapped_name); + + if (NT_STATUS_IS_OK(status) + || NT_STATUS_EQUAL(status, NT_STATUS_FILE_RENAMED)) { + /* + * normalize_name_map did something + */ + fstrcpy(state->pw->pw_name, mapped_name); + TALLOC_FREE(mapped_name); + } else { + fill_domain_username(state->pw->pw_name, + state->user_domain->name, + username, True); + } + fstrcpy(state->pw->pw_passwd, "*"); + fstrcpy(state->pw->pw_gecos, state->userinfo->full_name); + + if (!fillup_pw_field(lp_template_homedir(), username, + state->user_domain->name, state->pw->pw_uid, + state->pw->pw_gid, state->userinfo->homedir, + state->pw->pw_dir)) { + DEBUG(5, ("Could not compose homedir\n")); + tevent_req_nterror(req, NT_STATUS_NO_MEMORY); + return; + } + + if (!fillup_pw_field(lp_template_shell(), state->pw->pw_name, + state->user_domain->name, state->pw->pw_uid, + state->pw->pw_gid, state->userinfo->shell, + state->pw->pw_shell)) { + DEBUG(5, ("Could not compose shell\n")); + tevent_req_nterror(req, NT_STATUS_NO_MEMORY); + return; + } + + tevent_req_done(req); +} + +NTSTATUS wb_getpwsid_recv(struct tevent_req *req) +{ + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + return NT_STATUS_OK; +} diff --git a/source3/winbindd/wb_gettoken.c b/source3/winbindd/wb_gettoken.c new file mode 100644 index 0000000000..26189e5a97 --- /dev/null +++ b/source3/winbindd/wb_gettoken.c @@ -0,0 +1,218 @@ +/* + Unix SMB/CIFS implementation. + async gettoken + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" +#include "librpc/gen_ndr/cli_wbint.h" + +struct wb_gettoken_state { + struct tevent_context *ev; + struct dom_sid usersid; + int num_sids; + struct dom_sid *sids; +}; + +static bool wb_add_rids_to_sids(TALLOC_CTX *mem_ctx, + int *pnum_sids, struct dom_sid **psids, + const struct dom_sid *domain_sid, + int num_rids, uint32_t *rids); + +static void wb_gettoken_gotgroups(struct tevent_req *subreq); +static void wb_gettoken_gotlocalgroups(struct tevent_req *subreq); +static void wb_gettoken_gotbuiltins(struct tevent_req *subreq); + +struct tevent_req *wb_gettoken_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const struct dom_sid *sid) +{ + struct tevent_req *req, *subreq; + struct wb_gettoken_state *state; + struct winbindd_domain *domain; + + req = tevent_req_create(mem_ctx, &state, struct wb_gettoken_state); + if (req == NULL) { + return NULL; + } + sid_copy(&state->usersid, sid); + state->ev = ev; + + domain = find_domain_from_sid_noinit(sid); + if (domain == NULL) { + DEBUG(5, ("Could not find domain from SID %s\n", + sid_string_dbg(sid))); + tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER); + return tevent_req_post(req, ev); + } + + subreq = wb_lookupusergroups_send(state, ev, domain, &state->usersid); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_gettoken_gotgroups, req); + return req; +} + +static void wb_gettoken_gotgroups(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_gettoken_state *state = tevent_req_data( + req, struct wb_gettoken_state); + struct dom_sid *sids; + struct winbindd_domain *domain; + NTSTATUS status; + + status = wb_lookupusergroups_recv(subreq, state, &state->num_sids, + &state->sids); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + + sids = talloc_realloc(state, state->sids, struct dom_sid, + state->num_sids + 1); + if (tevent_req_nomem(sids, req)) { + return; + } + memmove(&sids[1], &sids[0], state->num_sids * sizeof(sids[0])); + sid_copy(&sids[0], &state->usersid); + state->num_sids += 1; + state->sids = sids; + + /* + * Expand our domain's aliases + */ + domain = find_our_domain(); + if (domain == NULL) { + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return; + } + + subreq = wb_lookupuseraliases_send(state, state->ev, domain, + state->num_sids, state->sids); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wb_gettoken_gotlocalgroups, req); +} + +static void wb_gettoken_gotlocalgroups(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_gettoken_state *state = tevent_req_data( + req, struct wb_gettoken_state); + uint32_t num_rids; + uint32_t *rids; + struct winbindd_domain *domain; + NTSTATUS status; + + status = wb_lookupuseraliases_recv(subreq, state, &num_rids, &rids); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + domain = find_our_domain(); + if (!wb_add_rids_to_sids(state, &state->num_sids, &state->sids, + &domain->sid, num_rids, rids)) { + tevent_req_nterror(req, NT_STATUS_NO_MEMORY); + return; + } + TALLOC_FREE(rids); + + /* + * Now expand the builtin groups + */ + + domain = find_builtin_domain(); + if (domain == NULL) { + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return; + } + + subreq = wb_lookupuseraliases_send(state, state->ev, domain, + state->num_sids, state->sids); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wb_gettoken_gotbuiltins, req); +} + +static void wb_gettoken_gotbuiltins(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_gettoken_state *state = tevent_req_data( + req, struct wb_gettoken_state); + uint32_t num_rids; + uint32_t *rids; + NTSTATUS status; + + status = wb_lookupuseraliases_recv(subreq, state, &num_rids, &rids); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + if (!wb_add_rids_to_sids(state, &state->num_sids, &state->sids, + &global_sid_Builtin, num_rids, rids)) { + tevent_req_nterror(req, NT_STATUS_NO_MEMORY); + return; + } + tevent_req_done(req); +} + +NTSTATUS wb_gettoken_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + int *num_sids, struct dom_sid **sids) +{ + struct wb_gettoken_state *state = tevent_req_data( + req, struct wb_gettoken_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + *num_sids = state->num_sids; + *sids = talloc_move(mem_ctx, &state->sids); + return NT_STATUS_OK; +} + +static bool wb_add_rids_to_sids(TALLOC_CTX *mem_ctx, + int *pnum_sids, struct dom_sid **psids, + const struct dom_sid *domain_sid, + int num_rids, uint32_t *rids) +{ + struct dom_sid *sids; + int i; + + sids = talloc_realloc(mem_ctx, *psids, struct dom_sid, + *pnum_sids + num_rids); + if (sids == NULL) { + return false; + } + for (i=0; i<num_rids; i++) { + sid_compose(&sids[i+*pnum_sids], domain_sid, rids[i]); + } + + *pnum_sids += num_rids; + *psids = sids; + return true; +} diff --git a/source3/winbindd/wb_gid2sid.c b/source3/winbindd/wb_gid2sid.c new file mode 100644 index 0000000000..a0ae850ef8 --- /dev/null +++ b/source3/winbindd/wb_gid2sid.c @@ -0,0 +1,119 @@ +/* + Unix SMB/CIFS implementation. + async gid2sid + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" +#include "librpc/gen_ndr/cli_wbint.h" + +struct wb_gid2sid_state { + struct tevent_context *ev; + char *dom_name; + struct dom_sid sid; +}; + +static void wb_gid2sid_done(struct tevent_req *subreq); + +struct tevent_req *wb_gid2sid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + gid_t gid) +{ + struct tevent_req *req, *subreq; + struct wb_gid2sid_state *state; + struct winbindd_domain *domain; + struct winbindd_child *child; + bool expired; + + req = tevent_req_create(mem_ctx, &state, struct wb_gid2sid_state); + if (req == NULL) { + return NULL; + } + + if (winbindd_use_idmap_cache() + && idmap_cache_find_gid2sid(gid, &state->sid, &expired)) { + + DEBUG(10, ("idmap_cache_find_gid2sid found %d%s\n", + (int)gid, expired ? " (expired)": "")); + + if (!expired || idmap_is_offline()) { + if (is_null_sid(&state->sid)) { + tevent_req_nterror(req, + NT_STATUS_NONE_MAPPED); + } else { + tevent_req_done(req); + } + return tevent_req_post(req, ev); + } + } + + state->dom_name = NULL; + + for (domain = domain_list(); domain != NULL; domain = domain->next) { + if (domain->have_idmap_config + && (gid >= domain->id_range_low) + && (gid <= domain->id_range_high)) { + state->dom_name = domain->name; + break; + } + } + + child = idmap_child(); + + subreq = rpccli_wbint_Gid2Sid_send( + state, ev, child->rpccli, state->dom_name, + gid, &state->sid); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_gid2sid_done, req); + return req; +} + +static void wb_gid2sid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_gid2sid_state *state = tevent_req_data( + req, struct wb_gid2sid_state); + NTSTATUS status, result; + + status = rpccli_wbint_Gid2Sid_recv(subreq, state, &result); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + if (!NT_STATUS_IS_OK(result)) { + tevent_req_nterror(req, result); + return; + } + tevent_req_done(req); +} + +NTSTATUS wb_gid2sid_recv(struct tevent_req *req, struct dom_sid *sid) +{ + struct wb_gid2sid_state *state = tevent_req_data( + req, struct wb_gid2sid_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + sid_copy(sid, &state->sid); + return NT_STATUS_OK; +} diff --git a/source3/winbindd/wb_lookupname.c b/source3/winbindd/wb_lookupname.c new file mode 100644 index 0000000000..d4e9b9ae6c --- /dev/null +++ b/source3/winbindd/wb_lookupname.c @@ -0,0 +1,104 @@ +/* + Unix SMB/CIFS implementation. + async lookupname + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" +#include "librpc/gen_ndr/cli_wbint.h" + +struct wb_lookupname_state { + struct dom_sid sid; + enum lsa_SidType type; +}; + +static void wb_lookupname_done(struct tevent_req *subreq); + +struct tevent_req *wb_lookupname_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const char *dom_name, const char *name, + uint32_t flags) +{ + struct tevent_req *req, *subreq; + struct wb_lookupname_state *state; + struct winbindd_domain *domain; + NTSTATUS status; + + req = tevent_req_create(mem_ctx, &state, struct wb_lookupname_state); + if (req == NULL) { + return NULL; + } + + domain = find_lookup_domain_from_name(dom_name); + if (domain == NULL) { + DEBUG(5, ("Could not find domain for %s\n", dom_name)); + tevent_req_nterror(req, NT_STATUS_NONE_MAPPED); + return tevent_req_post(req, ev); + } + + status = wcache_name_to_sid(domain, dom_name, name, + &state->sid, &state->type); + if (NT_STATUS_IS_OK(status)) { + tevent_req_done(req); + return tevent_req_post(req, ev); + } + + subreq = rpccli_wbint_LookupName_send( + state, ev, domain->child.rpccli, dom_name, name, flags, + &state->type, &state->sid); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_lookupname_done, req); + return req; +} + +static void wb_lookupname_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_lookupname_state *state = tevent_req_data( + req, struct wb_lookupname_state); + NTSTATUS status, result; + + status = rpccli_wbint_LookupName_recv(subreq, state, &result); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + if (!NT_STATUS_IS_OK(result)) { + tevent_req_nterror(req, result); + return; + } + tevent_req_done(req); +} + +NTSTATUS wb_lookupname_recv(struct tevent_req *req, struct dom_sid *sid, + enum lsa_SidType *type) +{ + struct wb_lookupname_state *state = tevent_req_data( + req, struct wb_lookupname_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + sid_copy(sid, &state->sid); + *type = state->type; + return NT_STATUS_OK; +} diff --git a/source3/winbindd/wb_lookupsid.c b/source3/winbindd/wb_lookupsid.c new file mode 100644 index 0000000000..f258828048 --- /dev/null +++ b/source3/winbindd/wb_lookupsid.c @@ -0,0 +1,132 @@ +/* + Unix SMB/CIFS implementation. + async lookupsid + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" +#include "librpc/gen_ndr/cli_wbint.h" + +struct wb_lookupsid_state { + struct tevent_context *ev; + struct winbindd_domain *lookup_domain; + struct dom_sid sid; + enum lsa_SidType type; + const char *domname; + const char *name; +}; + +static void wb_lookupsid_done(struct tevent_req *subreq); + +struct tevent_req *wb_lookupsid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const struct dom_sid *sid) +{ + struct tevent_req *req, *subreq; + struct wb_lookupsid_state *state; + char *dom_name, *name; + NTSTATUS status; + + req = tevent_req_create(mem_ctx, &state, struct wb_lookupsid_state); + if (req == NULL) { + return NULL; + } + sid_copy(&state->sid, sid); + state->ev = ev; + + state->lookup_domain = find_lookup_domain_from_sid(sid); + if (state->lookup_domain == NULL) { + DEBUG(5, ("Could not find domain for sid %s\n", + sid_string_dbg(sid))); + tevent_req_nterror(req, NT_STATUS_NONE_MAPPED); + return tevent_req_post(req, ev); + } + + status = wcache_sid_to_name(state->lookup_domain, sid, state, + &dom_name, &name, &state->type); + if (NT_STATUS_IS_OK(status)) { + state->domname = dom_name; + state->name = name; + tevent_req_done(req); + return tevent_req_post(req, ev); + } + + subreq = rpccli_wbint_LookupSid_send( + state, ev, state->lookup_domain->child.rpccli, + &state->sid, &state->type, &state->domname, &state->name); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_lookupsid_done, req); + return req; +} + +static void wb_lookupsid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_lookupsid_state *state = tevent_req_data( + req, struct wb_lookupsid_state); + struct winbindd_domain *forest_root; + NTSTATUS status, result; + + status = rpccli_wbint_LookupSid_recv(subreq, state, &result); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + if (NT_STATUS_IS_OK(result)) { + tevent_req_done(req); + return; + } + + /* + * Let's try the forest root + */ + forest_root = find_root_domain(); + if ((forest_root == NULL) || (forest_root == state->lookup_domain)) { + tevent_req_nterror(req, result); + return; + } + state->lookup_domain = forest_root; + + subreq = rpccli_wbint_LookupSid_send( + state, state->ev, state->lookup_domain->child.rpccli, + &state->sid, &state->type, &state->domname, &state->name); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wb_lookupsid_done, req); +} + +NTSTATUS wb_lookupsid_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + enum lsa_SidType *type, const char **domain, + const char **name) +{ + struct wb_lookupsid_state *state = tevent_req_data( + req, struct wb_lookupsid_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + *type = state->type; + *domain = talloc_move(mem_ctx, &state->domname); + *name = talloc_move(mem_ctx, &state->name); + return NT_STATUS_OK; +} diff --git a/source3/winbindd/wb_lookupuseraliases.c b/source3/winbindd/wb_lookupuseraliases.c new file mode 100644 index 0000000000..e2e5e2da08 --- /dev/null +++ b/source3/winbindd/wb_lookupuseraliases.c @@ -0,0 +1,101 @@ +/* + Unix SMB/CIFS implementation. + async lookupuseraliases + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" +#include "librpc/gen_ndr/cli_wbint.h" + +struct wb_lookupuseraliases_state { + struct tevent_context *ev; + struct wbint_SidArray sids; + struct wbint_RidArray rids; +}; + +static void wb_lookupuseraliases_done(struct tevent_req *subreq); + +struct tevent_req *wb_lookupuseraliases_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_domain *domain, + int num_sids, + const struct dom_sid *sids) +{ + struct tevent_req *req, *subreq; + struct wb_lookupuseraliases_state *state; + NTSTATUS status; + + req = tevent_req_create(mem_ctx, &state, + struct wb_lookupuseraliases_state); + if (req == NULL) { + return NULL; + } + state->sids.num_sids = num_sids; + state->sids.sids = CONST_DISCARD(struct dom_sid *, sids); + + status = wcache_lookup_useraliases(domain, state, num_sids, sids, + &state->rids.num_rids, + &state->rids.rids); + if (NT_STATUS_IS_OK(status)) { + tevent_req_done(req); + return tevent_req_post(req, ev); + } + + subreq = rpccli_wbint_LookupUserAliases_send( + state, ev, domain->child.rpccli, &state->sids, &state->rids); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_lookupuseraliases_done, req); + return req; +} + +static void wb_lookupuseraliases_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_lookupuseraliases_state *state = tevent_req_data( + req, struct wb_lookupuseraliases_state); + NTSTATUS status, result; + + status = rpccli_wbint_LookupUserAliases_recv(subreq, state, &result); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + if (!NT_STATUS_IS_OK(result)) { + tevent_req_nterror(req, result); + return; + } + tevent_req_done(req); +} + +NTSTATUS wb_lookupuseraliases_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + uint32_t *num_aliases, uint32_t **aliases) +{ + struct wb_lookupuseraliases_state *state = tevent_req_data( + req, struct wb_lookupuseraliases_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + *num_aliases = state->rids.num_rids; + *aliases = talloc_move(mem_ctx, &state->rids.rids); + return NT_STATUS_OK; +} diff --git a/source3/winbindd/wb_lookupusergroups.c b/source3/winbindd/wb_lookupusergroups.c new file mode 100644 index 0000000000..4e96b45c57 --- /dev/null +++ b/source3/winbindd/wb_lookupusergroups.c @@ -0,0 +1,99 @@ +/* + Unix SMB/CIFS implementation. + async lookupusergroups + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" +#include "librpc/gen_ndr/cli_wbint.h" + +struct wb_lookupusergroups_state { + struct tevent_context *ev; + struct dom_sid sid; + struct wbint_SidArray sids; +}; + +static void wb_lookupusergroups_done(struct tevent_req *subreq); + +struct tevent_req *wb_lookupusergroups_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_domain *domain, + const struct dom_sid *sid) +{ + struct tevent_req *req, *subreq; + struct wb_lookupusergroups_state *state; + NTSTATUS status; + + req = tevent_req_create(mem_ctx, &state, + struct wb_lookupusergroups_state); + if (req == NULL) { + return NULL; + } + sid_copy(&state->sid, sid); + + status = wcache_lookup_usergroups(domain, state, sid, + &state->sids.num_sids, + &state->sids.sids); + if (NT_STATUS_IS_OK(status)) { + tevent_req_done(req); + return tevent_req_post(req, ev); + } + + subreq = rpccli_wbint_LookupUserGroups_send( + state, ev, domain->child.rpccli, &state->sid, &state->sids); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_lookupusergroups_done, req); + return req; +} + +static void wb_lookupusergroups_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_lookupusergroups_state *state = tevent_req_data( + req, struct wb_lookupusergroups_state); + NTSTATUS status, result; + + status = rpccli_wbint_LookupUserGroups_recv(subreq, state, &result); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + if (!NT_STATUS_IS_OK(result)) { + tevent_req_nterror(req, result); + return; + } + tevent_req_done(req); +} + +NTSTATUS wb_lookupusergroups_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + int *num_sids, struct dom_sid **sids) +{ + struct wb_lookupusergroups_state *state = tevent_req_data( + req, struct wb_lookupusergroups_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + *num_sids = state->sids.num_sids; + *sids = talloc_move(mem_ctx, &state->sids.sids); + return NT_STATUS_OK; +} diff --git a/source3/winbindd/wb_queryuser.c b/source3/winbindd/wb_queryuser.c new file mode 100644 index 0000000000..27b8d29951 --- /dev/null +++ b/source3/winbindd/wb_queryuser.c @@ -0,0 +1,121 @@ +/* + Unix SMB/CIFS implementation. + async queryuser + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" +#include "librpc/gen_ndr/cli_wbint.h" + +struct wb_queryuser_state { + struct dom_sid sid; + struct wbint_userinfo info; +}; + +static void wb_queryuser_done(struct tevent_req *subreq); + +struct tevent_req *wb_queryuser_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const struct dom_sid *user_sid) +{ + struct tevent_req *req, *subreq; + struct wb_queryuser_state *state; + struct winbindd_domain *domain; + struct winbind_userinfo info; + NTSTATUS status; + + req = tevent_req_create(mem_ctx, &state, struct wb_queryuser_state); + if (req == NULL) { + return NULL; + } + sid_copy(&state->sid, user_sid); + + domain = find_domain_from_sid_noinit(user_sid); + if (domain == NULL) { + tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER); + return tevent_req_post(req, ev); + } + + status = wcache_query_user(domain, state, &state->sid, &info); + if (NT_STATUS_IS_OK(status)) { + state->info.acct_name = info.acct_name; + state->info.full_name = info.full_name; + state->info.homedir = info.homedir; + state->info.shell = info.shell; + state->info.primary_gid = info.primary_gid; + sid_copy(&state->info.user_sid, &info.user_sid); + sid_copy(&state->info.group_sid, &info.group_sid); + tevent_req_done(req); + return tevent_req_post(req, ev); + } + + subreq = rpccli_wbint_QueryUser_send(state, ev, domain->child.rpccli, + &state->sid, &state->info); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_queryuser_done, req); + return req; +} + +static void wb_queryuser_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_queryuser_state *state = tevent_req_data( + req, struct wb_queryuser_state); + NTSTATUS status, result; + + status = rpccli_wbint_QueryUser_recv(subreq, state, &result); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + if (!NT_STATUS_IS_OK(result)) { + tevent_req_nterror(req, result); + return; + } + tevent_req_done(req); +} + +NTSTATUS wb_queryuser_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + struct winbind_userinfo **pinfo) +{ + struct wb_queryuser_state *state = tevent_req_data( + req, struct wb_queryuser_state); + struct winbind_userinfo *info; + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + + info = talloc(mem_ctx, struct winbind_userinfo); + if (info == NULL) { + return NT_STATUS_NO_MEMORY; + } + info->acct_name = talloc_move(info, &state->info.acct_name); + info->full_name = talloc_move(info, &state->info.full_name); + info->homedir = talloc_move(info, &state->info.homedir); + info->shell = talloc_move(info, &state->info.shell); + info->primary_gid = state->info.primary_gid; + sid_copy(&info->user_sid, &state->info.user_sid); + sid_copy(&info->group_sid, &state->info.group_sid); + *pinfo = info; + return NT_STATUS_OK; +} diff --git a/source3/winbindd/wb_sid2gid.c b/source3/winbindd/wb_sid2gid.c new file mode 100644 index 0000000000..a578746ea2 --- /dev/null +++ b/source3/winbindd/wb_sid2gid.c @@ -0,0 +1,170 @@ +/* + Unix SMB/CIFS implementation. + async sid2gid + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" +#include "librpc/gen_ndr/cli_wbint.h" + +struct wb_sid2gid_state { + struct tevent_context *ev; + struct dom_sid sid; + char *dom_name; + uint64 gid64; + gid_t gid; +}; + +static void wb_sid2gid_lookup_done(struct tevent_req *subreq); +static void wb_sid2gid_done(struct tevent_req *subreq); + + +struct tevent_req *wb_sid2gid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const struct dom_sid *sid) +{ + struct tevent_req *req, *subreq; + struct wb_sid2gid_state *state; + bool expired; + + req = tevent_req_create(mem_ctx, &state, struct wb_sid2gid_state); + if (req == NULL) { + return NULL; + } + sid_copy(&state->sid, sid); + state->ev = ev; + + if (winbindd_use_idmap_cache() + && idmap_cache_find_sid2gid(sid, &state->gid, &expired)) { + + DEBUG(10, ("idmap_cache_find_sid2gid found %d%s\n", + (int)state->gid, expired ? " (expired)": "")); + + if (!expired || IS_DOMAIN_OFFLINE(find_our_domain())) { + if (state->gid == -1) { + tevent_req_nterror(req, NT_STATUS_NONE_MAPPED); + } else { + tevent_req_done(req); + } + return tevent_req_post(req, ev); + } + } + + /* + * We need to make sure the sid is of the right type to not flood + * idmap with wrong entries + */ + + subreq = wb_lookupsid_send(state, ev, &state->sid); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_sid2gid_lookup_done, req); + return req; +} + +static void wb_sid2gid_lookup_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_sid2gid_state *state = tevent_req_data( + req, struct wb_sid2gid_state); + struct winbindd_domain *domain; + const char *domname; + const char *name; + enum lsa_SidType type; + NTSTATUS status; + struct winbindd_child *child; + + status = wb_lookupsid_recv(subreq, talloc_tos(), &type, &domname, + &name); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + + if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) + && (type != SID_NAME_WKN_GRP)) { + DEBUG(5, ("Sid %s is not a group.\n", + sid_string_dbg(&state->sid))); + /* + * We have to set the cache ourselves here, the child + * which is normally responsible was not queried yet. + */ + idmap_cache_set_sid2gid(&state->sid, -1); + tevent_req_nterror(req, NT_STATUS_INVALID_SID); + return; + } + + domain = find_domain_from_sid_noinit(&state->sid); + + /* + * TODO: Issue a gettrustinfo here in case we don't have "domain" yet? + */ + + if ((domain != NULL) && domain->have_idmap_config) { + state->dom_name = domain->name; + } else { + state->dom_name = NULL; + } + + child = idmap_child(); + + subreq = rpccli_wbint_Sid2Gid_send(state, state->ev, child->rpccli, + state->dom_name, &state->sid, + &state->gid64); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wb_sid2gid_done, req); +} + +static void wb_sid2gid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_sid2gid_state *state = tevent_req_data( + req, struct wb_sid2gid_state); + NTSTATUS status, result; + + status = rpccli_wbint_Sid2Gid_recv(subreq, state, &result); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + if (!NT_STATUS_IS_OK(result)) { + tevent_req_nterror(req, result); + return; + } + + state->gid = state->gid64; + tevent_req_done(req); +} + +NTSTATUS wb_sid2gid_recv(struct tevent_req *req, gid_t *gid) +{ + struct wb_sid2gid_state *state = tevent_req_data( + req, struct wb_sid2gid_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + *gid = state->gid; + return NT_STATUS_OK; +} diff --git a/source3/winbindd/wb_sid2uid.c b/source3/winbindd/wb_sid2uid.c new file mode 100644 index 0000000000..abfe257bfa --- /dev/null +++ b/source3/winbindd/wb_sid2uid.c @@ -0,0 +1,168 @@ +/* + Unix SMB/CIFS implementation. + async sid2uid + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" +#include "librpc/gen_ndr/cli_wbint.h" + +struct wb_sid2uid_state { + struct tevent_context *ev; + struct dom_sid sid; + char *dom_name; + uint64 uid64; + uid_t uid; +}; + +static void wb_sid2uid_lookup_done(struct tevent_req *subreq); +static void wb_sid2uid_done(struct tevent_req *subreq); + +struct tevent_req *wb_sid2uid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const struct dom_sid *sid) +{ + struct tevent_req *req, *subreq; + struct wb_sid2uid_state *state; + bool expired; + + req = tevent_req_create(mem_ctx, &state, struct wb_sid2uid_state); + if (req == NULL) { + return NULL; + } + sid_copy(&state->sid, sid); + state->ev = ev; + + if (winbindd_use_idmap_cache() + && idmap_cache_find_sid2uid(sid, &state->uid, &expired)) { + + DEBUG(10, ("idmap_cache_find_sid2uid found %d%s\n", + (int)state->uid, expired ? " (expired)": "")); + + if (!expired || IS_DOMAIN_OFFLINE(find_our_domain())) { + if (state->uid == -1) { + tevent_req_nterror(req, NT_STATUS_NONE_MAPPED); + } else { + tevent_req_done(req); + } + return tevent_req_post(req, ev); + } + } + + /* + * We need to make sure the sid is of the right type to not flood + * idmap with wrong entries + */ + + subreq = wb_lookupsid_send(state, ev, &state->sid); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_sid2uid_lookup_done, req); + return req; +} + +static void wb_sid2uid_lookup_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_sid2uid_state *state = tevent_req_data( + req, struct wb_sid2uid_state); + struct winbindd_domain *domain; + const char *domname; + const char *name; + enum lsa_SidType type; + NTSTATUS status; + struct winbindd_child *child; + + status = wb_lookupsid_recv(subreq, talloc_tos(), &type, &domname, + &name); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + + if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER)) { + DEBUG(5, ("Sid %s is not a user or a computer.\n", + sid_string_dbg(&state->sid))); + /* + * We have to set the cache ourselves here, the child + * which is normally responsible was not queried yet. + */ + idmap_cache_set_sid2uid(&state->sid, -1); + tevent_req_nterror(req, NT_STATUS_INVALID_SID); + return; + } + + domain = find_domain_from_sid_noinit(&state->sid); + + /* + * TODO: Issue a gettrustinfo here in case we don't have "domain" yet? + */ + + if ((domain != NULL) && domain->have_idmap_config) { + state->dom_name = domain->name; + } else { + state->dom_name = NULL; + } + + child = idmap_child(); + + subreq = rpccli_wbint_Sid2Uid_send(state, state->ev, child->rpccli, + state->dom_name, &state->sid, + &state->uid64); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wb_sid2uid_done, req); +} + +static void wb_sid2uid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_sid2uid_state *state = tevent_req_data( + req, struct wb_sid2uid_state); + NTSTATUS status, result; + + status = rpccli_wbint_Sid2Uid_recv(subreq, state, &result); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + if (!NT_STATUS_IS_OK(result)) { + tevent_req_nterror(req, result); + return; + } + + state->uid = state->uid64; + tevent_req_done(req); +} + +NTSTATUS wb_sid2uid_recv(struct tevent_req *req, uid_t *uid) +{ + struct wb_sid2uid_state *state = tevent_req_data( + req, struct wb_sid2uid_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + *uid = state->uid; + return NT_STATUS_OK; +} diff --git a/source3/winbindd/wb_uid2sid.c b/source3/winbindd/wb_uid2sid.c new file mode 100644 index 0000000000..18ef3b214a --- /dev/null +++ b/source3/winbindd/wb_uid2sid.c @@ -0,0 +1,119 @@ +/* + Unix SMB/CIFS implementation. + async uid2sid + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" +#include "librpc/gen_ndr/cli_wbint.h" + +struct wb_uid2sid_state { + struct tevent_context *ev; + char *dom_name; + struct dom_sid sid; +}; + +static void wb_uid2sid_done(struct tevent_req *subreq); + +struct tevent_req *wb_uid2sid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + uid_t uid) +{ + struct tevent_req *req, *subreq; + struct wb_uid2sid_state *state; + struct winbindd_domain *domain; + struct winbindd_child *child; + bool expired; + + req = tevent_req_create(mem_ctx, &state, struct wb_uid2sid_state); + if (req == NULL) { + return NULL; + } + + if (winbindd_use_idmap_cache() + && idmap_cache_find_uid2sid(uid, &state->sid, &expired)) { + + DEBUG(10, ("idmap_cache_find_uid2sid found %d%s\n", + (int)uid, expired ? " (expired)": "")); + + if (!expired || idmap_is_offline()) { + if (is_null_sid(&state->sid)) { + tevent_req_nterror(req, + NT_STATUS_NONE_MAPPED); + } else { + tevent_req_done(req); + } + return tevent_req_post(req, ev); + } + } + + state->dom_name = NULL; + + for (domain = domain_list(); domain != NULL; domain = domain->next) { + if (domain->have_idmap_config + && (uid >= domain->id_range_low) + && (uid <= domain->id_range_high)) { + state->dom_name = domain->name; + break; + } + } + + child = idmap_child(); + + subreq = rpccli_wbint_Uid2Sid_send( + state, ev, child->rpccli, state->dom_name, + uid, &state->sid); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_uid2sid_done, req); + return req; +} + +static void wb_uid2sid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_uid2sid_state *state = tevent_req_data( + req, struct wb_uid2sid_state); + NTSTATUS status, result; + + status = rpccli_wbint_Uid2Sid_recv(subreq, state, &result); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + if (!NT_STATUS_IS_OK(result)) { + tevent_req_nterror(req, result); + return; + } + tevent_req_done(req); +} + +NTSTATUS wb_uid2sid_recv(struct tevent_req *req, struct dom_sid *sid) +{ + struct wb_uid2sid_state *state = tevent_req_data( + req, struct wb_uid2sid_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + sid_copy(sid, &state->sid); + return NT_STATUS_OK; +} diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c index 4b6ebd2c42..348816b39c 100644 --- a/source3/winbindd/winbindd.c +++ b/source3/winbindd/winbindd.c @@ -427,20 +427,11 @@ static struct winbindd_dispatch_table { /* User functions */ - { WINBINDD_GETPWNAM, winbindd_getpwnam, "GETPWNAM" }, - { WINBINDD_GETPWUID, winbindd_getpwuid, "GETPWUID" }, - { WINBINDD_GETPWSID, winbindd_getpwsid, "GETPWSID" }, - { WINBINDD_SETPWENT, winbindd_setpwent, "SETPWENT" }, { WINBINDD_ENDPWENT, winbindd_endpwent, "ENDPWENT" }, { WINBINDD_GETPWENT, winbindd_getpwent, "GETPWENT" }, - { WINBINDD_GETGROUPS, winbindd_getgroups, "GETGROUPS" }, { WINBINDD_GETUSERSIDS, winbindd_getusersids, "GETUSERSIDS" }, - { WINBINDD_GETUSERDOMGROUPS, winbindd_getuserdomgroups, - "GETUSERDOMGROUPS" }, - { WINBINDD_GETSIDALIASES, winbindd_getsidaliases, - "LOOKUPUSERALIASES" }, /* Group functions */ @@ -469,16 +460,10 @@ static struct winbindd_dispatch_table { /* SID related functions */ - { WINBINDD_LOOKUPSID, winbindd_lookupsid, "LOOKUPSID" }, - { WINBINDD_LOOKUPNAME, winbindd_lookupname, "LOOKUPNAME" }, { WINBINDD_LOOKUPRIDS, winbindd_lookuprids, "LOOKUPRIDS" }, /* Lookup related functions */ - { WINBINDD_SID_TO_UID, winbindd_sid_to_uid, "SID_TO_UID" }, - { WINBINDD_SID_TO_GID, winbindd_sid_to_gid, "SID_TO_GID" }, - { WINBINDD_UID_TO_SID, winbindd_uid_to_sid, "UID_TO_SID" }, - { WINBINDD_GID_TO_SID, winbindd_gid_to_sid, "GID_TO_SID" }, { WINBINDD_ALLOCATE_UID, winbindd_allocate_uid, "ALLOCATE_UID" }, { WINBINDD_ALLOCATE_GID, winbindd_allocate_gid, "ALLOCATE_GID" }, { WINBINDD_SET_MAPPING, winbindd_set_mapping, "SET_MAPPING" }, @@ -488,7 +473,6 @@ static struct winbindd_dispatch_table { /* Miscellaneous */ { WINBINDD_CHECK_MACHACC, winbindd_check_machine_acct, "CHECK_MACHACC" }, - { WINBINDD_PING, winbindd_ping, "PING" }, { WINBINDD_INFO, winbindd_info, "INFO" }, { WINBINDD_INTERFACE_VERSION, winbindd_interface_version, "INTERFACE_VERSION" }, @@ -526,6 +510,30 @@ struct winbindd_async_dispatch_table { static struct winbindd_async_dispatch_table async_nonpriv_table[] = { { WINBINDD_PING, "PING", wb_ping_send, wb_ping_recv }, + { WINBINDD_LOOKUPSID, "LOOKUPSID", + winbindd_lookupsid_send, winbindd_lookupsid_recv }, + { WINBINDD_LOOKUPNAME, "LOOKUPNAME", + winbindd_lookupname_send, winbindd_lookupname_recv }, + { WINBINDD_SID_TO_UID, "SID_TO_UID", + winbindd_sid_to_uid_send, winbindd_sid_to_uid_recv }, + { WINBINDD_SID_TO_GID, "SID_TO_GID", + winbindd_sid_to_gid_send, winbindd_sid_to_gid_recv }, + { WINBINDD_UID_TO_SID, "UID_TO_SID", + winbindd_uid_to_sid_send, winbindd_uid_to_sid_recv }, + { WINBINDD_GID_TO_SID, "GID_TO_SID", + winbindd_gid_to_sid_send, winbindd_gid_to_sid_recv }, + { WINBINDD_GETPWSID, "GETPWSID", + winbindd_getpwsid_send, winbindd_getpwsid_recv }, + { WINBINDD_GETPWNAM, "GETPWNAM", + winbindd_getpwnam_send, winbindd_getpwnam_recv }, + { WINBINDD_GETPWUID, "GETPWUID", + winbindd_getpwuid_send, winbindd_getpwuid_recv }, + { WINBINDD_GETSIDALIASES, "GETSIDALIASES", + winbindd_getsidaliases_send, winbindd_getsidaliases_recv }, + { WINBINDD_GETUSERDOMGROUPS, "GETUSERDOMGROUPS", + winbindd_getuserdomgroups_send, winbindd_getuserdomgroups_recv }, + { WINBINDD_GETGROUPS, "GETGROUPS", + winbindd_getgroups_send, winbindd_getgroups_recv }, { 0, NULL, NULL, NULL } }; diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h index 8f0db44617..baab7fd11a 100644 --- a/source3/winbindd/winbindd.h +++ b/source3/winbindd/winbindd.h @@ -138,6 +138,7 @@ struct winbindd_child { int sock; struct tevent_queue *queue; + struct rpc_pipe_client *rpccli; struct timed_event *lockout_policy_event; struct timed_event *machine_password_change_event; diff --git a/source3/winbindd/winbindd_async.c b/source3/winbindd/winbindd_async.c index f53875f617..094602160d 100644 --- a/source3/winbindd/winbindd_async.c +++ b/source3/winbindd/winbindd_async.c @@ -632,25 +632,32 @@ bool print_sidlist(TALLOC_CTX *mem_ctx, const DOM_SID *sids, return True; } -bool parse_sidlist(TALLOC_CTX *mem_ctx, char *sidstr, +bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr, DOM_SID **sids, size_t *num_sids) { - char *p, *q; + const char *p, *q; p = sidstr; if (p == NULL) return False; while (p[0] != '\0') { + fstring tmp; + size_t sidlen; DOM_SID sid; q = strchr(p, '\n'); if (q == NULL) { DEBUG(0, ("Got invalid sidstr: %s\n", p)); return False; } - *q = '\0'; + sidlen = PTR_DIFF(q, p); + if (sidlen >= sizeof(tmp)-1) { + return false; + } + memcpy(tmp, p, sidlen); + tmp[sidlen] = '\0'; q += 1; - if (!string_to_sid(&sid, p)) { + if (!string_to_sid(&sid, tmp)) { DEBUG(0, ("Could not parse sid %s\n", p)); return False; } diff --git a/source3/winbindd/winbindd_cache.c b/source3/winbindd/winbindd_cache.c index bec2a714c8..5dfdc5ae29 100644 --- a/source3/winbindd/winbindd_cache.c +++ b/source3/winbindd/winbindd_cache.c @@ -1605,28 +1605,31 @@ skip_save: return status; } -/* convert a single name to a sid in a domain */ -static NTSTATUS name_to_sid(struct winbindd_domain *domain, - TALLOC_CTX *mem_ctx, +NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain, const char *domain_name, const char *name, - uint32_t flags, - DOM_SID *sid, + struct dom_sid *sid, enum lsa_SidType *type) { struct winbind_cache *cache = get_cache(domain); - struct cache_entry *centry = NULL; + struct cache_entry *centry; NTSTATUS status; - fstring uname; + char *uname; - if (!cache->tdb) - goto do_query; + if (cache->tdb == NULL) { + return NT_STATUS_NOT_FOUND; + } + + uname = talloc_strdup_upper(talloc_tos(), name); + if (uname == NULL) { + return NT_STATUS_NO_MEMORY; + } - fstrcpy(uname, name); - strupper_m(uname); centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname); - if (!centry) - goto do_query; + TALLOC_FREE(uname); + if (centry == NULL) { + return NT_STATUS_NOT_FOUND; + } status = centry->status; if (NT_STATUS_IS_OK(status)) { @@ -1634,13 +1637,29 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain, centry_sid(centry, sid); } - DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n", - domain->name, nt_errstr(status) )); + DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: " + "%s\n", domain->name, nt_errstr(status) )); centry_free(centry); return status; +} + +/* convert a single name to a sid in a domain */ +static NTSTATUS name_to_sid(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const char *domain_name, + const char *name, + uint32_t flags, + DOM_SID *sid, + enum lsa_SidType *type) +{ + NTSTATUS status; + + status = wcache_name_to_sid(domain, domain_name, name, sid, type); + if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { + return status; + } -do_query: ZERO_STRUCTP(sid); /* If the seq number check indicated that there is a problem @@ -1678,42 +1697,65 @@ do_query: return status; } -/* convert a sid to a user or group name. The sid is guaranteed to be in the domain - given */ -static NTSTATUS sid_to_name(struct winbindd_domain *domain, +NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain, + const struct dom_sid *sid, TALLOC_CTX *mem_ctx, - const DOM_SID *sid, char **domain_name, char **name, enum lsa_SidType *type) { struct winbind_cache *cache = get_cache(domain); - struct cache_entry *centry = NULL; + struct cache_entry *centry; + char *sid_string; NTSTATUS status; - fstring sid_string; - if (!cache->tdb) - goto do_query; + if (cache->tdb == NULL) { + return NT_STATUS_NOT_FOUND; + } - centry = wcache_fetch(cache, domain, "SN/%s", - sid_to_fstring(sid_string, sid)); - if (!centry) - goto do_query; + sid_string = sid_string_tos(sid); + if (sid_string == NULL) { + return NT_STATUS_NO_MEMORY; + } - status = centry->status; - if (NT_STATUS_IS_OK(status)) { + centry = wcache_fetch(cache, domain, "SN/%s", sid_string); + TALLOC_FREE(sid_string); + if (centry == NULL) { + return NT_STATUS_NOT_FOUND; + } + + if (NT_STATUS_IS_OK(centry->status)) { *type = (enum lsa_SidType)centry_uint32(centry); *domain_name = centry_string(centry, mem_ctx); *name = centry_string(centry, mem_ctx); } - DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n", - domain->name, nt_errstr(status) )); - + status = centry->status; centry_free(centry); + + DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: " + "%s\n", domain->name, nt_errstr(status) )); + return status; +} + +/* convert a sid to a user or group name. The sid is guaranteed to be in the domain + given */ +static NTSTATUS sid_to_name(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const DOM_SID *sid, + char **domain_name, + char **name, + enum lsa_SidType *type) +{ + NTSTATUS status; + + status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name, + type); + if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { + return status; + } -do_query: *name = NULL; *domain_name = NULL; @@ -1897,38 +1939,46 @@ static NTSTATUS rids_to_names(struct winbindd_domain *domain, return result; } -/* Lookup user information from a rid */ -static NTSTATUS query_user(struct winbindd_domain *domain, - TALLOC_CTX *mem_ctx, - const DOM_SID *user_sid, - WINBIND_USERINFO *info) +NTSTATUS wcache_query_user(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const struct dom_sid *user_sid, + struct winbind_userinfo *info) { struct winbind_cache *cache = get_cache(domain); struct cache_entry *centry = NULL; NTSTATUS status; - fstring tmp; + char *sid_string; - if (!cache->tdb) - goto do_query; + if (cache->tdb == NULL) { + return NT_STATUS_NOT_FOUND; + } - centry = wcache_fetch(cache, domain, "U/%s", - sid_to_fstring(tmp, user_sid)); + sid_string = sid_string_tos(user_sid); + if (sid_string == NULL) { + return NT_STATUS_NO_MEMORY; + } - /* If we have an access denied cache entry and a cached info3 in the - samlogon cache then do a query. This will force the rpc back end - to return the info3 data. */ + centry = wcache_fetch(cache, domain, "U/%s", sid_string); + TALLOC_FREE(sid_string); + if (centry == NULL) { + return NT_STATUS_NOT_FOUND; + } - if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) && + /* + * If we have an access denied cache entry and a cached info3 + * in the samlogon cache then do a query. This will force the + * rpc back end to return the info3 data. + */ + + if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED) && netsamlogon_cache_have(user_sid)) { - DEBUG(10, ("query_user: cached access denied and have cached info3\n")); + DEBUG(10, ("query_user: cached access denied and have cached " + "info3\n")); domain->last_status = NT_STATUS_OK; centry_free(centry); - goto do_query; + return NT_STATUS_NOT_FOUND; } - if (!centry) - goto do_query; - /* if status is not ok then this is a negative hit and the rest of the data doesn't matter */ status = centry->status; @@ -1942,13 +1992,26 @@ static NTSTATUS query_user(struct winbindd_domain *domain, centry_sid(centry, &info->group_sid); } - DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n", - domain->name, nt_errstr(status) )); + DEBUG(10,("query_user: [Cached] - cached info for domain %s status: " + "%s\n", domain->name, nt_errstr(status) )); centry_free(centry); return status; +} + +/* Lookup user information from a rid */ +static NTSTATUS query_user(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const DOM_SID *user_sid, + WINBIND_USERINFO *info) +{ + NTSTATUS status; + + status = wcache_query_user(domain, mem_ctx, user_sid, info); + if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { + return status; + } -do_query: ZERO_STRUCTP(info); /* Return status value returned by seq number check */ @@ -1968,63 +2031,81 @@ do_query: return status; } - -/* Lookup groups a user is a member of. */ -static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, +NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, - const DOM_SID *user_sid, - uint32 *num_groups, DOM_SID **user_gids) + const struct dom_sid *user_sid, + uint32_t *pnum_sids, + struct dom_sid **psids) { struct winbind_cache *cache = get_cache(domain); struct cache_entry *centry = NULL; NTSTATUS status; - unsigned int i; + uint32_t i, num_sids; + struct dom_sid *sids; fstring sid_string; - if (!cache->tdb) - goto do_query; + if (cache->tdb == NULL) { + return NT_STATUS_NOT_FOUND; + } centry = wcache_fetch(cache, domain, "UG/%s", sid_to_fstring(sid_string, user_sid)); + if (centry == NULL) { + return NT_STATUS_NOT_FOUND; + } /* If we have an access denied cache entry and a cached info3 in the samlogon cache then do a query. This will force the rpc back end to return the info3 data. */ - if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) && - netsamlogon_cache_have(user_sid)) { - DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n")); + if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED) + && netsamlogon_cache_have(user_sid)) { + DEBUG(10, ("lookup_usergroups: cached access denied and have " + "cached info3\n")); domain->last_status = NT_STATUS_OK; centry_free(centry); - goto do_query; + return NT_STATUS_NOT_FOUND; } - if (!centry) - goto do_query; - - *num_groups = centry_uint32(centry); - - if (*num_groups == 0) - goto do_cached; - - (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups); - if (! (*user_gids)) { - smb_panic_fn("lookup_usergroups out of memory"); + num_sids = centry_uint32(centry); + sids = talloc_array(mem_ctx, struct dom_sid, num_sids); + if (sids == NULL) { + return NT_STATUS_NO_MEMORY; } - for (i=0; i<(*num_groups); i++) { - centry_sid(centry, &(*user_gids)[i]); + + for (i=0; i<num_sids; i++) { + centry_sid(centry, &sids[i]); } -do_cached: status = centry->status; - DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n", - domain->name, nt_errstr(status) )); + DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s " + "status: %s\n", domain->name, nt_errstr(status))); centry_free(centry); + + *pnum_sids = num_sids; + *psids = sids; return status; +} + +/* Lookup groups a user is a member of. */ +static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const DOM_SID *user_sid, + uint32 *num_groups, DOM_SID **user_gids) +{ + struct cache_entry *centry = NULL; + NTSTATUS status; + unsigned int i; + fstring sid_string; + + status = wcache_lookup_usergroups(domain, mem_ctx, user_sid, + num_groups, user_gids); + if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { + return status; + } -do_query: (*num_groups) = 0; (*user_gids) = NULL; @@ -2059,58 +2140,74 @@ skip_save: return status; } -static NTSTATUS lookup_useraliases(struct winbindd_domain *domain, - TALLOC_CTX *mem_ctx, - uint32 num_sids, const DOM_SID *sids, - uint32 *num_aliases, uint32 **alias_rids) +static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids, + const struct dom_sid *sids) +{ + uint32_t i; + char *sidlist; + + sidlist = talloc_strdup(mem_ctx, ""); + if (sidlist == NULL) { + return NULL; + } + for (i=0; i<num_sids; i++) { + fstring tmp; + sidlist = talloc_asprintf_append_buffer( + sidlist, "/%s", sid_to_fstring(tmp, &sids[i])); + if (sidlist == NULL) { + return NULL; + } + } + return sidlist; +} + +NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, uint32_t num_sids, + const struct dom_sid *sids, + uint32_t *pnum_aliases, uint32_t **paliases) { struct winbind_cache *cache = get_cache(domain); struct cache_entry *centry = NULL; + uint32_t num_aliases; + uint32_t *aliases; NTSTATUS status; - char *sidlist = talloc_strdup(mem_ctx, ""); + char *sidlist; int i; - if (!cache->tdb) - goto do_query; + if (cache->tdb == NULL) { + return NT_STATUS_NOT_FOUND; + } if (num_sids == 0) { - *num_aliases = 0; - *alias_rids = NULL; + *pnum_aliases = 0; + *paliases = NULL; return NT_STATUS_OK; } /* We need to cache indexed by the whole list of SIDs, the aliases * resulting might come from any of the SIDs. */ - for (i=0; i<num_sids; i++) { - fstring tmp; - sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist, - sid_to_fstring(tmp, &sids[i])); - if (sidlist == NULL) - return NT_STATUS_NO_MEMORY; + sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids); + if (sidlist == NULL) { + return NT_STATUS_NO_MEMORY; } centry = wcache_fetch(cache, domain, "UA%s", sidlist); + TALLOC_FREE(sidlist); + if (centry == NULL) { + return NT_STATUS_NOT_FOUND; + } - if (!centry) - goto do_query; - - *num_aliases = centry_uint32(centry); - *alias_rids = NULL; - - if (*num_aliases) { - (*alias_rids) = TALLOC_ARRAY(mem_ctx, uint32, *num_aliases); - - if ((*alias_rids) == NULL) { - centry_free(centry); - return NT_STATUS_NO_MEMORY; - } - } else { - (*alias_rids) = NULL; + num_aliases = centry_uint32(centry); + aliases = talloc_array(mem_ctx, uint32_t, num_aliases); + if (aliases == NULL) { + centry_free(centry); + return NT_STATUS_NO_MEMORY; } - for (i=0; i<(*num_aliases); i++) - (*alias_rids)[i] = centry_uint32(centry); + for (i=0; i<num_aliases; i++) { + aliases[i] = centry_uint32(centry); + } status = centry->status; @@ -2118,9 +2215,29 @@ static NTSTATUS lookup_useraliases(struct winbindd_domain *domain, "status %s\n", domain->name, nt_errstr(status))); centry_free(centry); + + *pnum_aliases = num_aliases; + *paliases = aliases; + return status; +} + +static NTSTATUS lookup_useraliases(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + uint32 num_sids, const DOM_SID *sids, + uint32 *num_aliases, uint32 **alias_rids) +{ + struct cache_entry *centry = NULL; + NTSTATUS status; + char *sidlist; + int i; + + status = wcache_lookup_useraliases(domain, mem_ctx, num_sids, sids, + num_aliases, alias_rids); + if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { + return status; + } - do_query: (*num_aliases) = 0; (*alias_rids) = NULL; @@ -2130,6 +2247,11 @@ static NTSTATUS lookup_useraliases(struct winbindd_domain *domain, DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info " "for domain %s\n", domain->name )); + sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids); + if (sidlist == NULL) { + return NT_STATUS_NO_MEMORY; + } + status = domain->backend->lookup_useraliases(domain, mem_ctx, num_sids, sids, num_aliases, alias_rids); @@ -2625,36 +2747,14 @@ bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid, enum lsa_SidType *type) { struct winbindd_domain *domain; - struct winbind_cache *cache; - struct cache_entry *centry = NULL; NTSTATUS status; - fstring tmp; domain = find_lookup_domain_from_sid(sid); if (domain == NULL) { return false; } - - cache = get_cache(domain); - - if (cache->tdb == NULL) { - return false; - } - - centry = wcache_fetch(cache, domain, "SN/%s", - sid_to_fstring(tmp, sid)); - if (centry == NULL) { - return false; - } - - if (NT_STATUS_IS_OK(centry->status)) { - *type = (enum lsa_SidType)centry_uint32(centry); - *domain_name = centry_string(centry, mem_ctx); - *name = centry_string(centry, mem_ctx); - } - - status = centry->status; - centry_free(centry); + status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name, + type); return NT_STATUS_IS_OK(status); } @@ -2665,46 +2765,22 @@ bool lookup_cached_name(TALLOC_CTX *mem_ctx, enum lsa_SidType *type) { struct winbindd_domain *domain; - struct winbind_cache *cache; - struct cache_entry *centry = NULL; NTSTATUS status; - fstring uname; - bool original_online_state; + bool original_online_state; domain = find_lookup_domain_from_name(domain_name); if (domain == NULL) { return false; } - cache = get_cache(domain); - - if (cache->tdb == NULL) { - return false; - } - - fstrcpy(uname, name); - strupper_m(uname); - /* If we are doing a cached logon, temporarily set the domain offline so the cache won't expire the entry */ original_online_state = domain->online; domain->online = false; - centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname); + status = wcache_name_to_sid(domain, domain_name, name, sid, type); domain->online = original_online_state; - if (centry == NULL) { - return false; - } - - if (NT_STATUS_IS_OK(centry->status)) { - *type = (enum lsa_SidType)centry_uint32(centry); - centry_sid(centry, sid); - } - - status = centry->status; - centry_free(centry); - return NT_STATUS_IS_OK(status); } diff --git a/source3/winbindd/winbindd_domain.c b/source3/winbindd/winbindd_domain.c index 8c52df3e16..5ff2e16abb 100644 --- a/source3/winbindd/winbindd_domain.c +++ b/source3/winbindd/winbindd_domain.c @@ -122,6 +122,10 @@ static const struct winbindd_child_dispatch_table domain_dispatch_table[] = { .struct_cmd = WINBINDD_CCACHE_NTLMAUTH, .struct_fn = winbindd_dual_ccache_ntlm_auth, },{ + .name = "NDRCMD", + .struct_cmd = WINBINDD_DUAL_NDRCMD, + .struct_fn = winbindd_dual_ndrcmd, + },{ .name = NULL, } }; diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c index 1985dd8b12..2158834bdd 100644 --- a/source3/winbindd/winbindd_dual.c +++ b/source3/winbindd/winbindd_dual.c @@ -592,6 +592,8 @@ void setup_child(struct winbindd_child *child, child->table = table; child->queue = tevent_queue_create(NULL, "winbind_child"); SMB_ASSERT(child->queue != NULL); + child->rpccli = wbint_rpccli_create(NULL, child); + SMB_ASSERT(child->rpccli != NULL); } struct winbindd_child *children = NULL; @@ -1307,6 +1309,16 @@ bool winbindd_reinit_after_fork(const char *logfilename) return true; } +/* + * In a child there will be only one domain, reference that here. + */ +static struct winbindd_domain *child_domain; + +struct winbindd_domain *wb_child_domain(void) +{ + return child_domain; +} + static bool fork_domain_child(struct winbindd_child *child) { int fdpair[2]; @@ -1321,6 +1333,7 @@ static bool fork_domain_child(struct winbindd_child *child) } else { DEBUG(10, ("fork_domain_child called without domain.\n")); } + child_domain = child->domain; if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) != 0) { DEBUG(0, ("Could not open child pipe: %s\n", diff --git a/source3/winbindd/winbindd_dual_ndr.c b/source3/winbindd/winbindd_dual_ndr.c new file mode 100644 index 0000000000..f72d6615a0 --- /dev/null +++ b/source3/winbindd/winbindd_dual_ndr.c @@ -0,0 +1,273 @@ +/* + Unix SMB/CIFS implementation. + + Provide parent->child communication based on NDR marshalling + + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +/* + * This file implements an RPC between winbind parent and child processes, + * leveraging the autogenerated marshalling routines for MSRPC. This is not + * MSRPC, as it does not go through the whole DCERPC fragmentation, we just + * leverage much the same infrastructure we already have for it. + */ + +#include "includes.h" +#include "winbindd/winbindd.h" +#include "winbindd/winbindd_proto.h" +#include "librpc/gen_ndr/srv_wbint.h" + +struct wb_ndr_transport_priv { + struct winbindd_child *child; +}; + +struct wb_ndr_dispatch_state { + const struct ndr_interface_call *call; + void *r; + struct ndr_push *push; + struct winbindd_request request; + struct winbindd_response *response; +}; + +static void wb_ndr_dispatch_done(struct tevent_req *subreq); + +static struct tevent_req *wb_ndr_dispatch_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct rpc_pipe_client *cli, + const struct ndr_interface_table *table, + uint32_t opnum, + void *r) +{ + struct tevent_req *req, *subreq; + struct wb_ndr_dispatch_state *state; + struct wb_ndr_transport_priv *transport = talloc_get_type_abort( + cli->transport->priv, struct wb_ndr_transport_priv); + DATA_BLOB blob; + enum ndr_err_code ndr_err; + + req = tevent_req_create(mem_ctx, &state, + struct wb_ndr_dispatch_state); + if (req == NULL) { + return NULL; + } + + state->r = r; + state->call = &table->calls[opnum]; + + state->push = ndr_push_init_ctx(state, NULL); + if (tevent_req_nomem(state->push, req)) { + return tevent_req_post(req, ev); + } + + ndr_err = state->call->ndr_push(state->push, NDR_IN, r); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + tevent_req_nterror(req, ndr_map_error2ntstatus(ndr_err)); + TALLOC_FREE(state->push); + return tevent_req_post(req, ev); + } + + blob = ndr_push_blob(state->push); + + state->request.cmd = WINBINDD_DUAL_NDRCMD; + state->request.data.ndrcmd = opnum; + state->request.extra_data.data = (char *)blob.data; + state->request.extra_len = blob.length; + + subreq = wb_child_request_send(state, ev, transport->child, + &state->request); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_ndr_dispatch_done, req); + return req; +} + +static void wb_ndr_dispatch_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_ndr_dispatch_state *state = tevent_req_data( + req, struct wb_ndr_dispatch_state); + int ret, err; + + ret = wb_child_request_recv(subreq, state, &state->response, &err); + TALLOC_FREE(subreq); + if (ret == -1) { + tevent_req_nterror(req, map_nt_error_from_unix(err)); + return; + } + tevent_req_done(req); +} + +static NTSTATUS wb_ndr_dispatch_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx) +{ + struct wb_ndr_dispatch_state *state = tevent_req_data( + req, struct wb_ndr_dispatch_state); + NTSTATUS status; + struct ndr_pull *pull; + enum ndr_err_code ndr_err; + DATA_BLOB blob; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + + blob.data = (uint8_t *)state->response->extra_data.data; + blob.length = state->response->length + - sizeof(struct winbindd_response); + + pull = ndr_pull_init_blob(&blob, mem_ctx, NULL); + if (pull == NULL) { + return NT_STATUS_NO_MEMORY; + } + + /* have the ndr parser alloc memory for us */ + pull->flags |= LIBNDR_FLAG_REF_ALLOC; + ndr_err = state->call->ndr_pull(pull, NDR_OUT, state->r); + TALLOC_FREE(pull); + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + return NT_STATUS_OK; +} + +static NTSTATUS wb_ndr_dispatch(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + const struct ndr_interface_table *table, + uint32_t opnum, void *r) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct event_context *ev; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_OK; + + ev = event_context_init(frame); + if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + req = wb_ndr_dispatch_send(frame, ev, cli, table, opnum, r); + if (req == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; + } + + status = wb_ndr_dispatch_recv(req, mem_ctx); + fail: + TALLOC_FREE(frame); + return status; +} + +struct rpc_pipe_client *wbint_rpccli_create(TALLOC_CTX *mem_ctx, + struct winbindd_child *child) +{ + struct rpc_pipe_client *result; + struct wb_ndr_transport_priv *transp; + + result = talloc(mem_ctx, struct rpc_pipe_client); + if (result == NULL) { + return NULL; + } + result->abstract_syntax = ndr_table_wbint.syntax_id; + result->transfer_syntax = ndr_transfer_syntax; + result->dispatch = wb_ndr_dispatch; + result->dispatch_send = wb_ndr_dispatch_send; + result->dispatch_recv = wb_ndr_dispatch_recv; + result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN; + result->max_recv_frag = RPC_MAX_PDU_FRAG_LEN; + result->desthost = NULL; + result->srv_name_slash = NULL; + + /* + * Initialize a fake transport. Due to our own wb_ndr_dispatch + * function we don't use all the fragmentation engine in + * cli_pipe, which would use all the _read and _write + * functions in rpc_cli_transport. But we need a place to + * store the child struct in, and we're re-using + * result->transport->priv for that. + */ + + result->transport = talloc_zero(result, struct rpc_cli_transport); + if (result->transport == NULL) { + TALLOC_FREE(result); + return NULL; + } + transp = talloc(result->transport, struct wb_ndr_transport_priv); + if (transp == NULL) { + TALLOC_FREE(result); + return NULL; + } + transp->child = child; + result->transport->priv = transp; + return result; +} + +enum winbindd_result winbindd_dual_ndrcmd(struct winbindd_domain *domain, + struct winbindd_cli_state *state) +{ + pipes_struct p; + struct api_struct *fns; + int num_fns; + bool ret; + + wbint_get_pipe_fns(&fns, &num_fns); + + if (state->request->data.ndrcmd >= num_fns) { + return WINBINDD_ERROR; + } + + ZERO_STRUCT(p); + p.mem_ctx = talloc_stackframe(); + p.in_data.data.buffer_size = state->request->extra_len; + p.in_data.data.data_p = state->request->extra_data.data; + prs_init(&p.out_data.rdata, 0, state->mem_ctx, false); + + ret = fns[state->request->data.ndrcmd].fn(&p); + TALLOC_FREE(p.mem_ctx); + if (!ret) { + return WINBINDD_ERROR; + } + + state->response->extra_data.data = + talloc_memdup(state->mem_ctx, p.out_data.rdata.data_p, + p.out_data.rdata.data_offset); + state->response->length += p.out_data.rdata.data_offset; + prs_mem_free(&p.out_data.rdata); + if (state->response->extra_data.data == NULL) { + return WINBINDD_ERROR; + } + return WINBINDD_OK; +} + +/* + * Just a dummy to make srv_wbint.c happy + */ +NTSTATUS rpc_srv_register(int version, const char *clnt, const char *srv, + const struct ndr_interface_table *iface, + const struct api_struct *cmds, int size) +{ + return NT_STATUS_OK; +} diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c new file mode 100644 index 0000000000..9be295ffdc --- /dev/null +++ b/source3/winbindd/winbindd_dual_srv.c @@ -0,0 +1,174 @@ +/* + Unix SMB/CIFS implementation. + + In-Child server implementation of the routines defined in wbint.idl + + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd/winbindd.h" +#include "winbindd/winbindd_proto.h" +#include "librpc/gen_ndr/srv_wbint.h" + +void _wbint_Ping(pipes_struct *p, struct wbint_Ping *r) +{ + *r->out.out_data = r->in.in_data; +} + +NTSTATUS _wbint_LookupSid(pipes_struct *p, struct wbint_LookupSid *r) +{ + struct winbindd_domain *domain = wb_child_domain(); + char *dom_name; + char *name; + enum lsa_SidType type; + NTSTATUS status; + + if (domain == NULL) { + return NT_STATUS_REQUEST_NOT_ACCEPTED; + } + + status = domain->methods->sid_to_name(domain, p->mem_ctx, r->in.sid, + &dom_name, &name, &type); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + *r->out.domain = dom_name; + *r->out.name = name; + *r->out.type = type; + return NT_STATUS_OK; +} + +NTSTATUS _wbint_LookupName(pipes_struct *p, struct wbint_LookupName *r) +{ + struct winbindd_domain *domain = wb_child_domain(); + + if (domain == NULL) { + return NT_STATUS_REQUEST_NOT_ACCEPTED; + } + + return domain->methods->name_to_sid( + domain, p->mem_ctx, r->in.domain, r->in.name, r->in.flags, + r->out.sid, r->out.type); +} + +NTSTATUS _wbint_Sid2Uid(pipes_struct *p, struct wbint_Sid2Uid *r) +{ + uid_t uid; + NTSTATUS status; + + status = idmap_sid_to_uid(r->in.dom_name ? r->in.dom_name : "", + r->in.sid, &uid); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + *r->out.uid = uid; + return NT_STATUS_OK; +} + +NTSTATUS _wbint_Sid2Gid(pipes_struct *p, struct wbint_Sid2Gid *r) +{ + gid_t gid; + NTSTATUS status; + + status = idmap_sid_to_gid(r->in.dom_name ? r->in.dom_name : "", + r->in.sid, &gid); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + *r->out.gid = gid; + return NT_STATUS_OK; +} + +NTSTATUS _wbint_Uid2Sid(pipes_struct *p, struct wbint_Uid2Sid *r) +{ + NTSTATUS status; + + status = idmap_uid_to_sid(r->in.dom_name ? r->in.dom_name : "", + r->out.sid, r->in.uid); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + return NT_STATUS_OK; +} + +NTSTATUS _wbint_Gid2Sid(pipes_struct *p, struct wbint_Gid2Sid *r) +{ + NTSTATUS status; + + status = idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "", + r->out.sid, r->in.gid); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + return NT_STATUS_OK; +} + +NTSTATUS _wbint_QueryUser(pipes_struct *p, struct wbint_QueryUser *r) +{ + struct winbindd_domain *domain = wb_child_domain(); + WINBIND_USERINFO uinfo; + NTSTATUS status; + + if (domain == NULL) { + return NT_STATUS_REQUEST_NOT_ACCEPTED; + } + + status = domain->methods->query_user(domain, p->mem_ctx, r->in.sid, + &uinfo); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + r->out.info->acct_name = uinfo.acct_name; + r->out.info->full_name = uinfo.full_name; + r->out.info->homedir = uinfo.homedir; + r->out.info->shell = uinfo.shell; + r->out.info->primary_gid = uinfo.primary_gid; + sid_copy(&r->out.info->user_sid, &uinfo.user_sid); + sid_copy(&r->out.info->group_sid, &uinfo.group_sid); + + return NT_STATUS_OK; +} + +NTSTATUS _wbint_LookupUserAliases(pipes_struct *p, + struct wbint_LookupUserAliases *r) +{ + struct winbindd_domain *domain = wb_child_domain(); + + if (domain == NULL) { + return NT_STATUS_REQUEST_NOT_ACCEPTED; + } + + return domain->methods->lookup_useraliases( + domain, p->mem_ctx, r->in.sids->num_sids, r->in.sids->sids, + &r->out.rids->num_rids, &r->out.rids->rids); +} + +NTSTATUS _wbint_LookupUserGroups(pipes_struct *p, + struct wbint_LookupUserGroups *r) +{ + struct winbindd_domain *domain = wb_child_domain(); + + if (domain == NULL) { + return NT_STATUS_REQUEST_NOT_ACCEPTED; + } + + return domain->methods->lookup_usergroups( + domain, p->mem_ctx, r->in.sid, + &r->out.sids->num_sids, &r->out.sids->sids); +} diff --git a/source3/winbindd/winbindd_getgroups.c b/source3/winbindd/winbindd_getgroups.c new file mode 100644 index 0000000000..9e6465696e --- /dev/null +++ b/source3/winbindd/winbindd_getgroups.c @@ -0,0 +1,222 @@ +/* + Unix SMB/CIFS implementation. + async implementation of WINBINDD_GETGROUPS + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" + +struct winbindd_getgroups_state { + struct tevent_context *ev; + fstring domname; + fstring username; + struct dom_sid sid; + enum lsa_SidType type; + int num_sids; + struct dom_sid *sids; + int next_sid; + int num_gids; + gid_t *gids; +}; + +static void winbindd_getgroups_lookupname_done(struct tevent_req *subreq); +static void winbindd_getgroups_gettoken_done(struct tevent_req *subreq); +static void winbindd_getgroups_sid2gid_done(struct tevent_req *subreq); + +struct tevent_req *winbindd_getgroups_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request) +{ + struct tevent_req *req, *subreq; + struct winbindd_getgroups_state *state; + char *domuser, *mapped_user; + struct winbindd_domain *domain; + NTSTATUS status; + + req = tevent_req_create(mem_ctx, &state, + struct winbindd_getgroups_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + + /* Ensure null termination */ + request->data.username[sizeof(request->data.username)-1]='\0'; + + DEBUG(3, ("getgroups %s\n", request->data.username)); + + domuser = request->data.username; + + status = normalize_name_unmap(state, domuser, &mapped_user); + + if (NT_STATUS_IS_OK(status) + || NT_STATUS_EQUAL(status, NT_STATUS_FILE_RENAMED)) { + /* normalize_name_unmapped did something */ + domuser = mapped_user; + } + + if (!parse_domain_user(domuser, state->domname, state->username)) { + DEBUG(5, ("Could not parse domain user: %s\n", domuser)); + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + domain = find_domain_from_name_noinit(state->domname); + if (domain == NULL) { + /* Retry with DNS name */ + char *p = strchr(domuser, '@'); + if (p != NULL) { + domain = find_domain_from_name_noinit(p+1); + } + } + if (domain == NULL) { + DEBUG(7, ("could not find domain entry for domain %s\n", + state->domname)); + tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER); + return tevent_req_post(req, ev); + } + + if (lp_winbind_trusted_domains_only() && domain->primary) { + DEBUG(7,("winbindd_getgroups: My domain -- " + "rejecting getgroups() for %s\\%s.\n", + state->domname, state->username)); + tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER); + return tevent_req_post(req, ev); + } + + subreq = wb_lookupname_send(state, ev, state->domname, state->username, + LOOKUP_NAME_NO_NSS); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, winbindd_getgroups_lookupname_done, + req); + return req; +} + +static void winbindd_getgroups_lookupname_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winbindd_getgroups_state *state = tevent_req_data( + req, struct winbindd_getgroups_state); + NTSTATUS status; + + status = wb_lookupname_recv(subreq, &state->sid, &state->type); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + + subreq = wb_gettoken_send(state, state->ev, &state->sid); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, winbindd_getgroups_gettoken_done, req); +} + +static void winbindd_getgroups_gettoken_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winbindd_getgroups_state *state = tevent_req_data( + req, struct winbindd_getgroups_state); + NTSTATUS status; + + status = wb_gettoken_recv(subreq, state, &state->num_sids, + &state->sids); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + + /* + * Convert the group SIDs to gids. state->sids[0] contains the user + * sid, so start at index 1. + */ + + state->gids = talloc_array(state, gid_t, state->num_sids-1); + if (tevent_req_nomem(state->gids, req)) { + return; + } + state->num_gids = 0; + state->next_sid = 1; + + subreq = wb_sid2gid_send(state, state->ev, + &state->sids[state->next_sid]); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, winbindd_getgroups_sid2gid_done, req); +} + +static void winbindd_getgroups_sid2gid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winbindd_getgroups_state *state = tevent_req_data( + req, struct winbindd_getgroups_state); + NTSTATUS status; + + status = wb_sid2gid_recv(subreq, &state->gids[state->num_gids]); + TALLOC_FREE(subreq); + + /* + * In case of failure, just continue with the next gid + */ + if (NT_STATUS_IS_OK(status)) { + state->num_gids += 1; + } + state->next_sid += 1; + + if (state->next_sid >= state->num_sids) { + tevent_req_done(req); + return; + } + + subreq = wb_sid2gid_send(state, state->ev, + &state->sids[state->next_sid]); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, winbindd_getgroups_sid2gid_done, req); +} + +NTSTATUS winbindd_getgroups_recv(struct tevent_req *req, + struct winbindd_response *response) +{ + struct winbindd_getgroups_state *state = tevent_req_data( + req, struct winbindd_getgroups_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + DEBUG(5, ("Could not convert sid %s: %s\n", + sid_string_dbg(&state->sid), nt_errstr(status))); + return status; + } + + response->data.num_entries = state->num_gids; + + if (state->num_gids > 0) { + response->extra_data.data = talloc_move(response, + &state->gids); + response->length += state->num_gids * sizeof(gid_t); + } + return NT_STATUS_OK; +} diff --git a/source3/winbindd/winbindd_getpwnam.c b/source3/winbindd/winbindd_getpwnam.c new file mode 100644 index 0000000000..80b618c4aa --- /dev/null +++ b/source3/winbindd/winbindd_getpwnam.c @@ -0,0 +1,142 @@ +/* + Unix SMB/CIFS implementation. + async implementation of WINBINDD_GETPWNAM + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" + +struct winbindd_getpwnam_state { + struct tevent_context *ev; + fstring domname; + fstring username; + struct dom_sid sid; + enum lsa_SidType type; + struct winbindd_pw pw; +}; + +static void winbindd_getpwnam_lookupname_done(struct tevent_req *subreq); +static void winbindd_getpwnam_done(struct tevent_req *subreq); + +struct tevent_req *winbindd_getpwnam_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request) +{ + struct tevent_req *req, *subreq; + struct winbindd_getpwnam_state *state; + char *domuser, *mapped_user; + NTSTATUS status; + + req = tevent_req_create(mem_ctx, &state, + struct winbindd_getpwnam_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + + /* Ensure null termination */ + request->data.username[sizeof(request->data.username)-1]='\0'; + + DEBUG(3, ("getpwnam %s\n", request->data.username)); + + domuser = request->data.username; + + status = normalize_name_unmap(state, domuser, &mapped_user); + + if (NT_STATUS_IS_OK(status) + || NT_STATUS_EQUAL(status, NT_STATUS_FILE_RENAMED)) { + /* normalize_name_unmapped did something */ + domuser = mapped_user; + } + + if (!parse_domain_user(domuser, state->domname, state->username)) { + DEBUG(5, ("Could not parse domain user: %s\n", domuser)); + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + if (lp_winbind_trusted_domains_only() + && strequal(state->domname, lp_workgroup())) { + DEBUG(7,("winbindd_getpwnam: My domain -- " + "rejecting getpwnam() for %s\\%s.\n", + state->domname, state->username)); + tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER); + return tevent_req_post(req, ev); + } + + subreq = wb_lookupname_send(state, ev, state->domname, state->username, + LOOKUP_NAME_NO_NSS); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, winbindd_getpwnam_lookupname_done, + req); + return req; +} + +static void winbindd_getpwnam_lookupname_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winbindd_getpwnam_state *state = tevent_req_data( + req, struct winbindd_getpwnam_state); + NTSTATUS status; + + status = wb_lookupname_recv(subreq, &state->sid, &state->type); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + + subreq = wb_getpwsid_send(state, state->ev, &state->sid, &state->pw); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, winbindd_getpwnam_done, req); +} + +static void winbindd_getpwnam_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + NTSTATUS status; + + status = wb_getpwsid_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + tevent_req_done(req); +} + +NTSTATUS winbindd_getpwnam_recv(struct tevent_req *req, + struct winbindd_response *response) +{ + struct winbindd_getpwnam_state *state = tevent_req_data( + req, struct winbindd_getpwnam_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + DEBUG(5, ("Could not convert sid %s: %s\n", + sid_string_dbg(&state->sid), nt_errstr(status))); + return status; + } + response->data.pw = state->pw; + return NT_STATUS_OK; +} diff --git a/source3/winbindd/winbindd_getpwsid.c b/source3/winbindd/winbindd_getpwsid.c new file mode 100644 index 0000000000..135cbf6f61 --- /dev/null +++ b/source3/winbindd/winbindd_getpwsid.c @@ -0,0 +1,92 @@ +/* + Unix SMB/CIFS implementation. + async implementation of WINBINDD_GETPWSID + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" + +struct winbindd_getpwsid_state { + struct dom_sid sid; + struct winbindd_pw pw; +}; + +static void winbindd_getpwsid_done(struct tevent_req *subreq); + +struct tevent_req *winbindd_getpwsid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request) +{ + struct tevent_req *req, *subreq; + struct winbindd_getpwsid_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct winbindd_getpwsid_state); + if (req == NULL) { + return NULL; + } + + /* Ensure null termination */ + request->data.sid[sizeof(request->data.sid)-1]='\0'; + + DEBUG(3, ("getpwsid %s\n", request->data.sid)); + + if (!string_to_sid(&state->sid, request->data.sid)) { + DEBUG(1, ("Could not get convert sid %s from string\n", + request->data.sid)); + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + subreq = wb_getpwsid_send(state, ev, &state->sid, &state->pw); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, winbindd_getpwsid_done, req); + return req; +} + +static void winbindd_getpwsid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + NTSTATUS status; + + status = wb_getpwsid_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + tevent_req_done(req); +} + +NTSTATUS winbindd_getpwsid_recv(struct tevent_req *req, + struct winbindd_response *response) +{ + struct winbindd_getpwsid_state *state = tevent_req_data( + req, struct winbindd_getpwsid_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + DEBUG(5, ("Could not convert sid %s: %s\n", + sid_string_dbg(&state->sid), nt_errstr(status))); + return status; + } + response->data.pw = state->pw; + return NT_STATUS_OK; +} diff --git a/source3/winbindd/winbindd_getpwuid.c b/source3/winbindd/winbindd_getpwuid.c new file mode 100644 index 0000000000..0c667cfccc --- /dev/null +++ b/source3/winbindd/winbindd_getpwuid.c @@ -0,0 +1,108 @@ +/* + Unix SMB/CIFS implementation. + async implementation of WINBINDD_GETPWUID + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" + +struct winbindd_getpwuid_state { + struct tevent_context *ev; + struct dom_sid sid; + struct winbindd_pw pw; +}; + +static void winbindd_getpwuid_uid2sid_done(struct tevent_req *subreq); +static void winbindd_getpwuid_done(struct tevent_req *subreq); + +struct tevent_req *winbindd_getpwuid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request) +{ + struct tevent_req *req, *subreq; + struct winbindd_getpwuid_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct winbindd_getpwuid_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + + DEBUG(3, ("getpwuid %d\n", (int)request->data.uid)); + + subreq = wb_uid2sid_send(state, ev, request->data.uid); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, winbindd_getpwuid_uid2sid_done, + req); + return req; +} + +static void winbindd_getpwuid_uid2sid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winbindd_getpwuid_state *state = tevent_req_data( + req, struct winbindd_getpwuid_state); + NTSTATUS status; + + status = wb_uid2sid_recv(subreq, &state->sid); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + + subreq = wb_getpwsid_send(state, state->ev, &state->sid, &state->pw); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, winbindd_getpwuid_done, req); +} + +static void winbindd_getpwuid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + NTSTATUS status; + + status = wb_getpwsid_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + tevent_req_done(req); +} + +NTSTATUS winbindd_getpwuid_recv(struct tevent_req *req, + struct winbindd_response *response) +{ + struct winbindd_getpwuid_state *state = tevent_req_data( + req, struct winbindd_getpwuid_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + DEBUG(5, ("Could not convert sid %s: %s\n", + sid_string_dbg(&state->sid), nt_errstr(status))); + return status; + } + response->data.pw = state->pw; + return NT_STATUS_OK; +} diff --git a/source3/winbindd/winbindd_getsidaliases.c b/source3/winbindd/winbindd_getsidaliases.c new file mode 100644 index 0000000000..788c88f550 --- /dev/null +++ b/source3/winbindd/winbindd_getsidaliases.c @@ -0,0 +1,137 @@ +/* + Unix SMB/CIFS implementation. + async implementation of WINBINDD_GETSIDALIASES + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" + +struct winbindd_getsidaliases_state { + struct dom_sid sid; + uint32_t num_aliases; + uint32_t *aliases; +}; + +static void winbindd_getsidaliases_done(struct tevent_req *subreq); + +struct tevent_req *winbindd_getsidaliases_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request) +{ + struct tevent_req *req, *subreq; + struct winbindd_getsidaliases_state *state; + struct winbindd_domain *domain; + size_t num_sids; + struct dom_sid *sids; + + req = tevent_req_create(mem_ctx, &state, + struct winbindd_getsidaliases_state); + if (req == NULL) { + return NULL; + } + + /* Ensure null termination */ + request->data.sid[sizeof(request->data.sid)-1]='\0'; + + DEBUG(3, ("getsidaliases %s\n", request->data.sid)); + + if (!string_to_sid(&state->sid, request->data.sid)) { + DEBUG(1, ("Could not get convert sid %s from string\n", + request->data.sid)); + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + domain = find_domain_from_sid_noinit(&state->sid); + if (domain == NULL) { + DEBUG(1,("could not find domain entry for sid %s\n", + request->data.sid)); + tevent_req_nterror(req, NT_STATUS_NO_SUCH_DOMAIN); + return tevent_req_post(req, ev); + } + + num_sids = 0; + sids = NULL; + + if ((request->extra_data.data != NULL) + && !parse_sidlist(state, request->extra_data.data, + &sids, &num_sids)) { + DEBUG(1, ("Could not parse SID list: %s\n", + request->extra_data.data)); + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + subreq = wb_lookupuseraliases_send(state, ev, domain, num_sids, sids); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, winbindd_getsidaliases_done, req); + return req; +} + +static void winbindd_getsidaliases_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winbindd_getsidaliases_state *state = tevent_req_data( + req, struct winbindd_getsidaliases_state); + NTSTATUS status; + + status = wb_lookupuseraliases_recv(subreq, state, &state->num_aliases, + &state->aliases); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + tevent_req_done(req); +} + +NTSTATUS winbindd_getsidaliases_recv(struct tevent_req *req, + struct winbindd_response *response) +{ + struct winbindd_getsidaliases_state *state = tevent_req_data( + req, struct winbindd_getsidaliases_state); + NTSTATUS status; + int i; + char *sidlist; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + + sidlist = talloc_strdup(response, ""); + if (sidlist == NULL) { + return NT_STATUS_NO_MEMORY; + } + for (i=0; i<state->num_aliases; i++) { + struct dom_sid sid; + fstring tmp; + sid_compose(&sid, &state->sid, state->aliases[i]); + + sidlist = talloc_asprintf_append_buffer( + sidlist, "%s\n", sid_to_fstring(tmp, &sid)); + if (sidlist == NULL) { + return NT_STATUS_NO_MEMORY; + } + } + response->extra_data.data = sidlist; + response->length += talloc_get_size(sidlist); + response->data.num_entries = state->num_aliases; + return NT_STATUS_OK; +} diff --git a/source3/winbindd/winbindd_getuserdomgroups.c b/source3/winbindd/winbindd_getuserdomgroups.c new file mode 100644 index 0000000000..e67768307f --- /dev/null +++ b/source3/winbindd/winbindd_getuserdomgroups.c @@ -0,0 +1,121 @@ +/* + Unix SMB/CIFS implementation. + async implementation of WINBINDD_GETUSERDOMGROUPS + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" + +struct winbindd_getuserdomgroups_state { + struct dom_sid sid; + int num_sids; + struct dom_sid *sids; +}; + +static void winbindd_getuserdomgroups_done(struct tevent_req *subreq); + +struct tevent_req *winbindd_getuserdomgroups_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request) +{ + struct tevent_req *req, *subreq; + struct winbindd_getuserdomgroups_state *state; + struct winbindd_domain *domain; + + req = tevent_req_create(mem_ctx, &state, + struct winbindd_getuserdomgroups_state); + if (req == NULL) { + return NULL; + } + + /* Ensure null termination */ + request->data.sid[sizeof(request->data.sid)-1]='\0'; + + DEBUG(3, ("getuserdomgroups %s\n", request->data.sid)); + + if (!string_to_sid(&state->sid, request->data.sid)) { + DEBUG(1, ("Could not get convert sid %s from string\n", + request->data.sid)); + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + domain = find_domain_from_sid_noinit(&state->sid); + if (domain == NULL) { + DEBUG(1,("could not find domain entry for sid %s\n", + request->data.sid)); + tevent_req_nterror(req, NT_STATUS_NO_SUCH_DOMAIN); + return tevent_req_post(req, ev); + } + + subreq = wb_lookupusergroups_send(state, ev, domain, &state->sid); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, winbindd_getuserdomgroups_done, req); + return req; +} + +static void winbindd_getuserdomgroups_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winbindd_getuserdomgroups_state *state = tevent_req_data( + req, struct winbindd_getuserdomgroups_state); + NTSTATUS status; + + status = wb_lookupusergroups_recv(subreq, state, &state->num_sids, + &state->sids); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + tevent_req_done(req); +} + +NTSTATUS winbindd_getuserdomgroups_recv(struct tevent_req *req, + struct winbindd_response *response) +{ + struct winbindd_getuserdomgroups_state *state = tevent_req_data( + req, struct winbindd_getuserdomgroups_state); + NTSTATUS status; + int i; + char *sidlist; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + + sidlist = talloc_strdup(response, ""); + if (sidlist == NULL) { + return NT_STATUS_NO_MEMORY; + } + for (i=0; i<state->num_sids; i++) { + fstring tmp; + sidlist = talloc_asprintf_append_buffer( + sidlist, "%s\n", + sid_to_fstring(tmp, &state->sids[i])); + if (sidlist == NULL) { + return NT_STATUS_NO_MEMORY; + } + } + response->extra_data.data = sidlist; + response->length += talloc_get_size(sidlist); + response->data.num_entries = state->num_sids; + return NT_STATUS_OK; +} diff --git a/source3/winbindd/winbindd_gid_to_sid.c b/source3/winbindd/winbindd_gid_to_sid.c new file mode 100644 index 0000000000..b2cc3c2613 --- /dev/null +++ b/source3/winbindd/winbindd_gid_to_sid.c @@ -0,0 +1,87 @@ +/* + Unix SMB/CIFS implementation. + async implementation of WINBINDD_GID_TO_SID + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" + +struct winbindd_gid_to_sid_state { + struct tevent_context *ev; + gid_t gid; + struct dom_sid sid; +}; + +static void winbindd_gid_to_sid_done(struct tevent_req *subreq); + +struct tevent_req *winbindd_gid_to_sid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request) +{ + struct tevent_req *req, *subreq; + struct winbindd_gid_to_sid_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct winbindd_gid_to_sid_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + + DEBUG(3, ("gid_to_sid %d\n", (int)request->data.gid)); + + subreq = wb_gid2sid_send(state, ev, request->data.gid); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, winbindd_gid_to_sid_done, req); + return req; +} + +static void winbindd_gid_to_sid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winbindd_gid_to_sid_state *state = tevent_req_data( + req, struct winbindd_gid_to_sid_state); + NTSTATUS status; + + status = wb_gid2sid_recv(subreq, &state->sid); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + tevent_req_done(req); +} + +NTSTATUS winbindd_gid_to_sid_recv(struct tevent_req *req, + struct winbindd_response *response) +{ + struct winbindd_gid_to_sid_state *state = tevent_req_data( + req, struct winbindd_gid_to_sid_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + DEBUG(5, ("Could not convert sid %s: %s\n", + sid_string_dbg(&state->sid), nt_errstr(status))); + return status; + } + sid_to_fstring(response->data.sid.sid, &state->sid); + response->data.sid.type = SID_NAME_USER; + return NT_STATUS_OK; +} diff --git a/source3/winbindd/winbindd_group.c b/source3/winbindd/winbindd_group.c index f78becb699..c1a898d73b 100644 --- a/source3/winbindd/winbindd_group.c +++ b/source3/winbindd/winbindd_group.c @@ -1559,178 +1559,6 @@ struct getgroups_state { size_t num_token_gids; }; -static void getgroups_usersid_recv(void *private_data, bool success, - const DOM_SID *sid, enum lsa_SidType type); -static void getgroups_tokensids_recv(void *private_data, bool success, - DOM_SID *token_sids, size_t num_token_sids); -static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid); - -void winbindd_getgroups(struct winbindd_cli_state *state) -{ - struct getgroups_state *s; - char *real_name = NULL; - NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; - - /* Ensure null termination */ - state->request->data.username - [sizeof(state->request->data.username)-1]='\0'; - - DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid, - state->request->data.username)); - - /* Parse domain and username */ - - s = TALLOC_P(state->mem_ctx, struct getgroups_state); - if (s == NULL) { - DEBUG(0, ("talloc failed\n")); - request_error(state); - return; - } - - s->state = state; - - nt_status = normalize_name_unmap(state->mem_ctx, - state->request->data.username, - &real_name); - - /* Reset the real_name pointer if we didn't do anything - productive in the above call */ - if (!NT_STATUS_IS_OK(nt_status) && - !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) - { - real_name = state->request->data.username; - } - - if (!parse_domain_user_talloc(state->mem_ctx, real_name, - &s->domname, &s->username)) { - DEBUG(5, ("Could not parse domain user: %s\n", - real_name)); - - /* error out if we do not have nested group support */ - - if ( !lp_winbind_nested_groups() ) { - request_error(state); - return; - } - - s->domname = talloc_strdup(state->mem_ctx, - get_global_sam_name()); - s->username = talloc_strdup(state->mem_ctx, - state->request->data.username); - } - - /* Get info for the domain (either by short domain name or - DNS name in the case of a UPN) */ - - s->domain = find_domain_from_name_noinit(s->domname); - if (!s->domain) { - char *p = strchr(s->username, '@'); - - if (p) { - s->domain = find_domain_from_name_noinit(p+1); - } - - } - - if (s->domain == NULL) { - DEBUG(7, ("could not find domain entry for domain %s\n", - s->domname)); - request_error(state); - return; - } - - if ( s->domain->primary && lp_winbind_trusted_domains_only()) { - DEBUG(7,("winbindd_getgroups: My domain -- rejecting " - "getgroups() for %s\\%s.\n", s->domname, - s->username)); - request_error(state); - return; - } - - /* Get rid and name type from name. The following costs 1 packet */ - - winbindd_lookupname_async(state->mem_ctx, - s->domname, s->username, - getgroups_usersid_recv, - WINBINDD_GETGROUPS, s); -} - -static void getgroups_usersid_recv(void *private_data, bool success, - const DOM_SID *sid, enum lsa_SidType type) -{ - struct getgroups_state *s = - (struct getgroups_state *)private_data; - - if ((!success) || - ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) { - request_error(s->state); - return; - } - - sid_copy(&s->user_sid, sid); - - winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid, - getgroups_tokensids_recv, s); -} - -static void getgroups_tokensids_recv(void *private_data, bool success, - DOM_SID *token_sids, size_t num_token_sids) -{ - struct getgroups_state *s = - (struct getgroups_state *)private_data; - - /* We need at least the user sid and the primary group in the token, - * otherwise it's an error */ - - if ((!success) || (num_token_sids < 2)) { - request_error(s->state); - return; - } - - s->token_sids = token_sids; - s->num_token_sids = num_token_sids; - s->i = 0; - - s->token_gids = NULL; - s->num_token_gids = 0; - - getgroups_sid2gid_recv(s, False, 0); -} - -static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid) -{ - struct getgroups_state *s = - (struct getgroups_state *)private_data; - - if (success) { - if (!add_gid_to_array_unique(s->state->mem_ctx, gid, - &s->token_gids, - &s->num_token_gids)) { - return; - } - } - - if (s->i < s->num_token_sids) { - const DOM_SID *sid = &s->token_sids[s->i]; - s->i += 1; - - if (sid_equal(sid, &s->user_sid)) { - getgroups_sid2gid_recv(s, False, 0); - return; - } - - winbindd_sid2gid_async(s->state->mem_ctx, sid, - getgroups_sid2gid_recv, s); - return; - } - - s->state->response->data.num_entries = s->num_token_gids; - if (s->num_token_gids) { - s->state->response->extra_data.data = s->token_gids; - s->state->response->length += s->num_token_gids * sizeof(gid_t); - } - request_ok(s->state); -} /* Get user supplementary sids. This is equivalent to the winbindd_getgroups() function but it involves a SID->SIDs mapping @@ -1815,32 +1643,6 @@ static void getusersids_recv(void *private_data, bool success, DOM_SID *sids, request_ok(state); } -void winbindd_getuserdomgroups(struct winbindd_cli_state *state) -{ - DOM_SID user_sid; - struct winbindd_domain *domain; - - /* Ensure null termination */ - state->request->data.sid[sizeof(state->request->data.sid)-1]='\0'; - - if (!string_to_sid(&user_sid, state->request->data.sid)) { - DEBUG(1, ("Could not get convert sid %s from string\n", - state->request->data.sid)); - request_error(state); - return; - } - - /* Get info for the domain */ - if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) { - DEBUG(0,("could not find domain entry for sid %s\n", - sid_string_dbg(&user_sid))); - request_error(state); - return; - } - - sendto_domain(state, domain); -} - enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain, struct winbindd_cli_state *state) { @@ -1887,32 +1689,6 @@ enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *doma return WINBINDD_OK; } -void winbindd_getsidaliases(struct winbindd_cli_state *state) -{ - DOM_SID domain_sid; - struct winbindd_domain *domain; - - /* Ensure null termination */ - state->request->data.sid[sizeof(state->request->data.sid)-1]='\0'; - - if (!string_to_sid(&domain_sid, state->request->data.sid)) { - DEBUG(1, ("Could not get convert sid %s from string\n", - state->request->data.sid)); - request_error(state); - return; - } - - /* Get info for the domain */ - if ((domain = find_domain_from_sid_noinit(&domain_sid)) == NULL) { - DEBUG(0,("could not find domain entry for sid %s\n", - sid_string_dbg(&domain_sid))); - request_error(state); - return; - } - - sendto_domain(state, domain); -} - enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain, struct winbindd_cli_state *state) { diff --git a/source3/winbindd/winbindd_idmap.c b/source3/winbindd/winbindd_idmap.c index 6e24a9c212..7bcc58a014 100644 --- a/source3/winbindd/winbindd_idmap.c +++ b/source3/winbindd/winbindd_idmap.c @@ -565,6 +565,10 @@ static const struct winbindd_child_dispatch_table idmap_dispatch_table[] = { .struct_cmd = WINBINDD_ALLOCATE_GID, .struct_fn = winbindd_dual_allocate_gid, },{ + .name = "NDRCMD", + .struct_cmd = WINBINDD_DUAL_NDRCMD, + .struct_fn = winbindd_dual_ndrcmd, + },{ .name = NULL, } }; diff --git a/source3/winbindd/winbindd_locator.c b/source3/winbindd/winbindd_locator.c index 43dadfae29..b35d8dcf54 100644 --- a/source3/winbindd/winbindd_locator.c +++ b/source3/winbindd/winbindd_locator.c @@ -165,6 +165,10 @@ static const struct winbindd_child_dispatch_table locator_dispatch_table[] = { .struct_cmd = WINBINDD_DSGETDCNAME, .struct_fn = dual_dsgetdcname, },{ + .name = "NDRCMD", + .struct_cmd = WINBINDD_DUAL_NDRCMD, + .struct_fn = winbindd_dual_ndrcmd, + },{ .name = NULL, } }; diff --git a/source3/winbindd/winbindd_lookupname.c b/source3/winbindd/winbindd_lookupname.c new file mode 100644 index 0000000000..0918076717 --- /dev/null +++ b/source3/winbindd/winbindd_lookupname.c @@ -0,0 +1,110 @@ +/* + Unix SMB/CIFS implementation. + async implementation of WINBINDD_GETPWNAM + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" + +struct winbindd_lookupname_state { + struct tevent_context *ev; + struct dom_sid sid; + enum lsa_SidType type; +}; + +static void winbindd_lookupname_done(struct tevent_req *subreq); + +struct tevent_req *winbindd_lookupname_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request) +{ + struct tevent_req *req, *subreq; + struct winbindd_lookupname_state *state; + char *domname, *name, *p; + + req = tevent_req_create(mem_ctx, &state, + struct winbindd_lookupname_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + + /* Ensure null termination */ + request->data.name.dom_name[ + sizeof(request->data.name.dom_name)-1]='\0'; + request->data.name.name[sizeof(request->data.name.name)-1]='\0'; + + /* cope with the name being a fully qualified name */ + p = strstr(request->data.name.name, lp_winbind_separator()); + if (p) { + *p = 0; + domname = request->data.name.name; + name = p+1; + } else if ((p = strchr(request->data.name.name, '@')) != NULL) { + /* upn */ + domname = p + 1; + *p = 0; + name = request->data.name.name; + } else { + domname = request->data.name.dom_name; + name = request->data.name.name; + } + + DEBUG(3, ("lookupname %s%s%s\n", domname, lp_winbind_separator(), + name)); + + subreq = wb_lookupname_send(state, ev, domname, name, 0); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, winbindd_lookupname_done, req); + return req; +} + +static void winbindd_lookupname_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winbindd_lookupname_state *state = tevent_req_data( + req, struct winbindd_lookupname_state); + NTSTATUS status; + + status = wb_lookupname_recv(subreq, &state->sid, &state->type); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + tevent_req_done(req); +} + +NTSTATUS winbindd_lookupname_recv(struct tevent_req *req, + struct winbindd_response *response) +{ + struct winbindd_lookupname_state *state = tevent_req_data( + req, struct winbindd_lookupname_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + DEBUG(5, ("Could not convert sid %s: %s\n", + sid_string_dbg(&state->sid), nt_errstr(status))); + return status; + } + sid_to_fstring(response->data.sid.sid, &state->sid); + response->data.sid.type = state->type; + return NT_STATUS_OK; +} diff --git a/source3/winbindd/winbindd_lookupsid.c b/source3/winbindd/winbindd_lookupsid.c new file mode 100644 index 0000000000..7647f1d682 --- /dev/null +++ b/source3/winbindd/winbindd_lookupsid.c @@ -0,0 +1,101 @@ +/* + Unix SMB/CIFS implementation. + async implementation of WINBINDD_GETPWNAM + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" + +struct winbindd_lookupsid_state { + struct tevent_context *ev; + struct dom_sid sid; + enum lsa_SidType type; + const char *domname; + const char *name; +}; + +static void winbindd_lookupsid_done(struct tevent_req *subreq); + +struct tevent_req *winbindd_lookupsid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request) +{ + struct tevent_req *req, *subreq; + struct winbindd_lookupsid_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct winbindd_lookupsid_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + + /* Ensure null termination */ + request->data.sid[sizeof(request->data.sid)-1]='\0'; + + DEBUG(3, ("lookupsid %s\n", request->data.sid)); + + if (!string_to_sid(&state->sid, request->data.sid)) { + DEBUG(5, ("%s not a SID\n", request->data.sid)); + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev);; + } + + subreq = wb_lookupsid_send(state, ev, &state->sid); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, winbindd_lookupsid_done, req); + return req; +} + +static void winbindd_lookupsid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winbindd_lookupsid_state *state = tevent_req_data( + req, struct winbindd_lookupsid_state); + NTSTATUS status; + + status = wb_lookupsid_recv(subreq, state, &state->type, + &state->domname, &state->name); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + tevent_req_done(req); +} + +NTSTATUS winbindd_lookupsid_recv(struct tevent_req *req, + struct winbindd_response *response) +{ + struct winbindd_lookupsid_state *state = tevent_req_data( + req, struct winbindd_lookupsid_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + DEBUG(5, ("Could not lookup sid %s: %s\n", + sid_string_dbg(&state->sid), nt_errstr(status))); + return status; + } + + fstrcpy(response->data.name.dom_name, state->domname); + fstrcpy(response->data.name.name, state->name); + response->data.name.type = state->type; + return NT_STATUS_OK; +} diff --git a/source3/winbindd/winbindd_misc.c b/source3/winbindd/winbindd_misc.c index 3f71910023..c6608316d1 100644 --- a/source3/winbindd/winbindd_misc.c +++ b/source3/winbindd/winbindd_misc.c @@ -741,12 +741,6 @@ static void domain_info_done(struct tevent_req *req) request_ok(state->cli); } -void winbindd_ping(struct winbindd_cli_state *state) -{ - DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid)); - request_ok(state); -} - /* List various tidbits of information */ void winbindd_info(struct winbindd_cli_state *state) diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index c9decf8cc4..a9a374a532 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -100,7 +100,7 @@ enum winbindd_result winbindd_dual_list_groups(struct winbindd_domain *domain, struct winbindd_cli_state *state); bool print_sidlist(TALLOC_CTX *mem_ctx, const DOM_SID *sids, size_t num_sids, char **result, ssize_t *len); -bool parse_sidlist(TALLOC_CTX *mem_ctx, char *sidstr, +bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr, DOM_SID **sids, size_t *num_sids); enum winbindd_result winbindd_dual_lookuprids(struct winbindd_domain *domain, struct winbindd_cli_state *state); @@ -149,6 +149,12 @@ bool wcache_invalidate_cache(void); bool init_wcache(void); bool initialize_winbindd_cache(void); void close_winbindd_cache(void); +NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain, + const struct dom_sid *sid, + TALLOC_CTX *mem_ctx, + char **domain_name, + char **name, + enum lsa_SidType *type); bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid, char **domain_name, char **name, enum lsa_SidType *type); @@ -160,6 +166,25 @@ bool lookup_cached_name(TALLOC_CTX *mem_ctx, void cache_name2sid(struct winbindd_domain *domain, const char *domain_name, const char *name, enum lsa_SidType type, const DOM_SID *sid); +NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain, + const char *domain_name, + const char *name, + struct dom_sid *sid, + enum lsa_SidType *type); +NTSTATUS wcache_query_user(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const struct dom_sid *user_sid, + struct winbind_userinfo *info); +NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + uint32 num_sids, const DOM_SID *sids, + uint32 *pnum_aliases, uint32 **paliases); +NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const struct dom_sid *user_sid, + uint32_t *pnum_sids, + struct dom_sid **psids); + void wcache_flush_cache(void); NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count); NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid) ; @@ -330,6 +355,7 @@ void winbind_msg_dump_domain_list(struct messaging_context *msg_ctx, struct server_id server_id, DATA_BLOB *data); bool winbindd_reinit_after_fork(const char *logfilename); +struct winbindd_domain *wb_child_domain(void); /* The following definitions come from winbindd/winbindd_group.c */ @@ -492,6 +518,14 @@ enum winbindd_result winbindd_dual_allocate_gid(struct winbindd_domain *domain, /* The following definitions come from winbindd/winbindd_user.c */ +bool fillup_pw_field(const char *lp_template, + const char *username, + const char *domname, + uid_t uid, + gid_t gid, + const char *in, + fstring out); + enum winbindd_result winbindd_dual_userinfo(struct winbindd_domain *domain, struct winbindd_cli_state *state); void winbindd_getpwnam(struct winbindd_cli_state *state); @@ -594,4 +628,145 @@ NTSTATUS wb_ping_recv(struct tevent_req *req, enum winbindd_result winbindd_dual_ping(struct winbindd_domain *domain, struct winbindd_cli_state *state); +struct rpc_pipe_client *wbint_rpccli_create(TALLOC_CTX *mem_ctx, + struct winbindd_child *child); +enum winbindd_result winbindd_dual_ndrcmd(struct winbindd_domain *domain, + struct winbindd_cli_state *state); + +struct tevent_req *wb_lookupsid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const struct dom_sid *sid); +NTSTATUS wb_lookupsid_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + enum lsa_SidType *type, const char **domain, + const char **name); + +struct tevent_req *winbindd_lookupsid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request); +NTSTATUS winbindd_lookupsid_recv(struct tevent_req *req, + struct winbindd_response *response); + +struct tevent_req *wb_lookupname_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const char *dom_name, const char *name, + uint32_t flags); +NTSTATUS wb_lookupname_recv(struct tevent_req *req, struct dom_sid *sid, + enum lsa_SidType *type); + +struct tevent_req *winbindd_lookupname_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request); +NTSTATUS winbindd_lookupname_recv(struct tevent_req *req, + struct winbindd_response *response); + +struct tevent_req *wb_sid2uid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const struct dom_sid *sid); +NTSTATUS wb_sid2uid_recv(struct tevent_req *req, uid_t *uid); + +struct tevent_req *winbindd_sid_to_uid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request); +NTSTATUS winbindd_sid_to_uid_recv(struct tevent_req *req, + struct winbindd_response *response); + +struct tevent_req *wb_sid2gid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const struct dom_sid *sid); +NTSTATUS wb_sid2gid_recv(struct tevent_req *req, gid_t *gid); + +struct tevent_req *winbindd_sid_to_gid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request); +NTSTATUS winbindd_sid_to_gid_recv(struct tevent_req *req, + struct winbindd_response *response); + +struct tevent_req *wb_uid2sid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + uid_t uid); +NTSTATUS wb_uid2sid_recv(struct tevent_req *req, struct dom_sid *sid); + +struct tevent_req *winbindd_uid_to_sid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request); +NTSTATUS winbindd_uid_to_sid_recv(struct tevent_req *req, + struct winbindd_response *response); + +struct tevent_req *wb_gid2sid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + gid_t gid); +NTSTATUS wb_gid2sid_recv(struct tevent_req *req, struct dom_sid *sid); + +struct tevent_req *winbindd_gid_to_sid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request); +NTSTATUS winbindd_gid_to_sid_recv(struct tevent_req *req, + struct winbindd_response *response); + +struct tevent_req *wb_queryuser_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const struct dom_sid *user_sid); +NTSTATUS wb_queryuser_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + struct winbind_userinfo **pinfo); + +struct tevent_req *wb_getpwsid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const struct dom_sid *user_sid, + struct winbindd_pw *pw); +NTSTATUS wb_getpwsid_recv(struct tevent_req *req); + +struct tevent_req *winbindd_getpwsid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request); +NTSTATUS winbindd_getpwsid_recv(struct tevent_req *req, + struct winbindd_response *response); + +struct tevent_req *winbindd_getpwnam_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request); +NTSTATUS winbindd_getpwnam_recv(struct tevent_req *req, + struct winbindd_response *response); + +struct tevent_req *winbindd_getpwuid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request); +NTSTATUS winbindd_getpwuid_recv(struct tevent_req *req, + struct winbindd_response *response); +struct tevent_req *wb_lookupuseraliases_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_domain *domain, + int num_sids, + const struct dom_sid *sids); +NTSTATUS wb_lookupuseraliases_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + uint32_t *num_aliases, uint32_t **aliases); +struct tevent_req *winbindd_getsidaliases_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request); +NTSTATUS winbindd_getsidaliases_recv(struct tevent_req *req, + struct winbindd_response *response); +struct tevent_req *wb_lookupusergroups_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_domain *domain, + const struct dom_sid *sid); +NTSTATUS wb_lookupusergroups_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + int *num_sids, struct dom_sid **sids); + +struct tevent_req *winbindd_getuserdomgroups_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request); +NTSTATUS winbindd_getuserdomgroups_recv(struct tevent_req *req, + struct winbindd_response *response); +struct tevent_req *wb_gettoken_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const struct dom_sid *sid); +NTSTATUS wb_gettoken_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + int *num_sids, struct dom_sid **sids); +struct tevent_req *winbindd_getgroups_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request); +NTSTATUS winbindd_getgroups_recv(struct tevent_req *req, + struct winbindd_response *response); + + + #endif /* _WINBINDD_PROTO_H_ */ diff --git a/source3/winbindd/winbindd_sid.c b/source3/winbindd/winbindd_sid.c index f8cf7db920..db000682ae 100644 --- a/source3/winbindd/winbindd_sid.c +++ b/source3/winbindd/winbindd_sid.c @@ -27,108 +27,6 @@ /* Convert a string */ -static void lookupsid_recv(void *private_data, bool success, - const char *dom_name, const char *name, - enum lsa_SidType type); - -void winbindd_lookupsid(struct winbindd_cli_state *state) -{ - DOM_SID sid; - - /* Ensure null termination */ - state->request->data.sid[sizeof(state->request->data.sid)-1]='\0'; - - DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid, - state->request->data.sid)); - - if (!string_to_sid(&sid, state->request->data.sid)) { - DEBUG(5, ("%s not a SID\n", state->request->data.sid)); - request_error(state); - return; - } - - winbindd_lookupsid_async(state->mem_ctx, &sid, lookupsid_recv, state); -} - -static void lookupsid_recv(void *private_data, bool success, - const char *dom_name, const char *name, - enum lsa_SidType type) -{ - struct winbindd_cli_state *state = - talloc_get_type_abort(private_data, struct winbindd_cli_state); - - if (!success) { - DEBUG(5, ("lookupsid returned an error\n")); - request_error(state); - return; - } - - fstrcpy(state->response->data.name.dom_name, dom_name); - fstrcpy(state->response->data.name.name, name); - state->response->data.name.type = type; - request_ok(state); -} - -/** - * Look up the SID for a qualified name. - **/ - -static void lookupname_recv(void *private_data, bool success, - const DOM_SID *sid, enum lsa_SidType type); - -void winbindd_lookupname(struct winbindd_cli_state *state) -{ - char *name_domain, *name_user; - char *p; - - /* Ensure null termination */ - state->request->data.name.dom_name[sizeof(state->request->data.name.dom_name)-1]='\0'; - - /* Ensure null termination */ - state->request->data.name.name[sizeof(state->request->data.name.name)-1]='\0'; - - /* cope with the name being a fully qualified name */ - p = strstr(state->request->data.name.name, lp_winbind_separator()); - if (p) { - *p = 0; - name_domain = state->request->data.name.name; - name_user = p+1; - } else if ((p = strchr(state->request->data.name.name, '@')) != NULL) { - /* upn */ - name_domain = p + 1; - *p = 0; - name_user = state->request->data.name.name; - } else { - name_domain = state->request->data.name.dom_name; - name_user = state->request->data.name.name; - } - - DEBUG(3, ("[%5lu]: lookupname %s%s%s\n", (unsigned long)state->pid, - name_domain, lp_winbind_separator(), name_user)); - - winbindd_lookupname_async(state->mem_ctx, name_domain, name_user, - lookupname_recv, WINBINDD_LOOKUPNAME, - state); -} - -static void lookupname_recv(void *private_data, bool success, - const DOM_SID *sid, enum lsa_SidType type) -{ - struct winbindd_cli_state *state = - talloc_get_type_abort(private_data, struct winbindd_cli_state); - - if (!success) { - DEBUG(5, ("lookupname returned an error\n")); - request_error(state); - return; - } - - sid_to_fstring(state->response->data.sid.sid, sid); - state->response->data.sid.type = type; - request_ok(state); - return; -} - void winbindd_lookuprids(struct winbindd_cli_state *state) { struct winbindd_domain *domain; @@ -157,228 +55,6 @@ void winbindd_lookuprids(struct winbindd_cli_state *state) sendto_domain(state, domain); } -/* Convert a sid to a uid. We assume we only have one rid attached to the - sid. */ - -static void sid2uid_recv(void *private_data, bool success, uid_t uid) -{ - struct winbindd_cli_state *state = - talloc_get_type_abort(private_data, struct winbindd_cli_state); - struct dom_sid sid; - - string_to_sid(&sid, state->request->data.sid); - - if (!success) { - DEBUG(5, ("Could not convert sid %s\n", - state->request->data.sid)); - request_error(state); - return; - } - - state->response->data.uid = uid; - request_ok(state); -} - -static void sid2uid_lookupsid_recv( void *private_data, bool success, - const char *domain_name, - const char *name, - enum lsa_SidType type) -{ - struct winbindd_cli_state *state = - talloc_get_type_abort(private_data, struct winbindd_cli_state); - DOM_SID sid; - - if (!string_to_sid(&sid, state->request->data.sid)) { - DEBUG(1, ("sid2uid_lookupsid_recv: Could not get convert sid " - "%s from string\n", state->request->data.sid)); - request_error(state); - return; - } - - if (!success) { - DEBUG(5, ("sid2uid_lookupsid_recv Could not convert get sid type for %s\n", - state->request->data.sid)); - goto fail; - } - - if ( (type!=SID_NAME_USER) && (type!=SID_NAME_COMPUTER) ) { - DEBUG(5,("sid2uid_lookupsid_recv: Sid %s is not a user or a computer.\n", - state->request->data.sid)); - goto fail; - } - - /* always use the async interface (may block) */ - winbindd_sid2uid_async(state->mem_ctx, &sid, sid2uid_recv, state); - return; - - fail: - /* - * We have to set the cache ourselves here, the child which is - * normally responsible was not queried yet. - */ - idmap_cache_set_sid2uid(&sid, -1); - request_error(state); - return; -} - -void winbindd_sid_to_uid(struct winbindd_cli_state *state) -{ - DOM_SID sid; - uid_t uid; - bool expired; - - /* Ensure null termination */ - state->request->data.sid[sizeof(state->request->data.sid)-1]='\0'; - - DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid, - state->request->data.sid)); - - if (!string_to_sid(&sid, state->request->data.sid)) { - DEBUG(1, ("Could not get convert sid %s from string\n", - state->request->data.sid)); - request_error(state); - return; - } - - if (idmap_cache_find_sid2uid(&sid, &uid, &expired)) { - DEBUG(10, ("idmap_cache_find_sid2uid found %d%s\n", - (int)uid, expired ? " (expired)": "")); - if (expired && IS_DOMAIN_ONLINE(find_our_domain())) { - DEBUG(10, ("revalidating expired entry\n")); - goto backend; - } - if (uid == -1) { - DEBUG(10, ("Returning negative cache entry\n")); - request_error(state); - return; - } - DEBUG(10, ("Returning positive cache entry\n")); - state->response->data.uid = uid; - request_ok(state); - return; - } - - /* Validate the SID as a user. Hopefully this will hit cache. - Needed to prevent DoS by exhausting the uid allocation - range from random SIDs. */ - - backend: - winbindd_lookupsid_async( state->mem_ctx, &sid, sid2uid_lookupsid_recv, state ); -} - -/* Convert a sid to a gid. We assume we only have one rid attached to the - sid.*/ - -static void sid2gid_recv(void *private_data, bool success, gid_t gid) -{ - struct winbindd_cli_state *state = - talloc_get_type_abort(private_data, struct winbindd_cli_state); - struct dom_sid sid; - - string_to_sid(&sid, state->request->data.sid); - - if (!success) { - DEBUG(5, ("Could not convert sid %s\n", - state->request->data.sid)); - request_error(state); - return; - } - - state->response->data.gid = gid; - request_ok(state); -} - -static void sid2gid_lookupsid_recv( void *private_data, bool success, - const char *domain_name, - const char *name, - enum lsa_SidType type) -{ - struct winbindd_cli_state *state = - talloc_get_type_abort(private_data, struct winbindd_cli_state); - DOM_SID sid; - - if (!string_to_sid(&sid, state->request->data.sid)) { - DEBUG(1, ("sid2gid_lookupsid_recv: Could not get convert sid " - "%s from string\n", state->request->data.sid)); - request_error(state); - return; - } - - if (!success) { - DEBUG(5, ("sid2gid_lookupsid_recv: Could not get sid type for %s\n", - state->request->data.sid)); - goto fail; - } - - if ( (type!=SID_NAME_DOM_GRP) && - (type!=SID_NAME_ALIAS) && - (type!=SID_NAME_WKN_GRP) ) - { - DEBUG(5,("sid2gid_lookupsid_recv: Sid %s is not a group.\n", - state->request->data.sid)); - goto fail; - } - - /* always use the async interface (may block) */ - winbindd_sid2gid_async(state->mem_ctx, &sid, sid2gid_recv, state); - return; - - fail: - /* - * We have to set the cache ourselves here, the child which is - * normally responsible was not queried yet. - */ - idmap_cache_set_sid2gid(&sid, -1); - request_error(state); - return; -} - -void winbindd_sid_to_gid(struct winbindd_cli_state *state) -{ - DOM_SID sid; - gid_t gid; - bool expired; - - /* Ensure null termination */ - state->request->data.sid[sizeof(state->request->data.sid)-1]='\0'; - - DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid, - state->request->data.sid)); - - if (!string_to_sid(&sid, state->request->data.sid)) { - DEBUG(1, ("Could not get convert sid %s from string\n", - state->request->data.sid)); - request_error(state); - return; - } - - if (idmap_cache_find_sid2gid(&sid, &gid, &expired)) { - DEBUG(10, ("idmap_cache_find_sid2gid found %d%s\n", - (int)gid, expired ? " (expired)": "")); - if (expired && IS_DOMAIN_ONLINE(find_our_domain())) { - DEBUG(10, ("revalidating expired entry\n")); - goto backend; - } - if (gid == -1) { - DEBUG(10, ("Returning negative cache entry\n")); - request_error(state); - return; - } - DEBUG(10, ("Returning positive cache entry\n")); - state->response->data.gid = gid; - request_ok(state); - return; - } - - /* Validate the SID as a group. Hopefully this will hit cache. - Needed to prevent DoS by exhausting the uid allocation - range from random SIDs. */ - - backend: - winbindd_lookupsid_async( state->mem_ctx, &sid, sid2gid_lookupsid_recv, - state ); -} - static void set_mapping_recv(void *private_data, bool success) { struct winbindd_cli_state *state = @@ -495,122 +171,6 @@ void winbindd_set_hwm(struct winbindd_cli_state *state) winbindd_set_hwm_async(state->mem_ctx, &xid, set_hwm_recv, state); } -/* Convert a uid to a sid */ - -static void uid2sid_recv(void *private_data, bool success, const char *sidstr) -{ - struct winbindd_cli_state *state = - (struct winbindd_cli_state *)private_data; - struct dom_sid sid; - - if (!success || !string_to_sid(&sid, sidstr)) { - ZERO_STRUCT(sid); - idmap_cache_set_sid2uid(&sid, state->request->data.uid); - request_error(state); - return; - } - - DEBUG(10,("uid2sid: uid %lu has sid %s\n", - (unsigned long)(state->request->data.uid), sidstr)); - - idmap_cache_set_sid2uid(&sid, state->request->data.uid); - fstrcpy(state->response->data.sid.sid, sidstr); - state->response->data.sid.type = SID_NAME_USER; - request_ok(state); - return; -} - -void winbindd_uid_to_sid(struct winbindd_cli_state *state) -{ - struct dom_sid sid; - bool expired; - - DEBUG(3, ("[%5lu]: uid to sid %lu\n", (unsigned long)state->pid, - (unsigned long)state->request->data.uid)); - - if (idmap_cache_find_uid2sid(state->request->data.uid, &sid, - &expired)) { - DEBUG(10, ("idmap_cache_find_uid2sid found %d%s\n", - (int)state->request->data.uid, - expired ? " (expired)": "")); - if (expired && IS_DOMAIN_ONLINE(find_our_domain())) { - DEBUG(10, ("revalidating expired entry\n")); - goto backend; - } - if (is_null_sid(&sid)) { - DEBUG(10, ("Returning negative cache entry\n")); - request_error(state); - return; - } - DEBUG(10, ("Returning positive cache entry\n")); - sid_to_fstring(state->response->data.sid.sid, &sid); - request_ok(state); - return; - } - - /* always go via the async interface (may block) */ - backend: - winbindd_uid2sid_async(state->mem_ctx, state->request->data.uid, uid2sid_recv, state); -} - -/* Convert a gid to a sid */ - -static void gid2sid_recv(void *private_data, bool success, const char *sidstr) -{ - struct winbindd_cli_state *state = - (struct winbindd_cli_state *)private_data; - struct dom_sid sid; - - if (!success || !string_to_sid(&sid, sidstr)) { - ZERO_STRUCT(sid); - idmap_cache_set_sid2gid(&sid, state->request->data.gid); - request_error(state); - return; - } - DEBUG(10,("gid2sid: gid %lu has sid %s\n", - (unsigned long)(state->request->data.gid), sidstr)); - - idmap_cache_set_sid2gid(&sid, state->request->data.gid); - fstrcpy(state->response->data.sid.sid, sidstr); - state->response->data.sid.type = SID_NAME_DOM_GRP; - request_ok(state); - return; -} - - -void winbindd_gid_to_sid(struct winbindd_cli_state *state) -{ - struct dom_sid sid; - bool expired; - - DEBUG(3, ("[%5lu]: gid to sid %lu\n", (unsigned long)state->pid, - (unsigned long)state->request->data.gid)); - - if (idmap_cache_find_gid2sid(state->request->data.gid, &sid, - &expired)) { - DEBUG(10, ("idmap_cache_find_gid2sid found %d%s\n", - (int)state->request->data.gid, - expired ? " (expired)": "")); - if (expired && IS_DOMAIN_ONLINE(find_our_domain())) { - DEBUG(10, ("revalidating expired entry\n")); - goto backend; - } - if (is_null_sid(&sid)) { - DEBUG(10, ("Returning negative cache entry\n")); - request_error(state); - return; - } - DEBUG(10, ("Returning positive cache entry\n")); - sid_to_fstring(state->response->data.sid.sid, &sid); - request_ok(state); - return; - } - - /* always use async calls (may block) */ - backend: - winbindd_gid2sid_async(state->mem_ctx, state->request->data.gid, gid2sid_recv, state); -} - void winbindd_allocate_uid(struct winbindd_cli_state *state) { if ( !state->privileged ) { diff --git a/source3/winbindd/winbindd_sid_to_gid.c b/source3/winbindd/winbindd_sid_to_gid.c new file mode 100644 index 0000000000..323b44d7f9 --- /dev/null +++ b/source3/winbindd/winbindd_sid_to_gid.c @@ -0,0 +1,94 @@ +/* + Unix SMB/CIFS implementation. + async implementation of WINBINDD_SID_TO_GID + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" + +struct winbindd_sid_to_gid_state { + struct dom_sid sid; + gid_t gid; +}; + +static void winbindd_sid_to_gid_done(struct tevent_req *subreq); + +struct tevent_req *winbindd_sid_to_gid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request) +{ + struct tevent_req *req, *subreq; + struct winbindd_sid_to_gid_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct winbindd_sid_to_gid_state); + if (req == NULL) { + return NULL; + } + + /* Ensure null termination */ + request->data.sid[sizeof(request->data.sid)-1]='\0'; + + DEBUG(3, ("sid to gid %s\n", request->data.sid)); + + if (!string_to_sid(&state->sid, request->data.sid)) { + DEBUG(1, ("Could not get convert sid %s from string\n", + request->data.sid)); + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + subreq = wb_sid2gid_send(state, ev, &state->sid); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, winbindd_sid_to_gid_done, req); + return req; +} + +static void winbindd_sid_to_gid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winbindd_sid_to_gid_state *state = tevent_req_data( + req, struct winbindd_sid_to_gid_state); + NTSTATUS status; + + status = wb_sid2gid_recv(subreq, &state->gid); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + tevent_req_done(req); +} + +NTSTATUS winbindd_sid_to_gid_recv(struct tevent_req *req, + struct winbindd_response *response) +{ + struct winbindd_sid_to_gid_state *state = tevent_req_data( + req, struct winbindd_sid_to_gid_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + DEBUG(5, ("Could not convert sid %s: %s\n", + sid_string_dbg(&state->sid), nt_errstr(status))); + return status; + } + response->data.gid = state->gid; + return NT_STATUS_OK; +} diff --git a/source3/winbindd/winbindd_sid_to_uid.c b/source3/winbindd/winbindd_sid_to_uid.c new file mode 100644 index 0000000000..a6ff6cbaf4 --- /dev/null +++ b/source3/winbindd/winbindd_sid_to_uid.c @@ -0,0 +1,94 @@ +/* + Unix SMB/CIFS implementation. + async implementation of WINBINDD_SID_TO_UID + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" + +struct winbindd_sid_to_uid_state { + struct dom_sid sid; + uid_t uid; +}; + +static void winbindd_sid_to_uid_done(struct tevent_req *subreq); + +struct tevent_req *winbindd_sid_to_uid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request) +{ + struct tevent_req *req, *subreq; + struct winbindd_sid_to_uid_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct winbindd_sid_to_uid_state); + if (req == NULL) { + return NULL; + } + + /* Ensure null termination */ + request->data.sid[sizeof(request->data.sid)-1]='\0'; + + DEBUG(3, ("sid to uid %s\n", request->data.sid)); + + if (!string_to_sid(&state->sid, request->data.sid)) { + DEBUG(1, ("Could not get convert sid %s from string\n", + request->data.sid)); + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + subreq = wb_sid2uid_send(state, ev, &state->sid); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, winbindd_sid_to_uid_done, req); + return req; +} + +static void winbindd_sid_to_uid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winbindd_sid_to_uid_state *state = tevent_req_data( + req, struct winbindd_sid_to_uid_state); + NTSTATUS status; + + status = wb_sid2uid_recv(subreq, &state->uid); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + tevent_req_done(req); +} + +NTSTATUS winbindd_sid_to_uid_recv(struct tevent_req *req, + struct winbindd_response *response) +{ + struct winbindd_sid_to_uid_state *state = tevent_req_data( + req, struct winbindd_sid_to_uid_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + DEBUG(5, ("Could not convert sid %s: %s\n", + sid_string_dbg(&state->sid), nt_errstr(status))); + return status; + } + response->data.uid = state->uid; + return NT_STATUS_OK; +} diff --git a/source3/winbindd/winbindd_uid_to_sid.c b/source3/winbindd/winbindd_uid_to_sid.c new file mode 100644 index 0000000000..151fffd296 --- /dev/null +++ b/source3/winbindd/winbindd_uid_to_sid.c @@ -0,0 +1,87 @@ +/* + Unix SMB/CIFS implementation. + async implementation of WINBINDD_UID_TO_SID + Copyright (C) Volker Lendecke 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" + +struct winbindd_uid_to_sid_state { + struct tevent_context *ev; + uid_t uid; + struct dom_sid sid; +}; + +static void winbindd_uid_to_sid_done(struct tevent_req *subreq); + +struct tevent_req *winbindd_uid_to_sid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_request *request) +{ + struct tevent_req *req, *subreq; + struct winbindd_uid_to_sid_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct winbindd_uid_to_sid_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + + DEBUG(3, ("uid_to_sid %d\n", (int)request->data.uid)); + + subreq = wb_uid2sid_send(state, ev, request->data.uid); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, winbindd_uid_to_sid_done, req); + return req; +} + +static void winbindd_uid_to_sid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winbindd_uid_to_sid_state *state = tevent_req_data( + req, struct winbindd_uid_to_sid_state); + NTSTATUS status; + + status = wb_uid2sid_recv(subreq, &state->sid); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + tevent_req_done(req); +} + +NTSTATUS winbindd_uid_to_sid_recv(struct tevent_req *req, + struct winbindd_response *response) +{ + struct winbindd_uid_to_sid_state *state = tevent_req_data( + req, struct winbindd_uid_to_sid_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + DEBUG(5, ("Could not convert sid %s: %s\n", + sid_string_dbg(&state->sid), nt_errstr(status))); + return status; + } + sid_to_fstring(response->data.sid.sid, &state->sid); + response->data.sid.type = SID_NAME_USER; + return NT_STATUS_OK; +} diff --git a/source3/winbindd/winbindd_user.c b/source3/winbindd/winbindd_user.c index c445ef0bdc..240b0f524f 100644 --- a/source3/winbindd/winbindd_user.c +++ b/source3/winbindd/winbindd_user.c @@ -27,7 +27,7 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_WINBIND -static bool fillup_pw_field(const char *lp_template, +bool fillup_pw_field(const char *lp_template, const char *username, const char *domname, uid_t uid, @@ -195,386 +195,6 @@ enum winbindd_result winbindd_dual_userinfo(struct winbindd_domain *domain, return WINBINDD_OK; } -struct getpwsid_state { - struct winbindd_cli_state *state; - struct winbindd_domain *domain; - char *username; - char *fullname; - char *homedir; - char *shell; - DOM_SID user_sid; - uid_t uid; - DOM_SID group_sid; - gid_t gid; - bool username_mapped; -}; - -static void getpwsid_queryuser_recv(void *private_data, bool success, - const char *acct_name, - const char *full_name, - const char *homedir, - const char *shell, - gid_t gid, - uint32 group_rid); -static void getpwsid_sid2uid_recv(void *private_data, bool success, uid_t uid); -static void getpwsid_sid2gid_recv(void *private_data, bool success, gid_t gid); - -static void getpwsid_queryuser(struct winbindd_cli_state *state, - const DOM_SID *sid) -{ - struct getpwsid_state *s; - - s = TALLOC_ZERO_P(state->mem_ctx, struct getpwsid_state); - if (s == NULL) { - DEBUG(0, ("talloc failed\n")); - goto error; - } - - s->state = state; - s->domain = find_domain_from_sid_noinit(sid); - if (s->domain == NULL) { - DEBUG(3, ("Could not find domain for sid %s\n", - sid_string_dbg(sid))); - goto error; - } - - sid_copy(&s->user_sid, sid); - - query_user_async(s->state->mem_ctx, s->domain, sid, - getpwsid_queryuser_recv, s); - return; - - error: - request_error(state); -} - -static void getpwsid_queryuser_recv(void *private_data, bool success, - const char *acct_name, - const char *full_name, - const char *homedir, - const char *shell, - gid_t gid, - uint32 group_rid) -{ - fstring username; - struct getpwsid_state *s = - talloc_get_type_abort(private_data, struct getpwsid_state); - char *mapped_name; - NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; - - if (!success) { - DEBUG(5, ("Could not query domain %s SID %s\n", - s->domain->name, sid_string_dbg(&s->user_sid))); - request_error(s->state); - return; - } - - if ( acct_name && *acct_name ) { - fstrcpy( username, acct_name ); - } else { - char *domain_name = NULL; - enum lsa_SidType type; - char *user_name = NULL; - struct winbindd_domain *domain = NULL; - - domain = find_lookup_domain_from_sid(&s->user_sid); - if (domain == NULL) { - DEBUG(5, ("find_lookup_domain_from_sid(%s) failed\n", - sid_string_dbg(&s->user_sid))); - request_error(s->state); - return; - } - winbindd_lookup_name_by_sid(s->state->mem_ctx, domain, - &s->user_sid, &domain_name, - &user_name, &type ); - - /* If this still fails we are done. Just error out */ - if ( !user_name ) { - DEBUG(5,("Could not obtain a name for SID %s\n", - sid_string_dbg(&s->user_sid))); - request_error(s->state); - return; - } - - fstrcpy( username, user_name ); - } - - strlower_m( username ); - s->username = talloc_strdup(s->state->mem_ctx, username); - - nt_status = normalize_name_map(s->state->mem_ctx, s->domain, - s->username, &mapped_name); - - /* Basic removal of whitespace */ - if (NT_STATUS_IS_OK(nt_status)) { - s->username = mapped_name; - s->username_mapped = false; - } - /* Complete name replacement */ - else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) { - s->username = mapped_name; - s->username_mapped = true; - } - /* No change at all */ - else { - s->username_mapped = false; - } - - s->fullname = talloc_strdup(s->state->mem_ctx, full_name); - s->homedir = talloc_strdup(s->state->mem_ctx, homedir); - s->shell = talloc_strdup(s->state->mem_ctx, shell); - s->gid = gid; - sid_copy(&s->group_sid, &s->domain->sid); - sid_append_rid(&s->group_sid, group_rid); - - winbindd_sid2uid_async(s->state->mem_ctx, &s->user_sid, - getpwsid_sid2uid_recv, s); -} - -static void getpwsid_sid2uid_recv(void *private_data, bool success, uid_t uid) -{ - struct getpwsid_state *s = - talloc_get_type_abort(private_data, struct getpwsid_state); - - if (!success) { - DEBUG(5, ("Could not query uid for user %s\\%s\n", - s->domain->name, s->username)); - request_error(s->state); - return; - } - - s->uid = uid; - winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid, - getpwsid_sid2gid_recv, s); -} - -static void getpwsid_sid2gid_recv(void *private_data, bool success, gid_t gid) -{ - struct getpwsid_state *s = - talloc_get_type_abort(private_data, struct getpwsid_state); - struct winbindd_pw *pw; - fstring output_username; - - /* allow the nss backend to override the primary group ID. - If the gid has already been set, then keep it. - This makes me feel dirty. If the nss backend already - gave us a gid, we don't really care whether the sid2gid() - call worked or not. --jerry */ - - if ( s->gid == (gid_t)-1 ) { - - if (!success) { - DEBUG(5, ("Could not query gid for user %s\\%s\n", - s->domain->name, s->username)); - goto failed; - } - - /* take what the sid2gid() call gave us */ - s->gid = gid; - } - - pw = &s->state->response->data.pw; - pw->pw_uid = s->uid; - pw->pw_gid = s->gid; - - /* allow username to be overridden by the alias mapping */ - - if ( s->username_mapped ) { - fstrcpy( output_username, s->username ); - } else { - fill_domain_username(output_username, s->domain->name, - s->username, True); - } - - safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1); - safe_strcpy(pw->pw_gecos, s->fullname, sizeof(pw->pw_gecos) - 1); - - if (!fillup_pw_field(lp_template_homedir(), s->username, - s->domain->name, pw->pw_uid, pw->pw_gid, - s->homedir, pw->pw_dir)) { - DEBUG(5, ("Could not compose homedir\n")); - goto failed; - } - - if (!fillup_pw_field(lp_template_shell(), s->username, - s->domain->name, pw->pw_uid, pw->pw_gid, - s->shell, pw->pw_shell)) { - DEBUG(5, ("Could not compose shell\n")); - goto failed; - } - - /* Password - set to "*" as we can't generate anything useful here. - Authentication can be done using the pam_winbind module. */ - - safe_strcpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd) - 1); - - request_ok(s->state); - return; - - failed: - request_error(s->state); -} - -/* Return a password structure from a username. */ - -static void getpwnam_name2sid_recv(void *private_data, bool success, - const DOM_SID *sid, enum lsa_SidType type); - -void winbindd_getpwnam(struct winbindd_cli_state *state) -{ - struct winbindd_domain *domain; - fstring domname, username; - char *mapped_user = NULL; - char *domuser; - NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; - - domuser = state->request->data.username; - - /* Ensure null termination (it's an fstring) */ - domuser[sizeof(state->request->data.username)-1] = '\0'; - - DEBUG(3, ("[%5lu]: getpwnam %s\n", - (unsigned long)state->pid, - domuser)); - - nt_status = normalize_name_unmap(state->mem_ctx, domuser, - &mapped_user); - - /* If we could not convert from an aliased name or a - normalized name, then just use the original name */ - - if (!NT_STATUS_IS_OK(nt_status) && - !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) - { - mapped_user = domuser; - } - - if (!parse_domain_user(mapped_user, domname, username)) { - DEBUG(5, ("Could not parse domain user: %s\n", domuser)); - request_error(state); - return; - } - - /* Get info for the domain */ - - domain = find_domain_from_name_noinit(domname); - - if (domain == NULL) { - DEBUG(7, ("could not find domain entry for domain %s. " - "Using primary domain\n", domname)); - domain = find_our_domain(); - if (domain == NULL) { - DEBUG(0, ("Cannot find my primary domain " - "structure!\n")); - request_error(state); - return; - } - } - - if (strequal(domname, lp_workgroup()) && - lp_winbind_trusted_domains_only() ) { - DEBUG(7,("winbindd_getpwnam: My domain -- " - "rejecting getpwnam() for %s\\%s.\n", - domname, username)); - request_error(state); - return; - } - - /* Get rid and name type from name. The following costs 1 packet */ - - winbindd_lookupname_async(state->mem_ctx, domname, username, - getpwnam_name2sid_recv, WINBINDD_GETPWNAM, - state); -} - -static void getpwnam_name2sid_recv(void *private_data, bool success, - const DOM_SID *sid, enum lsa_SidType type) -{ - struct winbindd_cli_state *state = - (struct winbindd_cli_state *)private_data; - fstring domname, username; - char *domuser = state->request->data.username; - - if (!success) { - DEBUG(5, ("Could not lookup name for user %s\n", domuser)); - request_error(state); - return; - } - - if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER)) { - DEBUG(5, ("%s is not a user\n", domuser)); - request_error(state); - return; - } - - if (parse_domain_user(domuser, domname, username)) { - check_domain_trusted(domname, sid); - } - - getpwsid_queryuser(state, sid); -} - -static void getpwuid_recv(void *private_data, bool success, const char *sid) -{ - struct winbindd_cli_state *state = - (struct winbindd_cli_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)); - - if (!string_to_sid(&user_sid, sid)) { - DEBUG(1,("uid2sid_recv: Could not convert sid %s " - "from string\n,", sid)); - request_error(state); - return; - } - - getpwsid_queryuser(state, &user_sid); -} - -/* Return a password structure given a uid number */ -void winbindd_getpwuid(struct winbindd_cli_state *state) -{ - uid_t uid = state->request->data.uid; - - DEBUG(3, ("[%5lu]: getpwuid %lu\n", - (unsigned long)state->pid, - (unsigned long)uid)); - - /* always query idmap via the async interface */ - /* if this turns to be too slow we will add here - * a direct query to the cache */ - winbindd_uid2sid_async(state->mem_ctx, uid, getpwuid_recv, state); -} - -/* Return a password structure given a sid */ -void winbindd_getpwsid(struct winbindd_cli_state *state) -{ - DOM_SID sid; - - /* Ensure null termination */ - state->request->data.sid[sizeof(state->request->data.sid)-1]='\0'; - - DEBUG(3, ("[%5lu]: getpwsid %s\n", (unsigned long)state->pid, - state->request->data.sid)); - - if (!string_to_sid(&sid, state->request->data.sid)) { - DEBUG(5, ("%s not a SID\n", state->request->data.sid)); - request_error(state); - return; - } - - getpwsid_queryuser(state, &sid); -} - /* * set/get/endpwent functions */ |