root/source3/smbd/sesssetup.c

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

DEFINITIONS

This source file includes following definitions.
  1. do_map_to_guest
  2. push_signature
  3. sessionsetup_start_signing_engine
  4. reply_sesssetup_blob
  5. check_guest_password
  6. make_krb5_skew_error
  7. reply_spnego_kerberos
  8. reply_spnego_ntlmssp
  9. parse_spnego_mechanisms
  10. reply_spnego_downgrade_to_ntlmssp
  11. reply_spnego_negotiate
  12. reply_spnego_auth
  13. delete_partial_auth
  14. get_pending_auth_data
  15. check_spnego_blob_complete
  16. reply_sesssetup_and_X_spnego
  17. shutdown_other_smbds
  18. setup_new_vc_session
  19. reply_sesssetup_and_X

   1 /*
   2    Unix SMB/CIFS implementation.
   3    handle SMBsessionsetup
   4    Copyright (C) Andrew Tridgell 1998-2001
   5    Copyright (C) Andrew Bartlett      2001
   6    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
   7    Copyright (C) Luke Howard          2003
   8    Copyright (C) Volker Lendecke      2007
   9    Copyright (C) Jeremy Allison       2007
  10 
  11    This program is free software; you can redistribute it and/or modify
  12    it under the terms of the GNU General Public License as published by
  13    the Free Software Foundation; either version 3 of the License, or
  14    (at your option) any later version.
  15 
  16    This program is distributed in the hope that it will be useful,
  17    but WITHOUT ANY WARRANTY; without even the implied warranty of
  18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19    GNU General Public License for more details.
  20 
  21    You should have received a copy of the GNU General Public License
  22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  23 */
  24 
  25 #include "includes.h"
  26 #include "smbd/globals.h"
  27 
  28 extern enum protocol_types Protocol;
  29 
  30 /*
  31   on a logon error possibly map the error to success if "map to guest"
  32   is set approriately
  33 */
  34 static NTSTATUS do_map_to_guest(NTSTATUS status,
     /* [<][>][^][v][top][bottom][index][help] */
  35                                 auth_serversupplied_info **server_info,
  36                                 const char *user, const char *domain)
  37 {
  38         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
  39                 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
  40                     (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
  41                         DEBUG(3,("No such user %s [%s] - using guest account\n",
  42                                  user, domain));
  43                         status = make_server_info_guest(NULL, server_info);
  44                 }
  45         }
  46 
  47         if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
  48                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
  49                         DEBUG(3,("Registered username %s for guest access\n",
  50                                 user));
  51                         status = make_server_info_guest(NULL, server_info);
  52                 }
  53         }
  54 
  55         return status;
  56 }
  57 
  58 /****************************************************************************
  59  Add the standard 'Samba' signature to the end of the session setup.
  60 ****************************************************************************/
  61 
  62 static int push_signature(uint8 **outbuf)
     /* [<][>][^][v][top][bottom][index][help] */
  63 {
  64         char *lanman;
  65         int result, tmp;
  66 
  67         result = 0;
  68 
  69         tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
  70 
  71         if (tmp == -1) return -1;
  72         result += tmp;
  73 
  74         if (asprintf(&lanman, "Samba %s", samba_version_string()) != -1) {
  75                 tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
  76                 SAFE_FREE(lanman);
  77         }
  78         else {
  79                 tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
  80         }
  81 
  82         if (tmp == -1) return -1;
  83         result += tmp;
  84 
  85         tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
  86 
  87         if (tmp == -1) return -1;
  88         result += tmp;
  89 
  90         return result;
  91 }
  92 
  93 /****************************************************************************
  94  Start the signing engine if needed. Don't fail signing here.
  95 ****************************************************************************/
  96 
  97 static void sessionsetup_start_signing_engine(
     /* [<][>][^][v][top][bottom][index][help] */
  98                         const auth_serversupplied_info *server_info,
  99                         const uint8 *inbuf)
 100 {
 101         if (!server_info->guest && !srv_signing_started()) {
 102                 /* We need to start the signing engine
 103                  * here but a W2K client sends the old
 104                  * "BSRSPYL " signature instead of the
 105                  * correct one. Subsequent packets will
 106                  * be correct.
 107                  */
 108                 srv_check_sign_mac((char *)inbuf, False);
 109         }
 110 }
 111 
 112 /****************************************************************************
 113  Send a security blob via a session setup reply.
 114 ****************************************************************************/
 115 
 116 static void reply_sesssetup_blob(struct smb_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 117                                  DATA_BLOB blob,
 118                                  NTSTATUS nt_status)
 119 {
 120         if (!NT_STATUS_IS_OK(nt_status) &&
 121             !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
 122                 reply_nterror(req, nt_status_squash(nt_status));
 123                 return;
 124         }
 125 
 126         nt_status = nt_status_squash(nt_status);
 127         SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
 128         SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
 129         SSVAL(req->outbuf, smb_vwv3, blob.length);
 130 
 131         if ((message_push_blob(&req->outbuf, blob) == -1)
 132             || (push_signature(&req->outbuf) == -1)) {
 133                 reply_nterror(req, NT_STATUS_NO_MEMORY);
 134         }
 135 }
 136 
 137 /****************************************************************************
 138  Do a 'guest' logon, getting back the
 139 ****************************************************************************/
 140 
 141 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
     /* [<][>][^][v][top][bottom][index][help] */
 142 {
 143         struct auth_context *auth_context;
 144         auth_usersupplied_info *user_info = NULL;
 145 
 146         NTSTATUS nt_status;
 147         unsigned char chal[8];
 148 
 149         ZERO_STRUCT(chal);
 150 
 151         DEBUG(3,("Got anonymous request\n"));
 152 
 153         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context,
 154                                         chal))) {
 155                 return nt_status;
 156         }
 157 
 158         if (!make_user_info_guest(&user_info)) {
 159                 (auth_context->free)(&auth_context);
 160                 return NT_STATUS_NO_MEMORY;
 161         }
 162 
 163         nt_status = auth_context->check_ntlm_password(auth_context,
 164                                                 user_info,
 165                                                 server_info);
 166         (auth_context->free)(&auth_context);
 167         free_user_info(&user_info);
 168         return nt_status;
 169 }
 170 
 171 
 172 #ifdef HAVE_KRB5
 173 
 174 #if 0
 175 /* Experiment that failed. See "only happens with a KDC" comment below. */
 176 /****************************************************************************
 177  Cerate a clock skew error blob for a Windows client.
 178 ****************************************************************************/
 179 
 180 static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
     /* [<][>][^][v][top][bottom][index][help] */
 181 {
 182         krb5_context context = NULL;
 183         krb5_error_code kerr = 0;
 184         krb5_data reply;
 185         krb5_principal host_princ = NULL;
 186         char *host_princ_s = NULL;
 187         bool ret = False;
 188 
 189         *pblob_out = data_blob_null;
 190 
 191         initialize_krb5_error_table();
 192         kerr = krb5_init_context(&context);
 193         if (kerr) {
 194                 return False;
 195         }
 196         /* Create server principal. */
 197         asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
 198         if (!host_princ_s) {
 199                 goto out;
 200         }
 201         strlower_m(host_princ_s);
 202 
 203         kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
 204         if (kerr) {
 205                 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
 206                         "for name %s: Error %s\n",
 207                         host_princ_s, error_message(kerr) ));
 208                 goto out;
 209         }
 210 
 211         kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
 212                         host_princ, &reply);
 213         if (kerr) {
 214                 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
 215                         "failed: Error %s\n",
 216                         error_message(kerr) ));
 217                 goto out;
 218         }
 219 
 220         *pblob_out = data_blob(reply.data, reply.length);
 221         kerberos_free_data_contents(context,&reply);
 222         ret = True;
 223 
 224   out:
 225 
 226         if (host_princ_s) {
 227                 SAFE_FREE(host_princ_s);
 228         }
 229         if (host_princ) {
 230                 krb5_free_principal(context, host_princ);
 231         }
 232         krb5_free_context(context);
 233         return ret;
 234 }
 235 #endif
 236 
 237 /****************************************************************************
 238  Reply to a session setup spnego negotiate packet for kerberos.
 239 ****************************************************************************/
 240 
 241 static void reply_spnego_kerberos(struct smb_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 242                                   DATA_BLOB *secblob,
 243                                   const char *mechOID,
 244                                   uint16 vuid,
 245                                   bool *p_invalidate_vuid)
 246 {
 247         TALLOC_CTX *mem_ctx;
 248         DATA_BLOB ticket;
 249         char *client, *p, *domain;
 250         fstring netbios_domain_name;
 251         struct passwd *pw;
 252         fstring user;
 253         int sess_vuid = req->vuid;
 254         NTSTATUS ret = NT_STATUS_OK;
 255         struct PAC_DATA *pac_data = NULL;
 256         DATA_BLOB ap_rep, ap_rep_wrapped, response;
 257         auth_serversupplied_info *server_info = NULL;
 258         DATA_BLOB session_key = data_blob_null;
 259         uint8 tok_id[2];
 260         DATA_BLOB nullblob = data_blob_null;
 261         fstring real_username;
 262         bool map_domainuser_to_guest = False;
 263         bool username_was_mapped;
 264         struct PAC_LOGON_INFO *logon_info = NULL;
 265 
 266         ZERO_STRUCT(ticket);
 267         ZERO_STRUCT(ap_rep);
 268         ZERO_STRUCT(ap_rep_wrapped);
 269         ZERO_STRUCT(response);
 270 
 271         /* Normally we will always invalidate the intermediate vuid. */
 272         *p_invalidate_vuid = True;
 273 
 274         mem_ctx = talloc_init("reply_spnego_kerberos");
 275         if (mem_ctx == NULL) {
 276                 reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
 277                 return;
 278         }
 279 
 280         if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
 281                 talloc_destroy(mem_ctx);
 282                 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
 283                 return;
 284         }
 285 
 286         ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
 287                                 &client, &pac_data, &ap_rep,
 288                                 &session_key, True);
 289 
 290         data_blob_free(&ticket);
 291 
 292         if (!NT_STATUS_IS_OK(ret)) {
 293 #if 0
 294                 /* Experiment that failed.
 295                  * See "only happens with a KDC" comment below. */
 296 
 297                 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
 298 
 299                         /*
 300                          * Windows in this case returns
 301                          * NT_STATUS_MORE_PROCESSING_REQUIRED
 302                          * with a negTokenTarg blob containing an krb5_error
 303                          * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
 304                          * The client then fixes its clock and continues rather
 305                          * than giving an error. JRA.
 306                          * -- Looks like this only happens with a KDC. JRA.
 307                          */
 308 
 309                         bool ok = make_krb5_skew_error(&ap_rep);
 310                         if (!ok) {
 311                                 talloc_destroy(mem_ctx);
 312                                 return ERROR_NT(nt_status_squash(
 313                                                 NT_STATUS_LOGON_FAILURE));
 314                         }
 315                         ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
 316                                         TOK_ID_KRB_ERROR);
 317                         response = spnego_gen_auth_response(&ap_rep_wrapped,
 318                                         ret, OID_KERBEROS5_OLD);
 319                         reply_sesssetup_blob(conn, inbuf, outbuf, response,
 320                                         NT_STATUS_MORE_PROCESSING_REQUIRED);
 321 
 322                         /*
 323                          * In this one case we don't invalidate the
 324                          * intermediate vuid as we're expecting the client
 325                          * to re-use it for the next sessionsetupX packet. JRA.
 326                          */
 327 
 328                         *p_invalidate_vuid = False;
 329 
 330                         data_blob_free(&ap_rep);
 331                         data_blob_free(&ap_rep_wrapped);
 332                         data_blob_free(&response);
 333                         talloc_destroy(mem_ctx);
 334                         return -1; /* already replied */
 335                 }
 336 #else
 337                 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
 338                         ret = NT_STATUS_LOGON_FAILURE;
 339                 }
 340 #endif
 341                 DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
 342                                 nt_errstr(ret)));
 343                 talloc_destroy(mem_ctx);
 344                 reply_nterror(req, nt_status_squash(ret));
 345                 return;
 346         }
 347 
 348         DEBUG(3,("Ticket name is [%s]\n", client));
 349 
 350         p = strchr_m(client, '@');
 351         if (!p) {
 352                 DEBUG(3,("Doesn't look like a valid principal\n"));
 353                 data_blob_free(&ap_rep);
 354                 data_blob_free(&session_key);
 355                 talloc_destroy(mem_ctx);
 356                 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
 357                 return;
 358         }
 359 
 360         *p = 0;
 361 
 362         /* save the PAC data if we have it */
 363 
 364         if (pac_data) {
 365                 logon_info = get_logon_info_from_pac(pac_data);
 366                 if (logon_info) {
 367                         netsamlogon_cache_store( client, &logon_info->info3 );
 368                 }
 369         }
 370 
 371         if (!strequal(p+1, lp_realm())) {
 372                 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
 373                 if (!lp_allow_trusted_domains()) {
 374                         data_blob_free(&ap_rep);
 375                         data_blob_free(&session_key);
 376                         talloc_destroy(mem_ctx);
 377                         reply_nterror(req, nt_status_squash(
 378                                               NT_STATUS_LOGON_FAILURE));
 379                         return;
 380                 }
 381         }
 382 
 383         /* this gives a fully qualified user name (ie. with full realm).
 384            that leads to very long usernames, but what else can we do? */
 385 
 386         domain = p+1;
 387 
 388         if (logon_info && logon_info->info3.base.domain.string) {
 389                 fstrcpy(netbios_domain_name,
 390                         logon_info->info3.base.domain.string);
 391                 domain = netbios_domain_name;
 392                 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
 393 
 394         } else {
 395 
 396                 /* If we have winbind running, we can (and must) shorten the
 397                    username by using the short netbios name. Otherwise we will
 398                    have inconsistent user names. With Kerberos, we get the
 399                    fully qualified realm, with ntlmssp we get the short
 400                    name. And even w2k3 does use ntlmssp if you for example
 401                    connect to an ip address. */
 402 
 403                 wbcErr wbc_status;
 404                 struct wbcDomainInfo *info = NULL;
 405 
 406                 DEBUG(10, ("Mapping [%s] to short name\n", domain));
 407 
 408                 wbc_status = wbcDomainInfo(domain, &info);
 409 
 410                 if (WBC_ERROR_IS_OK(wbc_status)) {
 411 
 412                         fstrcpy(netbios_domain_name,
 413                                 info->short_name);
 414 
 415                         wbcFreeMemory(info);
 416                         domain = netbios_domain_name;
 417                         DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
 418                 } else {
 419                         DEBUG(3, ("Could not find short name: %s\n",
 420                                 wbcErrorString(wbc_status)));
 421                 }
 422         }
 423 
 424         fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
 425 
 426         /* lookup the passwd struct, create a new user if necessary */
 427 
 428         username_was_mapped = map_username( user );
 429 
 430         pw = smb_getpwnam( mem_ctx, user, real_username, True );
 431 
 432         if (pw) {
 433                 /* if a real user check pam account restrictions */
 434                 /* only really perfomed if "obey pam restriction" is true */
 435                 /* do this before an eventual mapping to guest occurs */
 436                 ret = smb_pam_accountcheck(pw->pw_name);
 437                 if (  !NT_STATUS_IS_OK(ret)) {
 438                         DEBUG(1,("PAM account restriction "
 439                                 "prevents user login\n"));
 440                         data_blob_free(&ap_rep);
 441                         data_blob_free(&session_key);
 442                         TALLOC_FREE(mem_ctx);
 443                         reply_nterror(req, nt_status_squash(ret));
 444                         return;
 445                 }
 446         }
 447 
 448         if (!pw) {
 449 
 450                 /* this was originally the behavior of Samba 2.2, if a user
 451                    did not have a local uid but has been authenticated, then
 452                    map them to a guest account */
 453 
 454                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
 455                         map_domainuser_to_guest = True;
 456                         fstrcpy(user,lp_guestaccount());
 457                         pw = smb_getpwnam( mem_ctx, user, real_username, True );
 458                 }
 459 
 460                 /* extra sanity check that the guest account is valid */
 461 
 462                 if ( !pw ) {
 463                         DEBUG(1,("Username %s is invalid on this system\n",
 464                                 user));
 465                         data_blob_free(&ap_rep);
 466                         data_blob_free(&session_key);
 467                         TALLOC_FREE(mem_ctx);
 468                         reply_nterror(req, nt_status_squash(
 469                                               NT_STATUS_LOGON_FAILURE));
 470                         return;
 471                 }
 472         }
 473 
 474         /* setup the string used by %U */
 475 
 476         sub_set_smb_name( real_username );
 477         reload_services(True);
 478 
 479         if ( map_domainuser_to_guest ) {
 480                 make_server_info_guest(NULL, &server_info);
 481         } else if (logon_info) {
 482                 /* pass the unmapped username here since map_username()
 483                    will be called again from inside make_server_info_info3() */
 484 
 485                 ret = make_server_info_info3(mem_ctx, client, domain,
 486                                              &server_info, &logon_info->info3);
 487                 if ( !NT_STATUS_IS_OK(ret) ) {
 488                         DEBUG(1,("make_server_info_info3 failed: %s!\n",
 489                                  nt_errstr(ret)));
 490                         data_blob_free(&ap_rep);
 491                         data_blob_free(&session_key);
 492                         TALLOC_FREE(mem_ctx);
 493                         reply_nterror(req, nt_status_squash(ret));
 494                         return;
 495                 }
 496 
 497         } else {
 498                 ret = make_server_info_pw(&server_info, real_username, pw);
 499 
 500                 if ( !NT_STATUS_IS_OK(ret) ) {
 501                         DEBUG(1,("make_server_info_pw failed: %s!\n",
 502                                  nt_errstr(ret)));
 503                         data_blob_free(&ap_rep);
 504                         data_blob_free(&session_key);
 505                         TALLOC_FREE(mem_ctx);
 506                         reply_nterror(req, nt_status_squash(ret));
 507                         return;
 508                 }
 509 
 510                 /* make_server_info_pw does not set the domain. Without this
 511                  * we end up with the local netbios name in substitutions for
 512                  * %D. */
 513 
 514                 if (server_info->sam_account != NULL) {
 515                         pdb_set_domain(server_info->sam_account,
 516                                         domain, PDB_SET);
 517                 }
 518         }
 519 
 520         server_info->nss_token |= username_was_mapped;
 521 
 522         /* we need to build the token for the user. make_server_info_guest()
 523            already does this */
 524 
 525         if ( !server_info->ptok ) {
 526                 ret = create_local_token( server_info );
 527                 if ( !NT_STATUS_IS_OK(ret) ) {
 528                         DEBUG(10,("failed to create local token: %s\n",
 529                                 nt_errstr(ret)));
 530                         data_blob_free(&ap_rep);
 531                         data_blob_free(&session_key);
 532                         TALLOC_FREE( mem_ctx );
 533                         TALLOC_FREE( server_info );
 534                         reply_nterror(req, nt_status_squash(ret));
 535                         return;
 536                 }
 537         }
 538 
 539         if (!is_partial_auth_vuid(sess_vuid)) {
 540                 sess_vuid = register_initial_vuid();
 541         }
 542 
 543         data_blob_free(&server_info->user_session_key);
 544         server_info->user_session_key = session_key;
 545         session_key = data_blob_null;
 546 
 547         /* register_existing_vuid keeps the server info */
 548         /* register_existing_vuid takes ownership of session_key on success,
 549          * no need to free after this on success. A better interface would copy
 550          * it.... */
 551 
 552         sess_vuid = register_existing_vuid(sess_vuid,
 553                                         server_info,
 554                                         nullblob,
 555                                         client);
 556 
 557         reply_outbuf(req, 4, 0);
 558         SSVAL(req->outbuf,smb_uid,sess_vuid);
 559 
 560         if (sess_vuid == UID_FIELD_INVALID ) {
 561                 ret = NT_STATUS_LOGON_FAILURE;
 562         } else {
 563                 /* current_user_info is changed on new vuid */
 564                 reload_services( True );
 565 
 566                 SSVAL(req->outbuf, smb_vwv3, 0);
 567 
 568                 if (server_info->guest) {
 569                         SSVAL(req->outbuf,smb_vwv2,1);
 570                 }
 571 
 572                 SSVAL(req->outbuf, smb_uid, sess_vuid);
 573 
 574                 sessionsetup_start_signing_engine(server_info, req->inbuf);
 575                 /* Successful logon. Keep this vuid. */
 576                 *p_invalidate_vuid = False;
 577         }
 578 
 579         /* wrap that up in a nice GSS-API wrapping */
 580         if (NT_STATUS_IS_OK(ret)) {
 581                 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
 582                                 TOK_ID_KRB_AP_REP);
 583         } else {
 584                 ap_rep_wrapped = data_blob_null;
 585         }
 586         response = spnego_gen_auth_response(&ap_rep_wrapped, ret,
 587                         mechOID);
 588         reply_sesssetup_blob(req, response, ret);
 589 
 590         data_blob_free(&ap_rep);
 591         data_blob_free(&ap_rep_wrapped);
 592         data_blob_free(&response);
 593         TALLOC_FREE(mem_ctx);
 594 }
 595 
 596 #endif
 597 
 598 /****************************************************************************
 599  Send a session setup reply, wrapped in SPNEGO.
 600  Get vuid and check first.
 601  End the NTLMSSP exchange context if we are OK/complete fail
 602  This should be split into two functions, one to handle each
 603  leg of the NTLM auth steps.
 604 ***************************************************************************/
 605 
 606 static void reply_spnego_ntlmssp(struct smb_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 607                                  uint16 vuid,
 608                                  AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
 609                                  DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
 610                                  const char *OID,
 611                                  bool wrap)
 612 {
 613         DATA_BLOB response;
 614         struct auth_serversupplied_info *server_info = NULL;
 615 
 616         if (NT_STATUS_IS_OK(nt_status)) {
 617                 server_info = (*auth_ntlmssp_state)->server_info;
 618         } else {
 619                 nt_status = do_map_to_guest(nt_status,
 620                             &server_info,
 621                             (*auth_ntlmssp_state)->ntlmssp_state->user,
 622                             (*auth_ntlmssp_state)->ntlmssp_state->domain);
 623         }
 624 
 625         reply_outbuf(req, 4, 0);
 626 
 627         SSVAL(req->outbuf, smb_uid, vuid);
 628 
 629         if (NT_STATUS_IS_OK(nt_status)) {
 630                 DATA_BLOB nullblob = data_blob_null;
 631 
 632                 if (!is_partial_auth_vuid(vuid)) {
 633                         nt_status = NT_STATUS_LOGON_FAILURE;
 634                         goto out;
 635                 }
 636 
 637                 data_blob_free(&server_info->user_session_key);
 638                 server_info->user_session_key =
 639                         data_blob_talloc(
 640                         server_info,
 641                         (*auth_ntlmssp_state)->ntlmssp_state->session_key.data,
 642                         (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
 643 
 644                 /* register_existing_vuid keeps the server info */
 645                 if (register_existing_vuid(vuid,
 646                                 server_info, nullblob,
 647                                 (*auth_ntlmssp_state)->ntlmssp_state->user) !=
 648                                         vuid) {
 649                         nt_status = NT_STATUS_LOGON_FAILURE;
 650                         goto out;
 651                 }
 652 
 653                 (*auth_ntlmssp_state)->server_info = NULL;
 654 
 655                 /* current_user_info is changed on new vuid */
 656                 reload_services( True );
 657 
 658                 SSVAL(req->outbuf, smb_vwv3, 0);
 659 
 660                 if (server_info->guest) {
 661                         SSVAL(req->outbuf,smb_vwv2,1);
 662                 }
 663 
 664                 sessionsetup_start_signing_engine(server_info,
 665                                                   (uint8 *)req->inbuf);
 666         }
 667 
 668   out:
 669 
 670         if (wrap) {
 671                 response = spnego_gen_auth_response(ntlmssp_blob,
 672                                 nt_status, OID);
 673         } else {
 674                 response = *ntlmssp_blob;
 675         }
 676 
 677         reply_sesssetup_blob(req, response, nt_status);
 678         if (wrap) {
 679                 data_blob_free(&response);
 680         }
 681 
 682         /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
 683            and the other end, that we are not finished yet. */
 684 
 685         if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
 686                 /* NB. This is *NOT* an error case. JRA */
 687                 auth_ntlmssp_end(auth_ntlmssp_state);
 688                 if (!NT_STATUS_IS_OK(nt_status)) {
 689                         /* Kill the intermediate vuid */
 690                         invalidate_vuid(vuid);
 691                 }
 692         }
 693 }
 694 
 695 /****************************************************************************
 696  Is this a krb5 mechanism ?
 697 ****************************************************************************/
 698 
 699 NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in,
     /* [<][>][^][v][top][bottom][index][help] */
 700                 DATA_BLOB *pblob_out,
 701                 char **kerb_mechOID)
 702 {
 703         char *OIDs[ASN1_MAX_OIDS];
 704         int i;
 705         NTSTATUS ret = NT_STATUS_OK;
 706 
 707         *kerb_mechOID = NULL;
 708 
 709         /* parse out the OIDs and the first sec blob */
 710         if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
 711                 return NT_STATUS_LOGON_FAILURE;
 712         }
 713 
 714         /* only look at the first OID for determining the mechToken --
 715            according to RFC2478, we should choose the one we want
 716            and renegotiate, but i smell a client bug here..
 717 
 718            Problem observed when connecting to a member (samba box)
 719            of an AD domain as a user in a Samba domain.  Samba member
 720            server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
 721            client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
 722            NTLMSSP mechtoken.                 --jerry              */
 723 
 724 #ifdef HAVE_KRB5
 725         if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
 726             strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
 727                 *kerb_mechOID = SMB_STRDUP(OIDs[0]);
 728                 if (*kerb_mechOID == NULL) {
 729                         ret = NT_STATUS_NO_MEMORY;
 730                 }
 731         }
 732 #endif
 733 
 734         for (i=0;OIDs[i];i++) {
 735                 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
 736                 talloc_free(OIDs[i]);
 737         }
 738         return ret;
 739 }
 740 
 741 /****************************************************************************
 742  Fall back from krb5 to NTLMSSP.
 743 ****************************************************************************/
 744 
 745 static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 746                                                 uint16 vuid)
 747 {
 748         DATA_BLOB response;
 749 
 750         reply_outbuf(req, 4, 0);
 751         SSVAL(req->outbuf,smb_uid,vuid);
 752 
 753         DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
 754                 "but set to downgrade to NTLMSSP\n"));
 755 
 756         response = spnego_gen_auth_response(NULL,
 757                         NT_STATUS_MORE_PROCESSING_REQUIRED,
 758                         OID_NTLMSSP);
 759         reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
 760         data_blob_free(&response);
 761 }
 762 
 763 /****************************************************************************
 764  Reply to a session setup spnego negotiate packet.
 765 ****************************************************************************/
 766 
 767 static void reply_spnego_negotiate(struct smb_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 768                                    uint16 vuid,
 769                                    DATA_BLOB blob1,
 770                                    AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
 771 {
 772         DATA_BLOB secblob;
 773         DATA_BLOB chal;
 774         char *kerb_mech = NULL;
 775         NTSTATUS status;
 776 
 777         status = parse_spnego_mechanisms(blob1, &secblob, &kerb_mech);
 778         if (!NT_STATUS_IS_OK(status)) {
 779                 /* Kill the intermediate vuid */
 780                 invalidate_vuid(vuid);
 781                 reply_nterror(req, nt_status_squash(status));
 782                 return;
 783         }
 784 
 785         DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
 786                                 (unsigned long)secblob.length));
 787 
 788 #ifdef HAVE_KRB5
 789         if (kerb_mech && ((lp_security()==SEC_ADS) ||
 790                                 USE_KERBEROS_KEYTAB) ) {
 791                 bool destroy_vuid = True;
 792                 reply_spnego_kerberos(req, &secblob, kerb_mech,
 793                                       vuid, &destroy_vuid);
 794                 data_blob_free(&secblob);
 795                 if (destroy_vuid) {
 796                         /* Kill the intermediate vuid */
 797                         invalidate_vuid(vuid);
 798                 }
 799                 SAFE_FREE(kerb_mech);
 800                 return;
 801         }
 802 #endif
 803 
 804         if (*auth_ntlmssp_state) {
 805                 auth_ntlmssp_end(auth_ntlmssp_state);
 806         }
 807 
 808         if (kerb_mech) {
 809                 data_blob_free(&secblob);
 810                 /* The mechtoken is a krb5 ticket, but
 811                  * we need to fall back to NTLM. */
 812                 reply_spnego_downgrade_to_ntlmssp(req, vuid);
 813                 SAFE_FREE(kerb_mech);
 814                 return;
 815         }
 816 
 817         status = auth_ntlmssp_start(auth_ntlmssp_state);
 818         if (!NT_STATUS_IS_OK(status)) {
 819                 /* Kill the intermediate vuid */
 820                 invalidate_vuid(vuid);
 821                 reply_nterror(req, nt_status_squash(status));
 822                 return;
 823         }
 824 
 825         status = auth_ntlmssp_update(*auth_ntlmssp_state,
 826                                         secblob, &chal);
 827 
 828         data_blob_free(&secblob);
 829 
 830         reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
 831                              &chal, status, OID_NTLMSSP, true);
 832 
 833         data_blob_free(&chal);
 834 
 835         /* already replied */
 836         return;
 837 }
 838 
 839 /****************************************************************************
 840  Reply to a session setup spnego auth packet.
 841 ****************************************************************************/
 842 
 843 static void reply_spnego_auth(struct smb_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 844                               uint16 vuid,
 845                               DATA_BLOB blob1,
 846                               AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
 847 {
 848         DATA_BLOB auth = data_blob_null;
 849         DATA_BLOB auth_reply = data_blob_null;
 850         DATA_BLOB secblob = data_blob_null;
 851         NTSTATUS status = NT_STATUS_LOGON_FAILURE;
 852 
 853         if (!spnego_parse_auth(blob1, &auth)) {
 854 #if 0
 855                 file_save("auth.dat", blob1.data, blob1.length);
 856 #endif
 857                 /* Kill the intermediate vuid */
 858                 invalidate_vuid(vuid);
 859 
 860                 reply_nterror(req, nt_status_squash(
 861                                       NT_STATUS_LOGON_FAILURE));
 862                 return;
 863         }
 864 
 865         if (auth.data[0] == ASN1_APPLICATION(0)) {
 866                 /* Might be a second negTokenTarg packet */
 867                 char *kerb_mech = NULL;
 868 
 869                 status = parse_spnego_mechanisms(auth, &secblob, &kerb_mech);
 870 
 871                 if (!NT_STATUS_IS_OK(status)) {
 872                         /* Kill the intermediate vuid */
 873                         invalidate_vuid(vuid);
 874                         reply_nterror(req, nt_status_squash(status));
 875                         return;
 876                 }
 877 
 878                 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
 879                                 (unsigned long)secblob.length));
 880 #ifdef HAVE_KRB5
 881                 if (kerb_mech && ((lp_security()==SEC_ADS) ||
 882                                         USE_KERBEROS_KEYTAB)) {
 883                         bool destroy_vuid = True;
 884                         reply_spnego_kerberos(req, &secblob, kerb_mech,
 885                                               vuid, &destroy_vuid);
 886                         data_blob_free(&secblob);
 887                         data_blob_free(&auth);
 888                         if (destroy_vuid) {
 889                                 /* Kill the intermediate vuid */
 890                                 invalidate_vuid(vuid);
 891                         }
 892                         SAFE_FREE(kerb_mech);
 893                         return;
 894                 }
 895 #endif
 896                 /* Can't blunder into NTLMSSP auth if we have
 897                  * a krb5 ticket. */
 898 
 899                 if (kerb_mech) {
 900                         /* Kill the intermediate vuid */
 901                         invalidate_vuid(vuid);
 902                         DEBUG(3,("reply_spnego_auth: network "
 903                                 "misconfiguration, client sent us a "
 904                                 "krb5 ticket and kerberos security "
 905                                 "not enabled\n"));
 906                         reply_nterror(req, nt_status_squash(
 907                                         NT_STATUS_LOGON_FAILURE));
 908                         SAFE_FREE(kerb_mech);
 909                 }
 910         }
 911 
 912         /* If we get here it wasn't a negTokenTarg auth packet. */
 913         data_blob_free(&secblob);
 914 
 915         if (!*auth_ntlmssp_state) {
 916                 status = auth_ntlmssp_start(auth_ntlmssp_state);
 917                 if (!NT_STATUS_IS_OK(status)) {
 918                         /* Kill the intermediate vuid */
 919                         invalidate_vuid(vuid);
 920                         reply_nterror(req, nt_status_squash(status));
 921                         return;
 922                 }
 923         }
 924 
 925         status = auth_ntlmssp_update(*auth_ntlmssp_state,
 926                                         auth, &auth_reply);
 927 
 928         data_blob_free(&auth);
 929 
 930         /* Don't send the mechid as we've already sent this (RFC4178). */
 931 
 932         reply_spnego_ntlmssp(req, vuid,
 933                              auth_ntlmssp_state,
 934                              &auth_reply, status, NULL, true);
 935 
 936         data_blob_free(&auth_reply);
 937 
 938         /* and tell smbd that we have already replied to this packet */
 939         return;
 940 }
 941 
 942 /****************************************************************************
 943  Delete an entry on the list.
 944 ****************************************************************************/
 945 
 946 static void delete_partial_auth(struct pending_auth_data *pad)
     /* [<][>][^][v][top][bottom][index][help] */
 947 {
 948         if (!pad) {
 949                 return;
 950         }
 951         DLIST_REMOVE(pd_list, pad);
 952         data_blob_free(&pad->partial_data);
 953         SAFE_FREE(pad);
 954 }
 955 
 956 /****************************************************************************
 957  Search for a partial SPNEGO auth fragment matching an smbpid.
 958 ****************************************************************************/
 959 
 960 static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
     /* [<][>][^][v][top][bottom][index][help] */
 961 {
 962         struct pending_auth_data *pad;
 963 
 964         for (pad = pd_list; pad; pad = pad->next) {
 965                 if (pad->smbpid == smbpid) {
 966                         break;
 967                 }
 968         }
 969         return pad;
 970 }
 971 
 972 /****************************************************************************
 973  Check the size of an SPNEGO blob. If we need more return
 974  NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
 975  the blob to be more than 64k.
 976 ****************************************************************************/
 977 
 978 static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid,
     /* [<][>][^][v][top][bottom][index][help] */
 979                 DATA_BLOB *pblob)
 980 {
 981         struct pending_auth_data *pad = NULL;
 982         ASN1_DATA *data;
 983         size_t needed_len = 0;
 984 
 985         pad = get_pending_auth_data(smbpid);
 986 
 987         /* Ensure we have some data. */
 988         if (pblob->length == 0) {
 989                 /* Caller can cope. */
 990                 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
 991                 delete_partial_auth(pad);
 992                 return NT_STATUS_OK;
 993         }
 994 
 995         /* Were we waiting for more data ? */
 996         if (pad) {
 997                 DATA_BLOB tmp_blob;
 998                 size_t copy_len = MIN(65536, pblob->length);
 999 
1000                 /* Integer wrap paranoia.... */
1001 
1002                 if (pad->partial_data.length + copy_len <
1003                                 pad->partial_data.length ||
1004                     pad->partial_data.length + copy_len < copy_len) {
1005 
1006                         DEBUG(2,("check_spnego_blob_complete: integer wrap "
1007                                 "pad->partial_data.length = %u, "
1008                                 "copy_len = %u\n",
1009                                 (unsigned int)pad->partial_data.length,
1010                                 (unsigned int)copy_len ));
1011 
1012                         delete_partial_auth(pad);
1013                         return NT_STATUS_INVALID_PARAMETER;
1014                 }
1015 
1016                 DEBUG(10,("check_spnego_blob_complete: "
1017                         "pad->partial_data.length = %u, "
1018                         "pad->needed_len = %u, "
1019                         "copy_len = %u, "
1020                         "pblob->length = %u,\n",
1021                         (unsigned int)pad->partial_data.length,
1022                         (unsigned int)pad->needed_len,
1023                         (unsigned int)copy_len,
1024                         (unsigned int)pblob->length ));
1025 
1026                 tmp_blob = data_blob(NULL,
1027                                 pad->partial_data.length + copy_len);
1028 
1029                 /* Concatenate the two (up to copy_len) bytes. */
1030                 memcpy(tmp_blob.data,
1031                         pad->partial_data.data,
1032                         pad->partial_data.length);
1033                 memcpy(tmp_blob.data + pad->partial_data.length,
1034                         pblob->data,
1035                         copy_len);
1036 
1037                 /* Replace the partial data. */
1038                 data_blob_free(&pad->partial_data);
1039                 pad->partial_data = tmp_blob;
1040                 ZERO_STRUCT(tmp_blob);
1041 
1042                 /* Are we done ? */
1043                 if (pblob->length >= pad->needed_len) {
1044                         /* Yes, replace pblob. */
1045                         data_blob_free(pblob);
1046                         *pblob = pad->partial_data;
1047                         ZERO_STRUCT(pad->partial_data);
1048                         delete_partial_auth(pad);
1049                         return NT_STATUS_OK;
1050                 }
1051 
1052                 /* Still need more data. */
1053                 pad->needed_len -= copy_len;
1054                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1055         }
1056 
1057         if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
1058             (pblob->data[0] != ASN1_CONTEXT(1))) {
1059                 /* Not something we can determine the
1060                  * length of.
1061                  */
1062                 return NT_STATUS_OK;
1063         }
1064 
1065         /* This is a new SPNEGO sessionsetup - see if
1066          * the data given in this blob is enough.
1067          */
1068 
1069         data = asn1_init(NULL);
1070         if (data == NULL) {
1071                 return NT_STATUS_NO_MEMORY;
1072         }
1073 
1074         asn1_load(data, *pblob);
1075         asn1_start_tag(data, pblob->data[0]);
1076         if (data->has_error || data->nesting == NULL) {
1077                 asn1_free(data);
1078                 /* Let caller catch. */
1079                 return NT_STATUS_OK;
1080         }
1081 
1082         /* Integer wrap paranoia.... */
1083 
1084         if (data->nesting->taglen + data->nesting->start < data->nesting->taglen ||
1085             data->nesting->taglen + data->nesting->start < data->nesting->start) {
1086 
1087                 DEBUG(2,("check_spnego_blob_complete: integer wrap "
1088                         "data.nesting->taglen = %u, "
1089                         "data.nesting->start = %u\n",
1090                         (unsigned int)data->nesting->taglen,
1091                         (unsigned int)data->nesting->start ));
1092 
1093                 asn1_free(data);
1094                 return NT_STATUS_INVALID_PARAMETER;
1095         }
1096 
1097         /* Total length of the needed asn1 is the tag length
1098          * plus the current offset. */
1099 
1100         needed_len = data->nesting->taglen + data->nesting->start;
1101         asn1_free(data);
1102 
1103         DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
1104                 "pblob->length = %u\n",
1105                 (unsigned int)needed_len,
1106                 (unsigned int)pblob->length ));
1107 
1108         if (needed_len <= pblob->length) {
1109                 /* Nothing to do - blob is complete. */
1110                 return NT_STATUS_OK;
1111         }
1112 
1113         /* Refuse the blob if it's bigger than 64k. */
1114         if (needed_len > 65536) {
1115                 DEBUG(2,("check_spnego_blob_complete: needed_len "
1116                         "too large (%u)\n",
1117                         (unsigned int)needed_len ));
1118                 return NT_STATUS_INVALID_PARAMETER;
1119         }
1120 
1121         /* We must store this blob until complete. */
1122         if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
1123                 return NT_STATUS_NO_MEMORY;
1124         }
1125         pad->needed_len = needed_len - pblob->length;
1126         pad->partial_data = data_blob(pblob->data, pblob->length);
1127         if (pad->partial_data.data == NULL) {
1128                 SAFE_FREE(pad);
1129                 return NT_STATUS_NO_MEMORY;
1130         }
1131         pad->smbpid = smbpid;
1132         pad->vuid = vuid;
1133         DLIST_ADD(pd_list, pad);
1134 
1135         return NT_STATUS_MORE_PROCESSING_REQUIRED;
1136 }
1137 
1138 /****************************************************************************
1139  Reply to a session setup command.
1140  conn POINTER CAN BE NULL HERE !
1141 ****************************************************************************/
1142 
1143 static void reply_sesssetup_and_X_spnego(struct smb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
1144 {
1145         const uint8 *p;
1146         DATA_BLOB blob1;
1147         size_t bufrem;
1148         char *tmp;
1149         const char *native_os;
1150         const char *native_lanman;
1151         const char *primary_domain;
1152         const char *p2;
1153         uint16 data_blob_len = SVAL(req->vwv+7, 0);
1154         enum remote_arch_types ra_type = get_remote_arch();
1155         int vuid = req->vuid;
1156         user_struct *vuser = NULL;
1157         NTSTATUS status = NT_STATUS_OK;
1158         uint16 smbpid = req->smbpid;
1159 
1160         DEBUG(3,("Doing spnego session setup\n"));
1161 
1162         if (global_client_caps == 0) {
1163                 global_client_caps = IVAL(req->vwv+10, 0);
1164 
1165                 if (!(global_client_caps & CAP_STATUS32)) {
1166                         remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1167                 }
1168 
1169         }
1170 
1171         p = req->buf;
1172 
1173         if (data_blob_len == 0) {
1174                 /* an invalid request */
1175                 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1176                 return;
1177         }
1178 
1179         bufrem = smbreq_bufrem(req, p);
1180         /* pull the spnego blob */
1181         blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1182 
1183 #if 0
1184         file_save("negotiate.dat", blob1.data, blob1.length);
1185 #endif
1186 
1187         p2 = (char *)req->buf + data_blob_len;
1188 
1189         p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1190                                      STR_TERMINATE);
1191         native_os = tmp ? tmp : "";
1192 
1193         p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1194                                      STR_TERMINATE);
1195         native_lanman = tmp ? tmp : "";
1196 
1197         p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1198                                      STR_TERMINATE);
1199         primary_domain = tmp ? tmp : "";
1200 
1201         DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1202                 native_os, native_lanman, primary_domain));
1203 
1204         if ( ra_type == RA_WIN2K ) {
1205                 /* Vista sets neither the OS or lanman strings */
1206 
1207                 if ( !strlen(native_os) && !strlen(native_lanman) )
1208                         set_remote_arch(RA_VISTA);
1209 
1210                 /* Windows 2003 doesn't set the native lanman string,
1211                    but does set primary domain which is a bug I think */
1212 
1213                 if ( !strlen(native_lanman) ) {
1214                         ra_lanman_string( primary_domain );
1215                 } else {
1216                         ra_lanman_string( native_lanman );
1217                 }
1218         }
1219 
1220         /* Did we get a valid vuid ? */
1221         if (!is_partial_auth_vuid(vuid)) {
1222                 /* No, then try and see if this is an intermediate sessionsetup
1223                  * for a large SPNEGO packet. */
1224                 struct pending_auth_data *pad = get_pending_auth_data(smbpid);
1225                 if (pad) {
1226                         DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1227                                 "pending vuid %u\n",
1228                                 (unsigned int)pad->vuid ));
1229                         vuid = pad->vuid;
1230                 }
1231         }
1232 
1233         /* Do we have a valid vuid now ? */
1234         if (!is_partial_auth_vuid(vuid)) {
1235                 /* No, start a new authentication setup. */
1236                 vuid = register_initial_vuid();
1237                 if (vuid == UID_FIELD_INVALID) {
1238                         data_blob_free(&blob1);
1239                         reply_nterror(req, nt_status_squash(
1240                                               NT_STATUS_INVALID_PARAMETER));
1241                         return;
1242                 }
1243         }
1244 
1245         vuser = get_partial_auth_user_struct(vuid);
1246         /* This MUST be valid. */
1247         if (!vuser) {
1248                 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1249         }
1250 
1251         /* Large (greater than 4k) SPNEGO blobs are split into multiple
1252          * sessionsetup requests as the Windows limit on the security blob
1253          * field is 4k. Bug #4400. JRA.
1254          */
1255 
1256         status = check_spnego_blob_complete(smbpid, vuid, &blob1);
1257         if (!NT_STATUS_IS_OK(status)) {
1258                 if (!NT_STATUS_EQUAL(status,
1259                                 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1260                         /* Real error - kill the intermediate vuid */
1261                         invalidate_vuid(vuid);
1262                 }
1263                 data_blob_free(&blob1);
1264                 reply_nterror(req, nt_status_squash(status));
1265                 return;
1266         }
1267 
1268         if (blob1.data[0] == ASN1_APPLICATION(0)) {
1269 
1270                 /* its a negTokenTarg packet */
1271 
1272                 reply_spnego_negotiate(req, vuid, blob1,
1273                                        &vuser->auth_ntlmssp_state);
1274                 data_blob_free(&blob1);
1275                 return;
1276         }
1277 
1278         if (blob1.data[0] == ASN1_CONTEXT(1)) {
1279 
1280                 /* its a auth packet */
1281 
1282                 reply_spnego_auth(req, vuid, blob1,
1283                                   &vuser->auth_ntlmssp_state);
1284                 data_blob_free(&blob1);
1285                 return;
1286         }
1287 
1288         if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1289                 DATA_BLOB chal;
1290 
1291                 if (!vuser->auth_ntlmssp_state) {
1292                         status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1293                         if (!NT_STATUS_IS_OK(status)) {
1294                                 /* Kill the intermediate vuid */
1295                                 invalidate_vuid(vuid);
1296                                 data_blob_free(&blob1);
1297                                 reply_nterror(req, nt_status_squash(status));
1298                                 return;
1299                         }
1300                 }
1301 
1302                 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1303                                                 blob1, &chal);
1304 
1305                 data_blob_free(&blob1);
1306 
1307                 reply_spnego_ntlmssp(req, vuid,
1308                                      &vuser->auth_ntlmssp_state,
1309                                      &chal, status, OID_NTLMSSP, false);
1310                 data_blob_free(&chal);
1311                 return;
1312         }
1313 
1314         /* what sort of packet is this? */
1315         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1316 
1317         data_blob_free(&blob1);
1318 
1319         reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1320 }
1321 
1322 /****************************************************************************
1323  On new VC == 0, shutdown *all* old connections and users.
1324  It seems that only NT4.x does this. At W2K and above (XP etc.).
1325  a new session setup with VC==0 is ignored.
1326 ****************************************************************************/
1327 
1328 static int shutdown_other_smbds(struct db_record *rec,
     /* [<][>][^][v][top][bottom][index][help] */
1329                                 const struct connections_key *key,
1330                                 const struct connections_data *crec,
1331                                 void *private_data)
1332 {
1333         const char *ip = (const char *)private_data;
1334 
1335         if (!process_exists(crec->pid)) {
1336                 return 0;
1337         }
1338 
1339         if (procid_is_me(&crec->pid)) {
1340                 return 0;
1341         }
1342 
1343         if (strcmp(ip, crec->addr) != 0) {
1344                 return 0;
1345         }
1346 
1347         DEBUG(0,("shutdown_other_smbds: shutting down pid %u "
1348                  "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid), ip));
1349 
1350         messaging_send(smbd_messaging_context(), crec->pid, MSG_SHUTDOWN,
1351                        &data_blob_null);
1352         return 0;
1353 }
1354 
1355 static void setup_new_vc_session(void)
     /* [<][>][^][v][top][bottom][index][help] */
1356 {
1357         char addr[INET6_ADDRSTRLEN];
1358 
1359         DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1360                 "compatible we would close all old resources.\n"));
1361 #if 0
1362         conn_close_all();
1363         invalidate_all_vuids();
1364 #endif
1365         if (lp_reset_on_zero_vc()) {
1366                 connections_forall(shutdown_other_smbds,
1367                         CONST_DISCARD(void *,
1368                         client_addr(get_client_fd(),addr,sizeof(addr))));
1369         }
1370 }
1371 
1372 /****************************************************************************
1373  Reply to a session setup command.
1374 ****************************************************************************/
1375 
1376 void reply_sesssetup_and_X(struct smb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
1377 {
1378         int sess_vuid;
1379         int smb_bufsize;
1380         DATA_BLOB lm_resp;
1381         DATA_BLOB nt_resp;
1382         DATA_BLOB plaintext_password;
1383         char *tmp;
1384         const char *user;
1385         fstring sub_user; /* Sainitised username for substituion */
1386         const char *domain;
1387         const char *native_os;
1388         const char *native_lanman;
1389         const char *primary_domain;
1390         auth_usersupplied_info *user_info = NULL;
1391         auth_serversupplied_info *server_info = NULL;
1392         uint16 smb_flag2 = req->flags2;
1393 
1394         NTSTATUS nt_status;
1395 
1396         bool doencrypt = global_encrypted_passwords_negotiated;
1397 
1398         START_PROFILE(SMBsesssetupX);
1399 
1400         ZERO_STRUCT(lm_resp);
1401         ZERO_STRUCT(nt_resp);
1402         ZERO_STRUCT(plaintext_password);
1403 
1404         DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1405 
1406         /* a SPNEGO session setup has 12 command words, whereas a normal
1407            NT1 session setup has 13. See the cifs spec. */
1408         if (req->wct == 12 &&
1409             (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1410 
1411                 if (!global_spnego_negotiated) {
1412                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt "
1413                                  "at SPNEGO session setup when it was not "
1414                                  "negotiated.\n"));
1415                         reply_nterror(req, nt_status_squash(
1416                                               NT_STATUS_LOGON_FAILURE));
1417                         END_PROFILE(SMBsesssetupX);
1418                         return;
1419                 }
1420 
1421                 if (SVAL(req->vwv+4, 0) == 0) {
1422                         setup_new_vc_session();
1423                 }
1424 
1425                 reply_sesssetup_and_X_spnego(req);
1426                 END_PROFILE(SMBsesssetupX);
1427                 return;
1428         }
1429 
1430         smb_bufsize = SVAL(req->vwv+2, 0);
1431 
1432         if (Protocol < PROTOCOL_NT1) {
1433                 uint16 passlen1 = SVAL(req->vwv+7, 0);
1434 
1435                 /* Never do NT status codes with protocols before NT1 as we
1436                  * don't get client caps. */
1437                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1438 
1439                 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
1440                         reply_nterror(req, nt_status_squash(
1441                                               NT_STATUS_INVALID_PARAMETER));
1442                         END_PROFILE(SMBsesssetupX);
1443                         return;
1444                 }
1445 
1446                 if (doencrypt) {
1447                         lm_resp = data_blob(req->buf, passlen1);
1448                 } else {
1449                         plaintext_password = data_blob(req->buf, passlen1+1);
1450                         /* Ensure null termination */
1451                         plaintext_password.data[passlen1] = 0;
1452                 }
1453 
1454                 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
1455                                        req->buf + passlen1, STR_TERMINATE);
1456                 user = tmp ? tmp : "";
1457 
1458                 domain = "";
1459 
1460         } else {
1461                 uint16 passlen1 = SVAL(req->vwv+7, 0);
1462                 uint16 passlen2 = SVAL(req->vwv+8, 0);
1463                 enum remote_arch_types ra_type = get_remote_arch();
1464                 const uint8_t *p = req->buf;
1465                 const uint8_t *save_p = req->buf;
1466                 uint16 byte_count;
1467 
1468 
1469                 if(global_client_caps == 0) {
1470                         global_client_caps = IVAL(req->vwv+11, 0);
1471 
1472                         if (!(global_client_caps & CAP_STATUS32)) {
1473                                 remove_from_common_flags2(
1474                                                 FLAGS2_32_BIT_ERROR_CODES);
1475                         }
1476 
1477                         /* client_caps is used as final determination if
1478                          * client is NT or Win95. This is needed to return
1479                          * the correct error codes in some circumstances.
1480                         */
1481 
1482                         if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1483                                         ra_type == RA_WIN95) {
1484                                 if(!(global_client_caps & (CAP_NT_SMBS|
1485                                                         CAP_STATUS32))) {
1486                                         set_remote_arch( RA_WIN95);
1487                                 }
1488                         }
1489                 }
1490 
1491                 if (!doencrypt) {
1492                         /* both Win95 and WinNT stuff up the password
1493                          * lengths for non-encrypting systems. Uggh.
1494 
1495                            if passlen1==24 its a win95 system, and its setting
1496                            the password length incorrectly. Luckily it still
1497                            works with the default code because Win95 will null
1498                            terminate the password anyway
1499 
1500                            if passlen1>0 and passlen2>0 then maybe its a NT box
1501                            and its setting passlen2 to some random value which
1502                            really stuffs things up. we need to fix that one.  */
1503 
1504                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1505                                         passlen2 != 1) {
1506                                 passlen2 = 0;
1507                         }
1508                 }
1509 
1510                 /* check for nasty tricks */
1511                 if (passlen1 > MAX_PASS_LEN
1512                     || passlen1 > smbreq_bufrem(req, p)) {
1513                         reply_nterror(req, nt_status_squash(
1514                                               NT_STATUS_INVALID_PARAMETER));
1515                         END_PROFILE(SMBsesssetupX);
1516                         return;
1517                 }
1518 
1519                 if (passlen2 > MAX_PASS_LEN
1520                     || passlen2 > smbreq_bufrem(req, p+passlen1)) {
1521                         reply_nterror(req, nt_status_squash(
1522                                               NT_STATUS_INVALID_PARAMETER));
1523                         END_PROFILE(SMBsesssetupX);
1524                         return;
1525                 }
1526 
1527                 /* Save the lanman2 password and the NT md4 password. */
1528 
1529                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1530                         doencrypt = False;
1531                 }
1532 
1533                 if (doencrypt) {
1534                         lm_resp = data_blob(p, passlen1);
1535                         nt_resp = data_blob(p+passlen1, passlen2);
1536                 } else if (lp_security() != SEC_SHARE) {
1537                         /*
1538                          * In share level we should ignore any passwords, so
1539                          * only read them if we're not.
1540                          */
1541                         char *pass = NULL;
1542                         bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1543 
1544                         if (unic && (passlen2 == 0) && passlen1) {
1545                                 /* Only a ascii plaintext password was sent. */
1546                                 (void)srvstr_pull_talloc(talloc_tos(),
1547                                                         req->inbuf,
1548                                                         req->flags2,
1549                                                         &pass,
1550                                                         req->buf,
1551                                                         passlen1,
1552                                                         STR_TERMINATE|STR_ASCII);
1553                         } else {
1554                                 (void)srvstr_pull_talloc(talloc_tos(),
1555                                                         req->inbuf,
1556                                                         req->flags2,
1557                                                         &pass,
1558                                                         req->buf,
1559                                                         unic ? passlen2 : passlen1,
1560                                                         STR_TERMINATE);
1561                         }
1562                         if (!pass) {
1563                                 reply_nterror(req, nt_status_squash(
1564                                               NT_STATUS_INVALID_PARAMETER));
1565                                 END_PROFILE(SMBsesssetupX);
1566                                 return;
1567                         }
1568                         plaintext_password = data_blob(pass, strlen(pass)+1);
1569                 }
1570 
1571                 p += passlen1 + passlen2;
1572 
1573                 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1574                                             STR_TERMINATE);
1575                 user = tmp ? tmp : "";
1576 
1577                 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1578                                             STR_TERMINATE);
1579                 domain = tmp ? tmp : "";
1580 
1581                 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1582                                             STR_TERMINATE);
1583                 native_os = tmp ? tmp : "";
1584 
1585                 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1586                                             STR_TERMINATE);
1587                 native_lanman = tmp ? tmp : "";
1588 
1589                 /* not documented or decoded by Ethereal but there is one more
1590                  * string in the extra bytes which is the same as the
1591                  * PrimaryDomain when using extended security.  Windows NT 4
1592                  * and 2003 use this string to store the native lanman string.
1593                  * Windows 9x does not include a string here at all so we have
1594                  * to check if we have any extra bytes left */
1595 
1596                 byte_count = SVAL(req->vwv+13, 0);
1597                 if ( PTR_DIFF(p, save_p) < byte_count) {
1598                         p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1599                                                     STR_TERMINATE);
1600                         primary_domain = tmp ? tmp : "";
1601                 } else {
1602                         primary_domain = talloc_strdup(talloc_tos(), "null");
1603                 }
1604 
1605                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s] "
1606                         "PrimaryDomain=[%s]\n",
1607                         domain, native_os, native_lanman, primary_domain));
1608 
1609                 if ( ra_type == RA_WIN2K ) {
1610                         if ( strlen(native_lanman) == 0 )
1611                                 ra_lanman_string( primary_domain );
1612                         else
1613                                 ra_lanman_string( native_lanman );
1614                 }
1615 
1616         }
1617 
1618         if (SVAL(req->vwv+4, 0) == 0) {
1619                 setup_new_vc_session();
1620         }
1621 
1622         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1623                                 domain, user, get_remote_machine_name()));
1624 
1625         if (*user) {
1626                 if (global_spnego_negotiated) {
1627 
1628                         /* This has to be here, because this is a perfectly
1629                          * valid behaviour for guest logons :-( */
1630 
1631                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt "
1632                                 "at 'normal' session setup after "
1633                                 "negotiating spnego.\n"));
1634                         reply_nterror(req, nt_status_squash(
1635                                               NT_STATUS_LOGON_FAILURE));
1636                         END_PROFILE(SMBsesssetupX);
1637                         return;
1638                 }
1639                 fstrcpy(sub_user, user);
1640         } else {
1641                 fstrcpy(sub_user, lp_guestaccount());
1642         }
1643 
1644         sub_set_smb_name(sub_user);
1645 
1646         reload_services(True);
1647 
1648         if (lp_security() == SEC_SHARE) {
1649                 /* In share level we should ignore any passwords */
1650 
1651                 data_blob_free(&lm_resp);
1652                 data_blob_free(&nt_resp);
1653                 data_blob_clear_free(&plaintext_password);
1654 
1655                 map_username(sub_user);
1656                 add_session_user(sub_user);
1657                 add_session_workgroup(domain);
1658                 /* Then force it to null for the benfit of the code below */
1659                 user = "";
1660         }
1661 
1662         if (!*user) {
1663 
1664                 nt_status = check_guest_password(&server_info);
1665 
1666         } else if (doencrypt) {
1667                 if (!negprot_global_auth_context) {
1668                         DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted "
1669                                 "session setup without negprot denied!\n"));
1670                         reply_nterror(req, nt_status_squash(
1671                                               NT_STATUS_LOGON_FAILURE));
1672                         END_PROFILE(SMBsesssetupX);
1673                         return;
1674                 }
1675                 nt_status = make_user_info_for_reply_enc(&user_info, user,
1676                                                 domain,
1677                                                 lm_resp, nt_resp);
1678                 if (NT_STATUS_IS_OK(nt_status)) {
1679                         nt_status = negprot_global_auth_context->check_ntlm_password(
1680                                         negprot_global_auth_context,
1681                                         user_info,
1682                                         &server_info);
1683                 }
1684         } else {
1685                 struct auth_context *plaintext_auth_context = NULL;
1686 
1687                 nt_status = make_auth_context_subsystem(
1688                                 &plaintext_auth_context);
1689 
1690                 if (NT_STATUS_IS_OK(nt_status)) {
1691                         uint8_t chal[8];
1692 
1693                         plaintext_auth_context->get_ntlm_challenge(
1694                                         plaintext_auth_context, chal);
1695 
1696                         if (!make_user_info_for_reply(&user_info,
1697                                                       user, domain, chal,
1698                                                       plaintext_password)) {
1699                                 nt_status = NT_STATUS_NO_MEMORY;
1700                         }
1701 
1702                         if (NT_STATUS_IS_OK(nt_status)) {
1703                                 nt_status = plaintext_auth_context->check_ntlm_password(
1704                                                 plaintext_auth_context,
1705                                                 user_info,
1706                                                 &server_info);
1707 
1708                                 (plaintext_auth_context->free)(
1709                                                 &plaintext_auth_context);
1710                         }
1711                 }
1712         }
1713 
1714         free_user_info(&user_info);
1715 
1716         if (!NT_STATUS_IS_OK(nt_status)) {
1717                 nt_status = do_map_to_guest(nt_status, &server_info,
1718                                 user, domain);
1719         }
1720 
1721         if (!NT_STATUS_IS_OK(nt_status)) {
1722                 data_blob_free(&nt_resp);
1723                 data_blob_free(&lm_resp);
1724                 data_blob_clear_free(&plaintext_password);
1725                 reply_nterror(req, nt_status_squash(nt_status));
1726                 END_PROFILE(SMBsesssetupX);
1727                 return;
1728         }
1729 
1730         /* Ensure we can't possible take a code path leading to a
1731          * null defref. */
1732         if (!server_info) {
1733                 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1734                 END_PROFILE(SMBsesssetupX);
1735                 return;
1736         }
1737 
1738         if (!server_info->ptok) {
1739                 nt_status = create_local_token(server_info);
1740 
1741                 if (!NT_STATUS_IS_OK(nt_status)) {
1742                         DEBUG(10, ("create_local_token failed: %s\n",
1743                                    nt_errstr(nt_status)));
1744                         data_blob_free(&nt_resp);
1745                         data_blob_free(&lm_resp);
1746                         data_blob_clear_free(&plaintext_password);
1747                         reply_nterror(req, nt_status_squash(nt_status));
1748                         END_PROFILE(SMBsesssetupX);
1749                         return;
1750                 }
1751         }
1752 
1753         data_blob_clear_free(&plaintext_password);
1754 
1755         /* it's ok - setup a reply */
1756         reply_outbuf(req, 3, 0);
1757         if (Protocol >= PROTOCOL_NT1) {
1758                 push_signature(&req->outbuf);
1759                 /* perhaps grab OS version here?? */
1760         }
1761 
1762         if (server_info->guest) {
1763                 SSVAL(req->outbuf,smb_vwv2,1);
1764         }
1765 
1766         /* register the name and uid as being validated, so further connections
1767            to a uid can get through without a password, on the same VC */
1768 
1769         if (lp_security() == SEC_SHARE) {
1770                 sess_vuid = UID_FIELD_INVALID;
1771                 TALLOC_FREE(server_info);
1772         } else {
1773                 /* Ignore the initial vuid. */
1774                 sess_vuid = register_initial_vuid();
1775                 if (sess_vuid == UID_FIELD_INVALID) {
1776                         data_blob_free(&nt_resp);
1777                         data_blob_free(&lm_resp);
1778                         reply_nterror(req, nt_status_squash(
1779                                               NT_STATUS_LOGON_FAILURE));
1780                         END_PROFILE(SMBsesssetupX);
1781                         return;
1782                 }
1783                 /* register_existing_vuid keeps the server info */
1784                 sess_vuid = register_existing_vuid(sess_vuid,
1785                                         server_info,
1786                                         nt_resp.data ? nt_resp : lm_resp,
1787                                         sub_user);
1788                 if (sess_vuid == UID_FIELD_INVALID) {
1789                         data_blob_free(&nt_resp);
1790                         data_blob_free(&lm_resp);
1791                         reply_nterror(req, nt_status_squash(
1792                                               NT_STATUS_LOGON_FAILURE));
1793                         END_PROFILE(SMBsesssetupX);
1794                         return;
1795                 }
1796 
1797                 /* current_user_info is changed on new vuid */
1798                 reload_services( True );
1799 
1800                 sessionsetup_start_signing_engine(server_info, req->inbuf);
1801         }
1802 
1803         data_blob_free(&nt_resp);
1804         data_blob_free(&lm_resp);
1805 
1806         SSVAL(req->outbuf,smb_uid,sess_vuid);
1807         SSVAL(req->inbuf,smb_uid,sess_vuid);
1808         req->vuid = sess_vuid;
1809 
1810         if (!done_sesssetup)
1811                 max_send = MIN(max_send,smb_bufsize);
1812 
1813         done_sesssetup = True;
1814 
1815         END_PROFILE(SMBsesssetupX);
1816         chain_reply(req);
1817         return;
1818 }

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