LCOV - code coverage report
Current view: top level - source4/wrepl_server - wrepl_in_connection.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 95 206 46.1 %
Date: 2024-04-21 15:09:00 Functions: 6 9 66.7 %

          Line data    Source code
       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 "samba/service_task.h"
      26             : #include "samba/service_stream.h"
      27             : #include "samba/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 "samba/process_model.h"
      32             : #include "system/network.h"
      33             : #include "lib/socket/netif.h"
      34             : #include "lib/tsocket/tsocket.h"
      35             : #include "libcli/util/tstream.h"
      36             : #include "param/param.h"
      37             : 
      38         679 : void wreplsrv_terminate_in_connection(struct wreplsrv_in_connection *wreplconn, const char *reason)
      39             : {
      40         679 :         stream_terminate_connection(wreplconn->conn, reason);
      41         679 : }
      42             : 
      43             : /*
      44             :   receive some data on a WREPL connection
      45             : */
      46        2139 : static NTSTATUS wreplsrv_process(struct wreplsrv_in_connection *wrepl_conn,
      47             :                                  struct wreplsrv_in_call **_call)
      48             : {
      49           0 :         struct wrepl_wrap packet_out_wrap;
      50           0 :         NTSTATUS status;
      51           0 :         enum ndr_err_code ndr_err;
      52        2139 :         struct wreplsrv_in_call *call = *_call;
      53             : 
      54        2139 :         ndr_err = ndr_pull_struct_blob(&call->in, call,
      55        2139 :                                        &call->req_packet,
      56             :                                        (ndr_pull_flags_fn_t)ndr_pull_wrepl_packet);
      57        2139 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
      58           0 :                 return ndr_map_error2ntstatus(ndr_err);
      59             :         }
      60             : 
      61        2139 :         if (DEBUGLVL(10)) {
      62           0 :                 DEBUG(10,("Received WINS-Replication packet of length %u\n",
      63             :                           (unsigned int) call->in.length + 4));
      64           0 :                 NDR_PRINT_DEBUG(wrepl_packet, &call->req_packet);
      65             :         }
      66             : 
      67        2139 :         status = wreplsrv_in_call(call);
      68        2139 :         if (NT_STATUS_IS_ERR(status)) {
      69           0 :                 return status;
      70             :         }
      71        2139 :         if (!NT_STATUS_IS_OK(status)) {
      72             :                 /* w2k just ignores invalid packets, so we do */
      73         675 :                 DEBUG(10,("Received WINS-Replication packet was invalid, we just ignore it\n"));
      74         675 :                 TALLOC_FREE(call);
      75         675 :                 *_call = NULL;
      76         675 :                 return NT_STATUS_OK;
      77             :         }
      78             : 
      79             :         /* and now encode the reply */
      80        1464 :         packet_out_wrap.packet = call->rep_packet;
      81        1464 :         ndr_err = ndr_push_struct_blob(&call->out, call,
      82             :                                        &packet_out_wrap,
      83             :                                        (ndr_push_flags_fn_t) ndr_push_wrepl_wrap);
      84        1464 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
      85           0 :                 return ndr_map_error2ntstatus(ndr_err);
      86             :         }
      87             : 
      88        1464 :         if (DEBUGLVL(10)) {
      89           0 :                 DEBUG(10,("Sending WINS-Replication packet of length %u\n",
      90             :                          (unsigned int) call->out.length));
      91           0 :                 NDR_PRINT_DEBUG(wrepl_packet, &call->rep_packet);
      92             :         }
      93             : 
      94        1464 :         return NT_STATUS_OK;
      95             : }
      96             : 
      97             : static void wreplsrv_call_loop(struct tevent_req *subreq);
      98             : 
      99             : /*
     100             :   called when we get a new connection
     101             : */
     102         679 : static void wreplsrv_accept(struct stream_connection *conn)
     103             : {
     104         679 :         struct wreplsrv_service *service = talloc_get_type(conn->private_data, struct wreplsrv_service);
     105           0 :         struct wreplsrv_in_connection *wrepl_conn;
     106           0 :         struct tsocket_address *peer_addr;
     107           0 :         char *peer_ip;
     108           0 :         struct tevent_req *subreq;
     109           0 :         int rc;
     110             : 
     111         679 :         wrepl_conn = talloc_zero(conn, struct wreplsrv_in_connection);
     112         679 :         if (wrepl_conn == NULL) {
     113           0 :                 stream_terminate_connection(conn,
     114             :                                             "wreplsrv_accept: out of memory");
     115           0 :                 return;
     116             :         }
     117             : 
     118         679 :         wrepl_conn->send_queue = tevent_queue_create(conn, "wrepl_accept");
     119         679 :         if (wrepl_conn->send_queue == NULL) {
     120           0 :                 stream_terminate_connection(conn,
     121             :                                             "wrepl_accept: out of memory");
     122           0 :                 return;
     123             :         }
     124             : 
     125         679 :         TALLOC_FREE(conn->event.fde);
     126             : 
     127         679 :         rc = tstream_bsd_existing_socket(wrepl_conn,
     128             :                                          socket_get_fd(conn->socket),
     129             :                                          &wrepl_conn->tstream);
     130         679 :         if (rc < 0) {
     131           0 :                 stream_terminate_connection(conn,
     132             :                                             "wrepl_accept: out of memory");
     133           0 :                 return;
     134             :         }
     135         679 :         socket_set_flags(conn->socket, SOCKET_FLAG_NOCLOSE);
     136             :         /* as server we want to fail early */
     137         679 :         tstream_bsd_fail_readv_first_error(wrepl_conn->tstream, true);
     138             : 
     139         679 :         wrepl_conn->conn = conn;
     140         679 :         wrepl_conn->service = service;
     141             : 
     142         679 :         peer_addr = conn->remote_address;
     143             : 
     144         679 :         if (!tsocket_address_is_inet(peer_addr, "ipv4")) {
     145           0 :                 DEBUG(0,("wreplsrv_accept: non ipv4 peer addr '%s'\n",
     146             :                         tsocket_address_string(peer_addr, wrepl_conn)));
     147           0 :                 wreplsrv_terminate_in_connection(wrepl_conn, "wreplsrv_accept: "
     148             :                                 "invalid peer IP");
     149           0 :                 return;
     150             :         }
     151             : 
     152         679 :         peer_ip = tsocket_address_inet_addr_string(peer_addr, wrepl_conn);
     153         679 :         if (peer_ip == NULL) {
     154           0 :                 wreplsrv_terminate_in_connection(wrepl_conn, "wreplsrv_accept: "
     155             :                                 "could not convert peer IP into a string");
     156           0 :                 return;
     157             :         }
     158             : 
     159         679 :         wrepl_conn->partner = wreplsrv_find_partner(service, peer_ip);
     160         679 :         irpc_add_name(conn->msg_ctx, "wreplsrv_connection");
     161             : 
     162             :         /*
     163             :          * The wrepl pdu's has the length as 4 byte (initial_read_size),
     164             :          * tstream_full_request_u32 provides the pdu length then.
     165             :          */
     166         679 :         subreq = tstream_read_pdu_blob_send(wrepl_conn,
     167         679 :                                             wrepl_conn->conn->event.ctx,
     168             :                                             wrepl_conn->tstream,
     169             :                                             4, /* initial_read_size */
     170             :                                             tstream_full_request_u32,
     171             :                                             wrepl_conn);
     172         679 :         if (subreq == NULL) {
     173           0 :                 wreplsrv_terminate_in_connection(wrepl_conn, "wrepl_accept: "
     174             :                                 "no memory for tstream_read_pdu_blob_send");
     175           0 :                 return;
     176             :         }
     177         679 :         tevent_req_set_callback(subreq, wreplsrv_call_loop, wrepl_conn);
     178             : }
     179             : 
     180             : static void wreplsrv_call_writev_done(struct tevent_req *subreq);
     181             : 
     182        2143 : static void wreplsrv_call_loop(struct tevent_req *subreq)
     183             : {
     184        2143 :         struct wreplsrv_in_connection *wrepl_conn = tevent_req_callback_data(subreq,
     185             :                                       struct wreplsrv_in_connection);
     186           0 :         struct wreplsrv_in_call *call;
     187           0 :         NTSTATUS status;
     188             : 
     189        2143 :         call = talloc_zero(wrepl_conn, struct wreplsrv_in_call);
     190        2143 :         if (call == NULL) {
     191           0 :                 wreplsrv_terminate_in_connection(wrepl_conn, "wreplsrv_call_loop: "
     192             :                                 "no memory for wrepl_samba3_call");
     193         679 :                 return;
     194             :         }
     195        2143 :         call->wreplconn = wrepl_conn;
     196             : 
     197        2143 :         status = tstream_read_pdu_blob_recv(subreq,
     198             :                                             call,
     199        2143 :                                             &call->in);
     200        2143 :         TALLOC_FREE(subreq);
     201        2143 :         if (!NT_STATUS_IS_OK(status)) {
     202           0 :                 const char *reason;
     203             : 
     204           4 :                 reason = talloc_asprintf(call, "wreplsrv_call_loop: "
     205             :                                          "tstream_read_pdu_blob_recv() - %s",
     206             :                                          nt_errstr(status));
     207           4 :                 if (!reason) {
     208           0 :                         reason = nt_errstr(status);
     209             :                 }
     210             : 
     211           4 :                 wreplsrv_terminate_in_connection(wrepl_conn, reason);
     212           4 :                 return;
     213             :         }
     214             : 
     215        2139 :         DEBUG(10,("Received wrepl packet of length %lu from %s\n",
     216             :                  (long) call->in.length,
     217             :                  tsocket_address_string(wrepl_conn->conn->remote_address, call)));
     218             : 
     219             :         /* skip length header */
     220        2139 :         call->in.data += 4;
     221        2139 :         call->in.length -= 4;
     222             : 
     223        2139 :         status = wreplsrv_process(wrepl_conn, &call);
     224        2139 :         if (!NT_STATUS_IS_OK(status)) {
     225           0 :                 const char *reason;
     226             : 
     227           0 :                 reason = talloc_asprintf(call, "wreplsrv_call_loop: "
     228             :                                          "tstream_read_pdu_blob_recv() - %s",
     229             :                                          nt_errstr(status));
     230           0 :                 if (reason == NULL) {
     231           0 :                         reason = nt_errstr(status);
     232             :                 }
     233             : 
     234           0 :                 wreplsrv_terminate_in_connection(wrepl_conn, reason);
     235           0 :                 return;
     236             :         }
     237             : 
     238             :         /* We handed over the connection so we're done here */
     239        2139 :         if (wrepl_conn->tstream == NULL) {
     240         675 :             return;
     241             :         }
     242             : 
     243             :         /* Invalid WINS-Replication packet, we just ignore it */
     244        1464 :         if (call == NULL) {
     245           0 :                 goto noreply;
     246             :         }
     247             : 
     248        1464 :         call->out_iov[0].iov_base = (char *) call->out.data;
     249        1464 :         call->out_iov[0].iov_len = call->out.length;
     250             : 
     251        1464 :         subreq = tstream_writev_queue_send(call,
     252        1464 :                                            wrepl_conn->conn->event.ctx,
     253             :                                            wrepl_conn->tstream,
     254             :                                            wrepl_conn->send_queue,
     255        1464 :                                            call->out_iov, 1);
     256        1464 :         if (subreq == NULL) {
     257           0 :                 wreplsrv_terminate_in_connection(wrepl_conn, "wreplsrv_call_loop: "
     258             :                                 "no memory for tstream_writev_queue_send");
     259           0 :                 return;
     260             :         }
     261        1464 :         tevent_req_set_callback(subreq, wreplsrv_call_writev_done, call);
     262             : 
     263        1464 : noreply:
     264             :         /*
     265             :          * The wrepl pdu's has the length as 4 byte (initial_read_size),
     266             :          *  provides the pdu length then.
     267             :          */
     268        1464 :         subreq = tstream_read_pdu_blob_send(wrepl_conn,
     269        1464 :                                             wrepl_conn->conn->event.ctx,
     270             :                                             wrepl_conn->tstream,
     271             :                                             4, /* initial_read_size */
     272             :                                             tstream_full_request_u32,
     273             :                                             wrepl_conn);
     274        1464 :         if (subreq == NULL) {
     275           0 :                 wreplsrv_terminate_in_connection(wrepl_conn, "wreplsrv_call_loop: "
     276             :                                 "no memory for tstream_read_pdu_blob_send");
     277           0 :                 return;
     278             :         }
     279        1464 :         tevent_req_set_callback(subreq, wreplsrv_call_loop, wrepl_conn);
     280             : }
     281             : 
     282        1464 : static void wreplsrv_call_writev_done(struct tevent_req *subreq)
     283             : {
     284        1464 :         struct wreplsrv_in_call *call = tevent_req_callback_data(subreq,
     285             :                         struct wreplsrv_in_call);
     286           0 :         int sys_errno;
     287           0 :         int rc;
     288             : 
     289        1464 :         rc = tstream_writev_queue_recv(subreq, &sys_errno);
     290        1464 :         TALLOC_FREE(subreq);
     291        1464 :         if (rc == -1) {
     292           0 :                 const char *reason;
     293             : 
     294           0 :                 reason = talloc_asprintf(call, "wreplsrv_call_writev_done: "
     295             :                                          "tstream_writev_queue_recv() - %d:%s",
     296             :                                          sys_errno, strerror(sys_errno));
     297           0 :                 if (reason == NULL) {
     298           0 :                         reason = "wreplsrv_call_writev_done: "
     299             :                                  "tstream_writev_queue_recv() failed";
     300             :                 }
     301             : 
     302           0 :                 wreplsrv_terminate_in_connection(call->wreplconn, reason);
     303           0 :                 return;
     304             :         }
     305             : 
     306        1464 :         if (call->terminate_after_send) {
     307           0 :                 wreplsrv_terminate_in_connection(call->wreplconn,
     308             :                                 "wreplsrv_in_connection: terminate_after_send");
     309           0 :                 return;
     310             :         }
     311             : 
     312        1464 :         talloc_free(call);
     313             : }
     314             : 
     315             : /*
     316             :   called on a tcp recv
     317             : */
     318           0 : static void wreplsrv_recv(struct stream_connection *conn, uint16_t flags)
     319             : {
     320           0 :         struct wreplsrv_in_connection *wrepl_conn = talloc_get_type(conn->private_data,
     321             :                                                         struct wreplsrv_in_connection);
     322             :         /* this should never be triggered! */
     323           0 :         DEBUG(0,("Terminating connection - '%s'\n", "wrepl_recv: called"));
     324           0 :         wreplsrv_terminate_in_connection(wrepl_conn, "wrepl_recv: called");
     325           0 : }
     326             : 
     327             : /*
     328             :   called when we can write to a connection
     329             : */
     330           0 : static void wreplsrv_send(struct stream_connection *conn, uint16_t flags)
     331             : {
     332           0 :         struct wreplsrv_in_connection *wrepl_conn = talloc_get_type(conn->private_data,
     333             :                                                         struct wreplsrv_in_connection);
     334             :         /* this should never be triggered! */
     335           0 :         DEBUG(0,("Terminating connection - '%s'\n", "wrepl_send: called"));
     336           0 :         wreplsrv_terminate_in_connection(wrepl_conn, "wrepl_send: called");
     337           0 : }
     338             : 
     339             : static const struct stream_server_ops wreplsrv_stream_ops = {
     340             :         .name                   = "wreplsrv",
     341             :         .accept_connection      = wreplsrv_accept,
     342             :         .recv_handler           = wreplsrv_recv,
     343             :         .send_handler           = wreplsrv_send,
     344             : };
     345             : 
     346             : /*
     347             :   called when we get a new connection
     348             : */
     349           0 : NTSTATUS wreplsrv_in_connection_merge(struct wreplsrv_partner *partner,
     350             :                                       uint32_t peer_assoc_ctx,
     351             :                                       struct tstream_context **stream,
     352             :                                       struct wreplsrv_in_connection **_wrepl_in,
     353             :                                       void* process_context)
     354             : {
     355           0 :         struct wreplsrv_service *service = partner->service;
     356           0 :         struct wreplsrv_in_connection *wrepl_in;
     357           0 :         struct stream_connection *conn;
     358           0 :         struct tevent_req *subreq;
     359           0 :         NTSTATUS status;
     360             : 
     361           0 :         wrepl_in = talloc_zero(partner, struct wreplsrv_in_connection);
     362           0 :         NT_STATUS_HAVE_NO_MEMORY(wrepl_in);
     363             : 
     364           0 :         wrepl_in->service    = service;
     365           0 :         wrepl_in->partner    = partner;
     366           0 :         wrepl_in->tstream    = talloc_move(wrepl_in, stream);
     367           0 :         wrepl_in->assoc_ctx.peer_ctx = peer_assoc_ctx;
     368             : 
     369           0 :         status = stream_new_connection_merge(service->task->event_ctx,
     370           0 :                                              service->task->lp_ctx,
     371           0 :                                              service->task->model_ops,
     372             :                                              &wreplsrv_stream_ops,
     373           0 :                                              service->task->msg_ctx,
     374             :                                              wrepl_in,
     375             :                                              &conn,
     376             :                                              process_context);
     377           0 :         NT_STATUS_NOT_OK_RETURN(status);
     378             : 
     379             :         /*
     380             :          * make the wreplsrv_in_connection structure a child of the
     381             :          * stream_connection, to match the hierarchy of wreplsrv_accept
     382             :          */
     383           0 :         wrepl_in->conn               = conn;
     384           0 :         talloc_steal(conn, wrepl_in);
     385             : 
     386           0 :         wrepl_in->send_queue = tevent_queue_create(wrepl_in, "wreplsrv_in_connection_merge");
     387           0 :         if (wrepl_in->send_queue == NULL) {
     388           0 :                 stream_terminate_connection(conn,
     389             :                                             "wreplsrv_in_connection_merge: out of memory");
     390           0 :                 return NT_STATUS_NO_MEMORY;
     391             :         }
     392             : 
     393             :         /* we're now a server and want to fail early */
     394           0 :         tstream_bsd_fail_readv_first_error(wrepl_in->tstream, true);
     395             : 
     396             :         /*
     397             :          * The wrepl pdu's has the length as 4 byte (initial_read_size),
     398             :          * tstream_full_request_u32 provides the pdu length then.
     399             :          */
     400           0 :         subreq = tstream_read_pdu_blob_send(wrepl_in,
     401           0 :                                             wrepl_in->conn->event.ctx,
     402             :                                             wrepl_in->tstream,
     403             :                                             4, /* initial_read_size */
     404             :                                             tstream_full_request_u32,
     405             :                                             wrepl_in);
     406           0 :         if (subreq == NULL) {
     407           0 :                 wreplsrv_terminate_in_connection(wrepl_in, "wreplsrv_in_connection_merge: "
     408             :                                 "no memory for tstream_read_pdu_blob_send");
     409           0 :                 return NT_STATUS_NO_MEMORY;
     410             :         }
     411           0 :         tevent_req_set_callback(subreq, wreplsrv_call_loop, wrepl_in);
     412             : 
     413           0 :         *_wrepl_in = wrepl_in;
     414             : 
     415           0 :         return NT_STATUS_OK;
     416             : }
     417             : 
     418             : /*
     419             :   startup the wrepl port 42 server sockets
     420             : */
     421          65 : NTSTATUS wreplsrv_setup_sockets(struct wreplsrv_service *service, struct loadparm_context *lp_ctx)
     422             : {
     423           2 :         NTSTATUS status;
     424          65 :         struct task_server *task = service->task;
     425           2 :         const char *address;
     426          65 :         uint16_t port = WINS_REPLICATION_PORT;
     427             : 
     428          65 :         if (lpcfg_interfaces(lp_ctx) && lpcfg_bind_interfaces_only(lp_ctx)) {
     429           0 :                 int num_interfaces;
     430           0 :                 int i;
     431           0 :                 struct interface *ifaces;
     432             : 
     433           0 :                 load_interface_list(task, lp_ctx, &ifaces);
     434             : 
     435           0 :                 num_interfaces = iface_list_count(ifaces);
     436             : 
     437             :                 /* We have been given an interfaces line, and been 
     438             :                    told to only bind to those interfaces. Create a
     439             :                    socket per interface and bind to only these.
     440             :                 */
     441           0 :                 for(i = 0; i < num_interfaces; i++) {
     442           0 :                         if (!iface_list_n_is_v4(ifaces, i)) {
     443           0 :                                 continue;
     444             :                         }
     445           0 :                         address = iface_list_n_ip(ifaces, i);
     446           0 :                         status = stream_setup_socket(
     447             :                                         task, task->event_ctx,
     448             :                                         task->lp_ctx,
     449             :                                         task->model_ops,
     450             :                                         &wreplsrv_stream_ops,
     451             :                                         "ipv4", address, &port,
     452             :                                         lpcfg_socket_options(task->lp_ctx),
     453             :                                         service, task->process_context);
     454           0 :                         if (!NT_STATUS_IS_OK(status)) {
     455           0 :                                 DEBUG(0,("stream_setup_socket(address=%s,port=%u) failed - %s\n",
     456             :                                          address, port, nt_errstr(status)));
     457           0 :                                 return status;
     458             :                         }
     459             :                 }
     460             :         } else {
     461          65 :                 address = "0.0.0.0";
     462          65 :                 status = stream_setup_socket(task, task->event_ctx,
     463             :                                              task->lp_ctx, task->model_ops,
     464             :                                              &wreplsrv_stream_ops,
     465             :                                              "ipv4", address, &port,
     466             :                                              lpcfg_socket_options(task->lp_ctx),
     467             :                                              service, task->process_context);
     468          65 :                 if (!NT_STATUS_IS_OK(status)) {
     469           0 :                         DEBUG(0,("stream_setup_socket(address=%s,port=%u) failed - %s\n",
     470             :                                  address, port, nt_errstr(status)));
     471           0 :                         return status;
     472             :                 }
     473             :         }
     474             : 
     475          65 :         return NT_STATUS_OK;
     476             : }

Generated by: LCOV version 1.14