1/* 2 Unix SMB/CIFS implementation. 3 async next_grent 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#include "librpc/gen_ndr/cli_wbint.h" 23 24struct wb_next_grent_state { 25 struct tevent_context *ev; 26 int max_nesting; 27 struct getgrent_state *gstate; 28 struct wbint_Principals next_groups; 29 struct winbindd_gr *gr; 30 struct talloc_dict *members; 31}; 32 33static void wb_next_grent_fetch_done(struct tevent_req *subreq); 34static void wb_next_grent_getgrsid_done(struct tevent_req *subreq); 35 36struct tevent_req *wb_next_grent_send(TALLOC_CTX *mem_ctx, 37 struct tevent_context *ev, 38 int max_nesting, 39 struct getgrent_state *gstate, 40 struct winbindd_gr *gr) 41{ 42 struct tevent_req *req, *subreq; 43 struct wb_next_grent_state *state; 44 45 req = tevent_req_create(mem_ctx, &state, struct wb_next_grent_state); 46 if (req == NULL) { 47 return NULL; 48 } 49 state->ev = ev; 50 state->gstate = gstate; 51 state->gr = gr; 52 state->max_nesting = max_nesting; 53 54 if (state->gstate->next_group >= state->gstate->num_groups) { 55 TALLOC_FREE(state->gstate->groups); 56 57 if (state->gstate->domain == NULL) { 58 state->gstate->domain = domain_list(); 59 } else { 60 state->gstate->domain = state->gstate->domain->next; 61 } 62 63 if ((state->gstate->domain != NULL) 64 && sid_check_is_domain(&state->gstate->domain->sid)) { 65 state->gstate->domain = state->gstate->domain->next; 66 } 67 68 if (state->gstate->domain == NULL) { 69 tevent_req_nterror(req, NT_STATUS_NO_MORE_ENTRIES); 70 return tevent_req_post(req, ev); 71 } 72 subreq = rpccli_wbint_QueryGroupList_send( 73 state, state->ev, state->gstate->domain->child.rpccli, 74 &state->next_groups); 75 if (tevent_req_nomem(subreq, req)) { 76 return tevent_req_post(req, ev); 77 } 78 tevent_req_set_callback(subreq, wb_next_grent_fetch_done, req); 79 return req; 80 } 81 82 subreq = wb_getgrsid_send( 83 state, state->ev, 84 &state->gstate->groups[state->gstate->next_group].sid, 85 state->max_nesting); 86 if (tevent_req_nomem(subreq, req)) { 87 return tevent_req_post(req, ev); 88 } 89 tevent_req_set_callback(subreq, wb_next_grent_getgrsid_done, req); 90 return req; 91} 92 93static void wb_next_grent_fetch_done(struct tevent_req *subreq) 94{ 95 struct tevent_req *req = tevent_req_callback_data( 96 subreq, struct tevent_req); 97 struct wb_next_grent_state *state = tevent_req_data( 98 req, struct wb_next_grent_state); 99 NTSTATUS status, result; 100 101 status = rpccli_wbint_QueryGroupList_recv(subreq, state, &result); 102 TALLOC_FREE(subreq); 103 if (!NT_STATUS_IS_OK(status) || !NT_STATUS_IS_OK(result)) { 104 /* Ignore errors here, just log it */ 105 DEBUG(10, ("query_user_list for domain %s returned %s/%s\n", 106 state->gstate->domain->name, 107 nt_errstr(status), nt_errstr(result))); 108 tevent_req_nterror(req, result); 109 return; 110 } 111 112 state->gstate->num_groups = state->next_groups.num_principals; 113 state->gstate->groups = talloc_move( 114 state->gstate, &state->next_groups.principals); 115 116 if (state->gstate->num_groups == 0) { 117 state->gstate->domain = state->gstate->domain->next; 118 119 if ((state->gstate->domain != NULL) 120 && sid_check_is_domain(&state->gstate->domain->sid)) { 121 state->gstate->domain = state->gstate->domain->next; 122 } 123 124 if (state->gstate->domain == NULL) { 125 tevent_req_nterror(req, NT_STATUS_NO_MORE_ENTRIES); 126 return; 127 } 128 subreq = rpccli_wbint_QueryGroupList_send( 129 state, state->ev, state->gstate->domain->child.rpccli, 130 &state->next_groups); 131 if (tevent_req_nomem(subreq, req)) { 132 return; 133 } 134 tevent_req_set_callback(subreq, wb_next_grent_fetch_done, req); 135 return; 136 } 137 138 state->gstate->next_group = 0; 139 140 subreq = wb_getgrsid_send( 141 state, state->ev, 142 &state->gstate->groups[state->gstate->next_group].sid, 143 state->max_nesting); 144 if (tevent_req_nomem(subreq, req)) { 145 return; 146 } 147 tevent_req_set_callback(subreq, wb_next_grent_getgrsid_done, req); 148 return; 149} 150 151static void wb_next_grent_getgrsid_done(struct tevent_req *subreq) 152{ 153 struct tevent_req *req = tevent_req_callback_data( 154 subreq, struct tevent_req); 155 struct wb_next_grent_state *state = tevent_req_data( 156 req, struct wb_next_grent_state); 157 const char *domname, *name; 158 NTSTATUS status; 159 160 status = wb_getgrsid_recv(subreq, talloc_tos(), &domname, &name, 161 &state->gr->gr_gid, &state->members); 162 TALLOC_FREE(subreq); 163 if (!NT_STATUS_IS_OK(status)) { 164 tevent_req_nterror(req, status); 165 return; 166 } 167 if (!fill_grent(talloc_tos(), state->gr, domname, name, 168 state->gr->gr_gid)) { 169 DEBUG(5, ("fill_grent failed\n")); 170 tevent_req_nterror(req, NT_STATUS_NO_MEMORY); 171 return; 172 } 173 state->gstate->next_group += 1; 174 tevent_req_done(req); 175} 176 177NTSTATUS wb_next_grent_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, 178 struct talloc_dict **members) 179{ 180 struct wb_next_grent_state *state = tevent_req_data( 181 req, struct wb_next_grent_state); 182 NTSTATUS status; 183 184 if (tevent_req_is_nterror(req, &status)) { 185 return status; 186 } 187 *members = talloc_move(mem_ctx, &state->members); 188 return NT_STATUS_OK; 189} 190