LCOV - code coverage report
Current view: top level - source4/samba - service_stream.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 128 172 74.4 %
Date: 2024-04-21 15:09:00 Functions: 7 9 77.8 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    helper functions for stream based servers
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2003-2005
       7             :    Copyright (C) Stefan (metze) Metzmacher      2004
       8             :    
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             :    
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             :    
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include <tevent.h>
      25             : #include "process_model.h"
      26             : #include "lib/util/server_id.h"
      27             : #include "lib/messaging/irpc.h"
      28             : #include "cluster/cluster.h"
      29             : #include "param/param.h"
      30             : #include "../lib/tsocket/tsocket.h"
      31             : #include "lib/util/util_net.h"
      32             : 
      33             : /* size of listen() backlog in smbd */
      34             : #define SERVER_LISTEN_BACKLOG 10
      35             : 
      36             : 
      37             : /*
      38             :   private structure for a single listening stream socket
      39             : */
      40             : struct stream_socket {
      41             :         const struct stream_server_ops *ops;
      42             :         struct loadparm_context *lp_ctx;
      43             :         struct tevent_context *event_ctx;
      44             :         const struct model_ops *model_ops;
      45             :         struct socket_context *sock;
      46             :         void *private_data;
      47             :         void *process_context;
      48             : };
      49             : 
      50             : 
      51             : /*
      52             :   close the socket and shutdown a stream_connection
      53             : */
      54      131924 : void stream_terminate_connection(struct stream_connection *srv_conn, const char *reason)
      55             : {
      56      131924 :         struct tevent_context *event_ctx = srv_conn->event.ctx;
      57      131924 :         const struct model_ops *model_ops = srv_conn->model_ops;
      58      131924 :         struct loadparm_context *lp_ctx = srv_conn->lp_ctx;
      59      131924 :         void *process_context = srv_conn->process_context;
      60      131924 :         TALLOC_CTX *frame = NULL;
      61             : 
      62      131924 :         if (!reason) reason = "unknown reason";
      63             : 
      64      131924 :         if (srv_conn->processing) {
      65        2574 :                 DBG_NOTICE("Terminating connection deferred - '%s'\n", reason);
      66             :         } else {
      67      129350 :                 DBG_NOTICE("Terminating connection - '%s'\n", reason);
      68             :         }
      69             : 
      70      131924 :         srv_conn->terminate = reason;
      71             : 
      72      131924 :         if (srv_conn->processing) {
      73             :                 /* 
      74             :                  * if we're currently inside the stream_io_handler(),
      75             :                  * defer the termination to the end of stream_io_hendler()
      76             :                  *
      77             :                  * and we don't want to read or write to the connection...
      78             :                  */
      79        2574 :                 tevent_fd_set_flags(srv_conn->event.fde, 0);
      80        2574 :                 return;
      81             :         }
      82             : 
      83      129350 :         frame = talloc_stackframe();
      84             : 
      85      129350 :         reason = talloc_strdup(frame, reason);
      86      129350 :         if (reason == NULL) {
      87           0 :                 reason = "OOM - unknown reason";
      88             :         }
      89             : 
      90      129350 :         TALLOC_FREE(srv_conn->event.fde);
      91      129350 :         imessaging_cleanup(srv_conn->msg_ctx);
      92      129350 :         TALLOC_FREE(srv_conn);
      93      129350 :         model_ops->terminate_connection(
      94             :             event_ctx, lp_ctx, reason, process_context);
      95      113935 :         TALLOC_FREE(frame);
      96             : }
      97             : 
      98             : /**
      99             :   the select loop has indicated that a stream is ready for IO
     100             : */
     101     2602615 : static void stream_io_handler(struct stream_connection *conn, uint16_t flags)
     102             : {
     103     2602615 :         conn->processing++;
     104     2602615 :         if (flags & TEVENT_FD_WRITE) {
     105      886656 :                 conn->ops->send_handler(conn, flags);
     106     1715959 :         } else if (flags & TEVENT_FD_READ) {
     107     1715959 :                 conn->ops->recv_handler(conn, flags);
     108             :         }
     109     2602615 :         conn->processing--;
     110             : 
     111     2602615 :         if (conn->terminate) {
     112        2574 :                 stream_terminate_connection(conn, conn->terminate);
     113             :         }
     114     2602615 : }
     115             : 
     116     2602615 : void stream_io_handler_fde(struct tevent_context *ev, struct tevent_fd *fde,
     117             :                                   uint16_t flags, void *private_data)
     118             : {
     119     2602615 :         struct stream_connection *conn = talloc_get_type(private_data,
     120             :                                                          struct stream_connection);
     121     2602615 :         stream_io_handler(conn, flags);
     122     2602615 : }
     123             : 
     124           0 : void stream_io_handler_callback(void *private_data, uint16_t flags)
     125             : {
     126           0 :         struct stream_connection *conn = talloc_get_type(private_data,
     127             :                                                          struct stream_connection);
     128           0 :         stream_io_handler(conn, flags);
     129           0 : }
     130             : 
     131             : /*
     132             :   this creates a stream_connection from an already existing connection,
     133             :   used for protocols, where a client connection needs to switched into
     134             :   a server connection
     135             : */
     136           0 : NTSTATUS stream_new_connection_merge(struct tevent_context *ev,
     137             :                                      struct loadparm_context *lp_ctx,
     138             :                                      const struct model_ops *model_ops,
     139             :                                      const struct stream_server_ops *stream_ops,
     140             :                                      struct imessaging_context *msg_ctx,
     141             :                                      void *private_data,
     142             :                                      struct stream_connection **_srv_conn,
     143             :                                      void *process_context)
     144             : {
     145           0 :         struct stream_connection *srv_conn;
     146             : 
     147           0 :         srv_conn = talloc_zero(ev, struct stream_connection);
     148           0 :         NT_STATUS_HAVE_NO_MEMORY(srv_conn);
     149             : 
     150           0 :         srv_conn->private_data    = private_data;
     151           0 :         srv_conn->model_ops       = model_ops;
     152           0 :         srv_conn->socket       = NULL;
     153           0 :         srv_conn->server_id    = cluster_id(0, 0);
     154           0 :         srv_conn->ops             = stream_ops;
     155           0 :         srv_conn->msg_ctx      = msg_ctx;
     156           0 :         srv_conn->event.ctx    = ev;
     157           0 :         srv_conn->lp_ctx       = lp_ctx;
     158           0 :         srv_conn->event.fde    = NULL;
     159           0 :         srv_conn->process_context = process_context;
     160             : 
     161           0 :         *_srv_conn = srv_conn;
     162           0 :         return NT_STATUS_OK;
     163             : }
     164             : 
     165             : /*
     166             :   called when a new socket connection has been established. This is called in the process
     167             :   context of the new process (if appropriate)
     168             : */
     169      129382 : static void stream_new_connection(struct tevent_context *ev,
     170             :                                   struct loadparm_context *lp_ctx,
     171             :                                   struct socket_context *sock, 
     172             :                                   struct server_id server_id,
     173             :                                   void *private_data,
     174             :                                   void *process_context)
     175             : {
     176      129382 :         struct stream_socket *stream_socket = talloc_get_type(private_data, struct stream_socket);
     177        3243 :         struct stream_connection *srv_conn;
     178             : 
     179      129382 :         srv_conn = talloc_zero(ev, struct stream_connection);
     180      129382 :         if (!srv_conn) {
     181           0 :                 DBG_ERR("talloc(mem_ctx, struct stream_connection) failed\n");
     182           0 :                 return;
     183             :         }
     184             : 
     185      129382 :         talloc_steal(srv_conn, sock);
     186             : 
     187      129382 :         srv_conn->private_data         = stream_socket->private_data;
     188      129382 :         srv_conn->model_ops       = stream_socket->model_ops;
     189      129382 :         srv_conn->socket       = sock;
     190      129382 :         srv_conn->server_id    = server_id;
     191      129382 :         srv_conn->ops             = stream_socket->ops;
     192      129382 :         srv_conn->event.ctx    = ev;
     193      129382 :         srv_conn->lp_ctx       = lp_ctx;
     194      129382 :         srv_conn->process_context = process_context;
     195             : 
     196      129382 :         if (!socket_check_access(sock, "smbd", lpcfg_hosts_allow(NULL, lpcfg_default_service(lp_ctx)), lpcfg_hosts_deny(NULL, lpcfg_default_service(lp_ctx)))) {
     197           0 :                 stream_terminate_connection(srv_conn, "denied by access rules");
     198           0 :                 return;
     199             :         }
     200             : 
     201      129382 :         srv_conn->event.fde  = tevent_add_fd(ev, srv_conn, socket_get_fd(sock),
     202             :                                                 0, stream_io_handler_fde, srv_conn);
     203      129382 :         if (!srv_conn->event.fde) {
     204           0 :                 stream_terminate_connection(srv_conn, "tevent_add_fd() failed");
     205           0 :                 return;
     206             :         }
     207             : 
     208             :         /* setup to receive internal messages on this connection */
     209      129382 :         srv_conn->msg_ctx = imessaging_init(srv_conn,
     210             :                                             lp_ctx,
     211             :                                             srv_conn->server_id, ev);
     212      129382 :         if (!srv_conn->msg_ctx) {
     213           0 :                 stream_terminate_connection(srv_conn, "imessaging_init() failed");
     214           0 :                 return;
     215             :         }
     216             : 
     217      129382 :         srv_conn->remote_address = socket_get_remote_addr(srv_conn->socket, srv_conn);
     218      129382 :         if (!srv_conn->remote_address) {
     219           0 :                 stream_terminate_connection(srv_conn, "socket_get_remote_addr() failed");
     220           0 :                 return;
     221             :         }
     222             : 
     223      129382 :         srv_conn->local_address = socket_get_local_addr(srv_conn->socket, srv_conn);
     224      129382 :         if (!srv_conn->local_address) {
     225           0 :                 stream_terminate_connection(srv_conn, "socket_get_local_addr() failed");
     226           0 :                 return;
     227             :         }
     228             : 
     229             :         {
     230        3243 :                 TALLOC_CTX *tmp_ctx;
     231        3243 :                 const char *title;
     232        3243 :                 struct server_id_buf idbuf;
     233             : 
     234      129382 :                 tmp_ctx = talloc_new(srv_conn);
     235             : 
     236      129382 :                 title = talloc_asprintf(tmp_ctx, "conn[%s] c[%s] s[%s] server_id[%s]",
     237      129382 :                                         stream_socket->ops->name, 
     238      129382 :                                         tsocket_address_string(srv_conn->remote_address, tmp_ctx),
     239      129382 :                                         tsocket_address_string(srv_conn->local_address, tmp_ctx),
     240             :                                         server_id_str_buf(server_id, &idbuf));
     241      129382 :                 if (title) {
     242      129382 :                         stream_connection_set_title(srv_conn, title);
     243             :                 }
     244      129382 :                 talloc_free(tmp_ctx);
     245             :         }
     246             : 
     247             :         /* we're now ready to start receiving events on this stream */
     248      129382 :         TEVENT_FD_READABLE(srv_conn->event.fde);
     249             : 
     250             :         /* call the server specific accept code */
     251      129382 :         stream_socket->ops->accept_connection(srv_conn);
     252             : }
     253             : 
     254             : 
     255             : /*
     256             :   called when someone opens a connection to one of our listening ports
     257             : */
     258      159575 : static void stream_accept_handler(struct tevent_context *ev, struct tevent_fd *fde, 
     259             :                                   uint16_t flags, void *private_data)
     260             : {
     261      159575 :         struct stream_socket *stream_socket = talloc_get_type(private_data, struct stream_socket);
     262             : 
     263             :         /* ask the process model to create us a process for this new
     264             :            connection.  When done, it calls stream_new_connection()
     265             :            with the newly created socket */
     266      159575 :         stream_socket->model_ops->accept_connection(
     267             :                 ev,
     268             :                 stream_socket->lp_ctx,
     269             :                 stream_socket->sock,
     270             :                 stream_new_connection,
     271             :                 stream_socket,
     272             :                 stream_socket->process_context);
     273      159575 : }
     274             : 
     275             : /*
     276             :   setup a listen stream socket
     277             :   if you pass *port == 0, then a port > 1024 is used
     278             : 
     279             :   FIXME: This function is TCP/IP specific - uses an int rather than 
     280             :          a string for the port. Should leave allocating a port nr 
     281             :          to the socket implementation - JRV20070903
     282             :  */
     283        2454 : NTSTATUS stream_setup_socket(TALLOC_CTX *mem_ctx,
     284             :                              struct tevent_context *event_context,
     285             :                              struct loadparm_context *lp_ctx,
     286             :                              const struct model_ops *model_ops,
     287             :                              const struct stream_server_ops *stream_ops,
     288             :                              const char *family,
     289             :                              const char *sock_addr,
     290             :                              uint16_t *port,
     291             :                              const char *socket_options,
     292             :                              void *private_data,
     293             :                              void *process_context)
     294             : {
     295          74 :         NTSTATUS status;
     296          74 :         struct stream_socket *stream_socket;
     297          74 :         struct socket_address *socket_address;
     298          74 :         struct tevent_fd *fde;
     299          74 :         int i;
     300          74 :         struct sockaddr_storage ss;
     301             : 
     302        2454 :         stream_socket = talloc_zero(mem_ctx, struct stream_socket);
     303        2454 :         NT_STATUS_HAVE_NO_MEMORY(stream_socket);
     304             : 
     305        2454 :         if (strcmp(family, "ip") == 0) {
     306             :                 /* we will get the real family from the address itself */
     307        1264 :                 if (!interpret_string_addr(&ss, sock_addr, 0)) {
     308           0 :                         talloc_free(stream_socket);
     309           0 :                         return NT_STATUS_INVALID_ADDRESS;
     310             :                 }
     311             : 
     312        1264 :                 socket_address = socket_address_from_sockaddr_storage(stream_socket, &ss, port?*port:0);
     313        1264 :                 if (socket_address == NULL) {
     314           0 :                         TALLOC_FREE(stream_socket);
     315           0 :                         return NT_STATUS_NO_MEMORY;
     316             :                 }
     317             : 
     318        1264 :                 status = socket_create(stream_socket, socket_address->family,
     319             :                                        SOCKET_TYPE_STREAM,
     320             :                                        &stream_socket->sock, 0);
     321        1264 :                 NT_STATUS_NOT_OK_RETURN(status);
     322             :         } else {
     323        1190 :                 status = socket_create(stream_socket, family,
     324             :                                        SOCKET_TYPE_STREAM,
     325             :                                        &stream_socket->sock, 0);
     326        1190 :                 NT_STATUS_NOT_OK_RETURN(status);
     327             : 
     328             :                 /* this is for non-IP sockets, eg. unix domain sockets */
     329        1190 :                 socket_address = socket_address_from_strings(stream_socket,
     330        1190 :                                                              stream_socket->sock->backend_name,
     331         203 :                                                              sock_addr, port?*port:0);
     332        1190 :                 NT_STATUS_HAVE_NO_MEMORY(socket_address);
     333             :         }
     334             : 
     335             : 
     336        2454 :         stream_socket->lp_ctx = talloc_reference(stream_socket, lp_ctx);
     337             : 
     338             :         /* ready to listen */
     339        2454 :         status = socket_set_option(stream_socket->sock, "SO_KEEPALIVE", NULL);
     340        2454 :         NT_STATUS_NOT_OK_RETURN(status);
     341             : 
     342        2454 :         if (socket_options != NULL) {
     343        1652 :                 status = socket_set_option(stream_socket->sock, socket_options, NULL);
     344        1652 :                 NT_STATUS_NOT_OK_RETURN(status);
     345             :         }
     346             : 
     347             :         /* TODO: set socket ACL's (host allow etc) here when they're
     348             :          * implemented */
     349             : 
     350             :         /* Some sockets don't have a port, or are just described from
     351             :          * the string.  We are indicating this by having port == NULL */
     352        2454 :         if (!port) {
     353         987 :                 status = socket_listen(stream_socket->sock, socket_address, SERVER_LISTEN_BACKLOG, 0);
     354        1467 :         } else if (*port == 0) {
     355          68 :                 for (i = lpcfg_rpc_low_port(lp_ctx);
     356          68 :                      i <= lpcfg_rpc_high_port(lp_ctx);
     357           0 :                      i++) {
     358          68 :                         socket_address->port = i;
     359          68 :                         status = socket_listen(stream_socket->sock, socket_address, 
     360             :                                                SERVER_LISTEN_BACKLOG, 0);
     361          68 :                         if (NT_STATUS_IS_OK(status)) {
     362          68 :                                 *port = i;
     363          68 :                                 break;
     364             :                         }
     365             :                 }
     366             :         } else {
     367        1399 :                 status = socket_listen(stream_socket->sock, socket_address, SERVER_LISTEN_BACKLOG, 0);
     368             :         }
     369             : 
     370        2454 :         if (!NT_STATUS_IS_OK(status)) {
     371           0 :                 DBG_ERR("Failed to listen on %s:%u - %s\n",
     372             :                          sock_addr, port ? (unsigned int)(*port) : 0,
     373             :                          nt_errstr(status));
     374           0 :                 talloc_free(stream_socket);
     375           0 :                 return status;
     376             :         }
     377             : 
     378             :         /* Add the FD from the newly created socket into the event
     379             :          * subsystem.  it will call the accept handler whenever we get
     380             :          * new connections */
     381             : 
     382        2454 :         fde = tevent_add_fd(event_context, stream_socket->sock,
     383             :                             socket_get_fd(stream_socket->sock),
     384             :                             TEVENT_FD_READ,
     385             :                             stream_accept_handler, stream_socket);
     386        2454 :         if (!fde) {
     387           0 :                 DBG_ERR("Failed to setup fd event\n");
     388           0 :                 talloc_free(stream_socket);
     389           0 :                 return NT_STATUS_NO_MEMORY;
     390             :         }
     391             : 
     392             :         /* we let events system to the close on the socket. This avoids
     393             :          * nasty interactions with waiting for talloc to close the socket. */
     394        2454 :         tevent_fd_set_close_fn(fde, socket_tevent_fd_close_fn);
     395        2454 :         socket_set_flags(stream_socket->sock, SOCKET_FLAG_NOCLOSE);
     396             : 
     397        2454 :         stream_socket->private_data     = talloc_reference(stream_socket, private_data);
     398        2454 :         stream_socket->ops              = stream_ops;
     399        2454 :         stream_socket->event_ctx     = event_context;
     400        2454 :         stream_socket->model_ops        = model_ops;
     401        2454 :         stream_socket->process_context  = process_context;
     402             : 
     403        2454 :         return NT_STATUS_OK;
     404             : }
     405             : 
     406             : 
     407             : /*
     408             :   setup a connection title 
     409             : */
     410      129382 : void stream_connection_set_title(struct stream_connection *conn, const char *title)
     411             : {
     412      129382 :         conn->model_ops->set_title(conn->event.ctx, title);
     413      129382 : }

Generated by: LCOV version 1.14