1/* 2 Unix SMB/CIFS implementation. 3 async implementation of WINBINDD_LIST_GROUPS 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 winbindd_list_groups_domstate { 25 struct tevent_req *subreq; 26 struct winbindd_domain *domain; 27 struct wbint_Principals groups; 28}; 29 30struct winbindd_list_groups_state { 31 int num_received; 32 /* All domains */ 33 int num_domains; 34 struct winbindd_list_groups_domstate *domains; 35}; 36 37static void winbindd_list_groups_done(struct tevent_req *subreq); 38 39struct tevent_req *winbindd_list_groups_send(TALLOC_CTX *mem_ctx, 40 struct tevent_context *ev, 41 struct winbindd_cli_state *cli, 42 struct winbindd_request *request) 43{ 44 struct tevent_req *req; 45 struct winbindd_list_groups_state *state; 46 struct winbindd_domain *domain; 47 int i; 48 49 req = tevent_req_create(mem_ctx, &state, 50 struct winbindd_list_groups_state); 51 if (req == NULL) { 52 return NULL; 53 } 54 55 /* Ensure null termination */ 56 request->domain_name[sizeof(request->domain_name)-1]='\0'; 57 58 DEBUG(3, ("list_groups %s\n", request->domain_name)); 59 60 if (request->domain_name[0] != '\0') { 61 state->num_domains = 1; 62 } else { 63 state->num_domains = 0; 64 for (domain = domain_list(); domain; domain = domain->next) { 65 state->num_domains += 1; 66 } 67 } 68 69 state->domains = talloc_array(state, 70 struct winbindd_list_groups_domstate, 71 state->num_domains); 72 if (tevent_req_nomem(state->domains, req)) { 73 return tevent_req_post(req, ev); 74 } 75 76 if (request->domain_name[0] != '\0') { 77 state->domains[0].domain = find_domain_from_name_noinit( 78 request->domain_name); 79 if (state->domains[0].domain == NULL) { 80 tevent_req_nterror(req, NT_STATUS_NO_SUCH_DOMAIN); 81 return tevent_req_post(req, ev); 82 } 83 } else { 84 i = 0; 85 for (domain = domain_list(); domain; domain = domain->next) { 86 state->domains[i++].domain = domain; 87 } 88 } 89 90 for (i=0; i<state->num_domains; i++) { 91 struct winbindd_list_groups_domstate *d = &state->domains[i]; 92 93 d->subreq = rpccli_wbint_QueryGroupList_send( 94 state->domains, ev, d->domain->child.rpccli, 95 &d->groups); 96 if (tevent_req_nomem(d->subreq, req)) { 97 TALLOC_FREE(state->domains); 98 return tevent_req_post(req, ev); 99 } 100 tevent_req_set_callback(d->subreq, winbindd_list_groups_done, 101 req); 102 } 103 state->num_received = 0; 104 return req; 105} 106 107static void winbindd_list_groups_done(struct tevent_req *subreq) 108{ 109 struct tevent_req *req = tevent_req_callback_data( 110 subreq, struct tevent_req); 111 struct winbindd_list_groups_state *state = tevent_req_data( 112 req, struct winbindd_list_groups_state); 113 NTSTATUS status, result; 114 int i; 115 116 status = rpccli_wbint_QueryGroupList_recv(subreq, state->domains, 117 &result); 118 119 for (i=0; i<state->num_domains; i++) { 120 if (subreq == state->domains[i].subreq) { 121 break; 122 } 123 } 124 if (i < state->num_domains) { 125 struct winbindd_list_groups_domstate *d = &state->domains[i]; 126 127 DEBUG(10, ("Domain %s returned %d users\n", d->domain->name, 128 d->groups.num_principals)); 129 130 d->subreq = NULL; 131 132 if (!NT_STATUS_IS_OK(status) || !NT_STATUS_IS_OK(result)) { 133 DEBUG(10, ("list_groups for domain %s failed\n", 134 d->domain->name)); 135 d->groups.num_principals = 0; 136 } 137 } 138 139 TALLOC_FREE(subreq); 140 141 state->num_received += 1; 142 143 if (state->num_received >= state->num_domains) { 144 tevent_req_done(req); 145 } 146} 147 148NTSTATUS winbindd_list_groups_recv(struct tevent_req *req, 149 struct winbindd_response *response) 150{ 151 struct winbindd_list_groups_state *state = tevent_req_data( 152 req, struct winbindd_list_groups_state); 153 NTSTATUS status; 154 char *result; 155 int i; 156 uint32_t j; 157 size_t len; 158 159 if (tevent_req_is_nterror(req, &status)) { 160 return status; 161 } 162 163 len = 0; 164 for (i=0; i<state->num_domains; i++) { 165 struct winbindd_list_groups_domstate *d = &state->domains[i]; 166 167 for (j=0; j<d->groups.num_principals; j++) { 168 fstring name; 169 fill_domain_username(name, d->domain->name, 170 d->groups.principals[j].name, 171 True); 172 len += strlen(name)+1; 173 } 174 } 175 176 result = talloc_array(response, char, len+1); 177 if (result == 0) { 178 return NT_STATUS_NO_MEMORY; 179 } 180 181 len = 0; 182 for (i=0; i<state->num_domains; i++) { 183 struct winbindd_list_groups_domstate *d = &state->domains[i]; 184 185 for (j=0; j<d->groups.num_principals; j++) { 186 fstring name; 187 size_t this_len; 188 fill_domain_username(name, d->domain->name, 189 d->groups.principals[j].name, 190 True); 191 this_len = strlen(name); 192 memcpy(result+len, name, this_len); 193 len += this_len; 194 result[len] = ','; 195 len += 1; 196 } 197 } 198 result[len-1] = '\0'; 199 200 response->extra_data.data = result; 201 response->length += len; 202 203 return NT_STATUS_OK; 204} 205