Changeset 988 for vendor/current/source3/libads/cldap.c
- Timestamp:
- Nov 24, 2016, 1:14:11 PM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
vendor/current/source3/libads/cldap.c
r740 r988 24 24 #include "../libcli/cldap/cldap.h" 25 25 #include "../lib/tsocket/tsocket.h" 26 #include "../lib/util/tevent_ntstatus.h" 26 27 #include "libads/cldap.h" 28 29 struct cldap_multi_netlogon_state { 30 struct tevent_context *ev; 31 const struct tsocket_address * const *servers; 32 int num_servers; 33 const char *domain; 34 const char *hostname; 35 unsigned ntversion; 36 int min_servers; 37 38 struct cldap_socket **cldap; 39 struct tevent_req **subreqs; 40 int num_sent; 41 int num_received; 42 int num_good_received; 43 struct cldap_netlogon *ios; 44 struct netlogon_samlogon_response **responses; 45 }; 46 47 static void cldap_multi_netlogon_done(struct tevent_req *subreq); 48 static void cldap_multi_netlogon_next(struct tevent_req *subreq); 49 50 /* 51 * Do a parallel cldap ping to the servers. The first "min_servers" 52 * are fired directly, the remaining ones in 100msec intervals. If 53 * "min_servers" responses came in successfully, we immediately reply, 54 * not waiting for the remaining ones. 55 */ 56 57 struct tevent_req *cldap_multi_netlogon_send( 58 TALLOC_CTX *mem_ctx, struct tevent_context *ev, 59 const struct tsocket_address * const *servers, int num_servers, 60 const char *domain, const char *hostname, unsigned ntversion, 61 int min_servers) 62 { 63 struct tevent_req *req, *subreq; 64 struct cldap_multi_netlogon_state *state; 65 int i; 66 67 req = tevent_req_create(mem_ctx, &state, 68 struct cldap_multi_netlogon_state); 69 if (req == NULL) { 70 return NULL; 71 } 72 state->ev = ev; 73 state->servers = servers; 74 state->num_servers = num_servers; 75 state->domain = domain; 76 state->hostname = hostname; 77 state->ntversion = ntversion; 78 state->min_servers = min_servers; 79 80 if (min_servers > num_servers) { 81 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); 82 return tevent_req_post(req, ev); 83 } 84 85 state->subreqs = talloc_zero_array(state, 86 struct tevent_req *, 87 num_servers); 88 if (tevent_req_nomem(state->subreqs, req)) { 89 return tevent_req_post(req, ev); 90 } 91 92 state->cldap = talloc_zero_array(state, 93 struct cldap_socket *, 94 num_servers); 95 if (tevent_req_nomem(state->cldap, req)) { 96 return tevent_req_post(req, ev); 97 } 98 99 state->responses = talloc_zero_array(state, 100 struct netlogon_samlogon_response *, 101 num_servers); 102 if (tevent_req_nomem(state->responses, req)) { 103 return tevent_req_post(req, ev); 104 } 105 106 state->ios = talloc_zero_array(state->responses, 107 struct cldap_netlogon, 108 num_servers); 109 if (tevent_req_nomem(state->ios, req)) { 110 return tevent_req_post(req, ev); 111 } 112 113 for (i=0; i<num_servers; i++) { 114 NTSTATUS status; 115 116 status = cldap_socket_init(state->cldap, 117 NULL, /* local_addr */ 118 state->servers[i], 119 &state->cldap[i]); 120 if (tevent_req_nterror(req, status)) { 121 return tevent_req_post(req, ev); 122 } 123 124 state->ios[i].in.dest_address = NULL; 125 state->ios[i].in.dest_port = 0; 126 state->ios[i].in.realm = domain; 127 state->ios[i].in.host = NULL; 128 state->ios[i].in.user = NULL; 129 state->ios[i].in.domain_guid = NULL; 130 state->ios[i].in.domain_sid = NULL; 131 state->ios[i].in.acct_control = 0; 132 state->ios[i].in.version = ntversion; 133 state->ios[i].in.map_response = false; 134 } 135 136 for (i=0; i<min_servers; i++) { 137 state->subreqs[i] = cldap_netlogon_send(state->subreqs, 138 state->ev, 139 state->cldap[i], 140 &state->ios[i]); 141 if (tevent_req_nomem(state->subreqs[i], req)) { 142 return tevent_req_post(req, ev); 143 } 144 tevent_req_set_callback( 145 state->subreqs[i], cldap_multi_netlogon_done, req); 146 } 147 state->num_sent = min_servers; 148 149 if (state->num_sent < state->num_servers) { 150 /* 151 * After 100 milliseconds fire the next one 152 */ 153 subreq = tevent_wakeup_send(state, state->ev, 154 timeval_current_ofs(0, 100000)); 155 if (tevent_req_nomem(subreq, req)) { 156 return tevent_req_post(req, ev); 157 } 158 tevent_req_set_callback(subreq, cldap_multi_netlogon_next, 159 req); 160 } 161 162 return req; 163 } 164 165 static void cldap_multi_netlogon_done(struct tevent_req *subreq) 166 { 167 struct tevent_req *req = tevent_req_callback_data( 168 subreq, struct tevent_req); 169 struct cldap_multi_netlogon_state *state = tevent_req_data( 170 req, struct cldap_multi_netlogon_state); 171 NTSTATUS status; 172 struct netlogon_samlogon_response *response; 173 int i; 174 175 for (i=0; i<state->num_sent; i++) { 176 if (state->subreqs[i] == subreq) { 177 break; 178 } 179 } 180 if (i == state->num_sent) { 181 /* 182 * Got a response we did not fire... 183 */ 184 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); 185 return; 186 } 187 state->subreqs[i] = NULL; 188 189 response = talloc_zero(state, struct netlogon_samlogon_response); 190 if (tevent_req_nomem(response, req)) { 191 return; 192 } 193 194 status = cldap_netlogon_recv(subreq, response, 195 &state->ios[i]); 196 TALLOC_FREE(subreq); 197 state->num_received += 1; 198 199 if (NT_STATUS_IS_OK(status)) { 200 *response = state->ios[i].out.netlogon; 201 state->responses[i] = talloc_move(state->responses, 202 &response); 203 state->num_good_received += 1; 204 } 205 206 if ((state->num_received == state->num_servers) || 207 (state->num_good_received >= state->min_servers)) { 208 tevent_req_done(req); 209 return; 210 } 211 } 212 213 static void cldap_multi_netlogon_next(struct tevent_req *subreq) 214 { 215 struct tevent_req *req = tevent_req_callback_data( 216 subreq, struct tevent_req); 217 struct cldap_multi_netlogon_state *state = tevent_req_data( 218 req, struct cldap_multi_netlogon_state); 219 bool ret; 220 221 ret = tevent_wakeup_recv(subreq); 222 TALLOC_FREE(subreq); 223 if (!ret) { 224 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); 225 return; 226 } 227 228 subreq = cldap_netlogon_send(state->subreqs, 229 state->ev, 230 state->cldap[state->num_sent], 231 &state->ios[state->num_sent]); 232 if (tevent_req_nomem(subreq, req)) { 233 return; 234 } 235 tevent_req_set_callback(subreq, cldap_multi_netlogon_done, req); 236 state->subreqs[state->num_sent] = subreq; 237 state->num_sent += 1; 238 239 if (state->num_sent < state->num_servers) { 240 /* 241 * After 100 milliseconds fire the next one 242 */ 243 subreq = tevent_wakeup_send(state, state->ev, 244 timeval_current_ofs(0, 100000)); 245 if (tevent_req_nomem(subreq, req)) { 246 return; 247 } 248 tevent_req_set_callback(subreq, cldap_multi_netlogon_next, 249 req); 250 } 251 } 252 253 NTSTATUS cldap_multi_netlogon_recv( 254 struct tevent_req *req, TALLOC_CTX *mem_ctx, 255 struct netlogon_samlogon_response ***responses) 256 { 257 struct cldap_multi_netlogon_state *state = tevent_req_data( 258 req, struct cldap_multi_netlogon_state); 259 NTSTATUS status; 260 261 if (tevent_req_is_nterror(req, &status) && 262 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { 263 return status; 264 } 265 /* 266 * If we timeout, give back what we have so far 267 */ 268 *responses = talloc_move(mem_ctx, &state->responses); 269 return NT_STATUS_OK; 270 } 271 272 NTSTATUS cldap_multi_netlogon( 273 TALLOC_CTX *mem_ctx, 274 const struct tsocket_address * const *servers, 275 int num_servers, 276 const char *domain, const char *hostname, unsigned ntversion, 277 int min_servers, struct timeval timeout, 278 struct netlogon_samlogon_response ***responses) 279 { 280 struct tevent_context *ev; 281 struct tevent_req *req; 282 NTSTATUS status = NT_STATUS_NO_MEMORY; 283 284 ev = samba_tevent_context_init(talloc_tos()); 285 if (ev == NULL) { 286 goto fail; 287 } 288 req = cldap_multi_netlogon_send( 289 ev, ev, servers, num_servers, domain, hostname, ntversion, 290 min_servers); 291 if (req == NULL) { 292 goto fail; 293 } 294 if (!tevent_req_set_endtime(req, ev, timeout)) { 295 goto fail; 296 } 297 if (!tevent_req_poll_ntstatus(req, ev, &status)) { 298 goto fail; 299 } 300 status = cldap_multi_netlogon_recv(req, mem_ctx, responses); 301 fail: 302 TALLOC_FREE(ev); 303 return status; 304 } 27 305 28 306 /******************************************************************* … … 31 309 32 310 bool ads_cldap_netlogon(TALLOC_CTX *mem_ctx, 33 const char *server,311 struct sockaddr_storage *ss, 34 312 const char *realm, 35 313 uint32_t nt_version, 36 314 struct netlogon_samlogon_response **_reply) 37 315 { 38 struct cldap_socket *cldap;39 struct cldap_netlogon io;40 struct netlogon_samlogon_response *reply;41 316 NTSTATUS status; 42 struct sockaddr_storage ss;43 317 char addrstr[INET6_ADDRSTRLEN]; 44 318 const char *dest_str; 319 struct tsocket_address *dest_addr; 320 const struct tsocket_address * const *dest_addrs; 321 struct netlogon_samlogon_response **responses = NULL; 45 322 int ret; 46 struct tsocket_address *dest_addr; 47 48 if (!interpret_string_addr_prefer_ipv4(&ss, server, 0)) { 49 DEBUG(2,("Failed to resolve[%s] into an address for cldap\n", 50 server)); 51 return false; 52 } 53 dest_str = print_sockaddr(addrstr, sizeof(addrstr), &ss); 323 324 dest_str = print_sockaddr(addrstr, sizeof(addrstr), ss); 54 325 55 326 ret = tsocket_address_inet_from_strings(mem_ctx, "ip", … … 63 334 } 64 335 65 /* 66 * as we use a connected udp socket 67 */ 68 status = cldap_socket_init(mem_ctx, NULL, NULL, dest_addr, &cldap); 69 TALLOC_FREE(dest_addr); 336 dest_addrs = (const struct tsocket_address * const *)&dest_addr; 337 338 status = cldap_multi_netlogon(talloc_tos(), 339 dest_addrs, 1, 340 realm, NULL, 341 nt_version, 1, 342 timeval_current_ofs(MAX(3,lp_ldap_timeout()/2), 0), 343 &responses); 70 344 if (!NT_STATUS_IS_OK(status)) { 71 DEBUG(2,("Failed to create cldap socket to %s: %s\n", 72 dest_str, nt_errstr(status))); 73 return false; 74 } 75 76 reply = talloc(cldap, struct netlogon_samlogon_response); 77 if (!reply) { 78 goto failed; 79 } 80 81 /* 82 * as we use a connected socket, so we don't need to specify the 83 * destination 84 */ 85 io.in.dest_address = NULL; 86 io.in.dest_port = 0; 87 io.in.realm = realm; 88 io.in.host = NULL; 89 io.in.user = NULL; 90 io.in.domain_guid = NULL; 91 io.in.domain_sid = NULL; 92 io.in.acct_control = 0; 93 io.in.version = nt_version; 94 io.in.map_response = false; 95 96 status = cldap_netlogon(cldap, reply, &io); 97 if (!NT_STATUS_IS_OK(status)) { 98 DEBUG(2,("cldap_netlogon() failed: %s\n", nt_errstr(status))); 99 goto failed; 100 } 101 102 *reply = io.out.netlogon; 103 *_reply = talloc_move(mem_ctx, &reply); 104 TALLOC_FREE(cldap); 345 DEBUG(2, ("ads_cldap_netlogon: cldap_multi_netlogon " 346 "failed: %s\n", nt_errstr(status))); 347 return false; 348 } 349 if (responses[0] == NULL) { 350 DEBUG(2, ("ads_cldap_netlogon: did not get a reply\n")); 351 TALLOC_FREE(responses); 352 return false; 353 } 354 *_reply = talloc_move(mem_ctx, &responses[0]); 355 105 356 return true; 106 failed:107 TALLOC_FREE(cldap);108 return false;109 357 } 110 358 … … 114 362 115 363 bool ads_cldap_netlogon_5(TALLOC_CTX *mem_ctx, 116 const char *server,364 struct sockaddr_storage *ss, 117 365 const char *realm, 118 366 struct NETLOGON_SAM_LOGON_RESPONSE_EX *reply5) … … 122 370 bool ret; 123 371 124 ret = ads_cldap_netlogon(mem_ctx, s erver, realm, nt_version, &reply);372 ret = ads_cldap_netlogon(mem_ctx, ss, realm, nt_version, &reply); 125 373 if (!ret) { 126 374 return false;
Note:
See TracChangeset
for help on using the changeset viewer.