From: Volker Lendecke Date: Mon, 17 Aug 2009 21:13:48 +0000 (+0200) Subject: s3:winbind: Convert the GETPWENT routines to the new API X-Git-Tag: tevent-0.9.8~103 X-Git-Url: http://git.samba.org/?a=commitdiff_plain;h=9c30a8dc6fffd592592a108f3d9d93769ba74417;p=samba.git s3:winbind: Convert the GETPWENT routines to the new API --- diff --git a/source3/Makefile.in b/source3/Makefile.in index c930f2af3cc..2aa8e37ddbb 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -1198,6 +1198,9 @@ WINBINDD_OBJ1 = \ winbindd/winbindd_getgrgid.o \ winbindd/winbindd_getgrnam.o \ winbindd/winbindd_getusersids.o \ + winbindd/winbindd_setpwent.o \ + winbindd/winbindd_getpwent.o \ + winbindd/winbindd_endpwent.o \ auth/token_util.o \ ../nsswitch/libwbclient/wb_reqtrans.o \ smbd/connection.o diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c index 5c2ed961efa..85203fbed0c 100644 --- a/source3/winbindd/winbindd.c +++ b/source3/winbindd/winbindd.c @@ -425,12 +425,6 @@ static struct winbindd_dispatch_table { const char *winbindd_cmd_name; } dispatch_table[] = { - /* User functions */ - - { WINBINDD_SETPWENT, winbindd_setpwent, "SETPWENT" }, - { WINBINDD_ENDPWENT, winbindd_endpwent, "ENDPWENT" }, - { WINBINDD_GETPWENT, winbindd_getpwent, "GETPWENT" }, - /* Group functions */ { WINBINDD_SETGRENT, winbindd_setgrent, "SETGRENT" }, @@ -538,6 +532,12 @@ static struct winbindd_async_dispatch_table async_nonpriv_table[] = { winbindd_getgrnam_send, winbindd_getgrnam_recv }, { WINBINDD_GETUSERSIDS, "GETUSERSIDS", winbindd_getusersids_send, winbindd_getusersids_recv }, + { WINBINDD_SETPWENT, "SETPWENT", + winbindd_setpwent_send, winbindd_setpwent_recv }, + { WINBINDD_GETPWENT, "GETPWENT", + winbindd_getpwent_send, winbindd_getpwent_recv }, + { WINBINDD_ENDPWENT, "ENDPWENT", + winbindd_endpwent_send, winbindd_endpwent_recv }, { 0, NULL, NULL, NULL } }; @@ -814,7 +814,6 @@ static void remove_client(struct winbindd_cli_state *state) /* Free any getent state */ - free_getent_state(state->getpwent_state); free_getent_state(state->getgrent_state); TALLOC_FREE(state->mem_ctx); @@ -835,7 +834,7 @@ static bool remove_idle_client(void) for (state = winbindd_client_list(); state; state = state->next) { if (state->response == NULL && - !state->getpwent_state && !state->getgrent_state) { + !state->pwent_state && !state->getgrent_state) { nidle++; if (!last_access || state->last_access < last_access) { last_access = state->last_access; diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h index 454fea70e69..d199481a225 100644 --- a/source3/winbindd/winbindd.h +++ b/source3/winbindd/winbindd.h @@ -65,8 +65,9 @@ struct winbindd_cli_state { * initialized? */ bool getgrent_initialized; /* Has getgrent_state been * initialized? */ - struct getent_state *getpwent_state; /* State for getpwent() */ struct getent_state *getgrent_state; /* State for getgrent() */ + + struct getpwent_state *pwent_state; /* State for getpwent() */ }; /* State between get{pw,gr}ent() calls */ diff --git a/source3/winbindd/winbindd_endpwent.c b/source3/winbindd/winbindd_endpwent.c new file mode 100644 index 00000000000..8f785fb3a8a --- /dev/null +++ b/source3/winbindd/winbindd_endpwent.c @@ -0,0 +1,49 @@ +/* + Unix SMB/CIFS implementation. + async implementation of WINBINDD_ENDPWENT + 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 . +*/ + +#include "includes.h" +#include "winbindd.h" + +struct winbindd_endpwent_state { + uint8_t dummy; +}; + +struct tevent_req *winbindd_endpwent_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_cli_state *cli, + struct winbindd_request *request) +{ + struct tevent_req *req; + struct winbindd_endpwent_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct winbindd_endpwent_state); + if (req == NULL) { + return NULL; + } + TALLOC_FREE(cli->pwent_state); + tevent_req_done(req); + return tevent_req_post(req, ev); +} + +NTSTATUS winbindd_endpwent_recv(struct tevent_req *req, + struct winbindd_response *presp) +{ + return NT_STATUS_OK; +} diff --git a/source3/winbindd/winbindd_getpwent.c b/source3/winbindd/winbindd_getpwent.c new file mode 100644 index 00000000000..a0658747dae --- /dev/null +++ b/source3/winbindd/winbindd_getpwent.c @@ -0,0 +1,145 @@ +/* + Unix SMB/CIFS implementation. + async implementation of WINBINDD_SETPWENT + 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 . +*/ + +#include "includes.h" +#include "winbindd.h" + +struct winbindd_getpwent_state { + struct tevent_context *ev; + struct winbindd_cli_state *cli; + int max_users; + int num_users; + struct winbindd_pw *users; +}; + +static void winbindd_getpwent_done(struct tevent_req *subreq); + +struct tevent_req *winbindd_getpwent_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_cli_state *cli, + struct winbindd_request *request) +{ + struct tevent_req *req, *subreq; + struct winbindd_getpwent_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct winbindd_getpwent_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->num_users = 0; + state->cli = cli; + + DEBUG(3, ("[%5lu]: getpwent\n", (unsigned long)cli->pid)); + + if (!lp_winbind_enum_users()) { + tevent_req_nterror(req, NT_STATUS_NO_MORE_ENTRIES); + return tevent_req_post(req, ev); + } + + if (cli->pwent_state == NULL) { + tevent_req_nterror(req, NT_STATUS_NO_MORE_ENTRIES); + return tevent_req_post(req, ev); + } + + state->max_users = MIN(500, request->data.num_entries); + if (state->max_users == 0) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + state->users = talloc_zero_array(state, struct winbindd_pw, + state->max_users); + if (tevent_req_nomem(state->users, req)) { + return tevent_req_post(req, ev); + } + + subreq = wb_next_pwent_send(state, ev, cli->pwent_state, + &state->users[state->num_users]); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, winbindd_getpwent_done, req); + return req; +} + +static void winbindd_getpwent_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winbindd_getpwent_state *state = tevent_req_data( + req, struct winbindd_getpwent_state); + NTSTATUS status; + + status = wb_next_pwent_recv(subreq); + TALLOC_FREE(subreq); + if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) { + DEBUG(10, ("winbindd_getpwent_done: done with %d users\n", + (int)state->num_users)); + TALLOC_FREE(state->cli->pwent_state); + tevent_req_done(req); + return; + } + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + state->num_users += 1; + if (state->num_users >= state->max_users) { + DEBUG(10, ("winbindd_getpwent_done: Got enough users: %d\n", + (int)state->num_users)); + tevent_req_done(req); + return; + } + if (state->cli->pwent_state == NULL) { + DEBUG(10, ("winbindd_getpwent_done: endpwent called in " + "between\n")); + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return; + } + subreq = wb_next_pwent_send(state, state->ev, state->cli->pwent_state, + &state->users[state->num_users]); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, winbindd_getpwent_done, req); +} + +NTSTATUS winbindd_getpwent_recv(struct tevent_req *req, + struct winbindd_response *response) +{ + struct winbindd_getpwent_state *state = tevent_req_data( + req, struct winbindd_getpwent_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + DEBUG(5, ("getpwent failed: %s\n", nt_errstr(status))); + return status; + } + + if (state->num_users == 0) { + return NT_STATUS_NO_MORE_ENTRIES; + } + + response->data.num_entries = state->num_users; + response->extra_data.data = talloc_move(response, &state->users); + response->length += state->num_users * sizeof(struct winbindd_pw); + return NT_STATUS_OK; +} diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index f66becae33f..1cce60c1cbc 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -868,5 +868,25 @@ struct tevent_req *wb_next_pwent_send(TALLOC_CTX *mem_ctx, struct winbindd_pw *pw); NTSTATUS wb_next_pwent_recv(struct tevent_req *req); +struct tevent_req *winbindd_setpwent_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_cli_state *cli, + struct winbindd_request *request); +NTSTATUS winbindd_setpwent_recv(struct tevent_req *req, + struct winbindd_response *presp); + +struct tevent_req *winbindd_getpwent_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_cli_state *cli, + struct winbindd_request *request); +NTSTATUS winbindd_getpwent_recv(struct tevent_req *req, + struct winbindd_response *response); + +struct tevent_req *winbindd_endpwent_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_cli_state *cli, + struct winbindd_request *request); +NTSTATUS winbindd_endpwent_recv(struct tevent_req *req, + struct winbindd_response *response); #endif /* _WINBINDD_PROTO_H_ */ diff --git a/source3/winbindd/winbindd_setpwent.c b/source3/winbindd/winbindd_setpwent.c new file mode 100644 index 00000000000..af287584757 --- /dev/null +++ b/source3/winbindd/winbindd_setpwent.c @@ -0,0 +1,55 @@ +/* + Unix SMB/CIFS implementation. + async implementation of WINBINDD_SETPWENT + 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 . +*/ + +#include "includes.h" +#include "winbindd.h" + +struct winbindd_setpwent_state { + uint8_t dummy; +}; + +struct tevent_req *winbindd_setpwent_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_cli_state *cli, + struct winbindd_request *request) +{ + struct tevent_req *req; + struct winbindd_setpwent_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct winbindd_setpwent_state); + if (req == NULL) { + return NULL; + } + TALLOC_FREE(cli->pwent_state); + + cli->pwent_state = talloc_zero(cli, struct getpwent_state); + if (tevent_req_nomem(cli->pwent_state, req)) { + return tevent_req_post(req, ev); + } + + tevent_req_done(req); + return tevent_req_post(req, ev); +} + +NTSTATUS winbindd_setpwent_recv(struct tevent_req *req, + struct winbindd_response *presp) +{ + return NT_STATUS_OK; +} diff --git a/source3/winbindd/winbindd_user.c b/source3/winbindd/winbindd_user.c index 10fb1671bda..d72aaeff745 100644 --- a/source3/winbindd/winbindd_user.c +++ b/source3/winbindd/winbindd_user.c @@ -65,90 +65,6 @@ bool fillup_pw_field(const char *lp_template, return True; } -/* Fill a pwent structure with information we have obtained */ - -static bool winbindd_fill_pwent(TALLOC_CTX *ctx, char *dom_name, char *user_name, - DOM_SID *user_sid, DOM_SID *group_sid, - char *full_name, char *homedir, char *shell, - struct winbindd_pw *pw) -{ - fstring output_username; - char *mapped_name = NULL; - struct winbindd_domain *domain = NULL; - NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; - - if (!pw || !dom_name || !user_name) - return False; - - domain = find_domain_from_name_noinit(dom_name); - if (domain == NULL) { - DEBUG(5,("winbindd_fill_pwent: Failed to find domain for %s.\n", - dom_name)); - nt_status = NT_STATUS_NO_SUCH_DOMAIN; - return false; - } - - /* Resolve the uid number */ - - if (!NT_STATUS_IS_OK(idmap_sid_to_uid(domain->have_idmap_config ? - dom_name : "", user_sid, - &pw->pw_uid))) { - DEBUG(1, ("error getting user id for sid %s\n", - sid_string_dbg(user_sid))); - return False; - } - - /* Resolve the gid number */ - - if (!NT_STATUS_IS_OK(idmap_sid_to_gid(domain->have_idmap_config ? - dom_name : "", group_sid, - &pw->pw_gid))) { - DEBUG(1, ("error getting group id for sid %s\n", - sid_string_dbg(group_sid))); - return False; - } - - /* Username */ - - strlower_m(user_name); - nt_status = normalize_name_map(ctx, domain, user_name, &mapped_name); - - /* Basic removal of whitespace */ - if (NT_STATUS_IS_OK(nt_status)) { - fill_domain_username(output_username, dom_name, mapped_name, True); - } - /* Complete name replacement */ - else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) { - fstrcpy(output_username, mapped_name); - } - /* No change at all */ - else { - fill_domain_username(output_username, dom_name, user_name, True); - } - - safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1); - - /* Full name (gecos) */ - - safe_strcpy(pw->pw_gecos, full_name, sizeof(pw->pw_gecos) - 1); - - /* Home directory and shell */ - - if (!fillup_pw_field(lp_template_homedir(), user_name, dom_name, - pw->pw_uid, pw->pw_gid, homedir, pw->pw_dir)) - return False; - - if (!fillup_pw_field(lp_template_shell(), user_name, dom_name, - pw->pw_uid, pw->pw_gid, shell, pw->pw_shell)) - return False; - - /* 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); - - return True; -} /* Wrapper for domain->methods->query_user, only on the parent->child pipe */ @@ -195,298 +111,6 @@ enum winbindd_result winbindd_dual_userinfo(struct winbindd_domain *domain, return WINBINDD_OK; } -/* - * set/get/endpwent functions - */ - -/* Rewind file pointer for ntdom passwd database */ - -static bool winbindd_setpwent_internal(struct winbindd_cli_state *state) -{ - struct winbindd_domain *domain; - - DEBUG(3, ("[%5lu]: setpwent\n", (unsigned long)state->pid)); - - /* Check user has enabled this */ - - if (!lp_winbind_enum_users()) { - return False; - } - - /* Free old static data if it exists */ - - if (state->getpwent_state != NULL) { - free_getent_state(state->getpwent_state); - state->getpwent_state = NULL; - } - - /* Create sam pipes for each domain we know about */ - - for(domain = domain_list(); domain != NULL; domain = domain->next) { - struct getent_state *domain_state; - - - /* don't add our domaina if we are a PDC or if we - are a member of a Samba domain */ - - if ((IS_DC || lp_winbind_trusted_domains_only()) - && strequal(domain->name, lp_workgroup())) { - continue; - } - - /* Create a state record for this domain */ - - domain_state = SMB_MALLOC_P(struct getent_state); - if (!domain_state) { - DEBUG(0, ("malloc failed\n")); - return False; - } - - ZERO_STRUCTP(domain_state); - - fstrcpy(domain_state->domain_name, domain->name); - - /* Add to list of open domains */ - - DLIST_ADD(state->getpwent_state, domain_state); - } - - state->getpwent_initialized = True; - return True; -} - -void winbindd_setpwent(struct winbindd_cli_state *state) -{ - if (winbindd_setpwent_internal(state)) { - request_ok(state); - } else { - request_error(state); - } -} - -/* Close file pointer to ntdom passwd database */ - -void winbindd_endpwent(struct winbindd_cli_state *state) -{ - DEBUG(3, ("[%5lu]: endpwent\n", (unsigned long)state->pid)); - - free_getent_state(state->getpwent_state); - state->getpwent_initialized = False; - state->getpwent_state = NULL; - request_ok(state); -} - -/* Get partial list of domain users for a domain. We fill in the sam_entries, - and num_sam_entries fields with domain user information. The dispinfo_ndx - field is incremented to the index of the next user to fetch. Return True if - some users were returned, False otherwise. */ - -static bool get_sam_user_entries(struct getent_state *ent, TALLOC_CTX *mem_ctx) -{ - NTSTATUS status; - uint32 num_entries; - struct wbint_userinfo *info; - struct getpwent_user *name_list = NULL; - struct winbindd_domain *domain; - struct winbindd_methods *methods; - unsigned int i; - - if (ent->num_sam_entries) - return False; - - if (!(domain = find_domain_from_name(ent->domain_name))) { - DEBUG(3, ("no such domain %s in get_sam_user_entries\n", - ent->domain_name)); - return False; - } - - methods = domain->methods; - - /* Free any existing user info */ - - SAFE_FREE(ent->sam_entries); - ent->num_sam_entries = 0; - - /* Call query_user_list to get a list of usernames and user rids */ - - num_entries = 0; - - status = methods->query_user_list(domain, mem_ctx, &num_entries, &info); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10,("get_sam_user_entries: " - "query_user_list failed with %s\n", - nt_errstr(status))); - return False; - } - - if (num_entries) { - name_list = SMB_REALLOC_ARRAY(name_list, struct getpwent_user, - ent->num_sam_entries + num_entries); - if (!name_list) { - DEBUG(0,("get_sam_user_entries realloc failed.\n")); - return False; - } - } - - for (i = 0; i < num_entries; i++) { - /* Store account name and gecos */ - if (!info[i].acct_name) { - fstrcpy(name_list[ent->num_sam_entries + i].name, ""); - } else { - fstrcpy(name_list[ent->num_sam_entries + i].name, - info[i].acct_name); - } - if (!info[i].full_name) { - fstrcpy(name_list[ent->num_sam_entries + i].gecos, ""); - } else { - fstrcpy(name_list[ent->num_sam_entries + i].gecos, - info[i].full_name); - } - if (!info[i].homedir) { - fstrcpy(name_list[ent->num_sam_entries + i].homedir,""); - } else { - fstrcpy(name_list[ent->num_sam_entries + i].homedir, - info[i].homedir); - } - if (!info[i].shell) { - fstrcpy(name_list[ent->num_sam_entries + i].shell, ""); - } else { - fstrcpy(name_list[ent->num_sam_entries + i].shell, - info[i].shell); - } - - - /* User and group ids */ - sid_copy(&name_list[ent->num_sam_entries+i].user_sid, - &info[i].user_sid); - sid_copy(&name_list[ent->num_sam_entries+i].group_sid, - &info[i].group_sid); - } - - ent->num_sam_entries += num_entries; - - /* Fill in remaining fields */ - - ent->sam_entries = name_list; - ent->sam_entry_index = 0; - return ent->num_sam_entries > 0; -} - -/* Fetch next passwd entry from ntdom database */ - -#define MAX_GETPWENT_USERS 500 - -void winbindd_getpwent(struct winbindd_cli_state *state) -{ - struct getent_state *ent; - struct winbindd_pw *user_list; - int num_users, user_list_ndx; - - DEBUG(3, ("[%5lu]: getpwent\n", (unsigned long)state->pid)); - - /* Check user has enabled this */ - - if (!lp_winbind_enum_users()) { - request_error(state); - return; - } - - /* Allocate space for returning a chunk of users */ - - num_users = MIN(MAX_GETPWENT_USERS, state->request->data.num_entries); - - if (num_users == 0) { - request_error(state); - return; - } - - user_list = talloc_zero_array(state->mem_ctx, struct winbindd_pw, - num_users); - if (!user_list) { - request_error(state); - return; - } - state->response->extra_data.data = user_list; - - if (!state->getpwent_initialized) - winbindd_setpwent_internal(state); - - if (!(ent = state->getpwent_state)) { - request_error(state); - return; - } - - /* Start sending back users */ - - for (user_list_ndx = 0; user_list_ndx < num_users; ) { - struct getpwent_user *name_list = NULL; - uint32 result; - - /* Do we need to fetch another chunk of users? */ - - if (ent->num_sam_entries == ent->sam_entry_index) { - - while(ent && - !get_sam_user_entries(ent, state->mem_ctx)) { - struct getent_state *next_ent; - - /* Free state information for this domain */ - - SAFE_FREE(ent->sam_entries); - - next_ent = ent->next; - DLIST_REMOVE(state->getpwent_state, ent); - - SAFE_FREE(ent); - ent = next_ent; - } - - /* No more domains */ - - if (!ent) - break; - } - - name_list = (struct getpwent_user *)ent->sam_entries; - - /* Lookup user info */ - - result = winbindd_fill_pwent( - state->mem_ctx, - ent->domain_name, - name_list[ent->sam_entry_index].name, - &name_list[ent->sam_entry_index].user_sid, - &name_list[ent->sam_entry_index].group_sid, - name_list[ent->sam_entry_index].gecos, - name_list[ent->sam_entry_index].homedir, - name_list[ent->sam_entry_index].shell, - &user_list[user_list_ndx]); - - /* Add user to return list */ - - if (result) { - - user_list_ndx++; - state->response->data.num_entries++; - state->response->length += sizeof(struct winbindd_pw); - - } else - DEBUG(1, ("could not lookup domain user %s\n", - name_list[ent->sam_entry_index].name)); - - ent->sam_entry_index++; - - } - - /* Out of domains */ - - if (user_list_ndx > 0) - request_ok(state); - else - request_error(state); -} - /* List domain users without mapping to unix ids */ void winbindd_list_users(struct winbindd_cli_state *state) {