LCOV - code coverage report
Current view: top level - source4/libcli/smb_composite - connect.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 170 236 72.0 %
Date: 2024-04-21 15:09:00 Functions: 13 14 92.9 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Copyright (C) Andrew Tridgell 2005
       5             :    
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             :    
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             :    
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : /*
      20             :   a composite API for making a full SMB connection
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include "libcli/raw/libcliraw.h"
      25             : #include "libcli/raw/raw_proto.h"
      26             : #include "libcli/composite/composite.h"
      27             : #include "libcli/smb_composite/smb_composite.h"
      28             : #include "lib/events/events.h"
      29             : #include "libcli/resolve/resolve.h"
      30             : #include "auth/credentials/credentials.h"
      31             : #include "librpc/gen_ndr/ndr_nbt.h"
      32             : #include "param/param.h"
      33             : #include "lib/util/util_net.h"
      34             : #include "libcli/smb/smbXcli_base.h"
      35             : 
      36             : /* the stages of this call */
      37             : enum connect_stage {CONNECT_SOCKET, 
      38             :                     CONNECT_NEGPROT,
      39             :                     CONNECT_SESSION_SETUP,
      40             :                     CONNECT_SESSION_SETUP_ANON,
      41             :                     CONNECT_TCON,
      42             :                     CONNECT_DONE
      43             : };
      44             : 
      45             : struct connect_state {
      46             :         enum connect_stage stage;
      47             :         struct smbcli_socket *sock;
      48             :         struct smbcli_transport *transport;
      49             :         struct smbcli_session *session;
      50             :         struct smb_composite_connect *io;
      51             :         union smb_tcon *io_tcon;
      52             :         struct smb_composite_sesssetup *io_setup;
      53             :         struct smbcli_request *req;
      54             :         struct composite_context *creq;
      55             :         struct tevent_req *subreq;
      56             :         struct nbt_name calling, called;
      57             : };
      58             : 
      59             : 
      60             : static void request_handler(struct smbcli_request *);
      61             : static void composite_handler(struct composite_context *);
      62             : static void subreq_handler(struct tevent_req *subreq);
      63             : 
      64             : /*
      65             :   a tree connect request has completed
      66             : */
      67        2741 : static NTSTATUS connect_tcon(struct composite_context *c, 
      68             :                              struct smb_composite_connect *io)
      69             : {
      70        2741 :         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
      71         133 :         NTSTATUS status;
      72             : 
      73        2741 :         status = smb_raw_tcon_recv(state->req, c, state->io_tcon);
      74        2741 :         NT_STATUS_NOT_OK_RETURN(status);
      75             : 
      76        2741 :         if (state->io_tcon->tconx.out.options & SMB_EXTENDED_SIGNATURES) {
      77        1879 :                 smb1cli_session_protect_session_key(io->out.tree->session->smbXcli);
      78             :         }
      79             : 
      80        2741 :         io->out.tree->tid = state->io_tcon->tconx.out.tid;
      81        2741 :         if (state->io_tcon->tconx.out.dev_type) {
      82        2741 :                 io->out.tree->device = talloc_strdup(io->out.tree, 
      83        2608 :                                                      state->io_tcon->tconx.out.dev_type);
      84             :         }
      85        2741 :         if (state->io_tcon->tconx.out.fs_type) {
      86        2741 :                 io->out.tree->fs_type = talloc_strdup(io->out.tree, 
      87        2608 :                                                       state->io_tcon->tconx.out.fs_type);
      88             :         }
      89             : 
      90        2741 :         state->stage = CONNECT_DONE;
      91             : 
      92        2741 :         return NT_STATUS_OK;
      93             : }
      94             : 
      95             : 
      96             : /*
      97             :   a session setup request with anonymous fallback has completed
      98             : */
      99           0 : static NTSTATUS connect_session_setup_anon(struct composite_context *c, 
     100             :                                            struct smb_composite_connect *io)
     101             : {
     102           0 :         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
     103           0 :         NTSTATUS status;
     104             : 
     105           0 :         status = smb_composite_sesssetup_recv(state->creq);
     106           0 :         NT_STATUS_NOT_OK_RETURN(status);
     107             : 
     108           0 :         io->out.anonymous_fallback_done = true;
     109             :         
     110           0 :         state->session->vuid = state->io_setup->out.vuid;
     111             :         
     112             :         /* setup for a tconx */
     113           0 :         state->io_tcon = talloc(c, union smb_tcon);
     114           0 :         NT_STATUS_HAVE_NO_MEMORY(state->io_tcon);
     115             : 
     116             :         /* connect to a share using a tree connect */
     117           0 :         state->io_tcon->generic.level = RAW_TCON_TCONX;
     118           0 :         state->io_tcon->tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
     119           0 :         state->io_tcon->tconx.in.password = data_blob(NULL, 0);   
     120             :         
     121           0 :         state->io_tcon->tconx.in.path = talloc_asprintf(state->io_tcon, 
     122             :                                                  "\\\\%s\\%s", 
     123             :                                                  io->in.called_name, 
     124             :                                                  io->in.service);
     125           0 :         NT_STATUS_HAVE_NO_MEMORY(state->io_tcon->tconx.in.path);
     126           0 :         if (!io->in.service_type) {
     127           0 :                 state->io_tcon->tconx.in.device = "?????";
     128             :         } else {
     129           0 :                 state->io_tcon->tconx.in.device = io->in.service_type;
     130             :         }
     131             : 
     132           0 :         state->req = smb_raw_tcon_send(io->out.tree, state->io_tcon);
     133           0 :         NT_STATUS_HAVE_NO_MEMORY(state->req);
     134           0 :         if (state->req->state == SMBCLI_REQUEST_ERROR) {
     135           0 :                 return state->req->status;
     136             :         }
     137             : 
     138           0 :         state->req->async.fn = request_handler;
     139           0 :         state->req->async.private_data = c;
     140           0 :         state->stage = CONNECT_TCON;
     141             : 
     142           0 :         return NT_STATUS_OK;
     143             : }
     144             : 
     145             : /*
     146             :   a session setup request has completed
     147             : */
     148        2747 : static NTSTATUS connect_session_setup(struct composite_context *c, 
     149             :                                       struct smb_composite_connect *io)
     150             : {
     151        2747 :         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
     152         133 :         NTSTATUS status;
     153             : 
     154        2747 :         status = smb_composite_sesssetup_recv(state->creq);
     155             : 
     156        2747 :         if (!NT_STATUS_IS_OK(status) &&
     157           6 :             !cli_credentials_is_anonymous(state->io->in.credentials) &&
     158           6 :             io->in.fallback_to_anonymous) {
     159             : 
     160           0 :                 state->io_setup->in.credentials = cli_credentials_init(state);
     161           0 :                 NT_STATUS_HAVE_NO_MEMORY(state->io_setup->in.credentials);
     162           0 :                 cli_credentials_set_workstation(state->io_setup->in.credentials,
     163           0 :                    cli_credentials_get_workstation(state->io->in.credentials), 
     164             :                    CRED_SPECIFIED);
     165           0 :                 cli_credentials_set_anonymous(state->io_setup->in.credentials);
     166             : 
     167             :                 /* If the preceding attempt was with extended security, we
     168             :                  * have been given a uid in the NTLMSSP_CHALLENGE reply. This
     169             :                  * would lead to an invalid uid in the anonymous fallback */
     170           0 :                 state->session->vuid = 0;
     171           0 :                 talloc_free(state->session->gensec);
     172           0 :                 state->session->gensec = NULL;
     173             : 
     174           0 :                 state->creq = smb_composite_sesssetup_send(state->session,
     175             :                                                            state->io_setup);
     176           0 :                 NT_STATUS_HAVE_NO_MEMORY(state->creq);
     177           0 :                 if (state->creq->state == COMPOSITE_STATE_ERROR) {
     178           0 :                         return state->creq->status;
     179             :                 }
     180           0 :                 state->creq->async.fn = composite_handler;
     181           0 :                 state->creq->async.private_data = c;
     182           0 :                 state->stage = CONNECT_SESSION_SETUP_ANON;
     183             : 
     184           0 :                 return NT_STATUS_OK;
     185             :         }
     186             : 
     187        2747 :         NT_STATUS_NOT_OK_RETURN(status);
     188             :         
     189        2741 :         state->session->vuid = state->io_setup->out.vuid;
     190             :         
     191             :         /* If we don't have a remote share name then this indicates that
     192             :          * we don't want to do a tree connect */
     193        2741 :         if (!io->in.service) {
     194           0 :                 state->stage = CONNECT_DONE;
     195           0 :                 return NT_STATUS_OK;
     196             :         }
     197             : 
     198        2741 :         state->io_tcon = talloc(c, union smb_tcon);
     199        2741 :         NT_STATUS_HAVE_NO_MEMORY(state->io_tcon);
     200             : 
     201             :         /* connect to a share using a tree connect */
     202        2741 :         state->io_tcon->generic.level = RAW_TCON_TCONX;
     203        2741 :         state->io_tcon->tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
     204        2741 :         state->io_tcon->tconx.in.flags |= TCONX_FLAG_EXTENDED_SIGNATURES;
     205        2741 :         state->io_tcon->tconx.in.password = data_blob(NULL, 0);   
     206             :         
     207        2741 :         state->io_tcon->tconx.in.path = talloc_asprintf(state->io_tcon, 
     208             :                                                  "\\\\%s\\%s", 
     209             :                                                  io->in.called_name, 
     210             :                                                  io->in.service);
     211        2741 :         NT_STATUS_HAVE_NO_MEMORY(state->io_tcon->tconx.in.path);
     212        2741 :         if (!io->in.service_type) {
     213        2481 :                 state->io_tcon->tconx.in.device = "?????";
     214             :         } else {
     215         260 :                 state->io_tcon->tconx.in.device = io->in.service_type;
     216             :         }
     217             : 
     218        2741 :         state->req = smb_raw_tcon_send(io->out.tree, state->io_tcon);
     219        2741 :         NT_STATUS_HAVE_NO_MEMORY(state->req);
     220        2741 :         if (state->req->state == SMBCLI_REQUEST_ERROR) {
     221           0 :                 return state->req->status;
     222             :         }
     223             : 
     224        2741 :         state->req->async.fn = request_handler;
     225        2741 :         state->req->async.private_data = c;
     226        2741 :         state->stage = CONNECT_TCON;
     227             : 
     228        2741 :         return NT_STATUS_OK;
     229             : }
     230             : 
     231        2749 : static NTSTATUS connect_send_session(struct composite_context *c,
     232             :                                      struct smb_composite_connect *io)
     233             : {
     234        2749 :         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
     235             : 
     236             :         /* next step is a session setup */
     237        2749 :         state->session = smbcli_session_init(state->transport, state, true, io->in.session_options);
     238        2749 :         NT_STATUS_HAVE_NO_MEMORY(state->session);
     239             :         
     240             :         /* setup for a tconx (or at least have the structure ready to
     241             :          * return, if we won't go that far) */
     242        2749 :         io->out.tree = smbcli_tree_init(state->session, state, true);
     243        2749 :         NT_STATUS_HAVE_NO_MEMORY(io->out.tree);
     244             : 
     245             :         /* If we don't have any credentials then this indicates that
     246             :          * we don't want to do a session setup */
     247        2749 :         if (!io->in.credentials) {
     248           0 :                 state->stage = CONNECT_DONE;
     249           0 :                 return NT_STATUS_OK;
     250             :         }
     251             : 
     252        2749 :         state->io_setup = talloc(c, struct smb_composite_sesssetup);
     253        2749 :         NT_STATUS_HAVE_NO_MEMORY(state->io_setup);
     254             : 
     255             :         /* prepare a session setup to establish a security context */
     256        2749 :         state->io_setup->in.sesskey      = state->transport->negotiate.sesskey;
     257        2749 :         state->io_setup->in.capabilities = state->transport->negotiate.capabilities;
     258        2749 :         state->io_setup->in.credentials  = io->in.credentials;
     259        2749 :         state->io_setup->in.workgroup    = io->in.workgroup;
     260        2749 :         state->io_setup->in.gensec_settings = io->in.gensec_settings;
     261             : 
     262        2749 :         state->creq = smb_composite_sesssetup_send(state->session, state->io_setup);
     263        2749 :         NT_STATUS_HAVE_NO_MEMORY(state->creq);
     264        2749 :         if (state->creq->state == COMPOSITE_STATE_ERROR) {
     265           2 :                 return state->creq->status;
     266             :         }
     267             : 
     268        2747 :         state->creq->async.fn = composite_handler;
     269        2747 :         state->creq->async.private_data = c;
     270             : 
     271        2747 :         state->stage = CONNECT_SESSION_SETUP;
     272             :         
     273        2747 :         return NT_STATUS_OK;
     274             : }
     275             : 
     276             : /*
     277             :   a negprot request has completed
     278             : */
     279        2831 : static NTSTATUS connect_negprot(struct composite_context *c,
     280             :                                 struct smb_composite_connect *io)
     281             : {
     282        2831 :         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
     283         141 :         NTSTATUS status;
     284             : 
     285        2831 :         status = smb_raw_negotiate_recv(state->subreq);
     286        2831 :         TALLOC_FREE(state->subreq);
     287        2831 :         NT_STATUS_NOT_OK_RETURN(status);
     288             : 
     289        2723 :         return connect_send_session(c, io);
     290             : }
     291             : 
     292             : /*
     293             :   setup a negprot send 
     294             : */
     295        2831 : static NTSTATUS connect_send_negprot(struct composite_context *c, 
     296             :                                      struct smb_composite_connect *io)
     297             : {
     298        2831 :         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
     299             : 
     300             :         /* the socket is up - we can initialise the smbcli transport layer */
     301        2831 :         state->transport = smbcli_transport_init(state->sock, state, true,
     302             :                                                  &io->in.options);
     303        2831 :         NT_STATUS_HAVE_NO_MEMORY(state->transport);
     304             : 
     305        5521 :         state->subreq = smb_raw_negotiate_send(state,
     306        2690 :                                                state->transport->ev,
     307             :                                                state->transport,
     308        2690 :                                                state->transport->options.min_protocol,
     309        2690 :                                                state->transport->options.max_protocol);
     310        2831 :         NT_STATUS_HAVE_NO_MEMORY(state->subreq);
     311        2831 :         tevent_req_set_callback(state->subreq, subreq_handler, c);
     312        2831 :         state->stage = CONNECT_NEGPROT;
     313             : 
     314        2831 :         return NT_STATUS_OK;
     315             : }
     316             : 
     317             : /*
     318             :   a socket connection operation has completed
     319             : */
     320        2831 : static NTSTATUS connect_socket(struct composite_context *c, 
     321             :                                struct smb_composite_connect *io)
     322             : {
     323        2831 :         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
     324         141 :         NTSTATUS status;
     325             : 
     326        2831 :         status = smbcli_sock_connect_recv(state->creq, state, &state->sock);
     327        2831 :         NT_STATUS_NOT_OK_RETURN(status);
     328             : 
     329        2831 :         if (is_ipaddress(state->sock->hostname) &&
     330        1104 :             (state->io->in.called_name != NULL)) {
     331             :                 /* If connecting to an IP address, we might want the real name
     332             :                  * of the host for later kerberos. The called name is a better
     333             :                  * approximation */
     334        2208 :                 state->sock->hostname =
     335        1104 :                         talloc_strdup(state->sock, io->in.called_name);
     336        1104 :                 NT_STATUS_HAVE_NO_MEMORY(state->sock->hostname);
     337             :         }
     338             : 
     339             :         /* next step is a negprot */
     340        2831 :         return connect_send_negprot(c, io);
     341             : }
     342             : 
     343             : 
     344             : /*
     345             :   handle and dispatch state transitions
     346             : */
     347       11150 : static void state_handler(struct composite_context *c)
     348             : {
     349       11150 :         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
     350             : 
     351       11150 :         switch (state->stage) {
     352        2831 :         case CONNECT_SOCKET:
     353        2831 :                 c->status = connect_socket(c, state->io);
     354        2831 :                 break;
     355        2831 :         case CONNECT_NEGPROT:
     356        2831 :                 c->status = connect_negprot(c, state->io);
     357        2831 :                 break;
     358        2747 :         case CONNECT_SESSION_SETUP:
     359        2747 :                 c->status = connect_session_setup(c, state->io);
     360        2747 :                 break;
     361           0 :         case CONNECT_SESSION_SETUP_ANON:
     362           0 :                 c->status = connect_session_setup_anon(c, state->io);
     363           0 :                 break;
     364        2741 :         case CONNECT_TCON:
     365        2741 :                 c->status = connect_tcon(c, state->io);
     366        2741 :                 break;
     367           0 :         case CONNECT_DONE:
     368           0 :                 break;
     369             :         }
     370             : 
     371       11150 :         if (state->stage == CONNECT_DONE) {
     372             :                 /* all done! */
     373        2741 :                 composite_done(c);
     374             :         } else {
     375        8409 :                 composite_is_ok(c);
     376             :         }
     377       11150 : }
     378             : 
     379             : 
     380             : /*
     381             :   handler for completion of a smbcli_request sub-request
     382             : */
     383        2741 : static void request_handler(struct smbcli_request *req)
     384             : {
     385        2741 :         struct composite_context *c = talloc_get_type(req->async.private_data,
     386             :                                                      struct composite_context);
     387        2741 :         state_handler(c);
     388        2741 : }
     389             : 
     390             : /*
     391             :   handler for completion of a smbcli_composite sub-request
     392             : */
     393        5578 : static void composite_handler(struct composite_context *creq)
     394             : {
     395        5578 :         struct composite_context *c = talloc_get_type(creq->async.private_data, 
     396             :                                                      struct composite_context);
     397        5578 :         state_handler(c);
     398        5578 : }
     399             : 
     400             : /*
     401             :   handler for completion of a tevent_req sub-request
     402             : */
     403        2831 : static void subreq_handler(struct tevent_req *subreq)
     404             : {
     405         141 :         struct composite_context *c =
     406        2831 :                 tevent_req_callback_data(subreq,
     407             :                 struct composite_context);
     408        2831 :         state_handler(c);
     409        2831 : }
     410             : 
     411             : /*
     412             :   a function to establish a smbcli_tree from scratch
     413             : */
     414        2857 : struct composite_context *smb_composite_connect_send(struct smb_composite_connect *io,
     415             :                                                      TALLOC_CTX *mem_ctx,
     416             :                                                      struct resolve_context *resolve_ctx,
     417             :                                                      struct tevent_context *event_ctx)
     418             : {
     419         141 :         struct composite_context *c;
     420         141 :         struct connect_state *state;
     421             : 
     422        2857 :         c = talloc_zero(mem_ctx, struct composite_context);
     423        2857 :         if (c == NULL) {
     424           0 :                 goto nomem;
     425             :         }
     426             : 
     427        2857 :         state = talloc_zero(c, struct connect_state);
     428        2857 :         if (state == NULL) {
     429           0 :                 goto nomem;
     430             :         }
     431             : 
     432        2857 :         c->event_ctx = event_ctx;
     433        2857 :         if (c->event_ctx == NULL) {
     434           0 :                 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
     435           0 :                 return c;
     436             :         }
     437             : 
     438        2857 :         if (io->in.gensec_settings == NULL) {
     439           0 :                 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
     440           0 :                 return c;
     441             :         }
     442        2857 :         state->io = io;
     443             : 
     444        2857 :         c->state = COMPOSITE_STATE_IN_PROGRESS;
     445        2857 :         c->private_data = state;
     446             : 
     447        2857 :         make_nbt_name_client(&state->calling,
     448             :                              cli_credentials_get_workstation(io->in.credentials));
     449             : 
     450        2857 :         nbt_choose_called_name(state, &state->called,
     451             :                                io->in.called_name, NBT_NAME_SERVER);
     452             : 
     453        2857 :         if (io->in.existing_conn != NULL) {
     454           0 :                 NTSTATUS status;
     455             : 
     456          26 :                 status = smbcli_transport_raw_init(state,
     457             :                                                    c->event_ctx,
     458             :                                                    &io->in.existing_conn,
     459          26 :                                                    &io->in.options,
     460             :                                                    &state->transport);
     461          26 :                 if (!NT_STATUS_IS_OK(status)) {
     462           0 :                         composite_error(c, status);
     463           0 :                         return c;
     464             :                 }
     465             : 
     466          26 :                 status = connect_send_session(c, io);
     467          26 :                 if (!NT_STATUS_IS_OK(status)) {
     468           2 :                         composite_error(c, status);
     469           2 :                         return c;
     470             :                 }
     471             : 
     472          24 :                 return c;
     473             :         }
     474             : 
     475        2831 :         state->creq = smbcli_sock_connect_send(state, 
     476             :                                                NULL,
     477             :                                                io->in.dest_ports,
     478             :                                                io->in.dest_host, 
     479             :                                                resolve_ctx, c->event_ctx, 
     480             :                                                io->in.socket_options,
     481             :                                                &state->calling,
     482             :                                                &state->called);
     483        2831 :         if (state->creq == NULL) {
     484           0 :                 composite_error(c, NT_STATUS_NO_MEMORY);
     485           0 :                 return c;
     486             :         }
     487             : 
     488        2831 :         state->stage = CONNECT_SOCKET;
     489        2831 :         state->creq->async.private_data = c;
     490        2831 :         state->creq->async.fn = composite_handler;
     491             : 
     492        2831 :         return c;
     493           0 : nomem:
     494           0 :         TALLOC_FREE(c);
     495           0 :         return NULL;
     496             : }
     497             : 
     498             : /*
     499             :   recv half of async composite connect code
     500             : */
     501        2857 : NTSTATUS smb_composite_connect_recv(struct composite_context *c, TALLOC_CTX *mem_ctx)
     502             : {
     503         141 :         NTSTATUS status;
     504             : 
     505        2857 :         status = composite_wait(c);
     506             : 
     507        2857 :         if (NT_STATUS_IS_OK(status)) {
     508        2741 :                 struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
     509        2741 :                 talloc_steal(mem_ctx, state->io->out.tree);
     510             :         }
     511             : 
     512        2857 :         talloc_free(c);
     513        2857 :         return status;
     514             : }
     515             : 
     516             : /*
     517             :   sync version of smb_composite_connect 
     518             : */
     519        2575 : NTSTATUS smb_composite_connect(struct smb_composite_connect *io, TALLOC_CTX *mem_ctx,
     520             :                                struct resolve_context *resolve_ctx,
     521             :                                struct tevent_context *ev)
     522             : {
     523        2575 :         struct composite_context *c = smb_composite_connect_send(io, mem_ctx, resolve_ctx, ev);
     524        2575 :         if (c == NULL) {
     525           0 :                 return NT_STATUS_NO_MEMORY;
     526             :         }
     527        2575 :         return smb_composite_connect_recv(c, mem_ctx);
     528             : }

Generated by: LCOV version 1.14