root/source4/wrepl_server/wrepl_in_connection.c

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

DEFINITIONS

This source file includes following definitions.
  1. wreplsrv_terminate_in_connection
  2. terminate_after_send_destructor
  3. wreplsrv_recv_request
  4. wreplsrv_recv
  5. wreplsrv_send
  6. wreplsrv_recv_error
  7. wreplsrv_accept
  8. wreplsrv_in_connection_merge
  9. wreplsrv_setup_sockets

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    
   4    WINS Replication server
   5    
   6    Copyright (C) Stefan Metzmacher      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/socket/socket.h"
  24 #include "lib/stream/packet.h"
  25 #include "smbd/service_task.h"
  26 #include "smbd/service_stream.h"
  27 #include "smbd/service.h"
  28 #include "lib/messaging/irpc.h"
  29 #include "librpc/gen_ndr/ndr_winsrepl.h"
  30 #include "wrepl_server/wrepl_server.h"
  31 #include "smbd/process_model.h"
  32 #include "system/network.h"
  33 #include "lib/socket/netif.h"
  34 #include "param/param.h"
  35 
  36 void wreplsrv_terminate_in_connection(struct wreplsrv_in_connection *wreplconn, const char *reason)
     /* [<][>][^][v][top][bottom][index][help] */
  37 {
  38         stream_terminate_connection(wreplconn->conn, reason);
  39 }
  40 
  41 static int terminate_after_send_destructor(struct wreplsrv_in_connection **tas)
     /* [<][>][^][v][top][bottom][index][help] */
  42 {
  43         wreplsrv_terminate_in_connection(*tas, "wreplsrv_in_connection: terminate_after_send");
  44         return 0;
  45 }
  46 
  47 /*
  48   receive some data on a WREPL connection
  49 */
  50 static NTSTATUS wreplsrv_recv_request(void *private_data, DATA_BLOB blob)
     /* [<][>][^][v][top][bottom][index][help] */
  51 {
  52         struct wreplsrv_in_connection *wreplconn = talloc_get_type(private_data, struct wreplsrv_in_connection);
  53         struct wreplsrv_in_call *call;
  54         DATA_BLOB packet_in_blob;
  55         DATA_BLOB packet_out_blob;
  56         struct wrepl_wrap packet_out_wrap;
  57         NTSTATUS status;
  58         enum ndr_err_code ndr_err;
  59 
  60         call = talloc_zero(wreplconn, struct wreplsrv_in_call);
  61         NT_STATUS_HAVE_NO_MEMORY(call);
  62         call->wreplconn = wreplconn;
  63         talloc_steal(call, blob.data);
  64 
  65         packet_in_blob.data = blob.data + 4;
  66         packet_in_blob.length = blob.length - 4;
  67 
  68         ndr_err = ndr_pull_struct_blob(&packet_in_blob, call, 
  69                                        lp_iconv_convenience(wreplconn->service->task->lp_ctx),
  70                                        &call->req_packet,
  71                                        (ndr_pull_flags_fn_t)ndr_pull_wrepl_packet);
  72         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
  73                 return ndr_map_error2ntstatus(ndr_err);
  74         }
  75 
  76         if (DEBUGLVL(10)) {
  77                 DEBUG(10,("Received WINS-Replication packet of length %u\n", 
  78                           (unsigned)packet_in_blob.length + 4));
  79                 NDR_PRINT_DEBUG(wrepl_packet, &call->req_packet);
  80         }
  81 
  82         status = wreplsrv_in_call(call);
  83         NT_STATUS_IS_ERR_RETURN(status);
  84         if (!NT_STATUS_IS_OK(status)) {
  85                 /* w2k just ignores invalid packets, so we do */
  86                 DEBUG(10,("Received WINS-Replication packet was invalid, we just ignore it\n"));
  87                 talloc_free(call);
  88                 return NT_STATUS_OK;
  89         }
  90 
  91         /* and now encode the reply */
  92         packet_out_wrap.packet = call->rep_packet;
  93         ndr_err = ndr_push_struct_blob(&packet_out_blob, call, 
  94                                        lp_iconv_convenience(wreplconn->service->task->lp_ctx),
  95                                        &packet_out_wrap,
  96                                       (ndr_push_flags_fn_t)ndr_push_wrepl_wrap);
  97         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
  98                 return ndr_map_error2ntstatus(ndr_err);
  99         }
 100 
 101         if (DEBUGLVL(10)) {
 102                 DEBUG(10,("Sending WINS-Replication packet of length %d\n", (int)packet_out_blob.length));
 103                 NDR_PRINT_DEBUG(wrepl_packet, &call->rep_packet);
 104         }
 105 
 106         if (call->terminate_after_send) {
 107                 struct wreplsrv_in_connection **tas;
 108                 tas = talloc(packet_out_blob.data, struct wreplsrv_in_connection *);
 109                 NT_STATUS_HAVE_NO_MEMORY(tas);
 110                 *tas = wreplconn;
 111                 talloc_set_destructor(tas, terminate_after_send_destructor);
 112         }
 113 
 114         status = packet_send(wreplconn->packet, packet_out_blob);
 115         NT_STATUS_NOT_OK_RETURN(status);
 116 
 117         talloc_free(call);
 118         return NT_STATUS_OK;
 119 }
 120 
 121 /*
 122   called when the socket becomes readable
 123 */
 124 static void wreplsrv_recv(struct stream_connection *conn, uint16_t flags)
     /* [<][>][^][v][top][bottom][index][help] */
 125 {
 126         struct wreplsrv_in_connection *wreplconn = talloc_get_type(conn->private_data,
 127                                                                    struct wreplsrv_in_connection);
 128 
 129         packet_recv(wreplconn->packet);
 130 }
 131 
 132 /*
 133   called when the socket becomes writable
 134 */
 135 static void wreplsrv_send(struct stream_connection *conn, uint16_t flags)
     /* [<][>][^][v][top][bottom][index][help] */
 136 {
 137         struct wreplsrv_in_connection *wreplconn = talloc_get_type(conn->private_data,
 138                                                                    struct wreplsrv_in_connection);
 139         packet_queue_run(wreplconn->packet);
 140 }
 141 
 142 /*
 143   handle socket recv errors
 144 */
 145 static void wreplsrv_recv_error(void *private_data, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 146 {
 147         struct wreplsrv_in_connection *wreplconn = talloc_get_type(private_data,
 148                                                                    struct wreplsrv_in_connection);
 149         wreplsrv_terminate_in_connection(wreplconn, nt_errstr(status));
 150 }
 151 
 152 /*
 153   called when we get a new connection
 154 */
 155 static void wreplsrv_accept(struct stream_connection *conn)
     /* [<][>][^][v][top][bottom][index][help] */
 156 {
 157         struct wreplsrv_service *service = talloc_get_type(conn->private_data, struct wreplsrv_service);
 158         struct wreplsrv_in_connection *wreplconn;
 159         struct socket_address *peer_ip;
 160 
 161         wreplconn = talloc_zero(conn, struct wreplsrv_in_connection);
 162         if (!wreplconn) {
 163                 stream_terminate_connection(conn, "wreplsrv_accept: out of memory");
 164                 return;
 165         }
 166 
 167         wreplconn->packet = packet_init(wreplconn);
 168         if (!wreplconn->packet) {
 169                 wreplsrv_terminate_in_connection(wreplconn, "wreplsrv_accept: out of memory");
 170                 return;
 171         }
 172         packet_set_private(wreplconn->packet, wreplconn);
 173         packet_set_socket(wreplconn->packet, conn->socket);
 174         packet_set_callback(wreplconn->packet, wreplsrv_recv_request);
 175         packet_set_full_request(wreplconn->packet, packet_full_request_u32);
 176         packet_set_error_handler(wreplconn->packet, wreplsrv_recv_error);
 177         packet_set_event_context(wreplconn->packet, conn->event.ctx);
 178         packet_set_fde(wreplconn->packet, conn->event.fde);
 179         packet_set_serialise(wreplconn->packet);
 180 
 181         wreplconn->conn         = conn;
 182         wreplconn->service      = service;
 183 
 184         peer_ip = socket_get_peer_addr(conn->socket, wreplconn);
 185         if (!peer_ip) {
 186                 wreplsrv_terminate_in_connection(wreplconn, "wreplsrv_accept: could not obtain peer IP from kernel");
 187                 return;
 188         }
 189 
 190         wreplconn->partner      = wreplsrv_find_partner(service, peer_ip->addr);
 191 
 192         conn->private_data = wreplconn;
 193 
 194         irpc_add_name(conn->msg_ctx, "wreplsrv_connection");
 195 }
 196 
 197 static const struct stream_server_ops wreplsrv_stream_ops = {
 198         .name                   = "wreplsrv",
 199         .accept_connection      = wreplsrv_accept,
 200         .recv_handler           = wreplsrv_recv,
 201         .send_handler           = wreplsrv_send,
 202 };
 203 
 204 /*
 205   called when we get a new connection
 206 */
 207 NTSTATUS wreplsrv_in_connection_merge(struct wreplsrv_partner *partner,
     /* [<][>][^][v][top][bottom][index][help] */
 208                                       struct socket_context *sock,
 209                                       struct packet_context *packet,
 210                                       struct wreplsrv_in_connection **_wrepl_in)
 211 {
 212         struct wreplsrv_service *service = partner->service;
 213         struct wreplsrv_in_connection *wrepl_in;
 214         const struct model_ops *model_ops;
 215         struct stream_connection *conn;
 216         NTSTATUS status;
 217 
 218         /* within the wrepl task we want to be a single process, so
 219            ask for the single process model ops and pass these to the
 220            stream_setup_socket() call. */
 221         model_ops = process_model_startup(service->task->event_ctx, "single");
 222         if (!model_ops) {
 223                 DEBUG(0,("Can't find 'single' process model_ops"));
 224                 return NT_STATUS_INTERNAL_ERROR;
 225         }
 226 
 227         wrepl_in = talloc_zero(partner, struct wreplsrv_in_connection);
 228         NT_STATUS_HAVE_NO_MEMORY(wrepl_in);
 229 
 230         wrepl_in->service       = service;
 231         wrepl_in->partner       = partner;
 232 
 233         status = stream_new_connection_merge(service->task->event_ctx, service->task->lp_ctx, model_ops,
 234                                              sock, &wreplsrv_stream_ops, service->task->msg_ctx,
 235                                              wrepl_in, &conn);
 236         NT_STATUS_NOT_OK_RETURN(status);
 237 
 238         /*
 239          * make the wreplsrv_in_connection structure a child of the
 240          * stream_connection, to match the hierarchy of wreplsrv_accept
 241          */
 242         wrepl_in->conn          = conn;
 243         talloc_steal(conn, wrepl_in);
 244 
 245         /*
 246          * now update the packet handling callback,...
 247          */
 248         wrepl_in->packet        = talloc_steal(wrepl_in, packet);
 249         packet_set_private(wrepl_in->packet, wrepl_in);
 250         packet_set_socket(wrepl_in->packet, conn->socket);
 251         packet_set_callback(wrepl_in->packet, wreplsrv_recv_request);
 252         packet_set_full_request(wrepl_in->packet, packet_full_request_u32);
 253         packet_set_error_handler(wrepl_in->packet, wreplsrv_recv_error);
 254         packet_set_event_context(wrepl_in->packet, conn->event.ctx);
 255         packet_set_fde(wrepl_in->packet, conn->event.fde);
 256         packet_set_serialise(wrepl_in->packet);
 257 
 258         *_wrepl_in = wrepl_in;
 259         return NT_STATUS_OK;
 260 }
 261 
 262 /*
 263   startup the wrepl port 42 server sockets
 264 */
 265 NTSTATUS wreplsrv_setup_sockets(struct wreplsrv_service *service, struct loadparm_context *lp_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 266 {
 267         NTSTATUS status;
 268         struct task_server *task = service->task;
 269         const struct model_ops *model_ops;
 270         const char *address;
 271         uint16_t port = WINS_REPLICATION_PORT;
 272 
 273         /* within the wrepl task we want to be a single process, so
 274            ask for the single process model ops and pass these to the
 275            stream_setup_socket() call. */
 276         model_ops = process_model_startup(task->event_ctx, "single");
 277         if (!model_ops) {
 278                 DEBUG(0,("Can't find 'single' process model_ops"));
 279                 return NT_STATUS_INTERNAL_ERROR;
 280         }
 281 
 282         if (lp_interfaces(lp_ctx) && lp_bind_interfaces_only(lp_ctx)) {
 283                 int num_interfaces;
 284                 int i;
 285                 struct interface *ifaces;
 286 
 287                 load_interfaces(task, lp_interfaces(lp_ctx), &ifaces);
 288 
 289                 num_interfaces = iface_count(ifaces);
 290 
 291                 /* We have been given an interfaces line, and been 
 292                    told to only bind to those interfaces. Create a
 293                    socket per interface and bind to only these.
 294                 */
 295                 for(i = 0; i < num_interfaces; i++) {
 296                         address = iface_n_ip(ifaces, i);
 297                         status = stream_setup_socket(task->event_ctx, 
 298                                                      task->lp_ctx, model_ops, 
 299                                                      &wreplsrv_stream_ops,
 300                                                      "ipv4", address, &port, 
 301                                                       lp_socket_options(task->lp_ctx), 
 302                                                      service);
 303                         if (!NT_STATUS_IS_OK(status)) {
 304                                 DEBUG(0,("stream_setup_socket(address=%s,port=%u) failed - %s\n",
 305                                          address, port, nt_errstr(status)));
 306                                 return status;
 307                         }
 308                 }
 309         } else {
 310                 address = lp_socket_address(lp_ctx);
 311                 status = stream_setup_socket(task->event_ctx, task->lp_ctx, 
 312                                              model_ops, &wreplsrv_stream_ops,
 313                                              "ipv4", address, &port, lp_socket_options(task->lp_ctx), 
 314                                              service);
 315                 if (!NT_STATUS_IS_OK(status)) {
 316                         DEBUG(0,("stream_setup_socket(address=%s,port=%u) failed - %s\n",
 317                                  address, port, nt_errstr(status)));
 318                         return status;
 319                 }
 320         }
 321 
 322         return NT_STATUS_OK;
 323 }

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