LCOV - code coverage report
Current view: top level - source4/wrepl_server - wrepl_in_connection.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 91 180 50.6 %
Date: 2024-06-13 04:01:37 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             :         struct wrepl_wrap packet_out_wrap;
      50             :         NTSTATUS status;
      51             :         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             :         struct wreplsrv_in_connection *wrepl_conn;
     106             :         struct tsocket_address *peer_addr;
     107             :         char *peer_ip;
     108             :         struct tevent_req *subreq;
     109             :         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             : 
     137         679 :         wrepl_conn->conn = conn;
     138         679 :         wrepl_conn->service = service;
     139             : 
     140         679 :         peer_addr = conn->remote_address;
     141             : 
     142         679 :         if (!tsocket_address_is_inet(peer_addr, "ipv4")) {
     143           0 :                 DEBUG(0,("wreplsrv_accept: non ipv4 peer addr '%s'\n",
     144             :                         tsocket_address_string(peer_addr, wrepl_conn)));
     145           0 :                 wreplsrv_terminate_in_connection(wrepl_conn, "wreplsrv_accept: "
     146             :                                 "invalid peer IP");
     147           0 :                 return;
     148             :         }
     149             : 
     150         679 :         peer_ip = tsocket_address_inet_addr_string(peer_addr, wrepl_conn);
     151         679 :         if (peer_ip == NULL) {
     152           0 :                 wreplsrv_terminate_in_connection(wrepl_conn, "wreplsrv_accept: "
     153             :                                 "could not convert peer IP into a string");
     154           0 :                 return;
     155             :         }
     156             : 
     157         679 :         wrepl_conn->partner = wreplsrv_find_partner(service, peer_ip);
     158         679 :         irpc_add_name(conn->msg_ctx, "wreplsrv_connection");
     159             : 
     160             :         /*
     161             :          * The wrepl pdu's has the length as 4 byte (initial_read_size),
     162             :          * packet_full_request_u32 provides the pdu length then.
     163             :          */
     164        1358 :         subreq = tstream_read_pdu_blob_send(wrepl_conn,
     165         679 :                                             wrepl_conn->conn->event.ctx,
     166             :                                             wrepl_conn->tstream,
     167             :                                             4, /* initial_read_size */
     168             :                                             packet_full_request_u32,
     169             :                                             wrepl_conn);
     170         679 :         if (subreq == NULL) {
     171           0 :                 wreplsrv_terminate_in_connection(wrepl_conn, "wrepl_accept: "
     172             :                                 "no memory for tstream_read_pdu_blob_send");
     173           0 :                 return;
     174             :         }
     175         679 :         tevent_req_set_callback(subreq, wreplsrv_call_loop, wrepl_conn);
     176             : }
     177             : 
     178             : static void wreplsrv_call_writev_done(struct tevent_req *subreq);
     179             : 
     180        2143 : static void wreplsrv_call_loop(struct tevent_req *subreq)
     181             : {
     182        2143 :         struct wreplsrv_in_connection *wrepl_conn = tevent_req_callback_data(subreq,
     183             :                                       struct wreplsrv_in_connection);
     184             :         struct wreplsrv_in_call *call;
     185             :         NTSTATUS status;
     186             : 
     187        2143 :         call = talloc_zero(wrepl_conn, struct wreplsrv_in_call);
     188        2143 :         if (call == NULL) {
     189           0 :                 wreplsrv_terminate_in_connection(wrepl_conn, "wreplsrv_call_loop: "
     190             :                                 "no memory for wrepl_samba3_call");
     191           0 :                 return;
     192             :         }
     193        2143 :         call->wreplconn = wrepl_conn;
     194             : 
     195        2143 :         status = tstream_read_pdu_blob_recv(subreq,
     196             :                                             call,
     197        2143 :                                             &call->in);
     198        2143 :         TALLOC_FREE(subreq);
     199        2143 :         if (!NT_STATUS_IS_OK(status)) {
     200             :                 const char *reason;
     201             : 
     202           4 :                 reason = talloc_asprintf(call, "wreplsrv_call_loop: "
     203             :                                          "tstream_read_pdu_blob_recv() - %s",
     204             :                                          nt_errstr(status));
     205           4 :                 if (!reason) {
     206           0 :                         reason = nt_errstr(status);
     207             :                 }
     208             : 
     209           4 :                 wreplsrv_terminate_in_connection(wrepl_conn, reason);
     210           4 :                 return;
     211             :         }
     212             : 
     213        2139 :         DEBUG(10,("Received wrepl packet of length %lu from %s\n",
     214             :                  (long) call->in.length,
     215             :                  tsocket_address_string(wrepl_conn->conn->remote_address, call)));
     216             : 
     217             :         /* skip length header */
     218        2139 :         call->in.data += 4;
     219        2139 :         call->in.length -= 4;
     220             : 
     221        2139 :         status = wreplsrv_process(wrepl_conn, &call);
     222        2139 :         if (!NT_STATUS_IS_OK(status)) {
     223             :                 const char *reason;
     224             : 
     225           0 :                 reason = talloc_asprintf(call, "wreplsrv_call_loop: "
     226             :                                          "tstream_read_pdu_blob_recv() - %s",
     227             :                                          nt_errstr(status));
     228           0 :                 if (reason == NULL) {
     229           0 :                         reason = nt_errstr(status);
     230             :                 }
     231             : 
     232           0 :                 wreplsrv_terminate_in_connection(wrepl_conn, reason);
     233           0 :                 return;
     234             :         }
     235             : 
     236             :         /* We handed over the connection so we're done here */
     237        2139 :         if (wrepl_conn->tstream == NULL) {
     238         675 :             return;
     239             :         }
     240             : 
     241             :         /* Invalid WINS-Replication packet, we just ignore it */
     242        1464 :         if (call == NULL) {
     243           0 :                 goto noreply;
     244             :         }
     245             : 
     246        1464 :         call->out_iov[0].iov_base = (char *) call->out.data;
     247        1464 :         call->out_iov[0].iov_len = call->out.length;
     248             : 
     249        2928 :         subreq = tstream_writev_queue_send(call,
     250        1464 :                                            wrepl_conn->conn->event.ctx,
     251             :                                            wrepl_conn->tstream,
     252             :                                            wrepl_conn->send_queue,
     253        1464 :                                            call->out_iov, 1);
     254        1464 :         if (subreq == NULL) {
     255           0 :                 wreplsrv_terminate_in_connection(wrepl_conn, "wreplsrv_call_loop: "
     256             :                                 "no memory for tstream_writev_queue_send");
     257           0 :                 return;
     258             :         }
     259        1464 :         tevent_req_set_callback(subreq, wreplsrv_call_writev_done, call);
     260             : 
     261        1464 : noreply:
     262             :         /*
     263             :          * The wrepl pdu's has the length as 4 byte (initial_read_size),
     264             :          *  provides the pdu length then.
     265             :          */
     266        2928 :         subreq = tstream_read_pdu_blob_send(wrepl_conn,
     267        1464 :                                             wrepl_conn->conn->event.ctx,
     268             :                                             wrepl_conn->tstream,
     269             :                                             4, /* initial_read_size */
     270             :                                             packet_full_request_u32,
     271             :                                             wrepl_conn);
     272        1464 :         if (subreq == NULL) {
     273           0 :                 wreplsrv_terminate_in_connection(wrepl_conn, "wreplsrv_call_loop: "
     274             :                                 "no memory for tstream_read_pdu_blob_send");
     275           0 :                 return;
     276             :         }
     277        1464 :         tevent_req_set_callback(subreq, wreplsrv_call_loop, wrepl_conn);
     278             : }
     279             : 
     280        1464 : static void wreplsrv_call_writev_done(struct tevent_req *subreq)
     281             : {
     282        1464 :         struct wreplsrv_in_call *call = tevent_req_callback_data(subreq,
     283             :                         struct wreplsrv_in_call);
     284             :         int sys_errno;
     285             :         int rc;
     286             : 
     287        1464 :         rc = tstream_writev_queue_recv(subreq, &sys_errno);
     288        1464 :         TALLOC_FREE(subreq);
     289        1464 :         if (rc == -1) {
     290             :                 const char *reason;
     291             : 
     292           0 :                 reason = talloc_asprintf(call, "wreplsrv_call_writev_done: "
     293             :                                          "tstream_writev_queue_recv() - %d:%s",
     294             :                                          sys_errno, strerror(sys_errno));
     295           0 :                 if (reason == NULL) {
     296           0 :                         reason = "wreplsrv_call_writev_done: "
     297             :                                  "tstream_writev_queue_recv() failed";
     298             :                 }
     299             : 
     300           0 :                 wreplsrv_terminate_in_connection(call->wreplconn, reason);
     301           0 :                 return;
     302             :         }
     303             : 
     304        1464 :         if (call->terminate_after_send) {
     305           0 :                 wreplsrv_terminate_in_connection(call->wreplconn,
     306             :                                 "wreplsrv_in_connection: terminate_after_send");
     307           0 :                 return;
     308             :         }
     309             : 
     310        1464 :         talloc_free(call);
     311             : }
     312             : 
     313             : /*
     314             :   called on a tcp recv
     315             : */
     316           0 : static void wreplsrv_recv(struct stream_connection *conn, uint16_t flags)
     317             : {
     318           0 :         struct wreplsrv_in_connection *wrepl_conn = talloc_get_type(conn->private_data,
     319             :                                                         struct wreplsrv_in_connection);
     320             :         /* this should never be triggered! */
     321           0 :         DEBUG(0,("Terminating connection - '%s'\n", "wrepl_recv: called"));
     322           0 :         wreplsrv_terminate_in_connection(wrepl_conn, "wrepl_recv: called");
     323           0 : }
     324             : 
     325             : /*
     326             :   called when we can write to a connection
     327             : */
     328           0 : static void wreplsrv_send(struct stream_connection *conn, uint16_t flags)
     329             : {
     330           0 :         struct wreplsrv_in_connection *wrepl_conn = talloc_get_type(conn->private_data,
     331             :                                                         struct wreplsrv_in_connection);
     332             :         /* this should never be triggered! */
     333           0 :         DEBUG(0,("Terminating connection - '%s'\n", "wrepl_send: called"));
     334           0 :         wreplsrv_terminate_in_connection(wrepl_conn, "wrepl_send: called");
     335           0 : }
     336             : 
     337             : static const struct stream_server_ops wreplsrv_stream_ops = {
     338             :         .name                   = "wreplsrv",
     339             :         .accept_connection      = wreplsrv_accept,
     340             :         .recv_handler           = wreplsrv_recv,
     341             :         .send_handler           = wreplsrv_send,
     342             : };
     343             : 
     344             : /*
     345             :   called when we get a new connection
     346             : */
     347           0 : NTSTATUS wreplsrv_in_connection_merge(struct wreplsrv_partner *partner,
     348             :                                       uint32_t peer_assoc_ctx,
     349             :                                       struct tstream_context **stream,
     350             :                                       struct wreplsrv_in_connection **_wrepl_in,
     351             :                                       void* process_context)
     352             : {
     353           0 :         struct wreplsrv_service *service = partner->service;
     354             :         struct wreplsrv_in_connection *wrepl_in;
     355             :         struct stream_connection *conn;
     356             :         struct tevent_req *subreq;
     357             :         NTSTATUS status;
     358             : 
     359           0 :         wrepl_in = talloc_zero(partner, struct wreplsrv_in_connection);
     360           0 :         NT_STATUS_HAVE_NO_MEMORY(wrepl_in);
     361             : 
     362           0 :         wrepl_in->service    = service;
     363           0 :         wrepl_in->partner    = partner;
     364           0 :         wrepl_in->tstream    = talloc_move(wrepl_in, stream);
     365           0 :         wrepl_in->assoc_ctx.peer_ctx = peer_assoc_ctx;
     366             : 
     367           0 :         status = stream_new_connection_merge(service->task->event_ctx,
     368           0 :                                              service->task->lp_ctx,
     369           0 :                                              service->task->model_ops,
     370             :                                              &wreplsrv_stream_ops,
     371           0 :                                              service->task->msg_ctx,
     372             :                                              wrepl_in,
     373             :                                              &conn,
     374             :                                              process_context);
     375           0 :         NT_STATUS_NOT_OK_RETURN(status);
     376             : 
     377             :         /*
     378             :          * make the wreplsrv_in_connection structure a child of the
     379             :          * stream_connection, to match the hierarchy of wreplsrv_accept
     380             :          */
     381           0 :         wrepl_in->conn               = conn;
     382           0 :         talloc_steal(conn, wrepl_in);
     383             : 
     384           0 :         wrepl_in->send_queue = tevent_queue_create(wrepl_in, "wreplsrv_in_connection_merge");
     385           0 :         if (wrepl_in->send_queue == NULL) {
     386           0 :                 stream_terminate_connection(conn,
     387             :                                             "wreplsrv_in_connection_merge: out of memory");
     388           0 :                 return NT_STATUS_NO_MEMORY;
     389             :         }
     390             : 
     391             :         /*
     392             :          * The wrepl pdu's has the length as 4 byte (initial_read_size),
     393             :          * packet_full_request_u32 provides the pdu length then.
     394             :          */
     395           0 :         subreq = tstream_read_pdu_blob_send(wrepl_in,
     396           0 :                                             wrepl_in->conn->event.ctx,
     397             :                                             wrepl_in->tstream,
     398             :                                             4, /* initial_read_size */
     399             :                                             packet_full_request_u32,
     400             :                                             wrepl_in);
     401           0 :         if (subreq == NULL) {
     402           0 :                 wreplsrv_terminate_in_connection(wrepl_in, "wreplsrv_in_connection_merge: "
     403             :                                 "no memory for tstream_read_pdu_blob_send");
     404           0 :                 return NT_STATUS_NO_MEMORY;
     405             :         }
     406           0 :         tevent_req_set_callback(subreq, wreplsrv_call_loop, wrepl_in);
     407             : 
     408           0 :         *_wrepl_in = wrepl_in;
     409             : 
     410           0 :         return NT_STATUS_OK;
     411             : }
     412             : 
     413             : /*
     414             :   startup the wrepl port 42 server sockets
     415             : */
     416          53 : NTSTATUS wreplsrv_setup_sockets(struct wreplsrv_service *service, struct loadparm_context *lp_ctx)
     417             : {
     418             :         NTSTATUS status;
     419          53 :         struct task_server *task = service->task;
     420             :         const char *address;
     421          53 :         uint16_t port = WINS_REPLICATION_PORT;
     422             : 
     423          53 :         if (lpcfg_interfaces(lp_ctx) && lpcfg_bind_interfaces_only(lp_ctx)) {
     424             :                 int num_interfaces;
     425             :                 int i;
     426             :                 struct interface *ifaces;
     427             : 
     428           0 :                 load_interface_list(task, lp_ctx, &ifaces);
     429             : 
     430           0 :                 num_interfaces = iface_list_count(ifaces);
     431             : 
     432             :                 /* We have been given an interfaces line, and been 
     433             :                    told to only bind to those interfaces. Create a
     434             :                    socket per interface and bind to only these.
     435             :                 */
     436           0 :                 for(i = 0; i < num_interfaces; i++) {
     437           0 :                         if (!iface_list_n_is_v4(ifaces, i)) {
     438           0 :                                 continue;
     439             :                         }
     440           0 :                         address = iface_list_n_ip(ifaces, i);
     441           0 :                         status = stream_setup_socket(
     442             :                                         task, task->event_ctx,
     443             :                                         task->lp_ctx,
     444             :                                         task->model_ops,
     445             :                                         &wreplsrv_stream_ops,
     446             :                                         "ipv4", address, &port,
     447             :                                         lpcfg_socket_options(task->lp_ctx),
     448             :                                         service, task->process_context);
     449           0 :                         if (!NT_STATUS_IS_OK(status)) {
     450           0 :                                 DEBUG(0,("stream_setup_socket(address=%s,port=%u) failed - %s\n",
     451             :                                          address, port, nt_errstr(status)));
     452           0 :                                 return status;
     453             :                         }
     454             :                 }
     455             :         } else {
     456          53 :                 address = "0.0.0.0";
     457          53 :                 status = stream_setup_socket(task, task->event_ctx,
     458             :                                              task->lp_ctx, task->model_ops,
     459             :                                              &wreplsrv_stream_ops,
     460             :                                              "ipv4", address, &port,
     461             :                                              lpcfg_socket_options(task->lp_ctx),
     462             :                                              service, task->process_context);
     463          53 :                 if (!NT_STATUS_IS_OK(status)) {
     464           0 :                         DEBUG(0,("stream_setup_socket(address=%s,port=%u) failed - %s\n",
     465             :                                  address, port, nt_errstr(status)));
     466           0 :                         return status;
     467             :                 }
     468             :         }
     469             : 
     470          53 :         return NT_STATUS_OK;
     471             : }

Generated by: LCOV version 1.13