| 1 | /* | 
|---|
| 2 | Unix SMB/CIFS implementation. | 
|---|
| 3 |  | 
|---|
| 4 | cldap client library | 
|---|
| 5 |  | 
|---|
| 6 | Copyright (C) Andrew Tridgell 2005 | 
|---|
| 7 | Copyright (C) Stefan Metzmacher 2009 | 
|---|
| 8 |  | 
|---|
| 9 | This program is free software; you can redistribute it and/or modify | 
|---|
| 10 | it under the terms of the GNU General Public License as published by | 
|---|
| 11 | the Free Software Foundation; either version 3 of the License, or | 
|---|
| 12 | (at your option) any later version. | 
|---|
| 13 |  | 
|---|
| 14 | This program is distributed in the hope that it will be useful, | 
|---|
| 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|---|
| 17 | GNU General Public License for more details. | 
|---|
| 18 |  | 
|---|
| 19 | You should have received a copy of the GNU General Public License | 
|---|
| 20 | along with this program.  If not, see <http://www.gnu.org/licenses/>. | 
|---|
| 21 | */ | 
|---|
| 22 |  | 
|---|
| 23 | /* | 
|---|
| 24 | see RFC1798 for details of CLDAP | 
|---|
| 25 |  | 
|---|
| 26 | basic properties | 
|---|
| 27 | - carried over UDP on port 389 | 
|---|
| 28 | - request and response matched by message ID | 
|---|
| 29 | - request consists of only a single searchRequest element | 
|---|
| 30 | - response can be in one of two forms | 
|---|
| 31 | - a single searchResponse, followed by a searchResult | 
|---|
| 32 | - a single searchResult | 
|---|
| 33 | */ | 
|---|
| 34 |  | 
|---|
| 35 | #include "includes.h" | 
|---|
| 36 | #include <tevent.h> | 
|---|
| 37 | #include "../lib/util/dlinklist.h" | 
|---|
| 38 | #include "../libcli/ldap/ldap_message.h" | 
|---|
| 39 | #include "../libcli/ldap/ldap_ndr.h" | 
|---|
| 40 | #include "../libcli/cldap/cldap.h" | 
|---|
| 41 | #include "../lib/tsocket/tsocket.h" | 
|---|
| 42 | #include "../libcli/security/dom_sid.h" | 
|---|
| 43 | #include "../librpc/gen_ndr/ndr_nbt.h" | 
|---|
| 44 | #include "../lib/util/asn1.h" | 
|---|
| 45 | #include "../lib/util/tevent_ntstatus.h" | 
|---|
| 46 |  | 
|---|
| 47 | #undef strcasecmp | 
|---|
| 48 |  | 
|---|
| 49 | /* | 
|---|
| 50 | context structure for operations on cldap packets | 
|---|
| 51 | */ | 
|---|
| 52 | struct cldap_socket { | 
|---|
| 53 | /* the low level socket */ | 
|---|
| 54 | struct tdgram_context *sock; | 
|---|
| 55 |  | 
|---|
| 56 | /* | 
|---|
| 57 | * Are we in connected mode, which means | 
|---|
| 58 | * we get ICMP errors back instead of timing | 
|---|
| 59 | * out requests. And we can only send requests | 
|---|
| 60 | * to the connected peer. | 
|---|
| 61 | */ | 
|---|
| 62 | bool connected; | 
|---|
| 63 |  | 
|---|
| 64 | /* | 
|---|
| 65 | * we allow sync requests only, if the caller | 
|---|
| 66 | * did not pass an event context to cldap_socket_init() | 
|---|
| 67 | */ | 
|---|
| 68 | struct { | 
|---|
| 69 | bool allow_poll; | 
|---|
| 70 | struct tevent_context *ctx; | 
|---|
| 71 | } event; | 
|---|
| 72 |  | 
|---|
| 73 | /* the queue for outgoing dgrams */ | 
|---|
| 74 | struct tevent_queue *send_queue; | 
|---|
| 75 |  | 
|---|
| 76 | /* do we have an async tsocket_recvfrom request pending */ | 
|---|
| 77 | struct tevent_req *recv_subreq; | 
|---|
| 78 |  | 
|---|
| 79 | struct { | 
|---|
| 80 | /* a queue of pending search requests */ | 
|---|
| 81 | struct cldap_search_state *list; | 
|---|
| 82 |  | 
|---|
| 83 | /* mapping from message_id to pending request */ | 
|---|
| 84 | struct idr_context *idr; | 
|---|
| 85 | } searches; | 
|---|
| 86 |  | 
|---|
| 87 | /* what to do with incoming request packets */ | 
|---|
| 88 | struct { | 
|---|
| 89 | void (*handler)(struct cldap_socket *, | 
|---|
| 90 | void *private_data, | 
|---|
| 91 | struct cldap_incoming *); | 
|---|
| 92 | void *private_data; | 
|---|
| 93 | } incoming; | 
|---|
| 94 | }; | 
|---|
| 95 |  | 
|---|
| 96 | struct cldap_search_state { | 
|---|
| 97 | struct cldap_search_state *prev, *next; | 
|---|
| 98 |  | 
|---|
| 99 | struct { | 
|---|
| 100 | struct cldap_socket *cldap; | 
|---|
| 101 | } caller; | 
|---|
| 102 |  | 
|---|
| 103 | int message_id; | 
|---|
| 104 |  | 
|---|
| 105 | struct { | 
|---|
| 106 | uint32_t idx; | 
|---|
| 107 | uint32_t delay; | 
|---|
| 108 | uint32_t count; | 
|---|
| 109 | struct tsocket_address *dest; | 
|---|
| 110 | DATA_BLOB blob; | 
|---|
| 111 | } request; | 
|---|
| 112 |  | 
|---|
| 113 | struct { | 
|---|
| 114 | struct cldap_incoming *in; | 
|---|
| 115 | struct asn1_data *asn1; | 
|---|
| 116 | } response; | 
|---|
| 117 |  | 
|---|
| 118 | struct tevent_req *req; | 
|---|
| 119 | }; | 
|---|
| 120 |  | 
|---|
| 121 | static int cldap_socket_destructor(struct cldap_socket *c) | 
|---|
| 122 | { | 
|---|
| 123 | while (c->searches.list) { | 
|---|
| 124 | struct cldap_search_state *s = c->searches.list; | 
|---|
| 125 | DLIST_REMOVE(c->searches.list, s); | 
|---|
| 126 | ZERO_STRUCT(s->caller); | 
|---|
| 127 | } | 
|---|
| 128 |  | 
|---|
| 129 | talloc_free(c->recv_subreq); | 
|---|
| 130 | talloc_free(c->send_queue); | 
|---|
| 131 | talloc_free(c->sock); | 
|---|
| 132 | return 0; | 
|---|
| 133 | } | 
|---|
| 134 |  | 
|---|
| 135 | static void cldap_recvfrom_done(struct tevent_req *subreq); | 
|---|
| 136 |  | 
|---|
| 137 | static bool cldap_recvfrom_setup(struct cldap_socket *c) | 
|---|
| 138 | { | 
|---|
| 139 | if (c->recv_subreq) { | 
|---|
| 140 | return true; | 
|---|
| 141 | } | 
|---|
| 142 |  | 
|---|
| 143 | if (!c->searches.list && !c->incoming.handler) { | 
|---|
| 144 | return true; | 
|---|
| 145 | } | 
|---|
| 146 |  | 
|---|
| 147 | c->recv_subreq = tdgram_recvfrom_send(c, c->event.ctx, c->sock); | 
|---|
| 148 | if (!c->recv_subreq) { | 
|---|
| 149 | return false; | 
|---|
| 150 | } | 
|---|
| 151 | tevent_req_set_callback(c->recv_subreq, cldap_recvfrom_done, c); | 
|---|
| 152 |  | 
|---|
| 153 | return true; | 
|---|
| 154 | } | 
|---|
| 155 |  | 
|---|
| 156 | static void cldap_recvfrom_stop(struct cldap_socket *c) | 
|---|
| 157 | { | 
|---|
| 158 | if (!c->recv_subreq) { | 
|---|
| 159 | return; | 
|---|
| 160 | } | 
|---|
| 161 |  | 
|---|
| 162 | if (c->searches.list || c->incoming.handler) { | 
|---|
| 163 | return; | 
|---|
| 164 | } | 
|---|
| 165 |  | 
|---|
| 166 | talloc_free(c->recv_subreq); | 
|---|
| 167 | c->recv_subreq = NULL; | 
|---|
| 168 | } | 
|---|
| 169 |  | 
|---|
| 170 | static bool cldap_socket_recv_dgram(struct cldap_socket *c, | 
|---|
| 171 | struct cldap_incoming *in); | 
|---|
| 172 |  | 
|---|
| 173 | static void cldap_recvfrom_done(struct tevent_req *subreq) | 
|---|
| 174 | { | 
|---|
| 175 | struct cldap_socket *c = tevent_req_callback_data(subreq, | 
|---|
| 176 | struct cldap_socket); | 
|---|
| 177 | struct cldap_incoming *in = NULL; | 
|---|
| 178 | ssize_t ret; | 
|---|
| 179 | bool setup_done; | 
|---|
| 180 |  | 
|---|
| 181 | c->recv_subreq = NULL; | 
|---|
| 182 |  | 
|---|
| 183 | in = talloc_zero(c, struct cldap_incoming); | 
|---|
| 184 | if (!in) { | 
|---|
| 185 | goto nomem; | 
|---|
| 186 | } | 
|---|
| 187 |  | 
|---|
| 188 | ret = tdgram_recvfrom_recv(subreq, | 
|---|
| 189 | &in->recv_errno, | 
|---|
| 190 | in, | 
|---|
| 191 | &in->buf, | 
|---|
| 192 | &in->src); | 
|---|
| 193 | talloc_free(subreq); | 
|---|
| 194 | subreq = NULL; | 
|---|
| 195 | if (ret >= 0) { | 
|---|
| 196 | in->len = ret; | 
|---|
| 197 | } | 
|---|
| 198 | if (ret == -1 && in->recv_errno == 0) { | 
|---|
| 199 | in->recv_errno = EIO; | 
|---|
| 200 | } | 
|---|
| 201 |  | 
|---|
| 202 | /* this function should free or steal 'in' */ | 
|---|
| 203 | setup_done = cldap_socket_recv_dgram(c, in); | 
|---|
| 204 | in = NULL; | 
|---|
| 205 |  | 
|---|
| 206 | if (!setup_done && !cldap_recvfrom_setup(c)) { | 
|---|
| 207 | goto nomem; | 
|---|
| 208 | } | 
|---|
| 209 |  | 
|---|
| 210 | return; | 
|---|
| 211 |  | 
|---|
| 212 | nomem: | 
|---|
| 213 | talloc_free(subreq); | 
|---|
| 214 | talloc_free(in); | 
|---|
| 215 | /*TODO: call a dead socket handler */ | 
|---|
| 216 | return; | 
|---|
| 217 | } | 
|---|
| 218 |  | 
|---|
| 219 | /* | 
|---|
| 220 | handle recv events on a cldap socket | 
|---|
| 221 | */ | 
|---|
| 222 | static bool cldap_socket_recv_dgram(struct cldap_socket *c, | 
|---|
| 223 | struct cldap_incoming *in) | 
|---|
| 224 | { | 
|---|
| 225 | DATA_BLOB blob; | 
|---|
| 226 | struct asn1_data *asn1; | 
|---|
| 227 | void *p; | 
|---|
| 228 | struct cldap_search_state *search; | 
|---|
| 229 | NTSTATUS status; | 
|---|
| 230 |  | 
|---|
| 231 | if (in->recv_errno != 0) { | 
|---|
| 232 | goto error; | 
|---|
| 233 | } | 
|---|
| 234 |  | 
|---|
| 235 | blob = data_blob_const(in->buf, in->len); | 
|---|
| 236 |  | 
|---|
| 237 | asn1 = asn1_init(in); | 
|---|
| 238 | if (!asn1) { | 
|---|
| 239 | goto nomem; | 
|---|
| 240 | } | 
|---|
| 241 |  | 
|---|
| 242 | if (!asn1_load(asn1, blob)) { | 
|---|
| 243 | goto nomem; | 
|---|
| 244 | } | 
|---|
| 245 |  | 
|---|
| 246 | in->ldap_msg = talloc(in, struct ldap_message); | 
|---|
| 247 | if (in->ldap_msg == NULL) { | 
|---|
| 248 | goto nomem; | 
|---|
| 249 | } | 
|---|
| 250 |  | 
|---|
| 251 | /* this initial decode is used to find the message id */ | 
|---|
| 252 | status = ldap_decode(asn1, NULL, in->ldap_msg); | 
|---|
| 253 | if (!NT_STATUS_IS_OK(status)) { | 
|---|
| 254 | goto nterror; | 
|---|
| 255 | } | 
|---|
| 256 |  | 
|---|
| 257 | /* find the pending request */ | 
|---|
| 258 | p = idr_find(c->searches.idr, in->ldap_msg->messageid); | 
|---|
| 259 | if (p == NULL) { | 
|---|
| 260 | if (!c->incoming.handler) { | 
|---|
| 261 | goto done; | 
|---|
| 262 | } | 
|---|
| 263 |  | 
|---|
| 264 | /* this function should free or steal 'in' */ | 
|---|
| 265 | c->incoming.handler(c, c->incoming.private_data, in); | 
|---|
| 266 | return false; | 
|---|
| 267 | } | 
|---|
| 268 |  | 
|---|
| 269 | search = talloc_get_type(p, struct cldap_search_state); | 
|---|
| 270 | search->response.in = talloc_move(search, &in); | 
|---|
| 271 | search->response.asn1 = asn1; | 
|---|
| 272 | search->response.asn1->ofs = 0; | 
|---|
| 273 |  | 
|---|
| 274 | DLIST_REMOVE(c->searches.list, search); | 
|---|
| 275 |  | 
|---|
| 276 | cldap_recvfrom_setup(c); | 
|---|
| 277 |  | 
|---|
| 278 | tevent_req_done(search->req); | 
|---|
| 279 | return true; | 
|---|
| 280 |  | 
|---|
| 281 | nomem: | 
|---|
| 282 | in->recv_errno = ENOMEM; | 
|---|
| 283 | error: | 
|---|
| 284 | status = map_nt_error_from_unix(in->recv_errno); | 
|---|
| 285 | nterror: | 
|---|
| 286 | TALLOC_FREE(in); | 
|---|
| 287 | /* in connected mode the first pending search gets the error */ | 
|---|
| 288 | if (!c->connected) { | 
|---|
| 289 | /* otherwise we just ignore the error */ | 
|---|
| 290 | goto done; | 
|---|
| 291 | } | 
|---|
| 292 | if (!c->searches.list) { | 
|---|
| 293 | goto done; | 
|---|
| 294 | } | 
|---|
| 295 | cldap_recvfrom_setup(c); | 
|---|
| 296 | tevent_req_nterror(c->searches.list->req, status); | 
|---|
| 297 | return true; | 
|---|
| 298 | done: | 
|---|
| 299 | TALLOC_FREE(in); | 
|---|
| 300 | return false; | 
|---|
| 301 | } | 
|---|
| 302 |  | 
|---|
| 303 | /* | 
|---|
| 304 | initialise a cldap_sock | 
|---|
| 305 | */ | 
|---|
| 306 | NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx, | 
|---|
| 307 | struct tevent_context *ev, | 
|---|
| 308 | const struct tsocket_address *local_addr, | 
|---|
| 309 | const struct tsocket_address *remote_addr, | 
|---|
| 310 | struct cldap_socket **_cldap) | 
|---|
| 311 | { | 
|---|
| 312 | struct cldap_socket *c = NULL; | 
|---|
| 313 | struct tsocket_address *any = NULL; | 
|---|
| 314 | NTSTATUS status; | 
|---|
| 315 | int ret; | 
|---|
| 316 | const char *fam = NULL; | 
|---|
| 317 |  | 
|---|
| 318 | if (local_addr == NULL && remote_addr == NULL) { | 
|---|
| 319 | return NT_STATUS_INVALID_PARAMETER_MIX; | 
|---|
| 320 | } | 
|---|
| 321 |  | 
|---|
| 322 | if (remote_addr) { | 
|---|
| 323 | bool is_ipv4; | 
|---|
| 324 | bool is_ipv6; | 
|---|
| 325 |  | 
|---|
| 326 | is_ipv4 = tsocket_address_is_inet(remote_addr, "ipv4"); | 
|---|
| 327 | is_ipv6 = tsocket_address_is_inet(remote_addr, "ipv6"); | 
|---|
| 328 |  | 
|---|
| 329 | if (is_ipv4) { | 
|---|
| 330 | fam = "ipv4"; | 
|---|
| 331 | } else if (is_ipv6) { | 
|---|
| 332 | fam = "ipv6"; | 
|---|
| 333 | } else { | 
|---|
| 334 | return NT_STATUS_INVALID_ADDRESS; | 
|---|
| 335 | } | 
|---|
| 336 | } | 
|---|
| 337 |  | 
|---|
| 338 | c = talloc_zero(mem_ctx, struct cldap_socket); | 
|---|
| 339 | if (!c) { | 
|---|
| 340 | goto nomem; | 
|---|
| 341 | } | 
|---|
| 342 |  | 
|---|
| 343 | if (!ev) { | 
|---|
| 344 | ev = tevent_context_init(c); | 
|---|
| 345 | if (!ev) { | 
|---|
| 346 | goto nomem; | 
|---|
| 347 | } | 
|---|
| 348 | c->event.allow_poll = true; | 
|---|
| 349 | } | 
|---|
| 350 | c->event.ctx = ev; | 
|---|
| 351 |  | 
|---|
| 352 | if (!local_addr) { | 
|---|
| 353 | /* | 
|---|
| 354 | * Here we know the address family of the remote address. | 
|---|
| 355 | */ | 
|---|
| 356 | if (fam == NULL) { | 
|---|
| 357 | return NT_STATUS_INVALID_PARAMETER_MIX; | 
|---|
| 358 | } | 
|---|
| 359 |  | 
|---|
| 360 | ret = tsocket_address_inet_from_strings(c, fam, | 
|---|
| 361 | NULL, 0, | 
|---|
| 362 | &any); | 
|---|
| 363 | if (ret != 0) { | 
|---|
| 364 | status = map_nt_error_from_unix(errno); | 
|---|
| 365 | goto nterror; | 
|---|
| 366 | } | 
|---|
| 367 | local_addr = any; | 
|---|
| 368 | } | 
|---|
| 369 |  | 
|---|
| 370 | c->searches.idr = idr_init(c); | 
|---|
| 371 | if (!c->searches.idr) { | 
|---|
| 372 | goto nomem; | 
|---|
| 373 | } | 
|---|
| 374 |  | 
|---|
| 375 | ret = tdgram_inet_udp_socket(local_addr, remote_addr, | 
|---|
| 376 | c, &c->sock); | 
|---|
| 377 | if (ret != 0) { | 
|---|
| 378 | status = map_nt_error_from_unix(errno); | 
|---|
| 379 | goto nterror; | 
|---|
| 380 | } | 
|---|
| 381 | talloc_free(any); | 
|---|
| 382 |  | 
|---|
| 383 | if (remote_addr) { | 
|---|
| 384 | c->connected = true; | 
|---|
| 385 | } | 
|---|
| 386 |  | 
|---|
| 387 | c->send_queue = tevent_queue_create(c, "cldap_send_queue"); | 
|---|
| 388 | if (!c->send_queue) { | 
|---|
| 389 | goto nomem; | 
|---|
| 390 | } | 
|---|
| 391 |  | 
|---|
| 392 | talloc_set_destructor(c, cldap_socket_destructor); | 
|---|
| 393 |  | 
|---|
| 394 | *_cldap = c; | 
|---|
| 395 | return NT_STATUS_OK; | 
|---|
| 396 |  | 
|---|
| 397 | nomem: | 
|---|
| 398 | status = NT_STATUS_NO_MEMORY; | 
|---|
| 399 | nterror: | 
|---|
| 400 | talloc_free(c); | 
|---|
| 401 | return status; | 
|---|
| 402 | } | 
|---|
| 403 |  | 
|---|
| 404 | /* | 
|---|
| 405 | setup a handler for incoming requests | 
|---|
| 406 | */ | 
|---|
| 407 | NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c, | 
|---|
| 408 | void (*handler)(struct cldap_socket *, | 
|---|
| 409 | void *private_data, | 
|---|
| 410 | struct cldap_incoming *), | 
|---|
| 411 | void *private_data) | 
|---|
| 412 | { | 
|---|
| 413 | if (c->connected) { | 
|---|
| 414 | return NT_STATUS_PIPE_CONNECTED; | 
|---|
| 415 | } | 
|---|
| 416 |  | 
|---|
| 417 | /* if sync requests are allowed, we don't allow an incoming handler */ | 
|---|
| 418 | if (c->event.allow_poll) { | 
|---|
| 419 | return NT_STATUS_INVALID_PIPE_STATE; | 
|---|
| 420 | } | 
|---|
| 421 |  | 
|---|
| 422 | c->incoming.handler = handler; | 
|---|
| 423 | c->incoming.private_data = private_data; | 
|---|
| 424 |  | 
|---|
| 425 | if (!cldap_recvfrom_setup(c)) { | 
|---|
| 426 | ZERO_STRUCT(c->incoming); | 
|---|
| 427 | return NT_STATUS_NO_MEMORY; | 
|---|
| 428 | } | 
|---|
| 429 |  | 
|---|
| 430 | return NT_STATUS_OK; | 
|---|
| 431 | } | 
|---|
| 432 |  | 
|---|
| 433 | struct cldap_reply_state { | 
|---|
| 434 | struct tsocket_address *dest; | 
|---|
| 435 | DATA_BLOB blob; | 
|---|
| 436 | }; | 
|---|
| 437 |  | 
|---|
| 438 | static void cldap_reply_state_destroy(struct tevent_req *subreq); | 
|---|
| 439 |  | 
|---|
| 440 | /* | 
|---|
| 441 | queue a cldap reply for send | 
|---|
| 442 | */ | 
|---|
| 443 | NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io) | 
|---|
| 444 | { | 
|---|
| 445 | struct cldap_reply_state *state = NULL; | 
|---|
| 446 | struct ldap_message *msg; | 
|---|
| 447 | DATA_BLOB blob1, blob2; | 
|---|
| 448 | NTSTATUS status; | 
|---|
| 449 | struct tevent_req *subreq; | 
|---|
| 450 |  | 
|---|
| 451 | if (cldap->connected) { | 
|---|
| 452 | return NT_STATUS_PIPE_CONNECTED; | 
|---|
| 453 | } | 
|---|
| 454 |  | 
|---|
| 455 | if (!io->dest) { | 
|---|
| 456 | return NT_STATUS_INVALID_ADDRESS; | 
|---|
| 457 | } | 
|---|
| 458 |  | 
|---|
| 459 | state = talloc(cldap, struct cldap_reply_state); | 
|---|
| 460 | NT_STATUS_HAVE_NO_MEMORY(state); | 
|---|
| 461 |  | 
|---|
| 462 | state->dest = tsocket_address_copy(io->dest, state); | 
|---|
| 463 | if (!state->dest) { | 
|---|
| 464 | goto nomem; | 
|---|
| 465 | } | 
|---|
| 466 |  | 
|---|
| 467 | msg = talloc(state, struct ldap_message); | 
|---|
| 468 | if (!msg) { | 
|---|
| 469 | goto nomem; | 
|---|
| 470 | } | 
|---|
| 471 |  | 
|---|
| 472 | msg->messageid       = io->messageid; | 
|---|
| 473 | msg->controls        = NULL; | 
|---|
| 474 |  | 
|---|
| 475 | if (io->response) { | 
|---|
| 476 | msg->type = LDAP_TAG_SearchResultEntry; | 
|---|
| 477 | msg->r.SearchResultEntry = *io->response; | 
|---|
| 478 |  | 
|---|
| 479 | if (!ldap_encode(msg, NULL, &blob1, state)) { | 
|---|
| 480 | status = NT_STATUS_INVALID_PARAMETER; | 
|---|
| 481 | goto failed; | 
|---|
| 482 | } | 
|---|
| 483 | } else { | 
|---|
| 484 | blob1 = data_blob(NULL, 0); | 
|---|
| 485 | } | 
|---|
| 486 |  | 
|---|
| 487 | msg->type = LDAP_TAG_SearchResultDone; | 
|---|
| 488 | msg->r.SearchResultDone = *io->result; | 
|---|
| 489 |  | 
|---|
| 490 | if (!ldap_encode(msg, NULL, &blob2, state)) { | 
|---|
| 491 | status = NT_STATUS_INVALID_PARAMETER; | 
|---|
| 492 | goto failed; | 
|---|
| 493 | } | 
|---|
| 494 | talloc_free(msg); | 
|---|
| 495 |  | 
|---|
| 496 | state->blob = data_blob_talloc(state, NULL, blob1.length + blob2.length); | 
|---|
| 497 | if (!state->blob.data) { | 
|---|
| 498 | goto nomem; | 
|---|
| 499 | } | 
|---|
| 500 |  | 
|---|
| 501 | memcpy(state->blob.data, blob1.data, blob1.length); | 
|---|
| 502 | memcpy(state->blob.data+blob1.length, blob2.data, blob2.length); | 
|---|
| 503 | data_blob_free(&blob1); | 
|---|
| 504 | data_blob_free(&blob2); | 
|---|
| 505 |  | 
|---|
| 506 | subreq = tdgram_sendto_queue_send(state, | 
|---|
| 507 | cldap->event.ctx, | 
|---|
| 508 | cldap->sock, | 
|---|
| 509 | cldap->send_queue, | 
|---|
| 510 | state->blob.data, | 
|---|
| 511 | state->blob.length, | 
|---|
| 512 | state->dest); | 
|---|
| 513 | if (!subreq) { | 
|---|
| 514 | goto nomem; | 
|---|
| 515 | } | 
|---|
| 516 | /* the callback will just free the state, as we don't need a result */ | 
|---|
| 517 | tevent_req_set_callback(subreq, cldap_reply_state_destroy, state); | 
|---|
| 518 |  | 
|---|
| 519 | return NT_STATUS_OK; | 
|---|
| 520 |  | 
|---|
| 521 | nomem: | 
|---|
| 522 | status = NT_STATUS_NO_MEMORY; | 
|---|
| 523 | failed: | 
|---|
| 524 | talloc_free(state); | 
|---|
| 525 | return status; | 
|---|
| 526 | } | 
|---|
| 527 |  | 
|---|
| 528 | static void cldap_reply_state_destroy(struct tevent_req *subreq) | 
|---|
| 529 | { | 
|---|
| 530 | struct cldap_reply_state *state = tevent_req_callback_data(subreq, | 
|---|
| 531 | struct cldap_reply_state); | 
|---|
| 532 |  | 
|---|
| 533 | /* we don't want to know the result here, we just free the state */ | 
|---|
| 534 | talloc_free(subreq); | 
|---|
| 535 | talloc_free(state); | 
|---|
| 536 | } | 
|---|
| 537 |  | 
|---|
| 538 | static int cldap_search_state_destructor(struct cldap_search_state *s) | 
|---|
| 539 | { | 
|---|
| 540 | if (s->caller.cldap) { | 
|---|
| 541 | if (s->message_id != -1) { | 
|---|
| 542 | idr_remove(s->caller.cldap->searches.idr, s->message_id); | 
|---|
| 543 | s->message_id = -1; | 
|---|
| 544 | } | 
|---|
| 545 | DLIST_REMOVE(s->caller.cldap->searches.list, s); | 
|---|
| 546 | cldap_recvfrom_stop(s->caller.cldap); | 
|---|
| 547 | ZERO_STRUCT(s->caller); | 
|---|
| 548 | } | 
|---|
| 549 |  | 
|---|
| 550 | return 0; | 
|---|
| 551 | } | 
|---|
| 552 |  | 
|---|
| 553 | static void cldap_search_state_queue_done(struct tevent_req *subreq); | 
|---|
| 554 | static void cldap_search_state_wakeup_done(struct tevent_req *subreq); | 
|---|
| 555 |  | 
|---|
| 556 | /* | 
|---|
| 557 | queue a cldap reply for send | 
|---|
| 558 | */ | 
|---|
| 559 | struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx, | 
|---|
| 560 | struct cldap_socket *cldap, | 
|---|
| 561 | const struct cldap_search *io) | 
|---|
| 562 | { | 
|---|
| 563 | struct tevent_req *req, *subreq; | 
|---|
| 564 | struct cldap_search_state *state = NULL; | 
|---|
| 565 | struct ldap_message *msg; | 
|---|
| 566 | struct ldap_SearchRequest *search; | 
|---|
| 567 | struct timeval now; | 
|---|
| 568 | struct timeval end; | 
|---|
| 569 | uint32_t i; | 
|---|
| 570 | int ret; | 
|---|
| 571 |  | 
|---|
| 572 | req = tevent_req_create(mem_ctx, &state, | 
|---|
| 573 | struct cldap_search_state); | 
|---|
| 574 | if (!req) { | 
|---|
| 575 | return NULL; | 
|---|
| 576 | } | 
|---|
| 577 | ZERO_STRUCTP(state); | 
|---|
| 578 | state->req = req; | 
|---|
| 579 | state->caller.cldap = cldap; | 
|---|
| 580 | state->message_id = -1; | 
|---|
| 581 |  | 
|---|
| 582 | talloc_set_destructor(state, cldap_search_state_destructor); | 
|---|
| 583 |  | 
|---|
| 584 | if (io->in.dest_address) { | 
|---|
| 585 | if (cldap->connected) { | 
|---|
| 586 | tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED); | 
|---|
| 587 | goto post; | 
|---|
| 588 | } | 
|---|
| 589 | ret = tsocket_address_inet_from_strings(state, | 
|---|
| 590 | "ip", | 
|---|
| 591 | io->in.dest_address, | 
|---|
| 592 | io->in.dest_port, | 
|---|
| 593 | &state->request.dest); | 
|---|
| 594 | if (ret != 0) { | 
|---|
| 595 | tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); | 
|---|
| 596 | goto post; | 
|---|
| 597 | } | 
|---|
| 598 | } else { | 
|---|
| 599 | if (!cldap->connected) { | 
|---|
| 600 | tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS); | 
|---|
| 601 | goto post; | 
|---|
| 602 | } | 
|---|
| 603 | state->request.dest = NULL; | 
|---|
| 604 | } | 
|---|
| 605 |  | 
|---|
| 606 | state->message_id = idr_get_new_random(cldap->searches.idr, | 
|---|
| 607 | state, UINT16_MAX); | 
|---|
| 608 | if (state->message_id == -1) { | 
|---|
| 609 | tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES); | 
|---|
| 610 | goto post; | 
|---|
| 611 | } | 
|---|
| 612 |  | 
|---|
| 613 | msg = talloc(state, struct ldap_message); | 
|---|
| 614 | if (tevent_req_nomem(msg, req)) { | 
|---|
| 615 | goto post; | 
|---|
| 616 | } | 
|---|
| 617 |  | 
|---|
| 618 | msg->messageid  = state->message_id; | 
|---|
| 619 | msg->type       = LDAP_TAG_SearchRequest; | 
|---|
| 620 | msg->controls   = NULL; | 
|---|
| 621 | search = &msg->r.SearchRequest; | 
|---|
| 622 |  | 
|---|
| 623 | search->basedn          = ""; | 
|---|
| 624 | search->scope           = LDAP_SEARCH_SCOPE_BASE; | 
|---|
| 625 | search->deref           = LDAP_DEREFERENCE_NEVER; | 
|---|
| 626 | search->timelimit       = 0; | 
|---|
| 627 | search->sizelimit       = 0; | 
|---|
| 628 | search->attributesonly  = false; | 
|---|
| 629 | search->num_attributes  = str_list_length(io->in.attributes); | 
|---|
| 630 | search->attributes      = io->in.attributes; | 
|---|
| 631 | search->tree            = ldb_parse_tree(msg, io->in.filter); | 
|---|
| 632 | if (tevent_req_nomem(search->tree, req)) { | 
|---|
| 633 | goto post; | 
|---|
| 634 | } | 
|---|
| 635 |  | 
|---|
| 636 | if (!ldap_encode(msg, NULL, &state->request.blob, state)) { | 
|---|
| 637 | tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); | 
|---|
| 638 | goto post; | 
|---|
| 639 | } | 
|---|
| 640 | talloc_free(msg); | 
|---|
| 641 |  | 
|---|
| 642 | state->request.idx = 0; | 
|---|
| 643 | state->request.delay = 10*1000*1000; | 
|---|
| 644 | state->request.count = 3; | 
|---|
| 645 | if (io->in.timeout > 0) { | 
|---|
| 646 | state->request.delay = io->in.timeout * 1000 * 1000; | 
|---|
| 647 | state->request.count = io->in.retries + 1; | 
|---|
| 648 | } | 
|---|
| 649 |  | 
|---|
| 650 | now = tevent_timeval_current(); | 
|---|
| 651 | end = now; | 
|---|
| 652 | for (i = 0; i < state->request.count; i++) { | 
|---|
| 653 | end = tevent_timeval_add(&end, 0, state->request.delay); | 
|---|
| 654 | } | 
|---|
| 655 |  | 
|---|
| 656 | if (!tevent_req_set_endtime(req, state->caller.cldap->event.ctx, end)) { | 
|---|
| 657 | tevent_req_nomem(NULL, req); | 
|---|
| 658 | goto post; | 
|---|
| 659 | } | 
|---|
| 660 |  | 
|---|
| 661 | subreq = tdgram_sendto_queue_send(state, | 
|---|
| 662 | state->caller.cldap->event.ctx, | 
|---|
| 663 | state->caller.cldap->sock, | 
|---|
| 664 | state->caller.cldap->send_queue, | 
|---|
| 665 | state->request.blob.data, | 
|---|
| 666 | state->request.blob.length, | 
|---|
| 667 | state->request.dest); | 
|---|
| 668 | if (tevent_req_nomem(subreq, req)) { | 
|---|
| 669 | goto post; | 
|---|
| 670 | } | 
|---|
| 671 | tevent_req_set_callback(subreq, cldap_search_state_queue_done, req); | 
|---|
| 672 |  | 
|---|
| 673 | DLIST_ADD_END(cldap->searches.list, state, struct cldap_search_state *); | 
|---|
| 674 |  | 
|---|
| 675 | return req; | 
|---|
| 676 |  | 
|---|
| 677 | post: | 
|---|
| 678 | return tevent_req_post(req, cldap->event.ctx); | 
|---|
| 679 | } | 
|---|
| 680 |  | 
|---|
| 681 | static void cldap_search_state_queue_done(struct tevent_req *subreq) | 
|---|
| 682 | { | 
|---|
| 683 | struct tevent_req *req = tevent_req_callback_data(subreq, | 
|---|
| 684 | struct tevent_req); | 
|---|
| 685 | struct cldap_search_state *state = tevent_req_data(req, | 
|---|
| 686 | struct cldap_search_state); | 
|---|
| 687 | ssize_t ret; | 
|---|
| 688 | int sys_errno = 0; | 
|---|
| 689 | struct timeval next; | 
|---|
| 690 |  | 
|---|
| 691 | ret = tdgram_sendto_queue_recv(subreq, &sys_errno); | 
|---|
| 692 | talloc_free(subreq); | 
|---|
| 693 | if (ret == -1) { | 
|---|
| 694 | NTSTATUS status; | 
|---|
| 695 | status = map_nt_error_from_unix(sys_errno); | 
|---|
| 696 | DLIST_REMOVE(state->caller.cldap->searches.list, state); | 
|---|
| 697 | ZERO_STRUCT(state->caller.cldap); | 
|---|
| 698 | tevent_req_nterror(req, status); | 
|---|
| 699 | return; | 
|---|
| 700 | } | 
|---|
| 701 |  | 
|---|
| 702 | state->request.idx++; | 
|---|
| 703 |  | 
|---|
| 704 | /* wait for incoming traffic */ | 
|---|
| 705 | if (!cldap_recvfrom_setup(state->caller.cldap)) { | 
|---|
| 706 | tevent_req_nomem(NULL, req); | 
|---|
| 707 | return; | 
|---|
| 708 | } | 
|---|
| 709 |  | 
|---|
| 710 | if (state->request.idx > state->request.count) { | 
|---|
| 711 | /* we just wait for the response or a timeout */ | 
|---|
| 712 | return; | 
|---|
| 713 | } | 
|---|
| 714 |  | 
|---|
| 715 | next = tevent_timeval_current_ofs(0, state->request.delay); | 
|---|
| 716 | subreq = tevent_wakeup_send(state, | 
|---|
| 717 | state->caller.cldap->event.ctx, | 
|---|
| 718 | next); | 
|---|
| 719 | if (tevent_req_nomem(subreq, req)) { | 
|---|
| 720 | return; | 
|---|
| 721 | } | 
|---|
| 722 | tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req); | 
|---|
| 723 | } | 
|---|
| 724 |  | 
|---|
| 725 | static void cldap_search_state_wakeup_done(struct tevent_req *subreq) | 
|---|
| 726 | { | 
|---|
| 727 | struct tevent_req *req = tevent_req_callback_data(subreq, | 
|---|
| 728 | struct tevent_req); | 
|---|
| 729 | struct cldap_search_state *state = tevent_req_data(req, | 
|---|
| 730 | struct cldap_search_state); | 
|---|
| 731 | bool ok; | 
|---|
| 732 |  | 
|---|
| 733 | ok = tevent_wakeup_recv(subreq); | 
|---|
| 734 | talloc_free(subreq); | 
|---|
| 735 | if (!ok) { | 
|---|
| 736 | tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); | 
|---|
| 737 | return; | 
|---|
| 738 | } | 
|---|
| 739 |  | 
|---|
| 740 | subreq = tdgram_sendto_queue_send(state, | 
|---|
| 741 | state->caller.cldap->event.ctx, | 
|---|
| 742 | state->caller.cldap->sock, | 
|---|
| 743 | state->caller.cldap->send_queue, | 
|---|
| 744 | state->request.blob.data, | 
|---|
| 745 | state->request.blob.length, | 
|---|
| 746 | state->request.dest); | 
|---|
| 747 | if (tevent_req_nomem(subreq, req)) { | 
|---|
| 748 | return; | 
|---|
| 749 | } | 
|---|
| 750 | tevent_req_set_callback(subreq, cldap_search_state_queue_done, req); | 
|---|
| 751 | } | 
|---|
| 752 |  | 
|---|
| 753 | /* | 
|---|
| 754 | receive a cldap reply | 
|---|
| 755 | */ | 
|---|
| 756 | NTSTATUS cldap_search_recv(struct tevent_req *req, | 
|---|
| 757 | TALLOC_CTX *mem_ctx, | 
|---|
| 758 | struct cldap_search *io) | 
|---|
| 759 | { | 
|---|
| 760 | struct cldap_search_state *state = tevent_req_data(req, | 
|---|
| 761 | struct cldap_search_state); | 
|---|
| 762 | struct ldap_message *ldap_msg; | 
|---|
| 763 | NTSTATUS status; | 
|---|
| 764 |  | 
|---|
| 765 | if (tevent_req_is_nterror(req, &status)) { | 
|---|
| 766 | goto failed; | 
|---|
| 767 | } | 
|---|
| 768 |  | 
|---|
| 769 | ldap_msg = talloc(mem_ctx, struct ldap_message); | 
|---|
| 770 | if (!ldap_msg) { | 
|---|
| 771 | goto nomem; | 
|---|
| 772 | } | 
|---|
| 773 |  | 
|---|
| 774 | status = ldap_decode(state->response.asn1, NULL, ldap_msg); | 
|---|
| 775 | if (!NT_STATUS_IS_OK(status)) { | 
|---|
| 776 | goto failed; | 
|---|
| 777 | } | 
|---|
| 778 |  | 
|---|
| 779 | ZERO_STRUCT(io->out); | 
|---|
| 780 |  | 
|---|
| 781 | /* the first possible form has a search result in first place */ | 
|---|
| 782 | if (ldap_msg->type == LDAP_TAG_SearchResultEntry) { | 
|---|
| 783 | io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry); | 
|---|
| 784 | if (!io->out.response) { | 
|---|
| 785 | goto nomem; | 
|---|
| 786 | } | 
|---|
| 787 | *io->out.response = ldap_msg->r.SearchResultEntry; | 
|---|
| 788 |  | 
|---|
| 789 | /* decode the 2nd part */ | 
|---|
| 790 | status = ldap_decode(state->response.asn1, NULL, ldap_msg); | 
|---|
| 791 | if (!NT_STATUS_IS_OK(status)) { | 
|---|
| 792 | goto failed; | 
|---|
| 793 | } | 
|---|
| 794 | } | 
|---|
| 795 |  | 
|---|
| 796 | if (ldap_msg->type != LDAP_TAG_SearchResultDone) { | 
|---|
| 797 | status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR); | 
|---|
| 798 | goto failed; | 
|---|
| 799 | } | 
|---|
| 800 |  | 
|---|
| 801 | io->out.result = talloc(mem_ctx, struct ldap_Result); | 
|---|
| 802 | if (!io->out.result) { | 
|---|
| 803 | goto nomem; | 
|---|
| 804 | } | 
|---|
| 805 | *io->out.result = ldap_msg->r.SearchResultDone; | 
|---|
| 806 |  | 
|---|
| 807 | if (io->out.result->resultcode != LDAP_SUCCESS) { | 
|---|
| 808 | status = NT_STATUS_LDAP(io->out.result->resultcode); | 
|---|
| 809 | goto failed; | 
|---|
| 810 | } | 
|---|
| 811 |  | 
|---|
| 812 | tevent_req_received(req); | 
|---|
| 813 | return NT_STATUS_OK; | 
|---|
| 814 |  | 
|---|
| 815 | nomem: | 
|---|
| 816 | status = NT_STATUS_NO_MEMORY; | 
|---|
| 817 | failed: | 
|---|
| 818 | tevent_req_received(req); | 
|---|
| 819 | return status; | 
|---|
| 820 | } | 
|---|
| 821 |  | 
|---|
| 822 |  | 
|---|
| 823 | /* | 
|---|
| 824 | synchronous cldap search | 
|---|
| 825 | */ | 
|---|
| 826 | NTSTATUS cldap_search(struct cldap_socket *cldap, | 
|---|
| 827 | TALLOC_CTX *mem_ctx, | 
|---|
| 828 | struct cldap_search *io) | 
|---|
| 829 | { | 
|---|
| 830 | struct tevent_req *req; | 
|---|
| 831 | NTSTATUS status; | 
|---|
| 832 |  | 
|---|
| 833 | if (!cldap->event.allow_poll) { | 
|---|
| 834 | return NT_STATUS_INVALID_PIPE_STATE; | 
|---|
| 835 | } | 
|---|
| 836 |  | 
|---|
| 837 | if (cldap->searches.list) { | 
|---|
| 838 | return NT_STATUS_PIPE_BUSY; | 
|---|
| 839 | } | 
|---|
| 840 |  | 
|---|
| 841 | req = cldap_search_send(mem_ctx, cldap, io); | 
|---|
| 842 | NT_STATUS_HAVE_NO_MEMORY(req); | 
|---|
| 843 |  | 
|---|
| 844 | if (!tevent_req_poll(req, cldap->event.ctx)) { | 
|---|
| 845 | talloc_free(req); | 
|---|
| 846 | return NT_STATUS_INTERNAL_ERROR; | 
|---|
| 847 | } | 
|---|
| 848 |  | 
|---|
| 849 | status = cldap_search_recv(req, mem_ctx, io); | 
|---|
| 850 | talloc_free(req); | 
|---|
| 851 |  | 
|---|
| 852 | return status; | 
|---|
| 853 | } | 
|---|
| 854 |  | 
|---|
| 855 | struct cldap_netlogon_state { | 
|---|
| 856 | struct cldap_search search; | 
|---|
| 857 | }; | 
|---|
| 858 |  | 
|---|
| 859 | static void cldap_netlogon_state_done(struct tevent_req *subreq); | 
|---|
| 860 | /* | 
|---|
| 861 | queue a cldap netlogon for send | 
|---|
| 862 | */ | 
|---|
| 863 | struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx, | 
|---|
| 864 | struct cldap_socket *cldap, | 
|---|
| 865 | const struct cldap_netlogon *io) | 
|---|
| 866 | { | 
|---|
| 867 | struct tevent_req *req, *subreq; | 
|---|
| 868 | struct cldap_netlogon_state *state; | 
|---|
| 869 | char *filter; | 
|---|
| 870 | static const char * const attr[] = { "NetLogon", NULL }; | 
|---|
| 871 |  | 
|---|
| 872 | req = tevent_req_create(mem_ctx, &state, | 
|---|
| 873 | struct cldap_netlogon_state); | 
|---|
| 874 | if (!req) { | 
|---|
| 875 | return NULL; | 
|---|
| 876 | } | 
|---|
| 877 |  | 
|---|
| 878 | filter = talloc_asprintf(state, "(&(NtVer=%s)", | 
|---|
| 879 | ldap_encode_ndr_uint32(state, io->in.version)); | 
|---|
| 880 | if (tevent_req_nomem(filter, req)) { | 
|---|
| 881 | goto post; | 
|---|
| 882 | } | 
|---|
| 883 | if (io->in.user) { | 
|---|
| 884 | filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user); | 
|---|
| 885 | if (tevent_req_nomem(filter, req)) { | 
|---|
| 886 | goto post; | 
|---|
| 887 | } | 
|---|
| 888 | } | 
|---|
| 889 | if (io->in.host) { | 
|---|
| 890 | filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host); | 
|---|
| 891 | if (tevent_req_nomem(filter, req)) { | 
|---|
| 892 | goto post; | 
|---|
| 893 | } | 
|---|
| 894 | } | 
|---|
| 895 | if (io->in.realm) { | 
|---|
| 896 | filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm); | 
|---|
| 897 | if (tevent_req_nomem(filter, req)) { | 
|---|
| 898 | goto post; | 
|---|
| 899 | } | 
|---|
| 900 | } | 
|---|
| 901 | if (io->in.acct_control != -1) { | 
|---|
| 902 | filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)", | 
|---|
| 903 | ldap_encode_ndr_uint32(state, io->in.acct_control)); | 
|---|
| 904 | if (tevent_req_nomem(filter, req)) { | 
|---|
| 905 | goto post; | 
|---|
| 906 | } | 
|---|
| 907 | } | 
|---|
| 908 | if (io->in.domain_sid) { | 
|---|
| 909 | struct dom_sid *sid = dom_sid_parse_talloc(state, io->in.domain_sid); | 
|---|
| 910 | if (tevent_req_nomem(sid, req)) { | 
|---|
| 911 | goto post; | 
|---|
| 912 | } | 
|---|
| 913 | filter = talloc_asprintf_append_buffer(filter, "(domainSid=%s)", | 
|---|
| 914 | ldap_encode_ndr_dom_sid(state, sid)); | 
|---|
| 915 | if (tevent_req_nomem(filter, req)) { | 
|---|
| 916 | goto post; | 
|---|
| 917 | } | 
|---|
| 918 | } | 
|---|
| 919 | if (io->in.domain_guid) { | 
|---|
| 920 | struct GUID guid; | 
|---|
| 921 | NTSTATUS status; | 
|---|
| 922 | status = GUID_from_string(io->in.domain_guid, &guid); | 
|---|
| 923 | if (tevent_req_nterror(req, status)) { | 
|---|
| 924 | goto post; | 
|---|
| 925 | } | 
|---|
| 926 | filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)", | 
|---|
| 927 | ldap_encode_ndr_GUID(state, &guid)); | 
|---|
| 928 | if (tevent_req_nomem(filter, req)) { | 
|---|
| 929 | goto post; | 
|---|
| 930 | } | 
|---|
| 931 | } | 
|---|
| 932 | filter = talloc_asprintf_append_buffer(filter, ")"); | 
|---|
| 933 | if (tevent_req_nomem(filter, req)) { | 
|---|
| 934 | goto post; | 
|---|
| 935 | } | 
|---|
| 936 |  | 
|---|
| 937 | if (io->in.dest_address) { | 
|---|
| 938 | state->search.in.dest_address = talloc_strdup(state, | 
|---|
| 939 | io->in.dest_address); | 
|---|
| 940 | if (tevent_req_nomem(state->search.in.dest_address, req)) { | 
|---|
| 941 | goto post; | 
|---|
| 942 | } | 
|---|
| 943 | state->search.in.dest_port = io->in.dest_port; | 
|---|
| 944 | } else { | 
|---|
| 945 | state->search.in.dest_address   = NULL; | 
|---|
| 946 | state->search.in.dest_port      = 0; | 
|---|
| 947 | } | 
|---|
| 948 | state->search.in.filter         = filter; | 
|---|
| 949 | state->search.in.attributes     = attr; | 
|---|
| 950 | state->search.in.timeout        = 2; | 
|---|
| 951 | state->search.in.retries        = 2; | 
|---|
| 952 |  | 
|---|
| 953 | subreq = cldap_search_send(state, cldap, &state->search); | 
|---|
| 954 | if (tevent_req_nomem(subreq, req)) { | 
|---|
| 955 | goto post; | 
|---|
| 956 | } | 
|---|
| 957 | tevent_req_set_callback(subreq, cldap_netlogon_state_done, req); | 
|---|
| 958 |  | 
|---|
| 959 | return req; | 
|---|
| 960 | post: | 
|---|
| 961 | return tevent_req_post(req, cldap->event.ctx); | 
|---|
| 962 | } | 
|---|
| 963 |  | 
|---|
| 964 | static void cldap_netlogon_state_done(struct tevent_req *subreq) | 
|---|
| 965 | { | 
|---|
| 966 | struct tevent_req *req = tevent_req_callback_data(subreq, | 
|---|
| 967 | struct tevent_req); | 
|---|
| 968 | struct cldap_netlogon_state *state = tevent_req_data(req, | 
|---|
| 969 | struct cldap_netlogon_state); | 
|---|
| 970 | NTSTATUS status; | 
|---|
| 971 |  | 
|---|
| 972 | status = cldap_search_recv(subreq, state, &state->search); | 
|---|
| 973 | talloc_free(subreq); | 
|---|
| 974 |  | 
|---|
| 975 | if (tevent_req_nterror(req, status)) { | 
|---|
| 976 | return; | 
|---|
| 977 | } | 
|---|
| 978 |  | 
|---|
| 979 | tevent_req_done(req); | 
|---|
| 980 | } | 
|---|
| 981 |  | 
|---|
| 982 | /* | 
|---|
| 983 | receive a cldap netlogon reply | 
|---|
| 984 | */ | 
|---|
| 985 | NTSTATUS cldap_netlogon_recv(struct tevent_req *req, | 
|---|
| 986 | TALLOC_CTX *mem_ctx, | 
|---|
| 987 | struct cldap_netlogon *io) | 
|---|
| 988 | { | 
|---|
| 989 | struct cldap_netlogon_state *state = tevent_req_data(req, | 
|---|
| 990 | struct cldap_netlogon_state); | 
|---|
| 991 | NTSTATUS status; | 
|---|
| 992 | DATA_BLOB *data; | 
|---|
| 993 |  | 
|---|
| 994 | if (tevent_req_is_nterror(req, &status)) { | 
|---|
| 995 | goto failed; | 
|---|
| 996 | } | 
|---|
| 997 |  | 
|---|
| 998 | if (state->search.out.response == NULL) { | 
|---|
| 999 | status = NT_STATUS_NOT_FOUND; | 
|---|
| 1000 | goto failed; | 
|---|
| 1001 | } | 
|---|
| 1002 |  | 
|---|
| 1003 | if (state->search.out.response->num_attributes != 1 || | 
|---|
| 1004 | strcasecmp(state->search.out.response->attributes[0].name, "netlogon") != 0 || | 
|---|
| 1005 | state->search.out.response->attributes[0].num_values != 1 || | 
|---|
| 1006 | state->search.out.response->attributes[0].values->length < 2) { | 
|---|
| 1007 | status = NT_STATUS_UNEXPECTED_NETWORK_ERROR; | 
|---|
| 1008 | goto failed; | 
|---|
| 1009 | } | 
|---|
| 1010 | data = state->search.out.response->attributes[0].values; | 
|---|
| 1011 |  | 
|---|
| 1012 | status = pull_netlogon_samlogon_response(data, mem_ctx, | 
|---|
| 1013 | &io->out.netlogon); | 
|---|
| 1014 | if (!NT_STATUS_IS_OK(status)) { | 
|---|
| 1015 | goto failed; | 
|---|
| 1016 | } | 
|---|
| 1017 |  | 
|---|
| 1018 | if (io->in.map_response) { | 
|---|
| 1019 | map_netlogon_samlogon_response(&io->out.netlogon); | 
|---|
| 1020 | } | 
|---|
| 1021 |  | 
|---|
| 1022 | status =  NT_STATUS_OK; | 
|---|
| 1023 | failed: | 
|---|
| 1024 | tevent_req_received(req); | 
|---|
| 1025 | return status; | 
|---|
| 1026 | } | 
|---|
| 1027 |  | 
|---|
| 1028 | /* | 
|---|
| 1029 | sync cldap netlogon search | 
|---|
| 1030 | */ | 
|---|
| 1031 | NTSTATUS cldap_netlogon(struct cldap_socket *cldap, | 
|---|
| 1032 | TALLOC_CTX *mem_ctx, | 
|---|
| 1033 | struct cldap_netlogon *io) | 
|---|
| 1034 | { | 
|---|
| 1035 | struct tevent_req *req; | 
|---|
| 1036 | NTSTATUS status; | 
|---|
| 1037 |  | 
|---|
| 1038 | if (!cldap->event.allow_poll) { | 
|---|
| 1039 | return NT_STATUS_INVALID_PIPE_STATE; | 
|---|
| 1040 | } | 
|---|
| 1041 |  | 
|---|
| 1042 | if (cldap->searches.list) { | 
|---|
| 1043 | return NT_STATUS_PIPE_BUSY; | 
|---|
| 1044 | } | 
|---|
| 1045 |  | 
|---|
| 1046 | req = cldap_netlogon_send(mem_ctx, cldap, io); | 
|---|
| 1047 | NT_STATUS_HAVE_NO_MEMORY(req); | 
|---|
| 1048 |  | 
|---|
| 1049 | if (!tevent_req_poll(req, cldap->event.ctx)) { | 
|---|
| 1050 | talloc_free(req); | 
|---|
| 1051 | return NT_STATUS_INTERNAL_ERROR; | 
|---|
| 1052 | } | 
|---|
| 1053 |  | 
|---|
| 1054 | status = cldap_netlogon_recv(req, mem_ctx, io); | 
|---|
| 1055 | talloc_free(req); | 
|---|
| 1056 |  | 
|---|
| 1057 | return status; | 
|---|
| 1058 | } | 
|---|
| 1059 |  | 
|---|
| 1060 |  | 
|---|
| 1061 | /* | 
|---|
| 1062 | send an empty reply (used on any error, so the client doesn't keep waiting | 
|---|
| 1063 | or send the bad request again) | 
|---|
| 1064 | */ | 
|---|
| 1065 | NTSTATUS cldap_empty_reply(struct cldap_socket *cldap, | 
|---|
| 1066 | uint32_t message_id, | 
|---|
| 1067 | struct tsocket_address *dest) | 
|---|
| 1068 | { | 
|---|
| 1069 | NTSTATUS status; | 
|---|
| 1070 | struct cldap_reply reply; | 
|---|
| 1071 | struct ldap_Result result; | 
|---|
| 1072 |  | 
|---|
| 1073 | reply.messageid    = message_id; | 
|---|
| 1074 | reply.dest         = dest; | 
|---|
| 1075 | reply.response     = NULL; | 
|---|
| 1076 | reply.result       = &result; | 
|---|
| 1077 |  | 
|---|
| 1078 | ZERO_STRUCT(result); | 
|---|
| 1079 |  | 
|---|
| 1080 | status = cldap_reply_send(cldap, &reply); | 
|---|
| 1081 |  | 
|---|
| 1082 | return status; | 
|---|
| 1083 | } | 
|---|
| 1084 |  | 
|---|
| 1085 | /* | 
|---|
| 1086 | send an error reply (used on any error, so the client doesn't keep waiting | 
|---|
| 1087 | or send the bad request again) | 
|---|
| 1088 | */ | 
|---|
| 1089 | NTSTATUS cldap_error_reply(struct cldap_socket *cldap, | 
|---|
| 1090 | uint32_t message_id, | 
|---|
| 1091 | struct tsocket_address *dest, | 
|---|
| 1092 | int resultcode, | 
|---|
| 1093 | const char *errormessage) | 
|---|
| 1094 | { | 
|---|
| 1095 | NTSTATUS status; | 
|---|
| 1096 | struct cldap_reply reply; | 
|---|
| 1097 | struct ldap_Result result; | 
|---|
| 1098 |  | 
|---|
| 1099 | reply.messageid    = message_id; | 
|---|
| 1100 | reply.dest         = dest; | 
|---|
| 1101 | reply.response     = NULL; | 
|---|
| 1102 | reply.result       = &result; | 
|---|
| 1103 |  | 
|---|
| 1104 | ZERO_STRUCT(result); | 
|---|
| 1105 | result.resultcode       = resultcode; | 
|---|
| 1106 | result.errormessage     = errormessage; | 
|---|
| 1107 |  | 
|---|
| 1108 | status = cldap_reply_send(cldap, &reply); | 
|---|
| 1109 |  | 
|---|
| 1110 | return status; | 
|---|
| 1111 | } | 
|---|
| 1112 |  | 
|---|
| 1113 |  | 
|---|
| 1114 | /* | 
|---|
| 1115 | send a netlogon reply | 
|---|
| 1116 | */ | 
|---|
| 1117 | NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap, | 
|---|
| 1118 | uint32_t message_id, | 
|---|
| 1119 | struct tsocket_address *dest, | 
|---|
| 1120 | uint32_t version, | 
|---|
| 1121 | struct netlogon_samlogon_response *netlogon) | 
|---|
| 1122 | { | 
|---|
| 1123 | NTSTATUS status; | 
|---|
| 1124 | struct cldap_reply reply; | 
|---|
| 1125 | struct ldap_SearchResEntry response; | 
|---|
| 1126 | struct ldap_Result result; | 
|---|
| 1127 | TALLOC_CTX *tmp_ctx = talloc_new(cldap); | 
|---|
| 1128 | DATA_BLOB blob; | 
|---|
| 1129 |  | 
|---|
| 1130 | status = push_netlogon_samlogon_response(&blob, tmp_ctx, | 
|---|
| 1131 | netlogon); | 
|---|
| 1132 | if (!NT_STATUS_IS_OK(status)) { | 
|---|
| 1133 | talloc_free(tmp_ctx); | 
|---|
| 1134 | return status; | 
|---|
| 1135 | } | 
|---|
| 1136 | reply.messageid    = message_id; | 
|---|
| 1137 | reply.dest         = dest; | 
|---|
| 1138 | reply.response     = &response; | 
|---|
| 1139 | reply.result       = &result; | 
|---|
| 1140 |  | 
|---|
| 1141 | ZERO_STRUCT(result); | 
|---|
| 1142 |  | 
|---|
| 1143 | response.dn = ""; | 
|---|
| 1144 | response.num_attributes = 1; | 
|---|
| 1145 | response.attributes = talloc(tmp_ctx, struct ldb_message_element); | 
|---|
| 1146 | NT_STATUS_HAVE_NO_MEMORY(response.attributes); | 
|---|
| 1147 | response.attributes->name = "netlogon"; | 
|---|
| 1148 | response.attributes->num_values = 1; | 
|---|
| 1149 | response.attributes->values = &blob; | 
|---|
| 1150 |  | 
|---|
| 1151 | status = cldap_reply_send(cldap, &reply); | 
|---|
| 1152 |  | 
|---|
| 1153 | talloc_free(tmp_ctx); | 
|---|
| 1154 |  | 
|---|
| 1155 | return status; | 
|---|
| 1156 | } | 
|---|
| 1157 |  | 
|---|