root/source4/libcli/wrepl/winsrepl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wrepl_socket_dead
  2. wrepl_request_timeout_handler
  3. wrepl_finish_recv
  4. wrepl_handler
  5. wrepl_error
  6. wrepl_socket_destructor
  7. wrepl_socket_init
  8. wrepl_socket_merge
  9. wrepl_request_destructor
  10. wrepl_request_wait
  11. wrepl_connect_handler
  12. wrepl_best_ip
  13. wrepl_connect_send
  14. wrepl_connect_recv
  15. wrepl_connect
  16. wrepl_request_trigger_handler
  17. wrepl_request_finished
  18. wrepl_send_ctrl_destructor
  19. wrepl_request_send
  20. wrepl_request_recv
  21. wrepl_request
  22. wrepl_associate_send
  23. wrepl_associate_recv
  24. wrepl_associate
  25. wrepl_associate_stop_send
  26. wrepl_associate_stop_recv
  27. wrepl_associate_stop
  28. wrepl_pull_table_send
  29. wrepl_pull_table_recv
  30. wrepl_pull_table
  31. wrepl_pull_names_send
  32. wrepl_pull_names_recv
  33. wrepl_pull_names

   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 
  34 static 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 */
  39 static void wrepl_socket_dead(struct wrepl_socket *wrepl_socket, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
  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 
  74 static void wrepl_request_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
     /* [<][>][^][v][top][bottom][index][help] */
  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 */
  84 static NTSTATUS wrepl_finish_recv(void *private_data, DATA_BLOB packet_blob_in)
     /* [<][>][^][v][top][bottom][index][help] */
  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 */
 125 static void wrepl_handler(struct tevent_context *ev, struct tevent_fd *fde, 
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 139 static void wrepl_error(void *private_data, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 150 static int wrepl_socket_destructor(struct wrepl_socket *sock)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 164 struct wrepl_socket *wrepl_socket_init(TALLOC_CTX *mem_ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 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 = talloc_reference(wrepl_socket, 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 
 190 failed:
 191         talloc_free(wrepl_socket);
 192         return NULL;
 193 }
 194 
 195 /*
 196   initialise a wrepl_socket from an already existing connection
 197 */
 198 struct wrepl_socket *wrepl_socket_merge(TALLOC_CTX *mem_ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 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 = talloc_reference(wrepl_socket, 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 
 240 failed:
 241         talloc_free(wrepl_socket);
 242         return NULL;
 243 }
 244 
 245 /*
 246   destroy a wrepl_request
 247 */
 248 static int wrepl_request_destructor(struct wrepl_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 260 static NTSTATUS wrepl_request_wait(struct wrepl_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 269 struct 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 */
 278 static void wrepl_connect_handler(struct composite_context *creq)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 309 const char *wrepl_best_ip(struct loadparm_context *lp_ctx, const char *peer_ip)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 320 struct composite_context *wrepl_connect_send(struct wrepl_socket *wrepl_socket,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 356 NTSTATUS wrepl_connect_recv(struct composite_context *result)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 374 NTSTATUS wrepl_connect(struct wrepl_socket *wrepl_socket,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 384 static void wrepl_request_trigger_handler(struct tevent_context *ev, struct tevent_timer *te,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 398 static struct wrepl_request *wrepl_request_finished(struct wrepl_request *req, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 433 struct wrepl_send_ctrl_state {
 434         struct wrepl_send_ctrl ctrl;
 435         struct wrepl_request *req;
 436         struct wrepl_socket *wrepl_sock;
 437 };
 438 
 439 static int wrepl_send_ctrl_destructor(struct wrepl_send_ctrl_state *s)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 470 struct wrepl_request *wrepl_request_send(struct wrepl_socket *wrepl_socket,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 535 NTSTATUS wrepl_request_recv(struct wrepl_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 550 NTSTATUS wrepl_request(struct wrepl_socket *wrepl_socket,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 563 struct wrepl_request *wrepl_associate_send(struct wrepl_socket *wrepl_socket,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 602 NTSTATUS wrepl_associate_recv(struct wrepl_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 623 NTSTATUS wrepl_associate(struct wrepl_socket *wrepl_socket,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 634 struct wrepl_request *wrepl_associate_stop_send(struct wrepl_socket *wrepl_socket,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 665 NTSTATUS wrepl_associate_stop_recv(struct wrepl_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 679 NTSTATUS wrepl_associate_stop(struct wrepl_socket *wrepl_socket,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 689 struct wrepl_request *wrepl_pull_table_send(struct wrepl_socket *wrepl_socket,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 714 NTSTATUS wrepl_pull_table_recv(struct wrepl_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 739 failed:
 740         talloc_free(packet);
 741         return status;
 742 }
 743 
 744 
 745 /*
 746   fetch the partner table - sync api
 747 */
 748 NTSTATUS wrepl_pull_table(struct wrepl_socket *wrepl_socket,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 760 struct wrepl_request *wrepl_pull_names_send(struct wrepl_socket *wrepl_socket,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 785 NTSTATUS wrepl_pull_names_recv(struct wrepl_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 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;
 853 nomem:
 854         status = NT_STATUS_NO_MEMORY;
 855 failed:
 856         talloc_free(packet);
 857         return status;
 858 }
 859 
 860 
 861 
 862 /*
 863   fetch the names for a WINS partner - sync api
 864 */
 865 NTSTATUS wrepl_pull_names(struct wrepl_socket *wrepl_socket,
     /* [<][>][^][v][top][bottom][index][help] */
 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 }

/* [<][>][^][v][top][bottom][index][help] */