diff options
-rw-r--r-- | source3/Makefile.in | 1 | ||||
-rw-r--r-- | source3/winbindd/wb_getpwsid.c | 223 | ||||
-rw-r--r-- | source3/winbindd/winbindd_proto.h | 6 |
3 files changed, 230 insertions, 0 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index b3f54e092b..ec47eccd4b 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -1159,6 +1159,7 @@ WINBINDD_OBJ1 = \ winbindd/wb_uid2sid.o \ winbindd/wb_gid2sid.o \ winbindd/wb_queryuser.o \ + winbindd/wb_getpwsid.o \ winbindd/winbindd_lookupsid.o \ winbindd/winbindd_lookupname.o \ winbindd/winbindd_sid_to_uid.o \ diff --git a/source3/winbindd/wb_getpwsid.c b/source3/winbindd/wb_getpwsid.c new file mode 100644 index 0000000000..a823ba3953 --- /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(), state->pw->pw_name, + 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_homedir(), state->pw->pw_name, + state->user_domain->name, state->pw->pw_uid, + state->pw->pw_gid, state->userinfo->homedir, + 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/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index bfcf315231..ef977bb3b0 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -699,4 +699,10 @@ struct tevent_req *wb_queryuser_send(TALLOC_CTX *mem_ctx, 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); + #endif /* _WINBINDD_PROTO_H_ */ |