LCOV - code coverage report
Current view: top level - source4/librpc/rpc - dcerpc_sock.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 147 205 71.7 %
Date: 2024-04-21 15:09:00 Functions: 10 14 71.4 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    dcerpc over standard sockets transport
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2003
       7             :    Copyright (C) Jelmer Vernooij 2004
       8             :    Copyright (C) Rafal Szczesniak 2006
       9             :    
      10             :    This program is free software; you can redistribute it and/or modify
      11             :    it under the terms of the GNU General Public License as published by
      12             :    the Free Software Foundation; either version 3 of the License, or
      13             :    (at your option) any later version.
      14             :    
      15             :    This program is distributed in the hope that it will be useful,
      16             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :    GNU General Public License for more details.
      19             :    
      20             :    You should have received a copy of the GNU General Public License
      21             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : #include "includes.h"
      25             : #include "system/filesys.h"
      26             : #include "lib/events/events.h"
      27             : #include "lib/socket/socket.h"
      28             : #include "lib/tsocket/tsocket.h"
      29             : #include "libcli/composite/composite.h"
      30             : #include "librpc/rpc/dcerpc.h"
      31             : #include "librpc/rpc/dcerpc_proto.h"
      32             : #include "libcli/resolve/resolve.h"
      33             : #include "librpc/rpc/rpc_common.h"
      34             : 
      35             : struct pipe_open_socket_state {
      36             :         struct dcecli_connection *conn;
      37             :         struct socket_context *socket_ctx;
      38             :         struct socket_address *localaddr;
      39             :         struct socket_address *server;
      40             :         const char *target_hostname;
      41             :         enum dcerpc_transport_t transport;
      42             :         struct socket_address *client;
      43             : };
      44             : 
      45             : 
      46       12307 : static void continue_socket_connect(struct composite_context *ctx)
      47             : {
      48         250 :         struct dcecli_connection *conn;
      49       12307 :         struct composite_context *c = talloc_get_type_abort(
      50             :                 ctx->async.private_data, struct composite_context);
      51       12307 :         struct pipe_open_socket_state *s = talloc_get_type_abort(
      52             :                 c->private_data, struct pipe_open_socket_state);
      53         250 :         int rc;
      54         250 :         int sock_fd;
      55             : 
      56             :         /* make it easier to write a function calls */
      57       12307 :         conn = s->conn;
      58             : 
      59       12307 :         c->status = socket_connect_recv(ctx);
      60       12307 :         if (!NT_STATUS_IS_OK(c->status)) {
      61           0 :                 DBG_NOTICE("Failed to connect host %s on port %d - %s\n",
      62             :                           s->server->addr, s->server->port,
      63             :                           nt_errstr(c->status));
      64           0 :                 composite_error(c, c->status);
      65           0 :                 return;
      66             :         }
      67             : 
      68       12307 :         s->client = socket_get_my_addr(s->socket_ctx, s);
      69       12307 :         if (s->client == NULL) {
      70           0 :                 TALLOC_FREE(s->socket_ctx);
      71           0 :                 composite_error(c, NT_STATUS_NO_MEMORY);
      72           0 :                 return;
      73             :         }
      74       12307 :         sock_fd = socket_get_fd(s->socket_ctx);
      75       12307 :         if (sock_fd == -1) {
      76           0 :                 TALLOC_FREE(s->socket_ctx);
      77           0 :                 composite_error(c, NT_STATUS_INVALID_HANDLE);
      78           0 :                 return;
      79             :         }
      80       12307 :         socket_set_flags(s->socket_ctx, SOCKET_FLAG_NOCLOSE);
      81       12307 :         TALLOC_FREE(s->socket_ctx);
      82             : 
      83             :         /*
      84             :           fill in the transport methods
      85             :         */
      86       12307 :         conn->transport.transport       = s->transport;
      87       12307 :         conn->transport.private_data    = NULL;
      88             : 
      89             :         /*
      90             :          * Windows uses 5840 for ncacn_ip_tcp,
      91             :          * so we also use it (for every transport which uses bsd sockets)
      92             :          */
      93       12307 :         conn->srv_max_xmit_frag = 5840;
      94       12307 :         conn->srv_max_recv_frag = 5840;
      95             : 
      96       12307 :         conn->transport.pending_reads = 0;
      97       12307 :         conn->server_name   = strupper_talloc(conn, s->target_hostname);
      98             : 
      99       12307 :         rc = tstream_bsd_existing_socket(conn, sock_fd,
     100             :                                          &conn->transport.stream);
     101       12307 :         if (rc < 0) {
     102           0 :                 close(sock_fd);
     103           0 :                 composite_error(c, NT_STATUS_NO_MEMORY);
     104           0 :                 return;
     105             :         }
     106             : 
     107       12557 :         conn->transport.write_queue =
     108       12307 :                 tevent_queue_create(conn, "dcerpc sock write queue");
     109       12307 :         if (conn->transport.write_queue == NULL) {
     110           0 :                 TALLOC_FREE(conn->transport.stream);
     111           0 :                 composite_error(c, NT_STATUS_NO_MEMORY);
     112           0 :                 return;
     113             :         }
     114             : 
     115             :         /* ensure we don't get SIGPIPE */
     116       12307 :         BlockSignals(true, SIGPIPE);
     117             : 
     118       12307 :         composite_done(c);
     119             : }
     120             : 
     121             : 
     122       12307 : static struct composite_context *dcerpc_pipe_open_socket_send(TALLOC_CTX *mem_ctx,
     123             :                                                        struct dcecli_connection *cn,
     124             :                                                        struct socket_address *localaddr,
     125             :                                                        struct socket_address *server,
     126             :                                                        const char *target_hostname,
     127             :                                                        const char *full_path,
     128             :                                                        enum dcerpc_transport_t transport)
     129             : {
     130         250 :         struct composite_context *c;
     131         250 :         struct pipe_open_socket_state *s;
     132         250 :         struct composite_context *conn_req;
     133             : 
     134       12307 :         c = composite_create(mem_ctx, cn->event_ctx);
     135       12307 :         if (c == NULL) return NULL;
     136             : 
     137       12307 :         s = talloc_zero(c, struct pipe_open_socket_state);
     138       12307 :         if (composite_nomem(s, c)) return c;
     139       12307 :         c->private_data = s;
     140             : 
     141       12307 :         s->conn      = cn;
     142       12307 :         s->transport = transport;
     143       12307 :         if (localaddr) {
     144         480 :                 s->localaddr = socket_address_copy(s, localaddr);
     145         480 :                 if (composite_nomem(s->localaddr, c)) return c;
     146             :         }
     147       12307 :         s->server = socket_address_copy(s, server);
     148       12307 :         if (composite_nomem(s->server, c)) return c;
     149       12307 :         if (target_hostname) {
     150       10855 :                 s->target_hostname = talloc_strdup(s, target_hostname);
     151       10855 :                 if (composite_nomem(s->target_hostname, c)) return c;
     152             :         }
     153             : 
     154       12307 :         c->status = socket_create(s, server->family, SOCKET_TYPE_STREAM,
     155             :                                   &s->socket_ctx, 0);
     156       12307 :         if (!composite_is_ok(c)) return c;
     157             : 
     158       12307 :         conn_req = socket_connect_send(s->socket_ctx, s->localaddr, s->server, 0,
     159             :                                        c->event_ctx);
     160       12307 :         composite_continue(c, conn_req, continue_socket_connect, c);
     161       12307 :         return c;
     162             : }
     163             : 
     164       12307 : static NTSTATUS dcerpc_pipe_open_socket_recv(struct composite_context *c,
     165             :                                              TALLOC_CTX *mem_ctx,
     166             :                                              struct socket_address **localaddr)
     167             : {
     168       12307 :         NTSTATUS status = composite_wait(c);
     169             : 
     170       12307 :         if (NT_STATUS_IS_OK(status)) {
     171         250 :                 struct pipe_open_socket_state *s =
     172       12307 :                         talloc_get_type_abort(c->private_data,
     173             :                         struct pipe_open_socket_state);
     174             : 
     175       12307 :                 if (localaddr != NULL) {
     176       10855 :                         *localaddr = talloc_move(mem_ctx, &s->client);
     177             :                 }
     178             :         }
     179             : 
     180       12307 :         talloc_free(c);
     181       12307 :         return status;
     182             : }
     183             : 
     184             : struct pipe_tcp_state {
     185             :         const char *server;
     186             :         const char *target_hostname;
     187             :         const char **addresses;
     188             :         uint32_t index;
     189             :         uint32_t port;
     190             :         struct socket_address *localaddr;
     191             :         struct socket_address *srvaddr;
     192             :         struct resolve_context *resolve_ctx;
     193             :         struct dcecli_connection *conn;
     194             :         struct nbt_name name;
     195             :         char *local_address;
     196             :         char *remote_address;
     197             : };
     198             : 
     199             : 
     200             : static void continue_ip_open_socket(struct composite_context *ctx);
     201             : static void continue_ip_resolve_name(struct composite_context *ctx);
     202             : 
     203       15349 : static void continue_ip_resolve_name(struct composite_context *ctx)
     204             : {
     205       15349 :         struct composite_context *c = talloc_get_type_abort(
     206             :                 ctx->async.private_data, struct composite_context);
     207       15349 :         struct pipe_tcp_state *s = talloc_get_type_abort(
     208             :                 c->private_data, struct pipe_tcp_state);
     209         242 :         struct composite_context *sock_ip_req;
     210             : 
     211       15349 :         c->status = resolve_name_multiple_recv(ctx, s, &s->addresses);
     212       15349 :         if (!composite_is_ok(c)) return;
     213             : 
     214             :         /* prepare server address using host ip:port and transport name */
     215       10855 :         s->srvaddr = socket_address_from_strings(s->conn, "ip", s->addresses[s->index], s->port);
     216       10855 :         s->index++;
     217       10855 :         if (composite_nomem(s->srvaddr, c)) return;
     218             : 
     219       10855 :         sock_ip_req = dcerpc_pipe_open_socket_send(c, s->conn, s->localaddr,
     220             :                                                      s->srvaddr, s->target_hostname,
     221             :                                                      NULL,
     222             :                                                      NCACN_IP_TCP);
     223       10855 :         composite_continue(c, sock_ip_req, continue_ip_open_socket, c);
     224             : }
     225             : 
     226             : 
     227             : /*
     228             :   Stage 2 of dcerpc_pipe_open_tcp_send: receive result of pipe open request
     229             :   on IP transport.
     230             : */
     231       10855 : static void continue_ip_open_socket(struct composite_context *ctx)
     232             : {
     233       10855 :         struct composite_context *c = talloc_get_type_abort(
     234             :                 ctx->async.private_data, struct composite_context);
     235       10855 :         struct pipe_tcp_state *s = talloc_get_type_abort(
     236             :                 c->private_data, struct pipe_tcp_state);
     237       10855 :         struct socket_address *localaddr = NULL;
     238             : 
     239             :         /* receive result socket open request */
     240       10855 :         c->status = dcerpc_pipe_open_socket_recv(ctx, s, &localaddr);
     241       10855 :         if (!NT_STATUS_IS_OK(c->status)) {
     242             :                 /* something went wrong... */
     243           0 :                 DBG_NOTICE("Failed to connect host %s (%s) on port %d - %s.\n",
     244             :                           s->addresses[s->index - 1], s->target_hostname,
     245             :                           s->port, nt_errstr(c->status));
     246           0 :                 if (s->addresses[s->index]) {
     247           0 :                         struct composite_context *sock_ip_req;
     248           0 :                         talloc_free(s->srvaddr);
     249             :                         /* prepare server address using host ip:port and transport name */
     250           0 :                         s->srvaddr = socket_address_from_strings(s->conn, "ip", s->addresses[s->index], s->port);
     251           0 :                         s->index++;
     252           0 :                         if (composite_nomem(s->srvaddr, c)) return;
     253             : 
     254           0 :                         sock_ip_req = dcerpc_pipe_open_socket_send(c, s->conn, s->localaddr,
     255             :                                                                 s->srvaddr, s->target_hostname,
     256             :                                                                 NULL,
     257             :                                                                 NCACN_IP_TCP);
     258           0 :                         composite_continue(c, sock_ip_req, continue_ip_open_socket, c);
     259             : 
     260           0 :                         return;
     261             :                 } else {
     262           0 :                         composite_error(c, c->status);
     263           0 :                         return;
     264             :                 }
     265             :         }
     266             : 
     267       10855 :         s->local_address = talloc_strdup(s, localaddr->addr);
     268       10855 :         if (composite_nomem(s->local_address, c)) return;
     269       10855 :         s->remote_address = talloc_strdup(s, s->addresses[s->index - 1]);
     270       10855 :         if (composite_nomem(s->remote_address, c)) return;
     271             : 
     272       10855 :         composite_done(c);
     273             : }
     274             : 
     275             : /*
     276             :   Send rpc pipe open request to given host:port using
     277             :   tcp/ip transport
     278             : */
     279       15350 : struct composite_context* dcerpc_pipe_open_tcp_send(struct dcecli_connection *conn,
     280             :                                                     const char *localaddr,
     281             :                                                     const char *server,
     282             :                                                     const char *target_hostname,
     283             :                                                     uint32_t port,
     284             :                                                     struct resolve_context *resolve_ctx)
     285             : {
     286         242 :         struct composite_context *c;
     287         242 :         struct pipe_tcp_state *s;
     288         242 :         struct composite_context *resolve_req;
     289             : 
     290             :         /* composite context allocation and setup */
     291       15350 :         c = composite_create(conn, conn->event_ctx);
     292       15350 :         if (c == NULL) return NULL;
     293             : 
     294       15350 :         s = talloc_zero(c, struct pipe_tcp_state);
     295       15350 :         if (composite_nomem(s, c)) return c;
     296       15350 :         c->private_data = s;
     297             : 
     298             :         /* store input parameters in state structure */
     299       15350 :         s->server          = talloc_strdup(c, server);
     300       15350 :         if (composite_nomem(s->server, c)) return c;
     301       15350 :         if (target_hostname) {
     302       15350 :                 s->target_hostname = talloc_strdup(c, target_hostname);
     303       15350 :                 if (composite_nomem(s->target_hostname, c)) return c;
     304             :         }
     305       15350 :         s->port            = port;
     306       15350 :         s->conn            = conn;
     307       15350 :         s->resolve_ctx     = resolve_ctx;
     308       15350 :         if (localaddr) {
     309         480 :                 s->localaddr = socket_address_from_strings(s, "ip", localaddr, 0);
     310             :                 /* if there is no localaddr, we pass NULL for
     311             :                    s->localaddr, which is handled by the socket libraries as
     312             :                    meaning no local binding address specified */
     313             :         }
     314             : 
     315       15350 :         make_nbt_name_server(&s->name, s->server);
     316       15350 :         resolve_req = resolve_name_send(resolve_ctx, s, &s->name, c->event_ctx);
     317       15350 :         composite_continue(c, resolve_req, continue_ip_resolve_name, c);
     318       15350 :         return c;
     319             : }
     320             : 
     321             : /*
     322             :   Receive result of pipe open request on tcp/ip
     323             : */
     324       15349 : NTSTATUS dcerpc_pipe_open_tcp_recv(struct composite_context *c,
     325             :                                    TALLOC_CTX *mem_ctx,
     326             :                                    char **localaddr,
     327             :                                    char **remoteaddr)
     328             : {
     329         242 :         NTSTATUS status;
     330       15349 :         status = composite_wait(c);
     331             : 
     332       15349 :         if (NT_STATUS_IS_OK(status)) {
     333       10855 :                 struct pipe_tcp_state *s = talloc_get_type_abort(
     334             :                         c->private_data, struct pipe_tcp_state);
     335             : 
     336       10855 :                 if (localaddr != NULL) {
     337       10855 :                         *localaddr = talloc_move(mem_ctx, &s->local_address);
     338             :                 }
     339       10855 :                 if (remoteaddr != NULL) {
     340       10855 :                         *remoteaddr = talloc_move(mem_ctx, &s->remote_address);
     341             :                 }
     342             :         }
     343             : 
     344       15349 :         talloc_free(c);
     345       15349 :         return status;
     346             : }
     347             : 
     348             : 
     349             : struct pipe_unix_state {
     350             :         const char *path;
     351             :         struct socket_address *srvaddr;
     352             :         struct dcecli_connection *conn;
     353             : };
     354             : 
     355             : 
     356             : /*
     357             :   Stage 2 of dcerpc_pipe_open_unix_stream_send: receive result of pipe open
     358             :   request on unix socket.
     359             : */
     360           0 : static void continue_unix_open_socket(struct composite_context *ctx)
     361             : {
     362           0 :         struct composite_context *c = talloc_get_type_abort(
     363             :                 ctx->async.private_data, struct composite_context);
     364             : 
     365           0 :         c->status = dcerpc_pipe_open_socket_recv(ctx, NULL, NULL);
     366           0 :         if (NT_STATUS_IS_OK(c->status)) {
     367           0 :                 composite_done(c);
     368           0 :                 return;
     369             :         }
     370             : 
     371           0 :         composite_error(c, c->status);
     372             : }
     373             : 
     374             : 
     375             : /*
     376             :   Send pipe open request on unix socket
     377             : */
     378           0 : struct composite_context *dcerpc_pipe_open_unix_stream_send(struct dcecli_connection *conn,
     379             :                                                             const char *path)
     380             : {
     381           0 :         struct composite_context *c;
     382           0 :         struct composite_context *sock_unix_req;
     383           0 :         struct pipe_unix_state *s;
     384             : 
     385             :         /* composite context allocation and setup */
     386           0 :         c = composite_create(conn, conn->event_ctx);
     387           0 :         if (c == NULL) return NULL;
     388             : 
     389           0 :         s = talloc_zero(c, struct pipe_unix_state);
     390           0 :         if (composite_nomem(s, c)) return c;
     391           0 :         c->private_data = s;
     392             : 
     393             :         /* store parameters in state structure */
     394           0 :         s->path = talloc_strdup(c, path);
     395           0 :         if (composite_nomem(s->path, c)) return c;
     396           0 :         s->conn = conn;
     397             : 
     398             :         /* prepare server address using socket path and transport name */
     399           0 :         s->srvaddr = socket_address_from_strings(conn, "unix", s->path, 0);
     400           0 :         if (composite_nomem(s->srvaddr, c)) return c;
     401             : 
     402             :         /* send socket open request */
     403           0 :         sock_unix_req = dcerpc_pipe_open_socket_send(c, s->conn, NULL,
     404             :                                                      s->srvaddr, NULL,
     405             :                                                      s->path,
     406             :                                                      NCALRPC);
     407           0 :         composite_continue(c, sock_unix_req, continue_unix_open_socket, c);
     408           0 :         return c;
     409             : }
     410             : 
     411             : 
     412             : /*
     413             :   Receive result of pipe open request on unix socket
     414             : */
     415           0 : NTSTATUS dcerpc_pipe_open_unix_stream_recv(struct composite_context *c)
     416             : {
     417           0 :         NTSTATUS status = composite_wait(c);
     418             : 
     419           0 :         talloc_free(c);
     420           0 :         return status;
     421             : }
     422             : 
     423             : 
     424             : /*
     425             :   Stage 2 of dcerpc_pipe_open_pipe_send: receive socket open request
     426             : */
     427        1452 : static void continue_np_open_socket(struct composite_context *ctx)
     428             : {
     429        1452 :         struct composite_context *c = talloc_get_type_abort(
     430             :                 ctx->async.private_data, struct composite_context);
     431             : 
     432        1452 :         c->status = dcerpc_pipe_open_socket_recv(ctx, NULL, NULL);
     433        1452 :         if (!composite_is_ok(c)) return;
     434             : 
     435        1452 :         composite_done(c);
     436             : }
     437             : 
     438             : 
     439             : /*
     440             :   Send pipe open request on ncalrpc
     441             : */
     442        1452 : struct composite_context* dcerpc_pipe_open_pipe_send(struct dcecli_connection *conn,
     443             :                                                      const char *ncalrpc_dir,
     444             :                                                      const char *identifier)
     445             : {
     446        1452 :         char *canon = NULL;
     447             : 
     448           8 :         struct composite_context *c;
     449           8 :         struct composite_context *sock_np_req;
     450           8 :         struct pipe_unix_state *s;
     451             : 
     452             :         /* composite context allocation and setup */
     453        1452 :         c = composite_create(conn, conn->event_ctx);
     454        1452 :         if (c == NULL) return NULL;
     455             : 
     456        1452 :         s = talloc_zero(c, struct pipe_unix_state);
     457        1452 :         if (composite_nomem(s, c)) return c;
     458        1452 :         c->private_data = s;
     459             : 
     460             :         /* store parameters in state structure */
     461        1452 :         canon = talloc_strdup(s, identifier);
     462        1452 :         if (composite_nomem(canon, c)) return c;
     463        1452 :         s->conn = conn;
     464             : 
     465        1452 :         string_replace(canon, '/', '\\');
     466        1452 :         s->path = talloc_asprintf(canon, "%s/%s", ncalrpc_dir, canon);
     467        1452 :         if (composite_nomem(s->path, c)) return c;
     468             : 
     469             :         /* prepare server address using path and transport name */
     470        1452 :         s->srvaddr = socket_address_from_strings(conn, "unix", s->path, 0);
     471        1452 :         if (composite_nomem(s->srvaddr, c)) return c;
     472             : 
     473             :         /* send socket open request */
     474        1452 :         sock_np_req = dcerpc_pipe_open_socket_send(c, s->conn, NULL, s->srvaddr, NULL, s->path, NCALRPC);
     475        1452 :         composite_continue(c, sock_np_req, continue_np_open_socket, c);
     476        1452 :         return c;
     477             : }
     478             : 
     479             : 
     480             : /*
     481             :   Receive result of pipe open request on ncalrpc
     482             : */
     483         182 : NTSTATUS dcerpc_pipe_open_pipe_recv(struct composite_context *c)
     484             : {
     485         182 :         NTSTATUS status = composite_wait(c);
     486             :         
     487         182 :         talloc_free(c);
     488         182 :         return status;
     489             : }
     490             : 
     491             : 
     492             : /*
     493             :   Open a rpc pipe on a named pipe - sync version
     494             : */
     495           0 : NTSTATUS dcerpc_pipe_open_pipe(struct dcecli_connection *conn, const char *ncalrpc_dir, const char *identifier)
     496             : {
     497           0 :         struct composite_context *c = dcerpc_pipe_open_pipe_send(conn, ncalrpc_dir, identifier);
     498           0 :         return dcerpc_pipe_open_pipe_recv(c);
     499             : }

Generated by: LCOV version 1.14