LCOV - code coverage report
Current view: top level - source4/libcli/smb2 - connect.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 187 213 87.8 %
Date: 2024-02-28 12:06:22 Functions: 11 11 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    SMB2 composite connection setup
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2005
       7             :    
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             :    
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             :    
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include <tevent.h>
      24             : #include "lib/util/tevent_ntstatus.h"
      25             : #include "libcli/raw/libcliraw.h"
      26             : #include "libcli/raw/raw_proto.h"
      27             : #include "libcli/smb2/smb2.h"
      28             : #include "libcli/smb2/smb2_calls.h"
      29             : #include "libcli/composite/composite.h"
      30             : #include "libcli/resolve/resolve.h"
      31             : #include "param/param.h"
      32             : #include "auth/credentials/credentials.h"
      33             : #include "../libcli/smb/smbXcli_base.h"
      34             : #include "smb2_constants.h"
      35             : 
      36             : struct smb2_connect_state {
      37             :         struct tevent_context *ev;
      38             :         struct cli_credentials *credentials;
      39             :         bool fallback_to_anonymous;
      40             :         uint64_t previous_session_id;
      41             :         struct resolve_context *resolve_ctx;
      42             :         const char *host;
      43             :         const char *share;
      44             :         const char *unc;
      45             :         const char **ports;
      46             :         const char *socket_options;
      47             :         struct nbt_name calling, called;
      48             :         struct gensec_settings *gensec_settings;
      49             :         struct smbcli_options options;
      50             :         struct smb2_transport *transport;
      51             :         struct smb2_session *session;
      52             :         struct smb2_tree *tree;
      53             : };
      54             : 
      55             : static void smb2_connect_session_start(struct tevent_req *req);
      56             : static void smb2_connect_socket_done(struct composite_context *creq);
      57             : 
      58             : /*
      59             :   a composite function that does a full negprot/sesssetup/tcon, returning
      60             :   a connected smb2_tree
      61             :  */
      62       12796 : struct tevent_req *smb2_connect_send(TALLOC_CTX *mem_ctx,
      63             :                                      struct tevent_context *ev,
      64             :                                      const char *host,
      65             :                                      const char **ports,
      66             :                                      const char *share,
      67             :                                      struct resolve_context *resolve_ctx,
      68             :                                      struct cli_credentials *credentials,
      69             :                                      bool fallback_to_anonymous,
      70             :                                      struct smbXcli_conn **existing_conn,
      71             :                                      uint64_t previous_session_id,
      72             :                                      const struct smbcli_options *options,
      73             :                                      const char *socket_options,
      74             :                                      struct gensec_settings *gensec_settings)
      75             : {
      76         701 :         struct tevent_req *req;
      77         701 :         struct smb2_connect_state *state;
      78         701 :         struct composite_context *creq;
      79         701 :         static const char *default_ports[] = { "445", "139", NULL };
      80         701 :         enum smb_encryption_setting encryption_state =
      81       12796 :                 cli_credentials_get_smb_encryption(credentials);
      82             : 
      83       12796 :         req = tevent_req_create(mem_ctx, &state,
      84             :                                 struct smb2_connect_state);
      85       12796 :         if (req == NULL) {
      86           0 :                 return NULL;
      87             :         }
      88             : 
      89       12796 :         state->ev = ev;
      90       12796 :         state->credentials = credentials;
      91       12796 :         state->fallback_to_anonymous = fallback_to_anonymous;
      92       12796 :         state->previous_session_id = previous_session_id;
      93       12796 :         state->options = *options;
      94       12796 :         state->host = host;
      95       12796 :         state->ports = ports;
      96       12796 :         state->share = share;
      97       12796 :         state->resolve_ctx = resolve_ctx;
      98       12796 :         state->socket_options = socket_options;
      99       12796 :         state->gensec_settings = gensec_settings;
     100             : 
     101       12796 :         if (state->ports == NULL) {
     102         124 :                 state->ports = default_ports;
     103             :         }
     104             : 
     105       12796 :         if (encryption_state >= SMB_ENCRYPTION_DESIRED) {
     106         719 :                 state->options.signing = SMB_SIGNING_REQUIRED;
     107             :         }
     108             : 
     109       12796 :         make_nbt_name_client(&state->calling,
     110             :                              cli_credentials_get_workstation(credentials));
     111             : 
     112       12796 :         nbt_choose_called_name(state, &state->called,
     113             :                                host, NBT_NAME_SERVER);
     114             : 
     115       25592 :         state->unc = talloc_asprintf(state, "\\\\%s\\%s",
     116       12796 :                                     state->host, state->share);
     117       12796 :         if (tevent_req_nomem(state->unc, req)) {
     118           0 :                 return tevent_req_post(req, ev);
     119             :         }
     120             : 
     121       12796 :         if (existing_conn != NULL) {
     122         390 :                 NTSTATUS status;
     123             : 
     124        6608 :                 status = smb2_transport_raw_init(state, ev,
     125             :                                                  existing_conn,
     126        6608 :                                                  &state->options,
     127        6608 :                                                  &state->transport);
     128        6608 :                 if (tevent_req_nterror(req, status)) {
     129           0 :                         return tevent_req_post(req, ev);
     130             :                 }
     131             : 
     132        6608 :                 smb2_connect_session_start(req);
     133        6608 :                 if (!tevent_req_is_in_progress(req)) {
     134         124 :                         return tevent_req_post(req, ev);
     135             :                 }
     136             : 
     137        6094 :                 return req;
     138             :         }
     139             : 
     140        6499 :         creq = smbcli_sock_connect_send(state, NULL, state->ports,
     141        5877 :                                         state->host, state->resolve_ctx,
     142        5877 :                                         state->ev, state->socket_options,
     143        5877 :                                         &state->calling,
     144        6188 :                                         &state->called);
     145        6188 :         if (tevent_req_nomem(creq, req)) {
     146           0 :                 return tevent_req_post(req, ev);
     147             :         }
     148        6188 :         creq->async.fn = smb2_connect_socket_done;
     149        6188 :         creq->async.private_data = req;
     150             : 
     151        6188 :         return req;
     152             : }
     153             : 
     154             : static void smb2_connect_negprot_done(struct tevent_req *subreq);
     155             : 
     156        6188 : static void smb2_connect_socket_done(struct composite_context *creq)
     157             : {
     158         311 :         struct tevent_req *req =
     159        6188 :                 talloc_get_type_abort(creq->async.private_data,
     160             :                 struct tevent_req);
     161         311 :         struct smb2_connect_state *state =
     162        6188 :                 tevent_req_data(req,
     163             :                 struct smb2_connect_state);
     164         311 :         struct smbcli_socket *sock;
     165         311 :         struct tevent_req *subreq;
     166         311 :         NTSTATUS status;
     167         311 :         uint32_t timeout_msec;
     168         311 :         enum protocol_types min_protocol;
     169             : 
     170        6188 :         status = smbcli_sock_connect_recv(creq, state, &sock);
     171        6188 :         if (tevent_req_nterror(req, status)) {
     172           0 :                 return;
     173             :         }
     174             : 
     175        6188 :         state->transport = smb2_transport_init(sock, state, &state->options);
     176        6188 :         if (tevent_req_nomem(state->transport, req)) {
     177           0 :                 return;
     178             :         }
     179             : 
     180        6188 :         timeout_msec = state->transport->options.request_timeout * 1000;
     181        6188 :         min_protocol = state->transport->options.min_protocol;
     182        6188 :         if (min_protocol < PROTOCOL_SMB2_02) {
     183        5077 :                 min_protocol = PROTOCOL_SMB2_02;
     184             :         }
     185             : 
     186        6499 :         subreq = smbXcli_negprot_send(state, state->ev,
     187        5877 :                                       state->transport->conn, timeout_msec,
     188             :                                       min_protocol,
     189        6188 :                                       state->transport->options.max_protocol,
     190        6188 :                                       state->transport->options.max_credits,
     191             :                                       NULL);
     192        6188 :         if (tevent_req_nomem(subreq, req)) {
     193           0 :                 return;
     194             :         }
     195        6188 :         tevent_req_set_callback(subreq, smb2_connect_negprot_done, req);
     196             : }
     197             : 
     198             : static void smb2_connect_session_done(struct tevent_req *subreq);
     199             : 
     200        6188 : static void smb2_connect_negprot_done(struct tevent_req *subreq)
     201             : {
     202         311 :         struct tevent_req *req =
     203        6188 :                 tevent_req_callback_data(subreq,
     204             :                 struct tevent_req);
     205         311 :         NTSTATUS status;
     206             : 
     207        6188 :         status = smbXcli_negprot_recv(subreq, NULL, NULL);
     208        6188 :         TALLOC_FREE(subreq);
     209        6188 :         if (tevent_req_nterror(req, status)) {
     210           0 :                 return;
     211             :         }
     212             : 
     213        6188 :         smb2_connect_session_start(req);
     214             : }
     215             : 
     216       12808 : static void smb2_connect_session_start(struct tevent_req *req)
     217             : {
     218         701 :         struct smb2_connect_state *state =
     219       12808 :                 tevent_req_data(req,
     220             :                 struct smb2_connect_state);
     221       12808 :         struct smb2_transport *transport = state->transport;
     222       12808 :         struct tevent_req *subreq = NULL;
     223             : 
     224       12808 :         state->session = smb2_session_init(transport, state->gensec_settings, state);
     225       12808 :         if (tevent_req_nomem(state->session, req)) {
     226           0 :                 return;
     227             :         }
     228             : 
     229       12808 :         if (state->options.only_negprot) {
     230        1306 :                 state->tree = smb2_tree_init(state->session, state, true);
     231        1306 :                 if (tevent_req_nomem(state->tree, req)) {
     232           0 :                         return;
     233             :                 }
     234        1306 :                 tevent_req_done(req);
     235        1306 :                 return;
     236             :         }
     237             : 
     238       11502 :         subreq = smb2_session_setup_spnego_send(state, state->ev,
     239             :                                                 state->session,
     240             :                                                 state->credentials,
     241             :                                                 state->previous_session_id);
     242       11502 :         if (tevent_req_nomem(subreq, req)) {
     243           0 :                 return;
     244             :         }
     245       11502 :         tevent_req_set_callback(subreq, smb2_connect_session_done, req);
     246             : }
     247             : 
     248             : static void smb2_connect_enc_start(struct tevent_req *req);
     249             : static void smb2_connect_tcon_start(struct tevent_req *req);
     250             : static void smb2_connect_tcon_done(struct tevent_req *subreq);
     251             : 
     252       11502 : static void smb2_connect_session_done(struct tevent_req *subreq)
     253             : {
     254         621 :         struct tevent_req *req =
     255       11502 :                 tevent_req_callback_data(subreq,
     256             :                 struct tevent_req);
     257         621 :         struct smb2_connect_state *state =
     258       11502 :                 tevent_req_data(req,
     259             :                 struct smb2_connect_state);
     260         621 :         NTSTATUS status;
     261             : 
     262       11502 :         status = smb2_session_setup_spnego_recv(subreq);
     263       11502 :         TALLOC_FREE(subreq);
     264       11502 :         if (!NT_STATUS_IS_OK(status) &&
     265          40 :             !cli_credentials_is_anonymous(state->credentials) &&
     266          40 :             state->fallback_to_anonymous) {
     267          12 :                 struct cli_credentials *anon_creds = NULL;
     268             : 
     269             :                 /*
     270             :                  * The transport was moved to session,
     271             :                  * we need to revert that before removing
     272             :                  * the old broken session.
     273             :                  */
     274          12 :                 state->transport = talloc_move(state, &state->session->transport);
     275          12 :                 TALLOC_FREE(state->session);
     276             : 
     277          12 :                 anon_creds = cli_credentials_init_anon(state);
     278          12 :                 if (tevent_req_nomem(anon_creds, req)) {
     279          40 :                         return;
     280             :                 }
     281          12 :                 cli_credentials_set_workstation(anon_creds,
     282             :                    cli_credentials_get_workstation(state->credentials),
     283             :                    CRED_SPECIFIED);
     284             : 
     285             :                 /*
     286             :                  * retry with anonymous credentials
     287             :                  */
     288          12 :                 state->credentials = anon_creds;
     289          12 :                 smb2_connect_session_start(req);
     290          12 :                 return;
     291             :         }
     292       11490 :         if (tevent_req_nterror(req, status)) {
     293          28 :                 return;
     294             :         }
     295             : 
     296       11462 :         state->tree = smb2_tree_init(state->session, state, true);
     297       11462 :         if (tevent_req_nomem(state->tree, req)) {
     298           0 :                 return;
     299             :         }
     300             : 
     301       11462 :         smb2_connect_enc_start(req);
     302             : }
     303             : 
     304       11462 : static void smb2_connect_enc_start(struct tevent_req *req)
     305             : {
     306         621 :         struct smb2_connect_state *state =
     307       11462 :                 tevent_req_data(req,
     308             :                                 struct smb2_connect_state);
     309         621 :         enum smb_encryption_setting encryption_state =
     310       11462 :                 cli_credentials_get_smb_encryption(state->credentials);
     311         621 :         NTSTATUS status;
     312             : 
     313       11462 :         if (encryption_state < SMB_ENCRYPTION_DESIRED) {
     314       11075 :                 smb2_connect_tcon_start(req);
     315       11077 :                 return;
     316             :         }
     317             : 
     318         387 :         status = smb2cli_session_encryption_on(state->session->smbXcli);
     319         387 :         if (!NT_STATUS_IS_OK(status)) {
     320           2 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
     321           2 :                         if (encryption_state < SMB_ENCRYPTION_REQUIRED) {
     322           0 :                                 smb2_connect_tcon_start(req);
     323           2 :                                 return;
     324             :                         }
     325             : 
     326           2 :                         DBG_ERR("Encryption required and server doesn't support "
     327             :                                 "SMB3 encryption - failing connect\n");
     328           2 :                         tevent_req_nterror(req, status);
     329           2 :                         return;
     330             :                 }
     331             : 
     332           0 :                 DBG_ERR("Encryption required and setup failed with error %s.\n",
     333             :                         nt_errstr(status));
     334           0 :                 tevent_req_nterror(req, NT_STATUS_PROTOCOL_NOT_SUPPORTED);
     335           0 :                 return;
     336             :         }
     337             : 
     338         385 :         smb2_connect_tcon_start(req);
     339             : }
     340             : 
     341       11460 : static void smb2_connect_tcon_start(struct tevent_req *req)
     342             : {
     343         621 :         struct smb2_connect_state *state =
     344       11460 :                 tevent_req_data(req,
     345             :                                 struct smb2_connect_state);
     346       11460 :         struct tevent_req *subreq = NULL;
     347         621 :         uint32_t timeout_msec;
     348             : 
     349       11460 :         timeout_msec = state->transport->options.request_timeout * 1000;
     350             : 
     351       12081 :         subreq = smb2cli_tcon_send(state, state->ev,
     352       10839 :                                    state->transport->conn,
     353             :                                    timeout_msec,
     354       11460 :                                    state->session->smbXcli,
     355       11460 :                                    state->tree->smbXcli,
     356             :                                    0, /* flags */
     357             :                                    state->unc);
     358       11460 :         if (tevent_req_nomem(subreq, req)) {
     359           0 :                 return;
     360             :         }
     361       11460 :         tevent_req_set_callback(subreq, smb2_connect_tcon_done, req);
     362             : }
     363             : 
     364       11460 : static void smb2_connect_tcon_done(struct tevent_req *subreq)
     365             : {
     366         621 :         struct tevent_req *req =
     367       11460 :                 tevent_req_callback_data(subreq,
     368             :                 struct tevent_req);
     369         621 :         NTSTATUS status;
     370             : 
     371       11460 :         status = smb2cli_tcon_recv(subreq);
     372       11460 :         if (tevent_req_nterror(req, status)) {
     373           0 :                 return;
     374             :         }
     375             : 
     376       11460 :         tevent_req_done(req);
     377             : }
     378             : 
     379       12796 : NTSTATUS smb2_connect_recv(struct tevent_req *req,
     380             :                            TALLOC_CTX *mem_ctx,
     381             :                            struct smb2_tree **tree)
     382             : {
     383         701 :         struct smb2_connect_state *state =
     384       12796 :                 tevent_req_data(req,
     385             :                 struct smb2_connect_state);
     386         701 :         NTSTATUS status;
     387             : 
     388       12796 :         if (tevent_req_is_nterror(req, &status)) {
     389          30 :                 tevent_req_received(req);
     390          30 :                 return status;
     391             :         }
     392             : 
     393       12766 :         *tree = talloc_move(mem_ctx, &state->tree);
     394             : 
     395       12766 :         tevent_req_received(req);
     396       12766 :         return NT_STATUS_OK;
     397             : }
     398             : 
     399             : /*
     400             :   sync version of smb2_connect
     401             : */
     402        6312 : NTSTATUS smb2_connect_ext(TALLOC_CTX *mem_ctx,
     403             :                           const char *host,
     404             :                           const char **ports,
     405             :                           const char *share,
     406             :                           struct resolve_context *resolve_ctx,
     407             :                           struct cli_credentials *credentials,
     408             :                           struct smbXcli_conn **existing_conn,
     409             :                           uint64_t previous_session_id,
     410             :                           struct smb2_tree **tree,
     411             :                           struct tevent_context *ev,
     412             :                           const struct smbcli_options *options,
     413             :                           const char *socket_options,
     414             :                           struct gensec_settings *gensec_settings)
     415             : {
     416         311 :         struct tevent_req *subreq;
     417         311 :         NTSTATUS status;
     418         311 :         bool ok;
     419        6312 :         TALLOC_CTX *frame = talloc_stackframe();
     420             : 
     421        6312 :         if (frame == NULL) {
     422           0 :                 return NT_STATUS_NO_MEMORY;
     423             :         }
     424             : 
     425        6312 :         subreq = smb2_connect_send(frame,
     426             :                                    ev,
     427             :                                    host,
     428             :                                    ports,
     429             :                                    share,
     430             :                                    resolve_ctx,
     431             :                                    credentials,
     432             :                                    false, /* fallback_to_anonymous */
     433             :                                    existing_conn,
     434             :                                    previous_session_id,
     435             :                                    options,
     436             :                                    socket_options,
     437             :                                    gensec_settings);
     438        6312 :         if (subreq == NULL) {
     439           0 :                 TALLOC_FREE(frame);
     440           0 :                 return NT_STATUS_NO_MEMORY;
     441             :         }
     442             : 
     443        6312 :         ok = tevent_req_poll(subreq, ev);
     444        6312 :         if (!ok) {
     445           0 :                 status = map_nt_error_from_unix_common(errno);
     446           0 :                 TALLOC_FREE(frame);
     447           0 :                 return status;
     448             :         }
     449             : 
     450        6312 :         status = smb2_connect_recv(subreq, mem_ctx, tree);
     451        6312 :         TALLOC_FREE(subreq);
     452        6312 :         if (!NT_STATUS_IS_OK(status)) {
     453           0 :                 TALLOC_FREE(frame);
     454           0 :                 return status;
     455             :         }
     456             : 
     457        6312 :         TALLOC_FREE(frame);
     458        6312 :         return NT_STATUS_OK;
     459             : }
     460             : 
     461        1898 : NTSTATUS smb2_connect(TALLOC_CTX *mem_ctx,
     462             :                       const char *host,
     463             :                       const char **ports,
     464             :                       const char *share,
     465             :                       struct resolve_context *resolve_ctx,
     466             :                       struct cli_credentials *credentials,
     467             :                       struct smb2_tree **tree,
     468             :                       struct tevent_context *ev,
     469             :                       const struct smbcli_options *options,
     470             :                       const char *socket_options,
     471             :                       struct gensec_settings *gensec_settings)
     472             : {
     473         186 :         NTSTATUS status;
     474             : 
     475        1898 :         status = smb2_connect_ext(mem_ctx, host, ports, share, resolve_ctx,
     476             :                                   credentials,
     477             :                                   NULL, /* existing_conn */
     478             :                                   0, /* previous_session_id */
     479             :                                   tree, ev, options, socket_options,
     480             :                                   gensec_settings);
     481             : 
     482        1898 :         return status;
     483             : }

Generated by: LCOV version 1.14