1/* 2 Unix SMB/CIFS implementation. 3 async implementation of WINBINDD_GETPWENT 4 Copyright (C) Volker Lendecke 2009 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18*/ 19 20#include "includes.h" 21#include "winbindd.h" 22 23struct winbindd_getpwent_state { 24 struct tevent_context *ev; 25 struct winbindd_cli_state *cli; 26 int max_users; 27 int num_users; 28 struct winbindd_pw *users; 29}; 30 31static void winbindd_getpwent_done(struct tevent_req *subreq); 32 33struct tevent_req *winbindd_getpwent_send(TALLOC_CTX *mem_ctx, 34 struct tevent_context *ev, 35 struct winbindd_cli_state *cli, 36 struct winbindd_request *request) 37{ 38 struct tevent_req *req, *subreq; 39 struct winbindd_getpwent_state *state; 40 41 req = tevent_req_create(mem_ctx, &state, 42 struct winbindd_getpwent_state); 43 if (req == NULL) { 44 return NULL; 45 } 46 state->ev = ev; 47 state->num_users = 0; 48 state->cli = cli; 49 50 DEBUG(3, ("[%5lu]: getpwent\n", (unsigned long)cli->pid)); 51 52 if (!lp_winbind_enum_users()) { 53 tevent_req_nterror(req, NT_STATUS_NO_MORE_ENTRIES); 54 return tevent_req_post(req, ev); 55 } 56 57 if (cli->pwent_state == NULL) { 58 tevent_req_nterror(req, NT_STATUS_NO_MORE_ENTRIES); 59 return tevent_req_post(req, ev); 60 } 61 62 state->max_users = MIN(500, request->data.num_entries); 63 if (state->max_users == 0) { 64 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); 65 return tevent_req_post(req, ev); 66 } 67 68 state->users = talloc_zero_array(state, struct winbindd_pw, 69 state->max_users); 70 if (tevent_req_nomem(state->users, req)) { 71 return tevent_req_post(req, ev); 72 } 73 74 subreq = wb_next_pwent_send(state, ev, cli->pwent_state, 75 &state->users[state->num_users]); 76 if (tevent_req_nomem(subreq, req)) { 77 return tevent_req_post(req, ev); 78 } 79 tevent_req_set_callback(subreq, winbindd_getpwent_done, req); 80 return req; 81} 82 83static void winbindd_getpwent_done(struct tevent_req *subreq) 84{ 85 struct tevent_req *req = tevent_req_callback_data( 86 subreq, struct tevent_req); 87 struct winbindd_getpwent_state *state = tevent_req_data( 88 req, struct winbindd_getpwent_state); 89 NTSTATUS status; 90 91 status = wb_next_pwent_recv(subreq); 92 TALLOC_FREE(subreq); 93 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) { 94 DEBUG(10, ("winbindd_getpwent_done: done with %d users\n", 95 (int)state->num_users)); 96 TALLOC_FREE(state->cli->pwent_state); 97 tevent_req_done(req); 98 return; 99 } 100 if (!NT_STATUS_IS_OK(status)) { 101 tevent_req_nterror(req, status); 102 return; 103 } 104 state->num_users += 1; 105 if (state->num_users >= state->max_users) { 106 DEBUG(10, ("winbindd_getpwent_done: Got enough users: %d\n", 107 (int)state->num_users)); 108 tevent_req_done(req); 109 return; 110 } 111 if (state->cli->pwent_state == NULL) { 112 DEBUG(10, ("winbindd_getpwent_done: endpwent called in " 113 "between\n")); 114 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); 115 return; 116 } 117 subreq = wb_next_pwent_send(state, state->ev, state->cli->pwent_state, 118 &state->users[state->num_users]); 119 if (tevent_req_nomem(subreq, req)) { 120 return; 121 } 122 tevent_req_set_callback(subreq, winbindd_getpwent_done, req); 123} 124 125NTSTATUS winbindd_getpwent_recv(struct tevent_req *req, 126 struct winbindd_response *response) 127{ 128 struct winbindd_getpwent_state *state = tevent_req_data( 129 req, struct winbindd_getpwent_state); 130 NTSTATUS status; 131 132 if (tevent_req_is_nterror(req, &status)) { 133 DEBUG(5, ("getpwent failed: %s\n", nt_errstr(status))); 134 return status; 135 } 136 137 if (state->num_users == 0) { 138 return NT_STATUS_NO_MORE_ENTRIES; 139 } 140 141 response->data.num_entries = state->num_users; 142 response->extra_data.data = talloc_move(response, &state->users); 143 response->length += state->num_users * sizeof(struct winbindd_pw); 144 return NT_STATUS_OK; 145} 146