1/* 2 Unix SMB/CIFS implementation. 3 4 low level WINS replication client code 5 6 Copyright (C) Andrew Tridgell 2005 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. 20*/ 21 22#include "includes.h" 23#include "lib/events/events.h" 24#include "../lib/util/dlinklist.h" 25#include "lib/socket/socket.h" 26#include "libcli/wrepl/winsrepl.h" 27#include "librpc/gen_ndr/ndr_winsrepl.h" 28#include "lib/stream/packet.h" 29#include "libcli/composite/composite.h" 30#include "system/network.h" 31#include "lib/socket/netif.h" 32#include "param/param.h" 33 34static struct wrepl_request *wrepl_request_finished(struct wrepl_request *req, NTSTATUS status); 35 36/* 37 mark all pending requests as dead - called when a socket error happens 38*/ 39static void wrepl_socket_dead(struct wrepl_socket *wrepl_socket, NTSTATUS status) 40{ 41 wrepl_socket->dead = true; 42 43 if (wrepl_socket->packet) { 44 packet_recv_disable(wrepl_socket->packet); 45 packet_set_fde(wrepl_socket->packet, NULL); 46 packet_set_socket(wrepl_socket->packet, NULL); 47 } 48 49 if (wrepl_socket->event.fde) { 50 talloc_free(wrepl_socket->event.fde); 51 wrepl_socket->event.fde = NULL; 52 } 53 54 if (wrepl_socket->sock) { 55 talloc_free(wrepl_socket->sock); 56 wrepl_socket->sock = NULL; 57 } 58 59 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) { 60 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR; 61 } 62 while (wrepl_socket->recv_queue) { 63 struct wrepl_request *req = wrepl_socket->recv_queue; 64 DLIST_REMOVE(wrepl_socket->recv_queue, req); 65 wrepl_request_finished(req, status); 66 } 67 68 talloc_set_destructor(wrepl_socket, NULL); 69 if (wrepl_socket->free_skipped) { 70 talloc_free(wrepl_socket); 71 } 72} 73 74static void wrepl_request_timeout_handler(struct tevent_context *ev, struct tevent_timer *te, 75 struct timeval t, void *ptr) 76{ 77 struct wrepl_request *req = talloc_get_type(ptr, struct wrepl_request); 78 wrepl_socket_dead(req->wrepl_socket, NT_STATUS_IO_TIMEOUT); 79} 80 81/* 82 handle recv events 83*/ 84static NTSTATUS wrepl_finish_recv(void *private_data, DATA_BLOB packet_blob_in) 85{ 86 struct wrepl_socket *wrepl_socket = talloc_get_type(private_data, struct wrepl_socket); 87 struct wrepl_request *req = wrepl_socket->recv_queue; 88 DATA_BLOB blob; 89 enum ndr_err_code ndr_err; 90 91 if (!req) { 92 DEBUG(1,("Received unexpected WINS packet of length %u!\n", 93 (unsigned)packet_blob_in.length)); 94 return NT_STATUS_INVALID_NETWORK_RESPONSE; 95 } 96 97 req->packet = talloc(req, struct wrepl_packet); 98 NT_STATUS_HAVE_NO_MEMORY(req->packet); 99 100 blob.data = packet_blob_in.data + 4; 101 blob.length = packet_blob_in.length - 4; 102 103 /* we have a full request - parse it */ 104 ndr_err = ndr_pull_struct_blob(&blob, req->packet, wrepl_socket->iconv_convenience, req->packet, 105 (ndr_pull_flags_fn_t)ndr_pull_wrepl_packet); 106 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 107 NTSTATUS status = ndr_map_error2ntstatus(ndr_err); 108 wrepl_request_finished(req, status); 109 return NT_STATUS_OK; 110 } 111 112 if (DEBUGLVL(10)) { 113 DEBUG(10,("Received WINS packet of length %u\n", 114 (unsigned)packet_blob_in.length)); 115 NDR_PRINT_DEBUG(wrepl_packet, req->packet); 116 } 117 118 wrepl_request_finished(req, NT_STATUS_OK); 119 return NT_STATUS_OK; 120} 121 122/* 123 handler for winrepl events 124*/ 125static void wrepl_handler(struct tevent_context *ev, struct tevent_fd *fde, 126 uint16_t flags, void *private_data) 127{ 128 struct wrepl_socket *wrepl_socket = talloc_get_type(private_data, 129 struct wrepl_socket); 130 if (flags & EVENT_FD_READ) { 131 packet_recv(wrepl_socket->packet); 132 return; 133 } 134 if (flags & EVENT_FD_WRITE) { 135 packet_queue_run(wrepl_socket->packet); 136 } 137} 138 139static void wrepl_error(void *private_data, NTSTATUS status) 140{ 141 struct wrepl_socket *wrepl_socket = talloc_get_type(private_data, 142 struct wrepl_socket); 143 wrepl_socket_dead(wrepl_socket, status); 144} 145 146 147/* 148 destroy a wrepl_socket destructor 149*/ 150static int wrepl_socket_destructor(struct wrepl_socket *sock) 151{ 152 if (sock->dead) { 153 sock->free_skipped = true; 154 return -1; 155 } 156 wrepl_socket_dead(sock, NT_STATUS_LOCAL_DISCONNECT); 157 return 0; 158} 159 160/* 161 initialise a wrepl_socket. The event_ctx is optional, if provided then 162 operations will use that event context 163*/ 164struct wrepl_socket *wrepl_socket_init(TALLOC_CTX *mem_ctx, 165 struct tevent_context *event_ctx, 166 struct smb_iconv_convenience *iconv_convenience) 167{ 168 struct wrepl_socket *wrepl_socket; 169 NTSTATUS status; 170 171 wrepl_socket = talloc_zero(mem_ctx, struct wrepl_socket); 172 if (!wrepl_socket) return NULL; 173 174 wrepl_socket->event.ctx = event_ctx; 175 if (!wrepl_socket->event.ctx) goto failed; 176 177 wrepl_socket->iconv_convenience = iconv_convenience; 178 179 status = socket_create("ip", SOCKET_TYPE_STREAM, &wrepl_socket->sock, 0); 180 if (!NT_STATUS_IS_OK(status)) goto failed; 181 182 talloc_steal(wrepl_socket, wrepl_socket->sock); 183 184 wrepl_socket->request_timeout = WREPL_SOCKET_REQUEST_TIMEOUT; 185 186 talloc_set_destructor(wrepl_socket, wrepl_socket_destructor); 187 188 return wrepl_socket; 189 190failed: 191 talloc_free(wrepl_socket); 192 return NULL; 193} 194 195/* 196 initialise a wrepl_socket from an already existing connection 197*/ 198struct wrepl_socket *wrepl_socket_merge(TALLOC_CTX *mem_ctx, 199 struct tevent_context *event_ctx, 200 struct socket_context *sock, 201 struct packet_context *pack) 202{ 203 struct wrepl_socket *wrepl_socket; 204 205 wrepl_socket = talloc_zero(mem_ctx, struct wrepl_socket); 206 if (wrepl_socket == NULL) goto failed; 207 208 wrepl_socket->event.ctx = event_ctx; 209 if (wrepl_socket->event.ctx == NULL) goto failed; 210 211 wrepl_socket->sock = sock; 212 talloc_steal(wrepl_socket, wrepl_socket->sock); 213 214 215 wrepl_socket->request_timeout = WREPL_SOCKET_REQUEST_TIMEOUT; 216 217 wrepl_socket->event.fde = event_add_fd(wrepl_socket->event.ctx, wrepl_socket, 218 socket_get_fd(wrepl_socket->sock), 219 EVENT_FD_READ, 220 wrepl_handler, wrepl_socket); 221 if (wrepl_socket->event.fde == NULL) { 222 goto failed; 223 } 224 225 wrepl_socket->packet = pack; 226 talloc_steal(wrepl_socket, wrepl_socket->packet); 227 packet_set_private(wrepl_socket->packet, wrepl_socket); 228 packet_set_socket(wrepl_socket->packet, wrepl_socket->sock); 229 packet_set_callback(wrepl_socket->packet, wrepl_finish_recv); 230 packet_set_full_request(wrepl_socket->packet, packet_full_request_u32); 231 packet_set_error_handler(wrepl_socket->packet, wrepl_error); 232 packet_set_event_context(wrepl_socket->packet, wrepl_socket->event.ctx); 233 packet_set_fde(wrepl_socket->packet, wrepl_socket->event.fde); 234 packet_set_serialise(wrepl_socket->packet); 235 236 talloc_set_destructor(wrepl_socket, wrepl_socket_destructor); 237 238 return wrepl_socket; 239 240failed: 241 talloc_free(wrepl_socket); 242 return NULL; 243} 244 245/* 246 destroy a wrepl_request 247*/ 248static int wrepl_request_destructor(struct wrepl_request *req) 249{ 250 if (req->state == WREPL_REQUEST_RECV) { 251 DLIST_REMOVE(req->wrepl_socket->recv_queue, req); 252 } 253 req->state = WREPL_REQUEST_ERROR; 254 return 0; 255} 256 257/* 258 wait for a request to complete 259*/ 260static NTSTATUS wrepl_request_wait(struct wrepl_request *req) 261{ 262 NT_STATUS_HAVE_NO_MEMORY(req); 263 while (req->state < WREPL_REQUEST_DONE) { 264 event_loop_once(req->wrepl_socket->event.ctx); 265 } 266 return req->status; 267} 268 269struct wrepl_connect_state { 270 struct composite_context *result; 271 struct wrepl_socket *wrepl_socket; 272 struct composite_context *creq; 273}; 274 275/* 276 handler for winrepl connection completion 277*/ 278static void wrepl_connect_handler(struct composite_context *creq) 279{ 280 struct wrepl_connect_state *state = talloc_get_type(creq->async.private_data, 281 struct wrepl_connect_state); 282 struct wrepl_socket *wrepl_socket = state->wrepl_socket; 283 struct composite_context *result = state->result; 284 285 result->status = socket_connect_recv(state->creq); 286 if (!composite_is_ok(result)) return; 287 288 wrepl_socket->event.fde = event_add_fd(wrepl_socket->event.ctx, wrepl_socket, 289 socket_get_fd(wrepl_socket->sock), 290 EVENT_FD_READ, 291 wrepl_handler, wrepl_socket); 292 if (composite_nomem(wrepl_socket->event.fde, result)) return; 293 294 /* setup the stream -> packet parser */ 295 wrepl_socket->packet = packet_init(wrepl_socket); 296 if (composite_nomem(wrepl_socket->packet, result)) return; 297 packet_set_private(wrepl_socket->packet, wrepl_socket); 298 packet_set_socket(wrepl_socket->packet, wrepl_socket->sock); 299 packet_set_callback(wrepl_socket->packet, wrepl_finish_recv); 300 packet_set_full_request(wrepl_socket->packet, packet_full_request_u32); 301 packet_set_error_handler(wrepl_socket->packet, wrepl_error); 302 packet_set_event_context(wrepl_socket->packet, wrepl_socket->event.ctx); 303 packet_set_fde(wrepl_socket->packet, wrepl_socket->event.fde); 304 packet_set_serialise(wrepl_socket->packet); 305 306 composite_done(result); 307} 308 309const char *wrepl_best_ip(struct loadparm_context *lp_ctx, const char *peer_ip) 310{ 311 struct interface *ifaces; 312 load_interfaces(lp_ctx, lp_interfaces(lp_ctx), &ifaces); 313 return iface_best_ip(ifaces, peer_ip); 314} 315 316 317/* 318 connect a wrepl_socket to a WINS server 319*/ 320struct composite_context *wrepl_connect_send(struct wrepl_socket *wrepl_socket, 321 const char *our_ip, const char *peer_ip) 322{ 323 struct composite_context *result; 324 struct wrepl_connect_state *state; 325 struct socket_address *peer, *us; 326 327 result = talloc_zero(wrepl_socket, struct composite_context); 328 if (!result) return NULL; 329 330 result->state = COMPOSITE_STATE_IN_PROGRESS; 331 result->event_ctx = wrepl_socket->event.ctx; 332 333 state = talloc_zero(result, struct wrepl_connect_state); 334 if (composite_nomem(state, result)) return result; 335 result->private_data = state; 336 state->result = result; 337 state->wrepl_socket = wrepl_socket; 338 339 us = socket_address_from_strings(state, wrepl_socket->sock->backend_name, 340 our_ip, 0); 341 if (composite_nomem(us, result)) return result; 342 343 peer = socket_address_from_strings(state, wrepl_socket->sock->backend_name, 344 peer_ip, WINS_REPLICATION_PORT); 345 if (composite_nomem(peer, result)) return result; 346 347 state->creq = socket_connect_send(wrepl_socket->sock, us, peer, 348 0, wrepl_socket->event.ctx); 349 composite_continue(result, state->creq, wrepl_connect_handler, state); 350 return result; 351} 352 353/* 354 connect a wrepl_socket to a WINS server - recv side 355*/ 356NTSTATUS wrepl_connect_recv(struct composite_context *result) 357{ 358 struct wrepl_connect_state *state = talloc_get_type(result->private_data, 359 struct wrepl_connect_state); 360 struct wrepl_socket *wrepl_socket = state->wrepl_socket; 361 NTSTATUS status = composite_wait(result); 362 363 if (!NT_STATUS_IS_OK(status)) { 364 wrepl_socket_dead(wrepl_socket, status); 365 } 366 367 talloc_free(result); 368 return status; 369} 370 371/* 372 connect a wrepl_socket to a WINS server - sync API 373*/ 374NTSTATUS wrepl_connect(struct wrepl_socket *wrepl_socket, 375 const char *our_ip, const char *peer_ip) 376{ 377 struct composite_context *c_req = wrepl_connect_send(wrepl_socket, our_ip, peer_ip); 378 return wrepl_connect_recv(c_req); 379} 380 381/* 382 callback from wrepl_request_trigger() 383*/ 384static void wrepl_request_trigger_handler(struct tevent_context *ev, struct tevent_timer *te, 385 struct timeval t, void *ptr) 386{ 387 struct wrepl_request *req = talloc_get_type(ptr, struct wrepl_request); 388 if (req->async.fn) { 389 req->async.fn(req); 390 } 391} 392 393/* 394 trigger an immediate event on a wrepl_request 395 the return value should only be used in wrepl_request_send() 396 this is the only place where req->trigger is true 397*/ 398static struct wrepl_request *wrepl_request_finished(struct wrepl_request *req, NTSTATUS status) 399{ 400 struct tevent_timer *te; 401 402 if (req->state == WREPL_REQUEST_RECV) { 403 DLIST_REMOVE(req->wrepl_socket->recv_queue, req); 404 } 405 406 if (!NT_STATUS_IS_OK(status)) { 407 req->state = WREPL_REQUEST_ERROR; 408 } else { 409 req->state = WREPL_REQUEST_DONE; 410 } 411 412 req->status = status; 413 414 if (req->trigger) { 415 req->trigger = false; 416 /* a zero timeout means immediate */ 417 te = event_add_timed(req->wrepl_socket->event.ctx, 418 req, timeval_zero(), 419 wrepl_request_trigger_handler, req); 420 if (!te) { 421 talloc_free(req); 422 return NULL; 423 } 424 return req; 425 } 426 427 if (req->async.fn) { 428 req->async.fn(req); 429 } 430 return NULL; 431} 432 433struct wrepl_send_ctrl_state { 434 struct wrepl_send_ctrl ctrl; 435 struct wrepl_request *req; 436 struct wrepl_socket *wrepl_sock; 437}; 438 439static int wrepl_send_ctrl_destructor(struct wrepl_send_ctrl_state *s) 440{ 441 struct wrepl_request *req = s->wrepl_sock->recv_queue; 442 443 /* check if the request is still in WREPL_STATE_RECV, 444 * we need this here because the caller has may called 445 * talloc_free(req) and wrepl_send_ctrl_state isn't 446 * a talloc child of the request, so our s->req pointer 447 * is maybe invalid! 448 */ 449 for (; req; req = req->next) { 450 if (req == s->req) break; 451 } 452 if (!req) return 0; 453 454 /* here, we need to make sure the async request handler is called 455 * later in the next event_loop and now now 456 */ 457 req->trigger = true; 458 wrepl_request_finished(req, NT_STATUS_OK); 459 460 if (s->ctrl.disconnect_after_send) { 461 wrepl_socket_dead(s->wrepl_sock, NT_STATUS_LOCAL_DISCONNECT); 462 } 463 464 return 0; 465} 466 467/* 468 send a generic wins replication request 469*/ 470struct wrepl_request *wrepl_request_send(struct wrepl_socket *wrepl_socket, 471 struct wrepl_packet *packet, 472 struct wrepl_send_ctrl *ctrl) 473{ 474 struct wrepl_request *req; 475 struct wrepl_wrap wrap; 476 DATA_BLOB blob; 477 NTSTATUS status; 478 enum ndr_err_code ndr_err; 479 480 req = talloc_zero(wrepl_socket, struct wrepl_request); 481 if (!req) return NULL; 482 req->wrepl_socket = wrepl_socket; 483 req->state = WREPL_REQUEST_RECV; 484 req->trigger = true; 485 486 DLIST_ADD_END(wrepl_socket->recv_queue, req, struct wrepl_request *); 487 talloc_set_destructor(req, wrepl_request_destructor); 488 489 if (wrepl_socket->dead) { 490 return wrepl_request_finished(req, NT_STATUS_INVALID_CONNECTION); 491 } 492 493 wrap.packet = *packet; 494 ndr_err = ndr_push_struct_blob(&blob, req, wrepl_socket->iconv_convenience, &wrap, 495 (ndr_push_flags_fn_t)ndr_push_wrepl_wrap); 496 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 497 status = ndr_map_error2ntstatus(ndr_err); 498 return wrepl_request_finished(req, status); 499 } 500 501 if (DEBUGLVL(10)) { 502 DEBUG(10,("Sending WINS packet of length %u\n", 503 (unsigned)blob.length)); 504 NDR_PRINT_DEBUG(wrepl_packet, &wrap.packet); 505 } 506 507 if (wrepl_socket->request_timeout > 0) { 508 req->te = event_add_timed(wrepl_socket->event.ctx, req, 509 timeval_current_ofs(wrepl_socket->request_timeout, 0), 510 wrepl_request_timeout_handler, req); 511 if (!req->te) return wrepl_request_finished(req, NT_STATUS_NO_MEMORY); 512 } 513 514 if (ctrl && (ctrl->send_only || ctrl->disconnect_after_send)) { 515 struct wrepl_send_ctrl_state *s = talloc(blob.data, struct wrepl_send_ctrl_state); 516 if (!s) return wrepl_request_finished(req, NT_STATUS_NO_MEMORY); 517 s->ctrl = *ctrl; 518 s->req = req; 519 s->wrepl_sock = wrepl_socket; 520 talloc_set_destructor(s, wrepl_send_ctrl_destructor); 521 } 522 523 status = packet_send(wrepl_socket->packet, blob); 524 if (!NT_STATUS_IS_OK(status)) { 525 return wrepl_request_finished(req, status); 526 } 527 528 req->trigger = false; 529 return req; 530} 531 532/* 533 receive a generic WINS replication reply 534*/ 535NTSTATUS wrepl_request_recv(struct wrepl_request *req, 536 TALLOC_CTX *mem_ctx, 537 struct wrepl_packet **packet) 538{ 539 NTSTATUS status = wrepl_request_wait(req); 540 if (NT_STATUS_IS_OK(status) && packet) { 541 *packet = talloc_steal(mem_ctx, req->packet); 542 } 543 talloc_free(req); 544 return status; 545} 546 547/* 548 a full WINS replication request/response 549*/ 550NTSTATUS wrepl_request(struct wrepl_socket *wrepl_socket, 551 TALLOC_CTX *mem_ctx, 552 struct wrepl_packet *req_packet, 553 struct wrepl_packet **reply_packet) 554{ 555 struct wrepl_request *req = wrepl_request_send(wrepl_socket, req_packet, NULL); 556 return wrepl_request_recv(req, mem_ctx, reply_packet); 557} 558 559 560/* 561 setup an association - send 562*/ 563struct wrepl_request *wrepl_associate_send(struct wrepl_socket *wrepl_socket, 564 struct wrepl_associate *io) 565{ 566 struct wrepl_packet *packet; 567 struct wrepl_request *req; 568 569 packet = talloc_zero(wrepl_socket, struct wrepl_packet); 570 if (packet == NULL) return NULL; 571 572 packet->opcode = WREPL_OPCODE_BITS; 573 packet->mess_type = WREPL_START_ASSOCIATION; 574 packet->message.start.minor_version = 2; 575 packet->message.start.major_version = 5; 576 577 /* 578 * nt4 uses 41 bytes for the start_association call 579 * so do it the same and as we don't know th emeanings of this bytes 580 * we just send zeros and nt4, w2k and w2k3 seems to be happy with this 581 * 582 * if we don't do this nt4 uses an old version of the wins replication protocol 583 * and that would break nt4 <-> samba replication 584 */ 585 packet->padding = data_blob_talloc(packet, NULL, 21); 586 if (packet->padding.data == NULL) { 587 talloc_free(packet); 588 return NULL; 589 } 590 memset(packet->padding.data, 0, packet->padding.length); 591 592 req = wrepl_request_send(wrepl_socket, packet, NULL); 593 594 talloc_free(packet); 595 596 return req; 597} 598 599/* 600 setup an association - recv 601*/ 602NTSTATUS wrepl_associate_recv(struct wrepl_request *req, 603 struct wrepl_associate *io) 604{ 605 struct wrepl_packet *packet=NULL; 606 NTSTATUS status; 607 status = wrepl_request_recv(req, req->wrepl_socket, &packet); 608 NT_STATUS_NOT_OK_RETURN(status); 609 if (packet->mess_type != WREPL_START_ASSOCIATION_REPLY) { 610 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR; 611 } 612 if (NT_STATUS_IS_OK(status)) { 613 io->out.assoc_ctx = packet->message.start_reply.assoc_ctx; 614 io->out.major_version = packet->message.start_reply.major_version; 615 } 616 talloc_free(packet); 617 return status; 618} 619 620/* 621 setup an association - sync api 622*/ 623NTSTATUS wrepl_associate(struct wrepl_socket *wrepl_socket, 624 struct wrepl_associate *io) 625{ 626 struct wrepl_request *req = wrepl_associate_send(wrepl_socket, io); 627 return wrepl_associate_recv(req, io); 628} 629 630 631/* 632 stop an association - send 633*/ 634struct wrepl_request *wrepl_associate_stop_send(struct wrepl_socket *wrepl_socket, 635 struct wrepl_associate_stop *io) 636{ 637 struct wrepl_packet *packet; 638 struct wrepl_request *req; 639 struct wrepl_send_ctrl ctrl; 640 641 packet = talloc_zero(wrepl_socket, struct wrepl_packet); 642 if (packet == NULL) return NULL; 643 644 packet->opcode = WREPL_OPCODE_BITS; 645 packet->assoc_ctx = io->in.assoc_ctx; 646 packet->mess_type = WREPL_STOP_ASSOCIATION; 647 packet->message.stop.reason = io->in.reason; 648 649 ZERO_STRUCT(ctrl); 650 if (io->in.reason == 0) { 651 ctrl.send_only = true; 652 ctrl.disconnect_after_send = true; 653 } 654 655 req = wrepl_request_send(wrepl_socket, packet, &ctrl); 656 657 talloc_free(packet); 658 659 return req; 660} 661 662/* 663 stop an association - recv 664*/ 665NTSTATUS wrepl_associate_stop_recv(struct wrepl_request *req, 666 struct wrepl_associate_stop *io) 667{ 668 struct wrepl_packet *packet=NULL; 669 NTSTATUS status; 670 status = wrepl_request_recv(req, req->wrepl_socket, &packet); 671 NT_STATUS_NOT_OK_RETURN(status); 672 talloc_free(packet); 673 return status; 674} 675 676/* 677 setup an association - sync api 678*/ 679NTSTATUS wrepl_associate_stop(struct wrepl_socket *wrepl_socket, 680 struct wrepl_associate_stop *io) 681{ 682 struct wrepl_request *req = wrepl_associate_stop_send(wrepl_socket, io); 683 return wrepl_associate_stop_recv(req, io); 684} 685 686/* 687 fetch the partner tables - send 688*/ 689struct wrepl_request *wrepl_pull_table_send(struct wrepl_socket *wrepl_socket, 690 struct wrepl_pull_table *io) 691{ 692 struct wrepl_packet *packet; 693 struct wrepl_request *req; 694 695 packet = talloc_zero(wrepl_socket, struct wrepl_packet); 696 if (packet == NULL) return NULL; 697 698 packet->opcode = WREPL_OPCODE_BITS; 699 packet->assoc_ctx = io->in.assoc_ctx; 700 packet->mess_type = WREPL_REPLICATION; 701 packet->message.replication.command = WREPL_REPL_TABLE_QUERY; 702 703 req = wrepl_request_send(wrepl_socket, packet, NULL); 704 705 talloc_free(packet); 706 707 return req; 708} 709 710 711/* 712 fetch the partner tables - recv 713*/ 714NTSTATUS wrepl_pull_table_recv(struct wrepl_request *req, 715 TALLOC_CTX *mem_ctx, 716 struct wrepl_pull_table *io) 717{ 718 struct wrepl_packet *packet=NULL; 719 NTSTATUS status; 720 struct wrepl_table *table; 721 int i; 722 723 status = wrepl_request_recv(req, req->wrepl_socket, &packet); 724 NT_STATUS_NOT_OK_RETURN(status); 725 if (packet->mess_type != WREPL_REPLICATION) { 726 status = NT_STATUS_NETWORK_ACCESS_DENIED; 727 } else if (packet->message.replication.command != WREPL_REPL_TABLE_REPLY) { 728 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR; 729 } 730 if (!NT_STATUS_IS_OK(status)) goto failed; 731 732 table = &packet->message.replication.info.table; 733 io->out.num_partners = table->partner_count; 734 io->out.partners = talloc_steal(mem_ctx, table->partners); 735 for (i=0;i<io->out.num_partners;i++) { 736 talloc_steal(io->out.partners, io->out.partners[i].address); 737 } 738 739failed: 740 talloc_free(packet); 741 return status; 742} 743 744 745/* 746 fetch the partner table - sync api 747*/ 748NTSTATUS wrepl_pull_table(struct wrepl_socket *wrepl_socket, 749 TALLOC_CTX *mem_ctx, 750 struct wrepl_pull_table *io) 751{ 752 struct wrepl_request *req = wrepl_pull_table_send(wrepl_socket, io); 753 return wrepl_pull_table_recv(req, mem_ctx, io); 754} 755 756 757/* 758 fetch the names for a WINS partner - send 759*/ 760struct wrepl_request *wrepl_pull_names_send(struct wrepl_socket *wrepl_socket, 761 struct wrepl_pull_names *io) 762{ 763 struct wrepl_packet *packet; 764 struct wrepl_request *req; 765 766 packet = talloc_zero(wrepl_socket, struct wrepl_packet); 767 if (packet == NULL) return NULL; 768 769 packet->opcode = WREPL_OPCODE_BITS; 770 packet->assoc_ctx = io->in.assoc_ctx; 771 packet->mess_type = WREPL_REPLICATION; 772 packet->message.replication.command = WREPL_REPL_SEND_REQUEST; 773 packet->message.replication.info.owner = io->in.partner; 774 775 req = wrepl_request_send(wrepl_socket, packet, NULL); 776 777 talloc_free(packet); 778 779 return req; 780} 781 782/* 783 fetch the names for a WINS partner - recv 784*/ 785NTSTATUS wrepl_pull_names_recv(struct wrepl_request *req, 786 TALLOC_CTX *mem_ctx, 787 struct wrepl_pull_names *io) 788{ 789 struct wrepl_packet *packet=NULL; 790 NTSTATUS status; 791 int i; 792 793 status = wrepl_request_recv(req, req->wrepl_socket, &packet); 794 NT_STATUS_NOT_OK_RETURN(status); 795 if (packet->mess_type != WREPL_REPLICATION || 796 packet->message.replication.command != WREPL_REPL_SEND_REPLY) { 797 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR; 798 } 799 if (!NT_STATUS_IS_OK(status)) goto failed; 800 801 io->out.num_names = packet->message.replication.info.reply.num_names; 802 803 io->out.names = talloc_array(packet, struct wrepl_name, io->out.num_names); 804 if (io->out.names == NULL) goto nomem; 805 806 /* convert the list of names and addresses to a sane format */ 807 for (i=0;i<io->out.num_names;i++) { 808 struct wrepl_wins_name *wname = &packet->message.replication.info.reply.names[i]; 809 struct wrepl_name *name = &io->out.names[i]; 810 811 name->name = *wname->name; 812 talloc_steal(io->out.names, wname->name); 813 name->type = WREPL_NAME_TYPE(wname->flags); 814 name->state = WREPL_NAME_STATE(wname->flags); 815 name->node = WREPL_NAME_NODE(wname->flags); 816 name->is_static = WREPL_NAME_IS_STATIC(wname->flags); 817 name->raw_flags = wname->flags; 818 name->version_id= wname->id; 819 name->owner = talloc_strdup(io->out.names, io->in.partner.address); 820 if (name->owner == NULL) goto nomem; 821 822 /* trying to save 1 or 2 bytes on the wire isn't a good idea */ 823 if (wname->flags & 2) { 824 int j; 825 826 name->num_addresses = wname->addresses.addresses.num_ips; 827 name->addresses = talloc_array(io->out.names, 828 struct wrepl_address, 829 name->num_addresses); 830 if (name->addresses == NULL) goto nomem; 831 for (j=0;j<name->num_addresses;j++) { 832 name->addresses[j].owner = 833 talloc_steal(name->addresses, 834 wname->addresses.addresses.ips[j].owner); 835 name->addresses[j].address = 836 talloc_steal(name->addresses, 837 wname->addresses.addresses.ips[j].ip); 838 } 839 } else { 840 name->num_addresses = 1; 841 name->addresses = talloc(io->out.names, struct wrepl_address); 842 if (name->addresses == NULL) goto nomem; 843 name->addresses[0].owner = talloc_strdup(name->addresses,io->in.partner.address); 844 if (name->addresses[0].owner == NULL) goto nomem; 845 name->addresses[0].address = talloc_steal(name->addresses, 846 wname->addresses.ip); 847 } 848 } 849 850 talloc_steal(mem_ctx, io->out.names); 851 talloc_free(packet); 852 return NT_STATUS_OK; 853nomem: 854 status = NT_STATUS_NO_MEMORY; 855failed: 856 talloc_free(packet); 857 return status; 858} 859 860 861 862/* 863 fetch the names for a WINS partner - sync api 864*/ 865NTSTATUS wrepl_pull_names(struct wrepl_socket *wrepl_socket, 866 TALLOC_CTX *mem_ctx, 867 struct wrepl_pull_names *io) 868{ 869 struct wrepl_request *req = wrepl_pull_names_send(wrepl_socket, io); 870 return wrepl_pull_names_recv(req, mem_ctx, io); 871} 872