LCOV - code coverage report
Current view: top level - source4/libcli/smb_composite - connect.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 150 227 66.1 %
Date: 2024-06-13 04:01:37 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         890 : static NTSTATUS connect_tcon(struct composite_context *c, 
      68             :                              struct smb_composite_connect *io)
      69             : {
      70         890 :         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
      71             :         NTSTATUS status;
      72             : 
      73         890 :         status = smb_raw_tcon_recv(state->req, c, state->io_tcon);
      74         890 :         NT_STATUS_NOT_OK_RETURN(status);
      75             : 
      76         890 :         if (state->io_tcon->tconx.out.options & SMB_EXTENDED_SIGNATURES) {
      77          18 :                 smb1cli_session_protect_session_key(io->out.tree->session->smbXcli);
      78             :         }
      79             : 
      80         890 :         io->out.tree->tid = state->io_tcon->tconx.out.tid;
      81         890 :         if (state->io_tcon->tconx.out.dev_type) {
      82         890 :                 io->out.tree->device = talloc_strdup(io->out.tree, 
      83         890 :                                                      state->io_tcon->tconx.out.dev_type);
      84             :         }
      85         890 :         if (state->io_tcon->tconx.out.fs_type) {
      86         890 :                 io->out.tree->fs_type = talloc_strdup(io->out.tree, 
      87         890 :                                                       state->io_tcon->tconx.out.fs_type);
      88             :         }
      89             : 
      90         890 :         state->stage = CONNECT_DONE;
      91             : 
      92         890 :         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             :         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         894 : static NTSTATUS connect_session_setup(struct composite_context *c, 
     149             :                                       struct smb_composite_connect *io)
     150             : {
     151         894 :         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
     152             :         NTSTATUS status;
     153             : 
     154         894 :         status = smb_composite_sesssetup_recv(state->creq);
     155             : 
     156         896 :         if (!NT_STATUS_IS_OK(status) &&
     157           6 :             !cli_credentials_is_anonymous(state->io->in.credentials) &&
     158           4 :             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         894 :         NT_STATUS_NOT_OK_RETURN(status);
     188             :         
     189         890 :         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         890 :         if (!io->in.service) {
     194           0 :                 state->stage = CONNECT_DONE;
     195           0 :                 return NT_STATUS_OK;
     196             :         }
     197             : 
     198         890 :         state->io_tcon = talloc(c, union smb_tcon);
     199         890 :         NT_STATUS_HAVE_NO_MEMORY(state->io_tcon);
     200             : 
     201             :         /* connect to a share using a tree connect */
     202         890 :         state->io_tcon->generic.level = RAW_TCON_TCONX;
     203         890 :         state->io_tcon->tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
     204         890 :         state->io_tcon->tconx.in.flags |= TCONX_FLAG_EXTENDED_SIGNATURES;
     205         890 :         state->io_tcon->tconx.in.password = data_blob(NULL, 0);   
     206             :         
     207         890 :         state->io_tcon->tconx.in.path = talloc_asprintf(state->io_tcon, 
     208             :                                                  "\\\\%s\\%s", 
     209             :                                                  io->in.called_name, 
     210             :                                                  io->in.service);
     211         890 :         NT_STATUS_HAVE_NO_MEMORY(state->io_tcon->tconx.in.path);
     212         890 :         if (!io->in.service_type) {
     213         710 :                 state->io_tcon->tconx.in.device = "?????";
     214             :         } else {
     215         180 :                 state->io_tcon->tconx.in.device = io->in.service_type;
     216             :         }
     217             : 
     218         890 :         state->req = smb_raw_tcon_send(io->out.tree, state->io_tcon);
     219         890 :         NT_STATUS_HAVE_NO_MEMORY(state->req);
     220         890 :         if (state->req->state == SMBCLI_REQUEST_ERROR) {
     221           0 :                 return state->req->status;
     222             :         }
     223             : 
     224         890 :         state->req->async.fn = request_handler;
     225         890 :         state->req->async.private_data = c;
     226         890 :         state->stage = CONNECT_TCON;
     227             : 
     228         890 :         return NT_STATUS_OK;
     229             : }
     230             : 
     231         894 : static NTSTATUS connect_send_session(struct composite_context *c,
     232             :                                      struct smb_composite_connect *io)
     233             : {
     234         894 :         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
     235             : 
     236             :         /* next step is a session setup */
     237         894 :         state->session = smbcli_session_init(state->transport, state, true, io->in.session_options);
     238         894 :         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         894 :         io->out.tree = smbcli_tree_init(state->session, state, true);
     243         894 :         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         894 :         if (!io->in.credentials) {
     248           0 :                 state->stage = CONNECT_DONE;
     249           0 :                 return NT_STATUS_OK;
     250             :         }
     251             : 
     252         894 :         state->io_setup = talloc(c, struct smb_composite_sesssetup);
     253         894 :         NT_STATUS_HAVE_NO_MEMORY(state->io_setup);
     254             : 
     255             :         /* prepare a session setup to establish a security context */
     256         894 :         state->io_setup->in.sesskey      = state->transport->negotiate.sesskey;
     257         894 :         state->io_setup->in.capabilities = state->transport->negotiate.capabilities;
     258         894 :         state->io_setup->in.credentials  = io->in.credentials;
     259         894 :         state->io_setup->in.workgroup    = io->in.workgroup;
     260         894 :         state->io_setup->in.gensec_settings = io->in.gensec_settings;
     261             : 
     262         894 :         state->creq = smb_composite_sesssetup_send(state->session, state->io_setup);
     263         894 :         NT_STATUS_HAVE_NO_MEMORY(state->creq);
     264         894 :         if (state->creq->state == COMPOSITE_STATE_ERROR) {
     265           0 :                 return state->creq->status;
     266             :         }
     267             : 
     268         894 :         state->creq->async.fn = composite_handler;
     269         894 :         state->creq->async.private_data = c;
     270             : 
     271         894 :         state->stage = CONNECT_SESSION_SETUP;
     272             :         
     273         894 :         return NT_STATUS_OK;
     274             : }
     275             : 
     276             : /*
     277             :   a negprot request has completed
     278             : */
     279         924 : static NTSTATUS connect_negprot(struct composite_context *c,
     280             :                                 struct smb_composite_connect *io)
     281             : {
     282         924 :         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
     283             :         NTSTATUS status;
     284             : 
     285         924 :         status = smb_raw_negotiate_recv(state->subreq);
     286         924 :         TALLOC_FREE(state->subreq);
     287         924 :         NT_STATUS_NOT_OK_RETURN(status);
     288             : 
     289         894 :         return connect_send_session(c, io);
     290             : }
     291             : 
     292             : /*
     293             :   setup a negprot send 
     294             : */
     295         924 : static NTSTATUS connect_send_negprot(struct composite_context *c, 
     296             :                                      struct smb_composite_connect *io)
     297             : {
     298         924 :         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         924 :         state->transport = smbcli_transport_init(state->sock, state, true,
     302             :                                                  &io->in.options);
     303         924 :         NT_STATUS_HAVE_NO_MEMORY(state->transport);
     304             : 
     305        2714 :         state->subreq = smb_raw_negotiate_send(state,
     306         924 :                                                state->transport->ev,
     307             :                                                state->transport,
     308         924 :                                                state->transport->options.min_protocol,
     309         924 :                                                state->transport->options.max_protocol);
     310         924 :         NT_STATUS_HAVE_NO_MEMORY(state->subreq);
     311         924 :         tevent_req_set_callback(state->subreq, subreq_handler, c);
     312         924 :         state->stage = CONNECT_NEGPROT;
     313             : 
     314         924 :         return NT_STATUS_OK;
     315             : }
     316             : 
     317             : /*
     318             :   a socket connection operation has completed
     319             : */
     320         924 : static NTSTATUS connect_socket(struct composite_context *c, 
     321             :                                struct smb_composite_connect *io)
     322             : {
     323         924 :         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
     324             :         NTSTATUS status;
     325             : 
     326         924 :         status = smbcli_sock_connect_recv(state->creq, state, &state->sock);
     327         924 :         NT_STATUS_NOT_OK_RETURN(status);
     328             : 
     329         924 :         if (is_ipaddress(state->sock->hostname) &&
     330           0 :             (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           0 :                 state->sock->hostname =
     335           0 :                         talloc_strdup(state->sock, io->in.called_name);
     336           0 :                 NT_STATUS_HAVE_NO_MEMORY(state->sock->hostname);
     337             :         }
     338             : 
     339             :         /* next step is a negprot */
     340         924 :         return connect_send_negprot(c, io);
     341             : }
     342             : 
     343             : 
     344             : /*
     345             :   handle and dispatch state transitions
     346             : */
     347        3632 : static void state_handler(struct composite_context *c)
     348             : {
     349        3632 :         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
     350             : 
     351        3632 :         switch (state->stage) {
     352         924 :         case CONNECT_SOCKET:
     353         924 :                 c->status = connect_socket(c, state->io);
     354         924 :                 break;
     355         924 :         case CONNECT_NEGPROT:
     356         924 :                 c->status = connect_negprot(c, state->io);
     357         924 :                 break;
     358         894 :         case CONNECT_SESSION_SETUP:
     359         894 :                 c->status = connect_session_setup(c, state->io);
     360         894 :                 break;
     361           0 :         case CONNECT_SESSION_SETUP_ANON:
     362           0 :                 c->status = connect_session_setup_anon(c, state->io);
     363           0 :                 break;
     364         890 :         case CONNECT_TCON:
     365         890 :                 c->status = connect_tcon(c, state->io);
     366         890 :                 break;
     367           0 :         case CONNECT_DONE:
     368           0 :                 break;
     369             :         }
     370             : 
     371        3632 :         if (state->stage == CONNECT_DONE) {
     372             :                 /* all done! */
     373         890 :                 composite_done(c);
     374             :         } else {
     375        2742 :                 composite_is_ok(c);
     376             :         }
     377        3632 : }
     378             : 
     379             : 
     380             : /*
     381             :   handler for completion of a smbcli_request sub-request
     382             : */
     383         890 : static void request_handler(struct smbcli_request *req)
     384             : {
     385         890 :         struct composite_context *c = talloc_get_type(req->async.private_data,
     386             :                                                      struct composite_context);
     387         890 :         state_handler(c);
     388         890 : }
     389             : 
     390             : /*
     391             :   handler for completion of a smbcli_composite sub-request
     392             : */
     393        1818 : static void composite_handler(struct composite_context *creq)
     394             : {
     395        1818 :         struct composite_context *c = talloc_get_type(creq->async.private_data, 
     396             :                                                      struct composite_context);
     397        1818 :         state_handler(c);
     398        1818 : }
     399             : 
     400             : /*
     401             :   handler for completion of a tevent_req sub-request
     402             : */
     403         924 : static void subreq_handler(struct tevent_req *subreq)
     404             : {
     405         866 :         struct composite_context *c =
     406         924 :                 tevent_req_callback_data(subreq,
     407             :                 struct composite_context);
     408         924 :         state_handler(c);
     409         924 : }
     410             : 
     411             : /*
     412             :   a function to establish a smbcli_tree from scratch
     413             : */
     414         932 : 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             :         struct composite_context *c;
     420             :         struct connect_state *state;
     421             : 
     422         932 :         c = talloc_zero(mem_ctx, struct composite_context);
     423         932 :         if (c == NULL) {
     424           0 :                 goto nomem;
     425             :         }
     426             : 
     427         932 :         state = talloc_zero(c, struct connect_state);
     428         932 :         if (state == NULL) {
     429           0 :                 goto nomem;
     430             :         }
     431             : 
     432         932 :         c->event_ctx = event_ctx;
     433         932 :         if (c->event_ctx == NULL) {
     434           0 :                 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
     435           0 :                 return c;
     436             :         }
     437             : 
     438         932 :         if (io->in.gensec_settings == NULL) {
     439           0 :                 composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
     440           0 :                 return c;
     441             :         }
     442         932 :         state->io = io;
     443             : 
     444         932 :         c->state = COMPOSITE_STATE_IN_PROGRESS;
     445         932 :         c->private_data = state;
     446             : 
     447         932 :         make_nbt_name_client(&state->calling,
     448             :                              cli_credentials_get_workstation(io->in.credentials));
     449             : 
     450         932 :         nbt_choose_called_name(state, &state->called,
     451             :                                io->in.called_name, NBT_NAME_SERVER);
     452             : 
     453         932 :         if (io->in.existing_conn != NULL) {
     454             :                 NTSTATUS status;
     455             : 
     456           0 :                 status = smbcli_transport_raw_init(state,
     457             :                                                    c->event_ctx,
     458             :                                                    &io->in.existing_conn,
     459           0 :                                                    &io->in.options,
     460             :                                                    &state->transport);
     461           0 :                 if (!NT_STATUS_IS_OK(status)) {
     462           0 :                         composite_error(c, status);
     463           0 :                         return c;
     464             :                 }
     465             : 
     466           0 :                 status = connect_send_session(c, io);
     467           0 :                 if (!NT_STATUS_IS_OK(status)) {
     468           0 :                         composite_error(c, status);
     469           0 :                         return c;
     470             :                 }
     471             : 
     472           0 :                 return c;
     473             :         }
     474             : 
     475         932 :         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         932 :         if (state->creq == NULL) {
     484           0 :                 composite_error(c, NT_STATUS_NO_MEMORY);
     485           0 :                 return c;
     486             :         }
     487             : 
     488         932 :         state->stage = CONNECT_SOCKET;
     489         932 :         state->creq->async.private_data = c;
     490         932 :         state->creq->async.fn = composite_handler;
     491             : 
     492         932 :         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         932 : NTSTATUS smb_composite_connect_recv(struct composite_context *c, TALLOC_CTX *mem_ctx)
     502             : {
     503             :         NTSTATUS status;
     504             : 
     505         932 :         status = composite_wait(c);
     506             : 
     507         924 :         if (NT_STATUS_IS_OK(status)) {
     508         890 :                 struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
     509         890 :                 talloc_steal(mem_ctx, state->io->out.tree);
     510             :         }
     511             : 
     512         924 :         talloc_free(c);
     513         924 :         return status;
     514             : }
     515             : 
     516             : /*
     517             :   sync version of smb_composite_connect 
     518             : */
     519         756 : 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         756 :         struct composite_context *c = smb_composite_connect_send(io, mem_ctx, resolve_ctx, ev);
     524         756 :         if (c == NULL) {
     525           0 :                 return NT_STATUS_NO_MEMORY;
     526             :         }
     527         756 :         return smb_composite_connect_recv(c, mem_ctx);
     528             : }

Generated by: LCOV version 1.13