LCOV - code coverage report
Current view: top level - source4/libcli/smb2 - session.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 184 227 81.1 %
Date: 2024-05-31 13:13:24 Functions: 10 10 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    SMB2 client session handling
       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 "system/network.h"
      24             : #include <tevent.h>
      25             : #include "lib/util/tevent_ntstatus.h"
      26             : #include "libcli/raw/libcliraw.h"
      27             : #include "libcli/smb2/smb2.h"
      28             : #include "libcli/smb2/smb2_calls.h"
      29             : #include "auth/gensec/gensec.h"
      30             : #include "auth/credentials/credentials.h"
      31             : #include "../libcli/smb/smbXcli_base.h"
      32             : 
      33             : /**
      34             :   initialise a smb2_session structure
      35             :  */
      36       15199 : struct smb2_session *smb2_session_init(struct smb2_transport *transport,
      37             :                                        struct gensec_settings *settings,
      38             :                                        TALLOC_CTX *parent_ctx)
      39             : {
      40         807 :         struct smb2_session *session;
      41         807 :         NTSTATUS status;
      42             : 
      43       15199 :         session = talloc_zero(parent_ctx, struct smb2_session);
      44       15199 :         if (!session) {
      45           0 :                 return NULL;
      46             :         }
      47       15199 :         session->transport = talloc_steal(session, transport);
      48             : 
      49       15199 :         session->smbXcli = smbXcli_session_create(session, transport->conn);
      50       15199 :         if (session->smbXcli == NULL) {
      51           0 :                 talloc_free(session);
      52           0 :                 return NULL;
      53             :         }
      54             : 
      55             :         /* prepare a gensec context for later use */
      56       15199 :         status = gensec_client_start(session, &session->gensec,
      57             :                                      settings);
      58       15199 :         if (!NT_STATUS_IS_OK(status)) {
      59           0 :                 talloc_free(session);
      60           0 :                 return NULL;
      61             :         }
      62             : 
      63       15199 :         gensec_want_feature(session->gensec, GENSEC_FEATURE_SESSION_KEY);
      64             : 
      65       15199 :         return session;
      66             : }
      67             : 
      68             : /*
      69             :  * Note: that the caller needs to keep 'transport' around as
      70             :  *       long as the returned session is active!
      71             :  */
      72        2262 : struct smb2_session *smb2_session_channel(struct smb2_transport *transport,
      73             :                                           struct gensec_settings *settings,
      74             :                                           TALLOC_CTX *parent_ctx,
      75             :                                           struct smb2_session *base_session)
      76             : {
      77         248 :         struct smb2_session *session;
      78         248 :         NTSTATUS status;
      79             : 
      80        2262 :         session = talloc_zero(parent_ctx, struct smb2_session);
      81        2262 :         if (!session) {
      82           0 :                 return NULL;
      83             :         }
      84        2262 :         session->transport = transport;
      85             : 
      86        2262 :         status = smb2cli_session_create_channel(session,
      87             :                                                 base_session->smbXcli,
      88             :                                                 transport->conn,
      89             :                                                 &session->smbXcli);
      90        2262 :         if (!NT_STATUS_IS_OK(status)) {
      91           0 :                 talloc_free(session);
      92           0 :                 return NULL;
      93             :         }
      94             : 
      95        2262 :         session->needs_bind = true;
      96             : 
      97             :         /* prepare a gensec context for later use */
      98        2262 :         status = gensec_client_start(session, &session->gensec,
      99             :                                      settings);
     100        2262 :         if (!NT_STATUS_IS_OK(status)) {
     101           0 :                 talloc_free(session);
     102           0 :                 return NULL;
     103             :         }
     104             : 
     105        2262 :         gensec_want_feature(session->gensec, GENSEC_FEATURE_SESSION_KEY);
     106             : 
     107        2262 :         return session;
     108             : }
     109             : 
     110             : struct smb2_session_setup_spnego_state {
     111             :         struct tevent_context *ev;
     112             :         struct smb2_session *session;
     113             :         struct cli_credentials *credentials;
     114             :         uint64_t previous_session_id;
     115             :         bool session_bind;
     116             :         bool reauth;
     117             :         NTSTATUS gensec_status;
     118             :         NTSTATUS remote_status;
     119             :         DATA_BLOB in_secblob;
     120             :         DATA_BLOB out_secblob;
     121             :         struct iovec *recv_iov;
     122             : };
     123             : 
     124             : static void smb2_session_setup_spnego_gensec_next(struct tevent_req *req);
     125             : static void smb2_session_setup_spnego_gensec_done(struct tevent_req *subreq);
     126             : static void smb2_session_setup_spnego_smb2_next(struct tevent_req *req);
     127             : static void smb2_session_setup_spnego_smb2_done(struct tevent_req *subreq);
     128             : static void smb2_session_setup_spnego_both_ready(struct tevent_req *req);
     129             : 
     130             : /*
     131             :   a composite function that does a full SPNEGO session setup
     132             :  */
     133       16288 : struct tevent_req *smb2_session_setup_spnego_send(
     134             :                                 TALLOC_CTX *mem_ctx,
     135             :                                 struct tevent_context *ev,
     136             :                                 struct smb2_session *session,
     137             :                                 struct cli_credentials *credentials,
     138             :                                 uint64_t previous_session_id)
     139             : {
     140       16288 :         struct smb2_transport *transport = session->transport;
     141         998 :         struct tevent_req *req;
     142         998 :         struct smb2_session_setup_spnego_state *state;
     143         998 :         uint64_t current_session_id;
     144         998 :         const char *chosen_oid;
     145         998 :         NTSTATUS status;
     146         998 :         const DATA_BLOB *server_gss_blob;
     147         998 :         struct timeval endtime;
     148         998 :         bool ok;
     149             : 
     150       16288 :         req = tevent_req_create(mem_ctx, &state,
     151             :                                 struct smb2_session_setup_spnego_state);
     152       16288 :         if (req == NULL) {
     153           0 :                 return NULL;
     154             :         }
     155       16288 :         state->ev = ev;
     156       16288 :         state->session = session;
     157       16288 :         state->credentials = credentials;
     158       16288 :         state->previous_session_id = previous_session_id;
     159       16288 :         state->gensec_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
     160       16288 :         state->remote_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
     161             : 
     162       16288 :         endtime = timeval_current_ofs(transport->options.request_timeout, 0);
     163             : 
     164       16288 :         ok = tevent_req_set_endtime(req, ev, endtime);
     165       16288 :         if (!ok) {
     166           0 :                 return tevent_req_post(req, ev);
     167             :         }
     168             : 
     169       16288 :         current_session_id = smb2cli_session_current_id(state->session->smbXcli);
     170       16288 :         if (state->session->needs_bind) {
     171        1816 :                 state->session_bind = true;
     172       14472 :         } else if (current_session_id != 0) {
     173        1013 :                 state->reauth = true;
     174             :         }
     175       16288 :         server_gss_blob = smbXcli_conn_server_gss_blob(session->transport->conn);
     176       16288 :         if (server_gss_blob) {
     177       16288 :                 state->out_secblob = *server_gss_blob;
     178             :         }
     179             : 
     180       16288 :         status = gensec_set_credentials(session->gensec, credentials);
     181       16288 :         if (tevent_req_nterror(req, status)) {
     182           0 :                 return tevent_req_post(req, ev);
     183             :         }
     184             : 
     185       16288 :         status = gensec_set_target_hostname(session->gensec,
     186       16288 :                                             smbXcli_conn_remote_name(session->transport->conn));
     187       16288 :         if (tevent_req_nterror(req, status)) {
     188           0 :                 return tevent_req_post(req, ev);
     189             :         }
     190             : 
     191       16288 :         status = gensec_set_target_service(session->gensec, "cifs");
     192       16288 :         if (tevent_req_nterror(req, status)) {
     193           0 :                 return tevent_req_post(req, ev);
     194             :         }
     195             : 
     196       16288 :         if (state->out_secblob.length > 0) {
     197       16288 :                 chosen_oid = GENSEC_OID_SPNEGO;
     198       16288 :                 status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
     199       16288 :                 if (!NT_STATUS_IS_OK(status)) {
     200          72 :                         DEBUG(1, ("Failed to start set GENSEC client mechanism %s: %s\n",
     201             :                                   gensec_get_name_by_oid(session->gensec,
     202             :                                                          chosen_oid),
     203             :                                   nt_errstr(status)));
     204          72 :                         state->out_secblob = data_blob_null;
     205          72 :                         chosen_oid = GENSEC_OID_NTLMSSP;
     206          72 :                         status = gensec_start_mech_by_oid(session->gensec,
     207             :                                                           chosen_oid);
     208          72 :                         if (!NT_STATUS_IS_OK(status)) {
     209           0 :                                 DEBUG(1, ("Failed to start set (fallback) GENSEC client mechanism %s: %s\n",
     210             :                                           gensec_get_name_by_oid(session->gensec,
     211             :                                                                  chosen_oid),
     212             :                                           nt_errstr(status)));
     213             :                         }
     214             :                 }
     215       16288 :                 if (tevent_req_nterror(req, status)) {
     216           0 :                         return tevent_req_post(req, ev);
     217             :                 }
     218             :         } else {
     219           0 :                 chosen_oid = GENSEC_OID_NTLMSSP;
     220           0 :                 status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
     221           0 :                 if (!NT_STATUS_IS_OK(status)) {
     222           0 :                         DEBUG(1, ("Failed to start set GENSEC client mechanism %s: %s\n",
     223             :                                   gensec_get_name_by_oid(session->gensec,
     224             :                                                          chosen_oid),
     225             :                                   nt_errstr(status)));
     226             :                 }
     227           0 :                 if (tevent_req_nterror(req, status)) {
     228           0 :                         return tevent_req_post(req, ev);
     229             :                 }
     230             :         }
     231             : 
     232       16288 :         smb2_session_setup_spnego_gensec_next(req);
     233       16288 :         if (!tevent_req_is_in_progress(req)) {
     234           0 :                 return tevent_req_post(req, ev);
     235             :         }
     236             : 
     237       15290 :         return req;
     238             : }
     239             : 
     240       36918 : static void smb2_session_setup_spnego_gensec_next(struct tevent_req *req)
     241             : {
     242        1854 :         struct smb2_session_setup_spnego_state *state =
     243       36918 :                 tevent_req_data(req,
     244             :                 struct smb2_session_setup_spnego_state);
     245       36918 :         struct smb2_session *session = state->session;
     246       36918 :         struct tevent_req *subreq = NULL;
     247             : 
     248       36918 :         if (NT_STATUS_IS_OK(state->gensec_status)) {
     249           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
     250           0 :                 return;
     251             :         }
     252             : 
     253       36918 :         subreq = gensec_update_send(state, state->ev,
     254             :                                     session->gensec,
     255             :                                     state->out_secblob);
     256       36918 :         if (tevent_req_nomem(subreq, req)) {
     257           0 :                 return;
     258             :         }
     259       36918 :         tevent_req_set_callback(subreq,
     260             :                                 smb2_session_setup_spnego_gensec_done,
     261             :                                 req);
     262             : }
     263             : 
     264       36918 : static void smb2_session_setup_spnego_gensec_done(struct tevent_req *subreq)
     265             : {
     266        1854 :         struct tevent_req *req =
     267       36918 :                 tevent_req_callback_data(subreq,
     268             :                 struct tevent_req);
     269        1854 :         struct smb2_session_setup_spnego_state *state =
     270       36918 :                 tevent_req_data(req,
     271             :                 struct smb2_session_setup_spnego_state);
     272        1854 :         NTSTATUS status;
     273             : 
     274       36918 :         status = gensec_update_recv(subreq, state,
     275             :                                     &state->in_secblob);
     276       36918 :         state->gensec_status = status;
     277       36918 :         state->out_secblob = data_blob_null;
     278       36918 :         if (!NT_STATUS_IS_OK(status) &&
     279       23240 :             !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
     280          20 :                 tevent_req_nterror(req, status);
     281          20 :                 return;
     282             :         }
     283             : 
     284       36898 :         if (NT_STATUS_IS_OK(state->remote_status) &&
     285       11752 :             NT_STATUS_IS_OK(state->gensec_status)) {
     286       12443 :                 smb2_session_setup_spnego_both_ready(req);
     287       12443 :                 return;
     288             :         }
     289             : 
     290       24455 :         smb2_session_setup_spnego_smb2_next(req);
     291             : }
     292             : 
     293       24455 : static void smb2_session_setup_spnego_smb2_next(struct tevent_req *req)
     294             : {
     295        1163 :         struct smb2_session_setup_spnego_state *state =
     296       24455 :                 tevent_req_data(req,
     297             :                 struct smb2_session_setup_spnego_state);
     298       24455 :         struct smb2_session *session = state->session;
     299        1163 :         uint32_t timeout_msec;
     300       24455 :         uint8_t in_flags = 0;
     301       24455 :         struct tevent_req *subreq = NULL;
     302             : 
     303       24455 :         if (NT_STATUS_IS_OK(state->remote_status)) {
     304           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
     305           0 :                 return;
     306             :         }
     307             : 
     308       24455 :         timeout_msec = session->transport->options.request_timeout * 1000;
     309             : 
     310       24455 :         if (state->session_bind) {
     311        2412 :                 in_flags |= SMB2_SESSION_FLAG_BINDING;
     312             :         }
     313             : 
     314       25618 :         subreq = smb2cli_session_setup_send(state, state->ev,
     315       23292 :                                             session->transport->conn,
     316             :                                             timeout_msec,
     317             :                                             session->smbXcli,
     318             :                                             in_flags,
     319             :                                             0, /* in_capabilities */
     320             :                                             0, /* in_channel */
     321             :                                             state->previous_session_id,
     322       24455 :                                             &state->in_secblob);
     323       24455 :         if (tevent_req_nomem(subreq, req)) {
     324           0 :                 return;
     325             :         }
     326       24455 :         tevent_req_set_callback(subreq,
     327             :                                 smb2_session_setup_spnego_smb2_done,
     328             :                                 req);
     329             : }
     330             : 
     331             : /*
     332             :   handle continuations of the spnego session setup
     333             : */
     334       24455 : static void smb2_session_setup_spnego_smb2_done(struct tevent_req *subreq)
     335             : {
     336        1163 :         struct tevent_req *req =
     337       24455 :                 tevent_req_callback_data(subreq,
     338             :                 struct tevent_req);
     339        1163 :         struct smb2_session_setup_spnego_state *state =
     340       24455 :                 tevent_req_data(req,
     341             :                 struct smb2_session_setup_spnego_state);
     342        1163 :         NTSTATUS status;
     343             : 
     344       24455 :         status = smb2cli_session_setup_recv(subreq, state,
     345             :                                             &state->recv_iov,
     346             :                                             &state->out_secblob);
     347       24455 :         state->remote_status = status;
     348       24455 :         state->in_secblob = data_blob_null;
     349       24455 :         if (!NT_STATUS_IS_OK(status) &&
     350       11468 :             !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
     351        3753 :                 tevent_req_nterror(req, status);
     352        3753 :                 return;
     353             :         }
     354             : 
     355       20702 :         if (NT_STATUS_IS_OK(state->remote_status) &&
     356       12515 :             NT_STATUS_IS_OK(state->gensec_status)) {
     357          72 :                 smb2_session_setup_spnego_both_ready(req);
     358          72 :                 return;
     359             :         }
     360             : 
     361       20630 :         smb2_session_setup_spnego_gensec_next(req);
     362             : }
     363             : 
     364       12515 : static void smb2_session_setup_spnego_both_ready(struct tevent_req *req)
     365             : {
     366         691 :         struct smb2_session_setup_spnego_state *state =
     367       12515 :                 tevent_req_data(req,
     368             :                 struct smb2_session_setup_spnego_state);
     369       12515 :         struct smb2_session *session = state->session;
     370         691 :         NTSTATUS status;
     371         691 :         DATA_BLOB session_key;
     372             : 
     373       12515 :         if (state->out_secblob.length != 0) {
     374           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
     375           0 :                 return;
     376             :         }
     377             : 
     378       12515 :         if (state->in_secblob.length != 0) {
     379           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
     380           0 :                 return;
     381             :         }
     382             : 
     383       12515 :         if (state->reauth) {
     384         138 :                 tevent_req_done(req);
     385         138 :                 return;
     386             :         }
     387             : 
     388       12377 :         if (cli_credentials_is_anonymous(state->credentials) &&
     389         425 :             !state->session->anonymous_session_key)
     390             :         {
     391             :                 /*
     392             :                  * Windows server does not set the
     393             :                  * SMB2_SESSION_FLAG_IS_GUEST nor
     394             :                  * SMB2_SESSION_FLAG_IS_NULL flag.
     395             :                  *
     396             :                  * This fix makes sure we do not try
     397             :                  * to verify a signature on the final
     398             :                  * session setup response.
     399             :                  */
     400         365 :                 tevent_req_done(req);
     401         365 :                 return;
     402             :         }
     403             : 
     404       12012 :         if (state->session->forced_session_key.length != 0) {
     405          24 :                 session_key = state->session->forced_session_key;
     406             :         } else {
     407       11988 :                 status = gensec_session_key(session->gensec, state,
     408             :                                             &session_key);
     409       11988 :                 if (tevent_req_nterror(req, status)) {
     410           0 :                         return;
     411             :                 }
     412             :         }
     413             : 
     414       12012 :         if (state->session_bind) {
     415         950 :                 status = smb2cli_session_set_channel_key(session->smbXcli,
     416             :                                                          session_key,
     417         950 :                                                          state->recv_iov);
     418         950 :                 if (tevent_req_nterror(req, status)) {
     419           0 :                         return;
     420             :                 }
     421         950 :                 session->needs_bind = false;
     422             :         } else {
     423       11062 :                 status = smb2cli_session_set_session_key(session->smbXcli,
     424             :                                                          session_key,
     425       11062 :                                                          state->recv_iov);
     426       11062 :                 if (tevent_req_nterror(req, status)) {
     427           0 :                         return;
     428             :                 }
     429             :         }
     430       12012 :         tevent_req_done(req);
     431       12012 :         return;
     432             : }
     433             : 
     434             : /*
     435             :   receive a composite session setup reply
     436             : */
     437       16288 : NTSTATUS smb2_session_setup_spnego_recv(struct tevent_req *req)
     438             : {
     439       16288 :         return tevent_req_simple_recv_ntstatus(req);
     440             : }
     441             : 
     442             : /*
     443             :   sync version of smb2_session_setup_spnego
     444             : */
     445        4905 : NTSTATUS smb2_session_setup_spnego(struct smb2_session *session, 
     446             :                                    struct cli_credentials *credentials,
     447             :                                    uint64_t previous_session_id)
     448             : {
     449         363 :         struct tevent_req *subreq;
     450         363 :         NTSTATUS status;
     451         363 :         bool ok;
     452        4905 :         TALLOC_CTX *frame = talloc_stackframe();
     453        4905 :         struct tevent_context *ev = session->transport->ev;
     454             : 
     455        4905 :         if (frame == NULL) {
     456           0 :                 return NT_STATUS_NO_MEMORY;
     457             :         }
     458             : 
     459        4905 :         subreq = smb2_session_setup_spnego_send(frame, ev,
     460             :                                                 session, credentials,
     461             :                                                 previous_session_id);
     462        4905 :         if (subreq == NULL) {
     463           0 :                 TALLOC_FREE(frame);
     464           0 :                 return NT_STATUS_NO_MEMORY;
     465             :         }
     466             : 
     467        4905 :         ok = tevent_req_poll(subreq, ev);
     468        4905 :         if (!ok) {
     469           0 :                 status = map_nt_error_from_unix_common(errno);
     470           0 :                 TALLOC_FREE(frame);
     471           0 :                 return status;
     472             :         }
     473             : 
     474        4905 :         status = smb2_session_setup_spnego_recv(subreq);
     475        4905 :         TALLOC_FREE(subreq);
     476        4905 :         if (!NT_STATUS_IS_OK(status)) {
     477        3731 :                 TALLOC_FREE(frame);
     478        3731 :                 return status;
     479             :         }
     480             : 
     481        1174 :         TALLOC_FREE(frame);
     482        1174 :         return NT_STATUS_OK;
     483             : }

Generated by: LCOV version 1.14