root/source4/libcli/smb_composite/sesssetup.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sesssetup_state_destructor
  2. set_user_session_key
  3. request_handler
  4. session_setup_nt1
  5. session_setup_old
  6. session_setup_spnego
  7. smb_composite_sesssetup_send
  8. smb_composite_sesssetup_recv
  9. smb_composite_sesssetup

   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 handling a generic async session setup
  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 "libcli/smb_composite/proto.h"
  29 #include "libcli/auth/libcli_auth.h"
  30 #include "auth/auth.h"
  31 #include "auth/gensec/gensec.h"
  32 #include "auth/credentials/credentials.h"
  33 #include "version.h"
  34 #include "param/param.h"
  35 
  36 struct sesssetup_state {
  37         union smb_sesssetup setup;
  38         NTSTATUS remote_status;
  39         NTSTATUS gensec_status;
  40         struct smb_composite_sesssetup *io;
  41         struct smbcli_request *req;
  42 };
  43 
  44 static int sesssetup_state_destructor(struct sesssetup_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
  45 {
  46         if (state->req) {
  47                 talloc_free(state->req);
  48                 state->req = NULL;
  49         }
  50 
  51         return 0;
  52 }
  53 
  54 static NTSTATUS session_setup_old(struct composite_context *c,
  55                                   struct smbcli_session *session, 
  56                                   struct smb_composite_sesssetup *io,
  57                                   struct smbcli_request **req); 
  58 static NTSTATUS session_setup_nt1(struct composite_context *c,
  59                                   struct smbcli_session *session, 
  60                                   struct smb_composite_sesssetup *io,
  61                                   struct smbcli_request **req); 
  62 static NTSTATUS session_setup_spnego(struct composite_context *c,
  63                                      struct smbcli_session *session, 
  64                                      struct smb_composite_sesssetup *io,
  65                                      struct smbcli_request **req);
  66 
  67 /*
  68   store the user session key for a transport
  69 */
  70 static void set_user_session_key(struct smbcli_session *session,
     /* [<][>][^][v][top][bottom][index][help] */
  71                                  const DATA_BLOB *session_key)
  72 {
  73         session->user_session_key = data_blob_talloc(session, 
  74                                                      session_key->data, 
  75                                                      session_key->length);
  76 }
  77 
  78 /*
  79   handler for completion of a smbcli_request sub-request
  80 */
  81 static void request_handler(struct smbcli_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
  82 {
  83         struct composite_context *c = (struct composite_context *)req->async.private_data;
  84         struct sesssetup_state *state = talloc_get_type(c->private_data, struct sesssetup_state);
  85         struct smbcli_session *session = req->session;
  86         DATA_BLOB session_key = data_blob(NULL, 0);
  87         DATA_BLOB null_data_blob = data_blob(NULL, 0);
  88         NTSTATUS session_key_err, nt_status;
  89         struct smbcli_request *check_req = NULL;
  90 
  91         if (req->sign_caller_checks) {
  92                 req->do_not_free = true;
  93                 check_req = req;
  94         }
  95 
  96         state->remote_status = smb_raw_sesssetup_recv(req, state, &state->setup);
  97         c->status = state->remote_status;
  98         state->req = NULL;
  99 
 100         /*
 101          * we only need to check the signature if the
 102          * NT_STATUS_OK is returned
 103          */
 104         if (!NT_STATUS_IS_OK(state->remote_status)) {
 105                 talloc_free(check_req);
 106                 check_req = NULL;
 107         }
 108 
 109         switch (state->setup.old.level) {
 110         case RAW_SESSSETUP_OLD:
 111                 state->io->out.vuid = state->setup.old.out.vuid;
 112                 /* This doesn't work, as this only happens on old
 113                  * protocols, where this comparison won't match. */
 114                 if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
 115                         /* we neet to reset the vuid for a new try */
 116                         session->vuid = 0;
 117                         if (cli_credentials_wrong_password(state->io->in.credentials)) {
 118                                 nt_status = session_setup_old(c, session, 
 119                                                               state->io, 
 120                                                               &state->req);
 121                                 if (NT_STATUS_IS_OK(nt_status)) {
 122                                         talloc_free(check_req);
 123                                         c->status = nt_status;
 124                                         composite_continue_smb(c, state->req, request_handler, c);
 125                                         return;
 126                                 }
 127                         }
 128                 }
 129                 break;
 130 
 131         case RAW_SESSSETUP_NT1:
 132                 state->io->out.vuid = state->setup.nt1.out.vuid;
 133                 if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
 134                         /* we neet to reset the vuid for a new try */
 135                         session->vuid = 0;
 136                         if (cli_credentials_wrong_password(state->io->in.credentials)) {
 137                                 nt_status = session_setup_nt1(c, session, 
 138                                                               state->io, 
 139                                                               &state->req);
 140                                 if (NT_STATUS_IS_OK(nt_status)) {
 141                                         talloc_free(check_req);
 142                                         c->status = nt_status;
 143                                         composite_continue_smb(c, state->req, request_handler, c);
 144                                         return;
 145                                 }
 146                         }
 147                 }
 148                 break;
 149 
 150         case RAW_SESSSETUP_SPNEGO:
 151                 state->io->out.vuid = state->setup.spnego.out.vuid;
 152                 if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
 153                         /* we need to reset the vuid for a new try */
 154                         session->vuid = 0;
 155                         if (cli_credentials_wrong_password(state->io->in.credentials)) {
 156                                 nt_status = session_setup_spnego(c, session, 
 157                                                                       state->io, 
 158                                                                       &state->req);
 159                                 if (NT_STATUS_IS_OK(nt_status)) {
 160                                         talloc_free(check_req);
 161                                         c->status = nt_status;
 162                                         composite_continue_smb(c, state->req, request_handler, c);
 163                                         return;
 164                                 }
 165                         }
 166                 }
 167                 if (!NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED) && 
 168                     !NT_STATUS_IS_OK(c->status)) {
 169                         break;
 170                 }
 171                 if (NT_STATUS_EQUAL(state->gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
 172 
 173                         /* The status value here, from the earlier pass at GENSEC is
 174                          * vital to the security of the system.  Even if the other end
 175                          * accepts, if GENSEC claims 'MORE_PROCESSING_REQUIRED' then
 176                          * you must keep feeding it blobs, or else the remote
 177                          * host/attacker might avoid mutal authentication
 178                          * requirements */
 179                         
 180                         state->gensec_status = gensec_update(session->gensec, state,
 181                                                          state->setup.spnego.out.secblob,
 182                                                          &state->setup.spnego.in.secblob);
 183                         c->status = state->gensec_status;
 184                         if (!NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED) && 
 185                             !NT_STATUS_IS_OK(c->status)) {
 186                                 break;
 187                         }
 188                 } else {
 189                         state->setup.spnego.in.secblob = data_blob(NULL, 0);
 190                 }
 191 
 192                 if (NT_STATUS_IS_OK(state->remote_status)) {
 193                         if (state->setup.spnego.in.secblob.length) {
 194                                 c->status = NT_STATUS_INTERNAL_ERROR;
 195                                 break;
 196                         }
 197                         session_key_err = gensec_session_key(session->gensec, &session_key);
 198                         if (NT_STATUS_IS_OK(session_key_err)) {
 199                                 set_user_session_key(session, &session_key);
 200                                 smbcli_transport_simple_set_signing(session->transport, session_key, null_data_blob);
 201                         }
 202                 }
 203 
 204                 if (state->setup.spnego.in.secblob.length) {
 205                         /* 
 206                          * set the session->vuid value only for calling
 207                          * smb_raw_sesssetup_send()
 208                          */
 209                         uint16_t vuid = session->vuid;
 210                         session->vuid = state->io->out.vuid;
 211                         state->req = smb_raw_sesssetup_send(session, &state->setup);
 212                         session->vuid = vuid;
 213                         if (state->req) {
 214                                 state->req->sign_caller_checks = true;
 215                         }
 216                         composite_continue_smb(c, state->req, request_handler, c);
 217                         return;
 218                 }
 219                 break;
 220 
 221         case RAW_SESSSETUP_SMB2:
 222                 c->status = NT_STATUS_INTERNAL_ERROR;
 223                 break;
 224         }
 225 
 226         if (check_req) {
 227                 check_req->sign_caller_checks = false;
 228                 if (!smbcli_request_check_sign_mac(check_req)) {
 229                         c->status = NT_STATUS_ACCESS_DENIED;
 230                 }
 231                 talloc_free(check_req);
 232                 check_req = NULL;
 233         }
 234 
 235         /* enforce the local signing required flag */
 236         if (NT_STATUS_IS_OK(c->status) && !cli_credentials_is_anonymous(state->io->in.credentials)) {
 237                 if (!session->transport->negotiate.sign_info.doing_signing 
 238                     && session->transport->negotiate.sign_info.mandatory_signing) {
 239                         DEBUG(0, ("SMB signing required, but server does not support it\n"));
 240                         c->status = NT_STATUS_ACCESS_DENIED;
 241                 }
 242         }
 243 
 244         if (!NT_STATUS_IS_OK(c->status)) {
 245                 composite_error(c, c->status);
 246                 return;
 247         }
 248 
 249         composite_done(c);
 250 }
 251 
 252 
 253 /*
 254   send a nt1 style session setup
 255 */
 256 static NTSTATUS session_setup_nt1(struct composite_context *c,
     /* [<][>][^][v][top][bottom][index][help] */
 257                                   struct smbcli_session *session, 
 258                                   struct smb_composite_sesssetup *io,
 259                                   struct smbcli_request **req) 
 260 {
 261         NTSTATUS nt_status = NT_STATUS_INTERNAL_ERROR;
 262         struct sesssetup_state *state = talloc_get_type(c->private_data, struct sesssetup_state);
 263         DATA_BLOB names_blob = NTLMv2_generate_names_blob(state, session->transport->socket->hostname, cli_credentials_get_domain(io->in.credentials));
 264         DATA_BLOB session_key = data_blob(NULL, 0);
 265         int flags = CLI_CRED_NTLM_AUTH;
 266 
 267         smbcli_temp_set_signing(session->transport);
 268 
 269         if (session->options.lanman_auth) {
 270                 flags |= CLI_CRED_LANMAN_AUTH;
 271         }
 272 
 273         if (session->options.ntlmv2_auth) {
 274                 flags |= CLI_CRED_NTLMv2_AUTH;
 275         }
 276 
 277         state->setup.nt1.level           = RAW_SESSSETUP_NT1;
 278         state->setup.nt1.in.bufsize      = session->transport->options.max_xmit;
 279         state->setup.nt1.in.mpx_max      = session->transport->options.max_mux;
 280         state->setup.nt1.in.vc_num       = 1;
 281         state->setup.nt1.in.sesskey      = io->in.sesskey;
 282         state->setup.nt1.in.capabilities = io->in.capabilities;
 283         state->setup.nt1.in.os           = "Unix";
 284         state->setup.nt1.in.lanman       = talloc_asprintf(state, "Samba %s", SAMBA_VERSION_STRING);
 285 
 286         cli_credentials_get_ntlm_username_domain(io->in.credentials, state, 
 287                                                  &state->setup.nt1.in.user,
 288                                                  &state->setup.nt1.in.domain);
 289         
 290 
 291         if (session->transport->negotiate.sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) {
 292                 nt_status = cli_credentials_get_ntlm_response(io->in.credentials, state, 
 293                                                               &flags, 
 294                                                               session->transport->negotiate.secblob, 
 295                                                               names_blob,
 296                                                               &state->setup.nt1.in.password1,
 297                                                               &state->setup.nt1.in.password2,
 298                                                               NULL, &session_key);
 299                 NT_STATUS_NOT_OK_RETURN(nt_status);
 300         } else if (session->options.plaintext_auth) {
 301                 const char *password = cli_credentials_get_password(io->in.credentials);
 302                 state->setup.nt1.in.password1 = data_blob_talloc(state, password, strlen(password));
 303                 state->setup.nt1.in.password2 = data_blob(NULL, 0);
 304         } else {
 305                 /* could match windows client and return 'cannot logon from this workstation', but it just confuses everybody */
 306                 return NT_STATUS_INVALID_PARAMETER;
 307         }
 308 
 309         *req = smb_raw_sesssetup_send(session, &state->setup);
 310         if (!*req) {
 311                 return NT_STATUS_NO_MEMORY;
 312         }
 313 
 314         if (NT_STATUS_IS_OK(nt_status)) {
 315                 smbcli_transport_simple_set_signing(session->transport, session_key, 
 316                                                     state->setup.nt1.in.password2);
 317                 set_user_session_key(session, &session_key);
 318                 
 319                 data_blob_free(&session_key);
 320         }
 321 
 322         return (*req)->status;
 323 }
 324 
 325 
 326 /*
 327   old style session setup (pre NT1 protocol level)
 328 */
 329 static NTSTATUS session_setup_old(struct composite_context *c,
     /* [<][>][^][v][top][bottom][index][help] */
 330                                   struct smbcli_session *session, 
 331                                   struct smb_composite_sesssetup *io,
 332                                   struct smbcli_request **req) 
 333 {
 334         NTSTATUS nt_status;
 335         struct sesssetup_state *state = talloc_get_type(c->private_data, struct sesssetup_state);
 336         const char *password = cli_credentials_get_password(io->in.credentials);
 337         DATA_BLOB names_blob = NTLMv2_generate_names_blob(state, session->transport->socket->hostname, cli_credentials_get_domain(io->in.credentials));
 338         DATA_BLOB session_key;
 339         int flags = 0;
 340         if (session->options.lanman_auth) {
 341                 flags |= CLI_CRED_LANMAN_AUTH;
 342         }
 343 
 344         if (session->options.ntlmv2_auth) {
 345                 flags |= CLI_CRED_NTLMv2_AUTH;
 346         }
 347 
 348         state->setup.old.level      = RAW_SESSSETUP_OLD;
 349         state->setup.old.in.bufsize = session->transport->options.max_xmit;
 350         state->setup.old.in.mpx_max = session->transport->options.max_mux;
 351         state->setup.old.in.vc_num  = 1;
 352         state->setup.old.in.sesskey = io->in.sesskey;
 353         state->setup.old.in.os      = "Unix";
 354         state->setup.old.in.lanman  = talloc_asprintf(state, "Samba %s", SAMBA_VERSION_STRING);
 355         cli_credentials_get_ntlm_username_domain(io->in.credentials, state, 
 356                                                  &state->setup.old.in.user,
 357                                                  &state->setup.old.in.domain);
 358         
 359         if (session->transport->negotiate.sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) {
 360                 nt_status = cli_credentials_get_ntlm_response(io->in.credentials, state, 
 361                                                               &flags, 
 362                                                               session->transport->negotiate.secblob, 
 363                                                               names_blob,
 364                                                               &state->setup.old.in.password,
 365                                                               NULL,
 366                                                               NULL, &session_key);
 367                 NT_STATUS_NOT_OK_RETURN(nt_status);
 368                 set_user_session_key(session, &session_key);
 369                 
 370                 data_blob_free(&session_key);
 371         } else if (session->options.plaintext_auth) {
 372                 state->setup.old.in.password = data_blob_talloc(state, password, strlen(password));
 373         } else {
 374                 /* could match windows client and return 'cannot logon from this workstation', but it just confuses everybody */
 375                 return NT_STATUS_INVALID_PARAMETER;
 376         }
 377         
 378         *req = smb_raw_sesssetup_send(session, &state->setup);
 379         if (!*req) {
 380                 return NT_STATUS_NO_MEMORY;
 381         }
 382         return (*req)->status;
 383 }
 384 
 385 
 386 /*
 387   Modern, all singing, all dancing extended security (and possibly SPNEGO) request
 388 */
 389 static NTSTATUS session_setup_spnego(struct composite_context *c,
     /* [<][>][^][v][top][bottom][index][help] */
 390                                      struct smbcli_session *session, 
 391                                      struct smb_composite_sesssetup *io,
 392                                      struct smbcli_request **req) 
 393 {
 394         struct sesssetup_state *state = talloc_get_type(c->private_data, struct sesssetup_state);
 395         NTSTATUS status;
 396         const char *chosen_oid = NULL;
 397 
 398         state->setup.spnego.level           = RAW_SESSSETUP_SPNEGO;
 399         state->setup.spnego.in.bufsize      = session->transport->options.max_xmit;
 400         state->setup.spnego.in.mpx_max      = session->transport->options.max_mux;
 401         state->setup.spnego.in.vc_num       = 1;
 402         state->setup.spnego.in.sesskey      = io->in.sesskey;
 403         state->setup.spnego.in.capabilities = io->in.capabilities;
 404         state->setup.spnego.in.os           = "Unix";
 405         state->setup.spnego.in.lanman       = talloc_asprintf(state, "Samba %s", SAMBA_VERSION_STRING);
 406         state->setup.spnego.in.workgroup    = io->in.workgroup;
 407 
 408         smbcli_temp_set_signing(session->transport);
 409 
 410         status = gensec_client_start(session, &session->gensec, c->event_ctx,
 411                                      io->in.gensec_settings);
 412         if (!NT_STATUS_IS_OK(status)) {
 413                 DEBUG(1, ("Failed to start GENSEC client mode: %s\n", nt_errstr(status)));
 414                 return status;
 415         }
 416 
 417         gensec_want_feature(session->gensec, GENSEC_FEATURE_SESSION_KEY);
 418 
 419         status = gensec_set_credentials(session->gensec, io->in.credentials);
 420         if (!NT_STATUS_IS_OK(status)) {
 421                 DEBUG(1, ("Failed to start set GENSEC client credentials: %s\n", 
 422                           nt_errstr(status)));
 423                 return status;
 424         }
 425 
 426         status = gensec_set_target_hostname(session->gensec, session->transport->socket->hostname);
 427         if (!NT_STATUS_IS_OK(status)) {
 428                 DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n", 
 429                           nt_errstr(status)));
 430                 return status;
 431         }
 432 
 433         status = gensec_set_target_service(session->gensec, "cifs");
 434         if (!NT_STATUS_IS_OK(status)) {
 435                 DEBUG(1, ("Failed to start set GENSEC target service: %s\n", 
 436                           nt_errstr(status)));
 437                 return status;
 438         }
 439 
 440         if (session->transport->negotiate.secblob.length) {
 441                 chosen_oid = GENSEC_OID_SPNEGO;
 442                 status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
 443                 if (!NT_STATUS_IS_OK(status)) {
 444                         DEBUG(1, ("Failed to start set GENSEC client mechanism %s: %s\n",
 445                                   gensec_get_name_by_oid(session->gensec, chosen_oid), nt_errstr(status)));
 446                         chosen_oid = GENSEC_OID_NTLMSSP;
 447                         status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
 448                         if (!NT_STATUS_IS_OK(status)) {
 449                                 DEBUG(1, ("Failed to start set (fallback) GENSEC client mechanism %s: %s\n",
 450                                           gensec_get_name_by_oid(session->gensec, chosen_oid), 
 451                                           nt_errstr(status)));
 452                         return status;
 453                         }
 454                 }
 455         } else {
 456                 /* without a sec blob, means raw NTLMSSP */
 457                 chosen_oid = GENSEC_OID_NTLMSSP;
 458                 status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
 459                 if (!NT_STATUS_IS_OK(status)) {
 460                         DEBUG(1, ("Failed to start set GENSEC client mechanism %s: %s\n",
 461                                   gensec_get_name_by_oid(session->gensec, chosen_oid), nt_errstr(status)));
 462                 }
 463         }
 464 
 465         if ((const void *)chosen_oid == (const void *)GENSEC_OID_SPNEGO) {
 466                 status = gensec_update(session->gensec, state,
 467                                        session->transport->negotiate.secblob,
 468                                        &state->setup.spnego.in.secblob);
 469         } else {
 470                 status = gensec_update(session->gensec, state,
 471                                        data_blob(NULL, 0),
 472                                        &state->setup.spnego.in.secblob);
 473 
 474         }
 475 
 476         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && 
 477             !NT_STATUS_IS_OK(status)) {
 478                 DEBUG(1, ("Failed initial gensec_update with mechanism %s: %s\n",
 479                           gensec_get_name_by_oid(session->gensec, chosen_oid), 
 480                           nt_errstr(status)));
 481                 return status;
 482         }
 483         state->gensec_status = status;
 484 
 485         *req = smb_raw_sesssetup_send(session, &state->setup);
 486         if (!*req) {
 487                 return NT_STATUS_NO_MEMORY;
 488         }
 489 
 490         /*
 491          * we need to check the signature ourself
 492          * as the session key might be the acceptor subkey
 493          * which comes within the response itself
 494          */
 495         (*req)->sign_caller_checks = true;
 496 
 497         return (*req)->status;
 498 }
 499 
 500 
 501 /*
 502   composite session setup function that hides the details of all the
 503   different session setup varients, including the multi-pass nature of
 504   the spnego varient
 505 */
 506 struct composite_context *smb_composite_sesssetup_send(struct smbcli_session *session, 
     /* [<][>][^][v][top][bottom][index][help] */
 507                                                        struct smb_composite_sesssetup *io)
 508 {
 509         struct composite_context *c;
 510         struct sesssetup_state *state;
 511         NTSTATUS status;
 512 
 513         c = composite_create(session, session->transport->socket->event.ctx);
 514         if (c == NULL) return NULL;
 515 
 516         state = talloc_zero(c, struct sesssetup_state);
 517         if (composite_nomem(state, c)) return c;
 518         c->private_data = state;
 519 
 520         state->io = io;
 521 
 522         talloc_set_destructor(state, sesssetup_state_destructor);
 523 
 524         /* no session setup at all in earliest protocol varients */
 525         if (session->transport->negotiate.protocol < PROTOCOL_LANMAN1) {
 526                 ZERO_STRUCT(io->out);
 527                 composite_done(c);
 528                 return c;
 529         }
 530 
 531         /* see what session setup interface we will use */
 532         if (session->transport->negotiate.protocol < PROTOCOL_NT1) {
 533                 status = session_setup_old(c, session, io, &state->req);
 534         } else if (!session->transport->options.use_spnego ||
 535                    !(io->in.capabilities & CAP_EXTENDED_SECURITY)) {
 536                 status = session_setup_nt1(c, session, io, &state->req);
 537         } else {
 538                 status = session_setup_spnego(c, session, io, &state->req);
 539         }
 540 
 541         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) || 
 542             NT_STATUS_IS_OK(status)) {
 543                 composite_continue_smb(c, state->req, request_handler, c);      
 544                 return c;
 545         }
 546 
 547         composite_error(c, status);
 548         return c;
 549 }
 550 
 551 
 552 /*
 553   receive a composite session setup reply
 554 */
 555 NTSTATUS smb_composite_sesssetup_recv(struct composite_context *c)
     /* [<][>][^][v][top][bottom][index][help] */
 556 {
 557         NTSTATUS status;
 558         status = composite_wait(c);
 559         talloc_free(c);
 560         return status;
 561 }
 562 
 563 /*
 564   sync version of smb_composite_sesssetup 
 565 */
 566 NTSTATUS smb_composite_sesssetup(struct smbcli_session *session, struct smb_composite_sesssetup *io)
     /* [<][>][^][v][top][bottom][index][help] */
 567 {
 568         struct composite_context *c = smb_composite_sesssetup_send(session, io);
 569         return smb_composite_sesssetup_recv(c);
 570 }

/* [<][>][^][v][top][bottom][index][help] */