Changeset 988 for vendor/current/source3/smbd/sesssetup.c
- Timestamp:
- Nov 24, 2016, 1:14:11 PM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
vendor/current/source3/smbd/sesssetup.c
r860 r988 27 27 #include "smbd/smbd.h" 28 28 #include "smbd/globals.h" 29 #include "../libcli/auth/spnego.h"30 #include "../libcli/auth/ntlmssp.h"31 #include "ntlmssp_wrap.h"32 #include "../librpc/gen_ndr/krb5pac.h"33 #include "libads/kerberos_proto.h"34 #include "../lib/util/asn1.h"35 29 #include "auth.h" 36 30 #include "messages.h" 37 31 #include "smbprofile.h" 38 39 /* For split krb5 SPNEGO blobs. */ 40 struct pending_auth_data { 41 struct pending_auth_data *prev, *next; 42 uint16 vuid; /* Tag for this entry. */ 43 uint16 smbpid; /* Alternate tag for this entry. */ 44 size_t needed_len; 45 DATA_BLOB partial_data; 46 }; 47 48 /* 49 on a logon error possibly map the error to success if "map to guest" 50 is set approriately 51 */ 52 NTSTATUS do_map_to_guest(NTSTATUS status, 53 struct auth_serversupplied_info **server_info, 54 const char *user, const char *domain) 55 { 56 user = user ? user : ""; 57 domain = domain ? domain : ""; 58 59 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) { 60 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || 61 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) { 62 DEBUG(3,("No such user %s [%s] - using guest account\n", 63 user, domain)); 64 status = make_server_info_guest(NULL, server_info); 65 } 66 } 67 68 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { 69 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) { 70 DEBUG(3,("Registered username %s for guest access\n", 71 user)); 72 status = make_server_info_guest(NULL, server_info); 73 } 74 } 75 76 return status; 77 } 32 #include "../libcli/security/security.h" 33 #include "auth/gensec/gensec.h" 34 #include "lib/conn_tdb.h" 35 #include "../libcli/smb/smb_signing.h" 78 36 79 37 /**************************************************************************** … … 81 39 ****************************************************************************/ 82 40 83 static int push_signature(uint8 **outbuf)41 static int push_signature(uint8_t **outbuf) 84 42 { 85 43 char *lanman; 86 44 int result, tmp; 45 fstring native_os; 87 46 88 47 result = 0; 89 48 90 tmp = message_push_string(outbuf, "Unix", STR_TERMINATE); 49 fstr_sprintf(native_os, "Windows %d.%d", SAMBA_MAJOR_NBT_ANNOUNCE_VERSION, 50 SAMBA_MINOR_NBT_ANNOUNCE_VERSION); 51 52 tmp = message_push_string(outbuf, native_os, STR_TERMINATE); 91 53 92 54 if (tmp == -1) return -1; … … 113 75 114 76 /**************************************************************************** 115 Send a security blob via a session setup reply.116 ****************************************************************************/117 118 static void reply_sesssetup_blob(struct smb_request *req,119 DATA_BLOB blob,120 NTSTATUS nt_status)121 {122 if (!NT_STATUS_IS_OK(nt_status) &&123 !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {124 reply_nterror(req, nt_status_squash(nt_status));125 return;126 }127 128 nt_status = nt_status_squash(nt_status);129 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));130 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */131 SSVAL(req->outbuf, smb_vwv3, blob.length);132 133 if ((message_push_blob(&req->outbuf, blob) == -1)134 || (push_signature(&req->outbuf) == -1)) {135 reply_nterror(req, NT_STATUS_NO_MEMORY);136 }137 }138 139 /****************************************************************************140 77 Do a 'guest' logon, getting back the 141 78 ****************************************************************************/ 142 79 143 static NTSTATUS check_guest_password(struct auth_serversupplied_info **server_info) 80 static NTSTATUS check_guest_password(const struct tsocket_address *remote_address, 81 TALLOC_CTX *mem_ctx, 82 struct auth_session_info **session_info) 144 83 { 145 struct auth _context *auth_context;84 struct auth4_context *auth_context; 146 85 struct auth_usersupplied_info *user_info = NULL; 147 86 uint8_t chal[8]; 148 87 NTSTATUS nt_status; 149 static unsigned char chal[8] = { 0, };150 88 151 89 DEBUG(3,("Got anonymous request\n")); 152 90 153 nt_status = make_auth _context_fixed(talloc_tos(), &auth_context, chal);91 nt_status = make_auth4_context(talloc_tos(), &auth_context); 154 92 if (!NT_STATUS_IS_OK(nt_status)) { 155 93 return nt_status; 156 94 } 157 95 158 if (!make_user_info_guest(&user_info)) { 96 auth_context->get_ntlm_challenge(auth_context, 97 chal); 98 99 if (!make_user_info_guest(talloc_tos(), remote_address, &user_info)) { 159 100 TALLOC_FREE(auth_context); 160 101 return NT_STATUS_NO_MEMORY; 161 102 } 162 103 163 nt_status = auth_c ontext->check_ntlm_password(auth_context,164 user_info,165 server_info);104 nt_status = auth_check_password_session_info(auth_context, 105 mem_ctx, user_info, session_info); 106 TALLOC_FREE(user_info); 166 107 TALLOC_FREE(auth_context); 167 free_user_info(&user_info);168 108 return nt_status; 169 }170 171 172 #ifdef HAVE_KRB5173 174 #if 0175 /* 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)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 #endif236 237 /****************************************************************************238 Reply to a session setup spnego negotiate packet for kerberos.239 ****************************************************************************/240 241 static void reply_spnego_kerberos(struct smb_request *req,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 struct passwd *pw;250 int sess_vuid = req->vuid;251 NTSTATUS ret = NT_STATUS_OK;252 DATA_BLOB ap_rep, ap_rep_wrapped, response;253 struct auth_serversupplied_info *server_info = NULL;254 DATA_BLOB session_key = data_blob_null;255 uint8 tok_id[2];256 DATA_BLOB nullblob = data_blob_null;257 bool map_domainuser_to_guest = False;258 bool username_was_mapped;259 struct PAC_LOGON_INFO *logon_info = NULL;260 struct smbd_server_connection *sconn = req->sconn;261 char *principal;262 char *user;263 char *domain;264 char *real_username;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(mem_ctx, *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 &principal, &logon_info, &ap_rep,288 &session_key, True);289 290 data_blob_free(&ticket);291 292 if (!NT_STATUS_IS_OK(ret)) {293 #if 0294 /* 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 returns301 * NT_STATUS_MORE_PROCESSING_REQUIRED302 * with a negTokenTarg blob containing an krb5_error303 * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.304 * The client then fixes its clock and continues rather305 * 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 the324 * intermediate vuid as we're expecting the client325 * 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 #else337 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {338 ret = NT_STATUS_LOGON_FAILURE;339 }340 #endif341 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 ret = get_user_from_kerberos_info(talloc_tos(),349 sconn->client_id.name,350 principal, logon_info,351 &username_was_mapped,352 &map_domainuser_to_guest,353 &user, &domain,354 &real_username, &pw);355 if (!NT_STATUS_IS_OK(ret)) {356 data_blob_free(&ap_rep);357 data_blob_free(&session_key);358 talloc_destroy(mem_ctx);359 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));360 return;361 }362 363 /* save the PAC data if we have it */364 if (logon_info) {365 netsamlogon_cache_store(user, &logon_info->info3);366 }367 368 /* setup the string used by %U */369 sub_set_smb_name(real_username);370 371 /* reload services so that the new %U is taken into account */372 reload_services(sconn->msg_ctx, sconn->sock, True);373 374 ret = make_server_info_krb5(mem_ctx,375 user, domain, real_username, pw,376 logon_info, map_domainuser_to_guest,377 &server_info);378 if (!NT_STATUS_IS_OK(ret)) {379 DEBUG(1, ("make_server_info_krb5 failed!\n"));380 data_blob_free(&ap_rep);381 data_blob_free(&session_key);382 TALLOC_FREE(mem_ctx);383 reply_nterror(req, nt_status_squash(ret));384 return;385 }386 387 server_info->nss_token |= username_was_mapped;388 389 /* we need to build the token for the user. make_server_info_guest()390 already does this */391 392 if ( !server_info->security_token ) {393 ret = create_local_token( server_info );394 if ( !NT_STATUS_IS_OK(ret) ) {395 DEBUG(10,("failed to create local token: %s\n",396 nt_errstr(ret)));397 data_blob_free(&ap_rep);398 data_blob_free(&session_key);399 TALLOC_FREE( mem_ctx );400 TALLOC_FREE( server_info );401 reply_nterror(req, nt_status_squash(ret));402 return;403 }404 }405 406 if (!is_partial_auth_vuid(sconn, sess_vuid)) {407 sess_vuid = register_initial_vuid(sconn);408 }409 410 data_blob_free(&server_info->user_session_key);411 /* Set the kerberos-derived session key onto the server_info */412 server_info->user_session_key = session_key;413 talloc_steal(server_info, session_key.data);414 415 session_key = data_blob_null;416 417 /* register_existing_vuid keeps the server info */418 /* register_existing_vuid takes ownership of session_key on success,419 * no need to free after this on success. A better interface would copy420 * it.... */421 422 sess_vuid = register_existing_vuid(sconn, sess_vuid,423 server_info, nullblob, user);424 425 reply_outbuf(req, 4, 0);426 SSVAL(req->outbuf,smb_uid,sess_vuid);427 428 if (sess_vuid == UID_FIELD_INVALID ) {429 ret = NT_STATUS_LOGON_FAILURE;430 } else {431 /* current_user_info is changed on new vuid */432 reload_services(sconn->msg_ctx, sconn->sock, True);433 434 SSVAL(req->outbuf, smb_vwv3, 0);435 436 if (server_info->guest) {437 SSVAL(req->outbuf,smb_vwv2,1);438 }439 440 SSVAL(req->outbuf, smb_uid, sess_vuid);441 442 /* Successful logon. Keep this vuid. */443 *p_invalidate_vuid = False;444 }445 446 /* wrap that up in a nice GSS-API wrapping */447 if (NT_STATUS_IS_OK(ret)) {448 ap_rep_wrapped = spnego_gen_krb5_wrap(talloc_tos(), ap_rep,449 TOK_ID_KRB_AP_REP);450 } else {451 ap_rep_wrapped = data_blob_null;452 }453 response = spnego_gen_auth_response(talloc_tos(), &ap_rep_wrapped, ret,454 mechOID);455 reply_sesssetup_blob(req, response, ret);456 457 data_blob_free(&ap_rep);458 data_blob_free(&ap_rep_wrapped);459 data_blob_free(&response);460 TALLOC_FREE(mem_ctx);461 }462 463 #endif464 465 /****************************************************************************466 Send a session setup reply, wrapped in SPNEGO.467 Get vuid and check first.468 End the NTLMSSP exchange context if we are OK/complete fail469 This should be split into two functions, one to handle each470 leg of the NTLM auth steps.471 ***************************************************************************/472 473 static void reply_spnego_ntlmssp(struct smb_request *req,474 uint16 vuid,475 struct auth_ntlmssp_state **auth_ntlmssp_state,476 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,477 const char *OID,478 bool wrap)479 {480 bool do_invalidate = true;481 DATA_BLOB response;482 struct auth_serversupplied_info *session_info = NULL;483 struct smbd_server_connection *sconn = req->sconn;484 485 if (NT_STATUS_IS_OK(nt_status)) {486 nt_status = auth_ntlmssp_steal_session_info(talloc_tos(),487 (*auth_ntlmssp_state), &session_info);488 } else {489 /* Note that this session_info won't have a session490 * key. But for map to guest, that's exactly the right491 * thing - we can't reasonably guess the key the492 * client wants, as the password was wrong */493 nt_status = do_map_to_guest(nt_status,494 &session_info,495 auth_ntlmssp_get_username(*auth_ntlmssp_state),496 auth_ntlmssp_get_domain(*auth_ntlmssp_state));497 }498 499 reply_outbuf(req, 4, 0);500 501 SSVAL(req->outbuf, smb_uid, vuid);502 503 if (NT_STATUS_IS_OK(nt_status)) {504 DATA_BLOB nullblob = data_blob_null;505 506 if (!is_partial_auth_vuid(sconn, vuid)) {507 nt_status = NT_STATUS_LOGON_FAILURE;508 goto out;509 }510 511 /* register_existing_vuid keeps the server info */512 if (register_existing_vuid(sconn, vuid,513 session_info, nullblob,514 auth_ntlmssp_get_username(*auth_ntlmssp_state)) !=515 vuid) {516 /* The problem is, *auth_ntlmssp_state points517 * into the vuser this will have518 * talloc_free()'ed in519 * register_existing_vuid() */520 do_invalidate = false;521 nt_status = NT_STATUS_LOGON_FAILURE;522 goto out;523 }524 525 /* current_user_info is changed on new vuid */526 reload_services(sconn->msg_ctx, sconn->sock, True);527 528 SSVAL(req->outbuf, smb_vwv3, 0);529 530 if (session_info->guest) {531 SSVAL(req->outbuf,smb_vwv2,1);532 }533 }534 535 out:536 537 if (wrap) {538 response = spnego_gen_auth_response(talloc_tos(),539 ntlmssp_blob,540 nt_status, OID);541 } else {542 response = *ntlmssp_blob;543 }544 545 reply_sesssetup_blob(req, response, nt_status);546 if (wrap) {547 data_blob_free(&response);548 }549 550 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,551 and the other end, that we are not finished yet. */552 553 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {554 /* NB. This is *NOT* an error case. JRA */555 if (do_invalidate) {556 TALLOC_FREE(*auth_ntlmssp_state);557 if (!NT_STATUS_IS_OK(nt_status)) {558 /* Kill the intermediate vuid */559 invalidate_vuid(sconn, vuid);560 }561 }562 }563 }564 565 /****************************************************************************566 Is this a krb5 mechanism ?567 ****************************************************************************/568 569 NTSTATUS parse_spnego_mechanisms(TALLOC_CTX *ctx,570 DATA_BLOB blob_in,571 DATA_BLOB *pblob_out,572 char **kerb_mechOID)573 {574 char *OIDs[ASN1_MAX_OIDS];575 int i;576 NTSTATUS ret = NT_STATUS_OK;577 578 *kerb_mechOID = NULL;579 580 /* parse out the OIDs and the first sec blob */581 if (!spnego_parse_negTokenInit(ctx, blob_in, OIDs, NULL, pblob_out) ||582 (OIDs[0] == NULL)) {583 return NT_STATUS_LOGON_FAILURE;584 }585 586 /* only look at the first OID for determining the mechToken --587 according to RFC2478, we should choose the one we want588 and renegotiate, but i smell a client bug here..589 590 Problem observed when connecting to a member (samba box)591 of an AD domain as a user in a Samba domain. Samba member592 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the593 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an594 NTLMSSP mechtoken. --jerry */595 596 #ifdef HAVE_KRB5597 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||598 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {599 *kerb_mechOID = talloc_strdup(ctx, OIDs[0]);600 if (*kerb_mechOID == NULL) {601 ret = NT_STATUS_NO_MEMORY;602 }603 }604 #endif605 606 for (i=0;OIDs[i];i++) {607 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));608 talloc_free(OIDs[i]);609 }610 return ret;611 }612 613 /****************************************************************************614 Fall back from krb5 to NTLMSSP.615 ****************************************************************************/616 617 static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,618 uint16 vuid)619 {620 DATA_BLOB response;621 622 reply_outbuf(req, 4, 0);623 SSVAL(req->outbuf,smb_uid,vuid);624 625 DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "626 "but set to downgrade to NTLMSSP\n"));627 628 response = spnego_gen_auth_response(talloc_tos(), NULL,629 NT_STATUS_MORE_PROCESSING_REQUIRED,630 OID_NTLMSSP);631 reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);632 data_blob_free(&response);633 }634 635 /****************************************************************************636 Reply to a session setup spnego negotiate packet.637 ****************************************************************************/638 639 static void reply_spnego_negotiate(struct smb_request *req,640 uint16 vuid,641 DATA_BLOB blob1,642 struct auth_ntlmssp_state **auth_ntlmssp_state)643 {644 DATA_BLOB secblob;645 DATA_BLOB chal;646 char *kerb_mech = NULL;647 NTSTATUS status;648 struct smbd_server_connection *sconn = req->sconn;649 650 status = parse_spnego_mechanisms(talloc_tos(),651 blob1, &secblob, &kerb_mech);652 if (!NT_STATUS_IS_OK(status)) {653 /* Kill the intermediate vuid */654 invalidate_vuid(sconn, vuid);655 reply_nterror(req, nt_status_squash(status));656 return;657 }658 659 DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",660 (unsigned long)secblob.length));661 662 #ifdef HAVE_KRB5663 if (kerb_mech && ((lp_security()==SEC_ADS) ||664 USE_KERBEROS_KEYTAB) ) {665 bool destroy_vuid = True;666 reply_spnego_kerberos(req, &secblob, kerb_mech,667 vuid, &destroy_vuid);668 data_blob_free(&secblob);669 if (destroy_vuid) {670 /* Kill the intermediate vuid */671 invalidate_vuid(sconn, vuid);672 }673 TALLOC_FREE(kerb_mech);674 return;675 }676 #endif677 678 TALLOC_FREE(*auth_ntlmssp_state);679 680 if (kerb_mech) {681 data_blob_free(&secblob);682 /* The mechtoken is a krb5 ticket, but683 * we need to fall back to NTLM. */684 reply_spnego_downgrade_to_ntlmssp(req, vuid);685 TALLOC_FREE(kerb_mech);686 return;687 }688 689 status = auth_ntlmssp_start(auth_ntlmssp_state);690 if (!NT_STATUS_IS_OK(status)) {691 /* Kill the intermediate vuid */692 invalidate_vuid(sconn, vuid);693 reply_nterror(req, nt_status_squash(status));694 return;695 }696 697 status = auth_ntlmssp_update(*auth_ntlmssp_state,698 secblob, &chal);699 700 data_blob_free(&secblob);701 702 reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,703 &chal, status, OID_NTLMSSP, true);704 705 data_blob_free(&chal);706 707 /* already replied */708 return;709 }710 711 /****************************************************************************712 Reply to a session setup spnego auth packet.713 ****************************************************************************/714 715 static void reply_spnego_auth(struct smb_request *req,716 uint16 vuid,717 DATA_BLOB blob1,718 struct auth_ntlmssp_state **auth_ntlmssp_state)719 {720 DATA_BLOB auth = data_blob_null;721 DATA_BLOB auth_reply = data_blob_null;722 DATA_BLOB secblob = data_blob_null;723 NTSTATUS status = NT_STATUS_LOGON_FAILURE;724 struct smbd_server_connection *sconn = req->sconn;725 726 if (!spnego_parse_auth(talloc_tos(), blob1, &auth)) {727 #if 0728 file_save("auth.dat", blob1.data, blob1.length);729 #endif730 /* Kill the intermediate vuid */731 invalidate_vuid(sconn, vuid);732 733 reply_nterror(req, nt_status_squash(734 NT_STATUS_LOGON_FAILURE));735 return;736 }737 738 if (auth.length > 0 && auth.data[0] == ASN1_APPLICATION(0)) {739 /* Might be a second negTokenTarg packet */740 char *kerb_mech = NULL;741 742 status = parse_spnego_mechanisms(talloc_tos(),743 auth, &secblob, &kerb_mech);744 745 if (!NT_STATUS_IS_OK(status)) {746 /* Kill the intermediate vuid */747 invalidate_vuid(sconn, vuid);748 reply_nterror(req, nt_status_squash(status));749 return;750 }751 752 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",753 (unsigned long)secblob.length));754 #ifdef HAVE_KRB5755 if (kerb_mech && ((lp_security()==SEC_ADS) ||756 USE_KERBEROS_KEYTAB)) {757 bool destroy_vuid = True;758 reply_spnego_kerberos(req, &secblob, kerb_mech,759 vuid, &destroy_vuid);760 data_blob_free(&secblob);761 data_blob_free(&auth);762 if (destroy_vuid) {763 /* Kill the intermediate vuid */764 invalidate_vuid(sconn, vuid);765 }766 TALLOC_FREE(kerb_mech);767 return;768 }769 #endif770 /* Can't blunder into NTLMSSP auth if we have771 * a krb5 ticket. */772 773 if (kerb_mech) {774 /* Kill the intermediate vuid */775 invalidate_vuid(sconn, vuid);776 DEBUG(3,("reply_spnego_auth: network "777 "misconfiguration, client sent us a "778 "krb5 ticket and kerberos security "779 "not enabled\n"));780 reply_nterror(req, nt_status_squash(781 NT_STATUS_LOGON_FAILURE));782 TALLOC_FREE(kerb_mech);783 }784 }785 786 /* If we get here it wasn't a negTokenTarg auth packet. */787 data_blob_free(&secblob);788 789 if (!*auth_ntlmssp_state) {790 status = auth_ntlmssp_start(auth_ntlmssp_state);791 if (!NT_STATUS_IS_OK(status)) {792 /* Kill the intermediate vuid */793 invalidate_vuid(sconn, vuid);794 reply_nterror(req, nt_status_squash(status));795 return;796 }797 }798 799 status = auth_ntlmssp_update(*auth_ntlmssp_state,800 auth, &auth_reply);801 802 data_blob_free(&auth);803 804 /* Don't send the mechid as we've already sent this (RFC4178). */805 806 reply_spnego_ntlmssp(req, vuid,807 auth_ntlmssp_state,808 &auth_reply, status, NULL, true);809 810 data_blob_free(&auth_reply);811 812 /* and tell smbd that we have already replied to this packet */813 return;814 }815 816 /****************************************************************************817 Delete an entry on the list.818 ****************************************************************************/819 820 static void delete_partial_auth(struct smbd_server_connection *sconn,821 struct pending_auth_data *pad)822 {823 if (!pad) {824 return;825 }826 DLIST_REMOVE(sconn->smb1.pd_list, pad);827 data_blob_free(&pad->partial_data);828 SAFE_FREE(pad);829 }830 831 /****************************************************************************832 Search for a partial SPNEGO auth fragment matching an smbpid.833 ****************************************************************************/834 835 static struct pending_auth_data *get_pending_auth_data(836 struct smbd_server_connection *sconn,837 uint16_t smbpid)838 {839 struct pending_auth_data *pad;840 /*841 * NOTE: using the smbpid here is completely wrong...842 * see [MS-SMB]843 * 3.3.5.3 Receiving an SMB_COM_SESSION_SETUP_ANDX Request844 */845 for (pad = sconn->smb1.pd_list; pad; pad = pad->next) {846 if (pad->smbpid == smbpid) {847 break;848 }849 }850 return pad;851 }852 853 /****************************************************************************854 Check the size of an SPNEGO blob. If we need more return855 NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow856 the blob to be more than 64k.857 ****************************************************************************/858 859 static NTSTATUS check_spnego_blob_complete(struct smbd_server_connection *sconn,860 uint16 smbpid, uint16 vuid,861 DATA_BLOB *pblob)862 {863 struct pending_auth_data *pad = NULL;864 ASN1_DATA *data;865 size_t needed_len = 0;866 867 pad = get_pending_auth_data(sconn, smbpid);868 869 /* Ensure we have some data. */870 if (pblob->length == 0) {871 /* Caller can cope. */872 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));873 delete_partial_auth(sconn, pad);874 return NT_STATUS_OK;875 }876 877 /* Were we waiting for more data ? */878 if (pad) {879 DATA_BLOB tmp_blob;880 size_t copy_len = MIN(65536, pblob->length);881 882 /* Integer wrap paranoia.... */883 884 if (pad->partial_data.length + copy_len <885 pad->partial_data.length ||886 pad->partial_data.length + copy_len < copy_len) {887 888 DEBUG(2,("check_spnego_blob_complete: integer wrap "889 "pad->partial_data.length = %u, "890 "copy_len = %u\n",891 (unsigned int)pad->partial_data.length,892 (unsigned int)copy_len ));893 894 delete_partial_auth(sconn, pad);895 return NT_STATUS_INVALID_PARAMETER;896 }897 898 DEBUG(10,("check_spnego_blob_complete: "899 "pad->partial_data.length = %u, "900 "pad->needed_len = %u, "901 "copy_len = %u, "902 "pblob->length = %u,\n",903 (unsigned int)pad->partial_data.length,904 (unsigned int)pad->needed_len,905 (unsigned int)copy_len,906 (unsigned int)pblob->length ));907 908 if (pblob->length > pad->needed_len) {909 DEBUG(2, ("subsequent security token data length %u "910 "exceeds expected length %u\n",911 (unsigned int)pblob->length,912 (unsigned int)pad->needed_len));913 }914 915 tmp_blob = data_blob(NULL,916 pad->partial_data.length + copy_len);917 918 /* Concatenate the two (up to copy_len) bytes. */919 memcpy(tmp_blob.data,920 pad->partial_data.data,921 pad->partial_data.length);922 memcpy(tmp_blob.data + pad->partial_data.length,923 pblob->data,924 copy_len);925 926 /* Replace the partial data. */927 data_blob_free(&pad->partial_data);928 pad->partial_data = tmp_blob;929 ZERO_STRUCT(tmp_blob);930 931 /* Are we done ? */932 if (pblob->length >= pad->needed_len) {933 /* Yes, replace pblob. */934 data_blob_free(pblob);935 *pblob = pad->partial_data;936 ZERO_STRUCT(pad->partial_data);937 delete_partial_auth(sconn, pad);938 return NT_STATUS_OK;939 }940 941 /* Still need more data. */942 pad->needed_len -= copy_len;943 return NT_STATUS_MORE_PROCESSING_REQUIRED;944 }945 946 if ((pblob->data[0] != ASN1_APPLICATION(0)) &&947 (pblob->data[0] != ASN1_CONTEXT(1))) {948 /* Not something we can determine the949 * length of.950 */951 return NT_STATUS_OK;952 }953 954 /* This is a new SPNEGO sessionsetup - see if955 * the data given in this blob is enough.956 */957 958 data = asn1_init(NULL);959 if (data == NULL) {960 return NT_STATUS_NO_MEMORY;961 }962 963 asn1_load(data, *pblob);964 if (asn1_start_tag(data, pblob->data[0])) {965 /* asn1_start_tag checks if the given966 length of the blob is enough to complete967 the tag. If it returns true we know968 there is nothing to do - the blob is969 complete. */970 asn1_free(data);971 return NT_STATUS_OK;972 }973 974 if (data->nesting == NULL) {975 /* Incorrect tag, allocation failed,976 or reading the tag length failed.977 Let the caller catch. */978 asn1_free(data);979 return NT_STATUS_OK;980 }981 982 /* Here we know asn1_start_tag() has set data->has_error to true.983 asn1_tag_remaining() will have failed due to the given blob984 being too short. We need to work out how short. */985 986 /* Integer wrap paranoia.... */987 988 if (data->nesting->taglen + data->nesting->start < data->nesting->taglen ||989 data->nesting->taglen + data->nesting->start < data->nesting->start) {990 991 DEBUG(2,("check_spnego_blob_complete: integer wrap "992 "data.nesting->taglen = %u, "993 "data.nesting->start = %u\n",994 (unsigned int)data->nesting->taglen,995 (unsigned int)data->nesting->start ));996 997 asn1_free(data);998 return NT_STATUS_INVALID_PARAMETER;999 }1000 1001 /* Total length of the needed asn1 is the tag length1002 * plus the current offset. */1003 1004 needed_len = data->nesting->taglen + data->nesting->start;1005 asn1_free(data);1006 1007 DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "1008 "pblob->length = %u\n",1009 (unsigned int)needed_len,1010 (unsigned int)pblob->length ));1011 1012 if (needed_len <= pblob->length) {1013 /* Nothing to do - blob is complete. */1014 /* THIS SHOULD NOT HAPPEN - asn1_start_tag()1015 above should have caught this !!! */1016 DEBUG(0,("check_spnego_blob_complete: logic "1017 "error (needed_len = %u, "1018 "pblob->length = %u).\n",1019 (unsigned int)needed_len,1020 (unsigned int)pblob->length ));1021 return NT_STATUS_OK;1022 }1023 1024 /* Refuse the blob if it's bigger than 64k. */1025 if (needed_len > 65536) {1026 DEBUG(2,("check_spnego_blob_complete: needed_len "1027 "too large (%u)\n",1028 (unsigned int)needed_len ));1029 return NT_STATUS_INVALID_PARAMETER;1030 }1031 1032 /* We must store this blob until complete. */1033 if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {1034 return NT_STATUS_NO_MEMORY;1035 }1036 pad->needed_len = needed_len - pblob->length;1037 pad->partial_data = data_blob(pblob->data, pblob->length);1038 if (pad->partial_data.data == NULL) {1039 SAFE_FREE(pad);1040 return NT_STATUS_NO_MEMORY;1041 }1042 pad->smbpid = smbpid;1043 pad->vuid = vuid;1044 DLIST_ADD(sconn->smb1.pd_list, pad);1045 1046 return NT_STATUS_MORE_PROCESSING_REQUIRED;1047 109 } 1048 110 … … 1054 116 static void reply_sesssetup_and_X_spnego(struct smb_request *req) 1055 117 { 1056 const uint8 *p; 1057 DATA_BLOB blob1; 118 const uint8_t *p; 119 DATA_BLOB in_blob; 120 DATA_BLOB out_blob = data_blob_null; 1058 121 size_t bufrem; 1059 122 char *tmp; … … 1061 124 const char *native_lanman; 1062 125 const char *primary_domain; 1063 const char *p2; 1064 uint16 data_blob_len = SVAL(req->vwv+7, 0); 126 uint16_t data_blob_len = SVAL(req->vwv+7, 0); 1065 127 enum remote_arch_types ra_type = get_remote_arch(); 1066 int vuid = req->vuid; 1067 user_struct *vuser = NULL; 128 uint64_t vuid = req->vuid; 1068 129 NTSTATUS status = NT_STATUS_OK; 1069 uint16 smbpid = req->smbpid;130 struct smbXsrv_connection *xconn = req->xconn; 1070 131 struct smbd_server_connection *sconn = req->sconn; 132 uint16_t action = 0; 133 NTTIME now = timeval_to_nttime(&req->request_time); 134 struct smbXsrv_session *session = NULL; 135 uint16_t smb_bufsize = SVAL(req->vwv+2, 0); 136 uint32_t client_caps = IVAL(req->vwv+10, 0); 137 struct smbXsrv_session_auth0 *auth; 1071 138 1072 139 DEBUG(3,("Doing spnego session setup\n")); 1073 140 1074 if ( global_client_caps == 0) {1075 global_client_caps = IVAL(req->vwv+10, 0);141 if (!xconn->smb1.sessions.done_sesssetup) { 142 global_client_caps = client_caps; 1076 143 1077 144 if (!(global_client_caps & CAP_STATUS32)) { 1078 145 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES); 1079 146 } 1080 1081 147 } 1082 148 … … 1091 157 bufrem = smbreq_bufrem(req, p); 1092 158 /* pull the spnego blob */ 1093 blob1 = data_blob(p, MIN(bufrem, data_blob_len));159 in_blob = data_blob_const(p, MIN(bufrem, data_blob_len)); 1094 160 1095 161 #if 0 1096 file_save("negotiate.dat", blob1.data, blob1.length);162 file_save("negotiate.dat", in_blob.data, in_blob.length); 1097 163 #endif 1098 164 1099 p 2 = (char *)req->buf + blob1.length;1100 1101 p 2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,165 p = req->buf + in_blob.length; 166 167 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p, 1102 168 STR_TERMINATE); 1103 169 native_os = tmp ? tmp : ""; 1104 170 1105 p 2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,171 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p, 1106 172 STR_TERMINATE); 1107 173 native_lanman = tmp ? tmp : ""; 1108 174 1109 p 2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,175 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p, 1110 176 STR_TERMINATE); 1111 177 primary_domain = tmp ? tmp : ""; … … 1134 200 } 1135 201 1136 /* Did we get a valid vuid ? */ 1137 if (!is_partial_auth_vuid(sconn, vuid)) { 1138 /* No, then try and see if this is an intermediate sessionsetup 1139 * for a large SPNEGO packet. */ 1140 struct pending_auth_data *pad; 1141 pad = get_pending_auth_data(sconn, smbpid); 1142 if (pad) { 1143 DEBUG(10,("reply_sesssetup_and_X_spnego: found " 1144 "pending vuid %u\n", 1145 (unsigned int)pad->vuid )); 1146 vuid = pad->vuid; 1147 } 1148 } 1149 1150 /* Do we have a valid vuid now ? */ 1151 if (!is_partial_auth_vuid(sconn, vuid)) { 1152 /* No, start a new authentication setup. */ 1153 vuid = register_initial_vuid(sconn); 1154 if (vuid == UID_FIELD_INVALID) { 1155 data_blob_free(&blob1); 1156 reply_nterror(req, nt_status_squash( 1157 NT_STATUS_INVALID_PARAMETER)); 1158 return; 1159 } 1160 } 1161 1162 vuser = get_partial_auth_user_struct(sconn, vuid); 1163 /* This MUST be valid. */ 1164 if (!vuser) { 1165 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid."); 1166 } 1167 1168 /* Large (greater than 4k) SPNEGO blobs are split into multiple 1169 * sessionsetup requests as the Windows limit on the security blob 1170 * field is 4k. Bug #4400. JRA. 1171 */ 1172 1173 status = check_spnego_blob_complete(sconn, smbpid, vuid, &blob1); 202 if (vuid != 0) { 203 status = smb1srv_session_lookup(xconn, 204 vuid, now, 205 &session); 206 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) { 207 reply_force_doserror(req, ERRSRV, ERRbaduid); 208 return; 209 } 210 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) { 211 status = NT_STATUS_OK; 212 } 213 if (NT_STATUS_IS_OK(status)) { 214 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED; 215 status = NT_STATUS_MORE_PROCESSING_REQUIRED; 216 TALLOC_FREE(session->pending_auth); 217 } 218 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { 219 reply_nterror(req, nt_status_squash(status)); 220 return; 221 } 222 } 223 224 if (session == NULL) { 225 /* create a new session */ 226 status = smbXsrv_session_create(xconn, 227 now, &session); 228 if (!NT_STATUS_IS_OK(status)) { 229 reply_nterror(req, nt_status_squash(status)); 230 return; 231 } 232 } 233 234 status = smbXsrv_session_find_auth(session, xconn, now, &auth); 1174 235 if (!NT_STATUS_IS_OK(status)) { 1175 /* 1176 * Pack error response, ensuring to fill NativeOS, NativeLanMan 1177 * & PrimaryDomain fields on NT_STATUS_MORE_PROCESSING_REQUIRED 1178 */ 1179 reply_outbuf(req, 4, 0); 1180 reply_sesssetup_blob(req, data_blob_null, status); 1181 if (!NT_STATUS_EQUAL(status, 1182 NT_STATUS_MORE_PROCESSING_REQUIRED)) { 1183 /* Real error - kill the intermediate vuid */ 1184 invalidate_vuid(sconn, vuid); 1185 } 1186 data_blob_free(&blob1); 236 status = smbXsrv_session_create_auth(session, xconn, now, 237 0, /* flags */ 238 0, /* security */ 239 &auth); 240 if (!NT_STATUS_IS_OK(status)) { 241 reply_nterror(req, nt_status_squash(status)); 242 return; 243 } 244 } 245 246 if (auth->gensec == NULL) { 247 status = auth_generic_prepare(session, xconn->remote_address, 248 &auth->gensec); 249 if (!NT_STATUS_IS_OK(status)) { 250 TALLOC_FREE(session); 251 reply_nterror(req, nt_status_squash(status)); 252 return; 253 } 254 255 gensec_want_feature(auth->gensec, GENSEC_FEATURE_SESSION_KEY); 256 gensec_want_feature(auth->gensec, GENSEC_FEATURE_UNIX_TOKEN); 257 258 status = gensec_start_mech_by_oid(auth->gensec, 259 GENSEC_OID_SPNEGO); 260 if (!NT_STATUS_IS_OK(status)) { 261 DEBUG(0, ("Failed to start SPNEGO handler!\n")); 262 TALLOC_FREE(session);; 263 reply_nterror(req, nt_status_squash(status)); 264 return; 265 } 266 } 267 268 become_root(); 269 status = gensec_update(auth->gensec, 270 talloc_tos(), 271 in_blob, &out_blob); 272 unbecome_root(); 273 if (!NT_STATUS_IS_OK(status) && 274 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { 275 TALLOC_FREE(session); 276 reply_nterror(req, nt_status_squash(status)); 1187 277 return; 1188 278 } 1189 279 1190 if (blob1.data[0] == ASN1_APPLICATION(0)) { 1191 1192 /* its a negTokenTarg packet */ 1193 1194 reply_spnego_negotiate(req, vuid, blob1, 1195 &vuser->auth_ntlmssp_state); 1196 data_blob_free(&blob1); 1197 return; 1198 } 1199 1200 if (blob1.data[0] == ASN1_CONTEXT(1)) { 1201 1202 /* its a auth packet */ 1203 1204 reply_spnego_auth(req, vuid, blob1, 1205 &vuser->auth_ntlmssp_state); 1206 data_blob_free(&blob1); 1207 return; 1208 } 1209 1210 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) { 1211 DATA_BLOB chal; 1212 1213 if (!vuser->auth_ntlmssp_state) { 1214 status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state); 1215 if (!NT_STATUS_IS_OK(status)) { 1216 /* Kill the intermediate vuid */ 1217 invalidate_vuid(sconn, vuid); 1218 data_blob_free(&blob1); 1219 reply_nterror(req, nt_status_squash(status)); 280 if (NT_STATUS_IS_OK(status) && session->global->auth_session_info == NULL) { 281 struct auth_session_info *session_info = NULL; 282 283 status = gensec_session_info(auth->gensec, 284 session, 285 &session_info); 286 if (!NT_STATUS_IS_OK(status)) { 287 DEBUG(1,("Failed to generate session_info " 288 "(user and group token) for session setup: %s\n", 289 nt_errstr(status))); 290 data_blob_free(&out_blob); 291 TALLOC_FREE(session); 292 reply_nterror(req, nt_status_squash(status)); 293 return; 294 } 295 296 if (security_session_user_level(session_info, NULL) == SECURITY_GUEST) { 297 action |= SMB_SETUP_GUEST; 298 } 299 300 if (session_info->session_key.length > 0) { 301 struct smbXsrv_session *x = session; 302 303 /* 304 * Note: the SMB1 signing key is not truncated to 16 byte! 305 */ 306 x->global->signing_key = 307 data_blob_dup_talloc(x->global, 308 session_info->session_key); 309 if (x->global->signing_key.data == NULL) { 310 data_blob_free(&out_blob); 311 TALLOC_FREE(session); 312 reply_nterror(req, NT_STATUS_NO_MEMORY); 1220 313 return; 1221 314 } 1222 } 1223 1224 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state, 1225 blob1, &chal); 1226 1227 data_blob_free(&blob1); 1228 1229 reply_spnego_ntlmssp(req, vuid, 1230 &vuser->auth_ntlmssp_state, 1231 &chal, status, OID_NTLMSSP, false); 1232 data_blob_free(&chal); 315 316 /* 317 * clear the session key 318 * the first tcon will add setup the application key 319 */ 320 data_blob_clear_free(&session_info->session_key); 321 } 322 323 session->compat = talloc_zero(session, struct user_struct); 324 if (session->compat == NULL) { 325 data_blob_free(&out_blob); 326 TALLOC_FREE(session); 327 reply_nterror(req, NT_STATUS_NO_MEMORY); 328 return; 329 } 330 session->compat->session = session; 331 session->compat->homes_snum = -1; 332 session->compat->session_info = session_info; 333 session->compat->session_keystr = NULL; 334 session->compat->vuid = session->global->session_wire_id; 335 DLIST_ADD(sconn->users, session->compat); 336 sconn->num_users++; 337 338 if (security_session_user_level(session_info, NULL) >= SECURITY_USER) { 339 session->compat->homes_snum = 340 register_homes_share(session_info->unix_info->unix_name); 341 } 342 343 if (srv_is_signing_negotiated(xconn) && 344 action == 0 && 345 session->global->signing_key.length > 0) 346 { 347 /* 348 * Try and turn on server signing on the first non-guest 349 * sessionsetup. 350 */ 351 srv_set_signing(xconn, 352 session->global->signing_key, 353 data_blob_null); 354 } 355 356 set_current_user_info(session_info->unix_info->sanitized_username, 357 session_info->unix_info->unix_name, 358 session_info->info->domain_name); 359 360 session->status = NT_STATUS_OK; 361 session->global->auth_session_info = talloc_move(session->global, 362 &session_info); 363 session->global->auth_session_info_seqnum += 1; 364 session->global->channels[0].auth_session_info_seqnum = 365 session->global->auth_session_info_seqnum; 366 session->global->auth_time = now; 367 if (client_caps & CAP_DYNAMIC_REAUTH) { 368 session->global->expiration_time = 369 gensec_expire_time(auth->gensec); 370 } else { 371 session->global->expiration_time = 372 GENSEC_EXPIRE_TIME_INFINITY; 373 } 374 375 if (!session_claim(session)) { 376 DEBUG(1, ("smb1: Failed to claim session for vuid=%llu\n", 377 (unsigned long long)session->compat->vuid)); 378 data_blob_free(&out_blob); 379 TALLOC_FREE(session); 380 reply_nterror(req, NT_STATUS_LOGON_FAILURE); 381 return; 382 } 383 384 status = smbXsrv_session_update(session); 385 if (!NT_STATUS_IS_OK(status)) { 386 DEBUG(0, ("smb1: Failed to update session for vuid=%llu - %s\n", 387 (unsigned long long)session->compat->vuid, 388 nt_errstr(status))); 389 data_blob_free(&out_blob); 390 TALLOC_FREE(session); 391 reply_nterror(req, NT_STATUS_LOGON_FAILURE); 392 return; 393 } 394 395 if (!xconn->smb1.sessions.done_sesssetup) { 396 if (smb_bufsize < SMB_BUFFER_SIZE_MIN) { 397 reply_force_doserror(req, ERRSRV, ERRerror); 398 return; 399 } 400 xconn->smb1.sessions.max_send = smb_bufsize; 401 xconn->smb1.sessions.done_sesssetup = true; 402 } 403 404 /* current_user_info is changed on new vuid */ 405 reload_services(sconn, conn_snum_used, true); 406 } else if (NT_STATUS_IS_OK(status)) { 407 struct auth_session_info *session_info = NULL; 408 409 status = gensec_session_info(auth->gensec, 410 session, 411 &session_info); 412 if (!NT_STATUS_IS_OK(status)) { 413 DEBUG(1,("Failed to generate session_info " 414 "(user and group token) for session setup: %s\n", 415 nt_errstr(status))); 416 data_blob_free(&out_blob); 417 TALLOC_FREE(session); 418 reply_nterror(req, nt_status_squash(status)); 419 return; 420 } 421 422 if (security_session_user_level(session_info, NULL) == SECURITY_GUEST) { 423 action |= SMB_SETUP_GUEST; 424 } 425 426 /* 427 * Keep the application key 428 */ 429 data_blob_clear_free(&session_info->session_key); 430 session_info->session_key = 431 session->global->auth_session_info->session_key; 432 talloc_steal(session_info, session_info->session_key.data); 433 TALLOC_FREE(session->global->auth_session_info); 434 435 session->compat->session_info = session_info; 436 437 session->compat->vuid = session->global->session_wire_id; 438 439 if (security_session_user_level(session_info, NULL) >= SECURITY_USER) { 440 session->compat->homes_snum = 441 register_homes_share(session_info->unix_info->unix_name); 442 } 443 444 set_current_user_info(session_info->unix_info->sanitized_username, 445 session_info->unix_info->unix_name, 446 session_info->info->domain_name); 447 448 session->status = NT_STATUS_OK; 449 session->global->auth_session_info = talloc_move(session->global, 450 &session_info); 451 session->global->auth_session_info_seqnum += 1; 452 session->global->channels[0].auth_session_info_seqnum = 453 session->global->auth_session_info_seqnum; 454 session->global->auth_time = now; 455 if (client_caps & CAP_DYNAMIC_REAUTH) { 456 session->global->expiration_time = 457 gensec_expire_time(auth->gensec); 458 } else { 459 session->global->expiration_time = 460 GENSEC_EXPIRE_TIME_INFINITY; 461 } 462 463 status = smbXsrv_session_update(session); 464 if (!NT_STATUS_IS_OK(status)) { 465 DEBUG(0, ("smb1: Failed to update session for vuid=%llu - %s\n", 466 (unsigned long long)session->compat->vuid, 467 nt_errstr(status))); 468 data_blob_free(&out_blob); 469 TALLOC_FREE(session); 470 reply_nterror(req, NT_STATUS_LOGON_FAILURE); 471 return; 472 } 473 474 conn_clear_vuid_caches(sconn, session->compat->vuid); 475 476 /* current_user_info is changed on new vuid */ 477 reload_services(sconn, conn_snum_used, true); 478 } 479 480 vuid = session->global->session_wire_id; 481 482 reply_outbuf(req, 4, 0); 483 484 SSVAL(req->outbuf, smb_uid, vuid); 485 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(status)); 486 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */ 487 SSVAL(req->outbuf, smb_vwv2, action); 488 SSVAL(req->outbuf, smb_vwv3, out_blob.length); 489 490 if (message_push_blob(&req->outbuf, out_blob) == -1) { 491 data_blob_free(&out_blob); 492 TALLOC_FREE(session); 493 reply_nterror(req, NT_STATUS_NO_MEMORY); 1233 494 return; 1234 495 } 1235 1236 /* what sort of packet is this? */ 1237 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));1238 1239 data_blob_free(&blob1);1240 1241 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));496 data_blob_free(&out_blob); 497 498 if (push_signature(&req->outbuf) == -1) { 499 TALLOC_FREE(session); 500 reply_nterror(req, NT_STATUS_NO_MEMORY); 501 return; 502 } 1242 503 } 1243 504 … … 1253 514 }; 1254 515 1255 static int shutdown_other_smbds(const struct connections_key *key, 1256 const struct connections_data *crec, 516 static int shutdown_other_smbds(struct smbXsrv_session_global0 *session, 1257 517 void *private_data) 1258 518 { 1259 519 struct shutdown_state *state = (struct shutdown_state *)private_data; 520 struct server_id self_pid = messaging_server_id(state->msg_ctx); 521 struct server_id pid = session->channels[0].server_id; 522 const char *addr = session->channels[0].remote_address; 523 struct server_id_buf tmp; 1260 524 1261 525 DEBUG(10, ("shutdown_other_smbds: %s, %s\n", 1262 procid_str(talloc_tos(), &crec->pid), crec->addr));1263 1264 if (!process_exists( crec->pid)) {526 server_id_str_buf(pid, &tmp), addr)); 527 528 if (!process_exists(pid)) { 1265 529 DEBUG(10, ("process does not exist\n")); 1266 530 return 0; 1267 531 } 1268 532 1269 if ( procid_is_me(&crec->pid)) {533 if (serverid_equal(&pid, &self_pid)) { 1270 534 DEBUG(10, ("It's me\n")); 1271 535 return 0; 1272 536 } 1273 537 1274 if (strcmp(state->ip, crec->addr) != 0) { 1275 DEBUG(10, ("%s does not match %s\n", state->ip, crec->addr)); 538 /* 539 * here we use strstr() because 'addr' 540 * (session->channels[0].remote_address) 541 * contains a string like: 542 * 'ipv4:127.0.0.1:48163' 543 */ 544 if (strstr(addr, state->ip) == NULL) { 545 DEBUG(10, ("%s does not match %s\n", state->ip, addr)); 1276 546 return 0; 1277 547 } 1278 548 1279 549 DEBUG(1, ("shutdown_other_smbds: shutting down pid %u " 1280 "(IP %s)\n", (unsigned int)procid_to_pid(& crec->pid),550 "(IP %s)\n", (unsigned int)procid_to_pid(&pid), 1281 551 state->ip)); 1282 552 1283 messaging_send(state->msg_ctx, crec->pid, MSG_SHUTDOWN,553 messaging_send(state->msg_ctx, pid, MSG_SHUTDOWN, 1284 554 &data_blob_null); 1285 555 return 0; … … 1305 575 state.ip = addr; 1306 576 state.msg_ctx = sconn->msg_ctx; 1307 connections_forall_read(shutdown_other_smbds, &state);577 smbXsrv_session_global_traverse(shutdown_other_smbds, &state); 1308 578 TALLOC_FREE(addr); 1309 579 } … … 1316 586 void reply_sesssetup_and_X(struct smb_request *req) 1317 587 { 1318 int sess_vuid;1319 int smb_bufsize;588 uint64_t sess_vuid; 589 uint16_t smb_bufsize; 1320 590 DATA_BLOB lm_resp; 1321 591 DATA_BLOB nt_resp; … … 1329 599 const char *primary_domain; 1330 600 struct auth_usersupplied_info *user_info = NULL; 1331 struct auth_serversupplied_info *server_info = NULL; 1332 uint16 smb_flag2 = req->flags2; 1333 601 struct auth_session_info *session_info = NULL; 602 uint16_t smb_flag2 = req->flags2; 603 uint16_t action = 0; 604 NTTIME now = timeval_to_nttime(&req->request_time); 605 struct smbXsrv_session *session = NULL; 1334 606 NTSTATUS nt_status; 607 struct smbXsrv_connection *xconn = req->xconn; 1335 608 struct smbd_server_connection *sconn = req->sconn; 1336 1337 bool doencrypt = sconn->smb1.negprot.encrypted_passwords; 609 bool doencrypt = xconn->smb1.negprot.encrypted_passwords; 610 bool signing_allowed = false; 611 bool signing_mandatory = smb_signing_is_mandatory( 612 xconn->smb1.signing_state); 1338 613 1339 614 START_PROFILE(SMBsesssetupX); … … 1344 619 1345 620 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2)); 621 622 if (req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES) { 623 signing_allowed = true; 624 } 625 if (req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED) { 626 signing_mandatory = true; 627 } 628 629 /* 630 * We can call srv_set_signing_negotiated() each time. 631 * It finds out when it needs to turn into a noop 632 * itself. 633 */ 634 srv_set_signing_negotiated(xconn, 635 signing_allowed, 636 signing_mandatory); 1346 637 1347 638 /* a SPNEGO session setup has 12 command words, whereas a normal … … 1350 641 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) { 1351 642 1352 if (! sconn->smb1.negprot.spnego) {643 if (!xconn->smb1.negprot.spnego) { 1353 644 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt " 1354 645 "at SPNEGO session setup when it was not " … … 1372 663 1373 664 if (get_Protocol() < PROTOCOL_NT1) { 1374 uint16 passlen1 = SVAL(req->vwv+7, 0);665 uint16_t passlen1 = SVAL(req->vwv+7, 0); 1375 666 1376 667 /* Never do NT status codes with protocols before NT1 as we … … 1400 691 1401 692 } else { 1402 uint16 passlen1 = SVAL(req->vwv+7, 0);1403 uint16 passlen2 = SVAL(req->vwv+8, 0);693 uint16_t passlen1 = SVAL(req->vwv+7, 0); 694 uint16_t passlen2 = SVAL(req->vwv+8, 0); 1404 695 enum remote_arch_types ra_type = get_remote_arch(); 1405 696 const uint8_t *p = req->buf; 1406 697 const uint8_t *save_p = req->buf; 1407 uint16 byte_count; 1408 1409 1410 if(global_client_caps == 0) { 698 uint16_t byte_count; 699 700 if (!xconn->smb1.sessions.done_sesssetup) { 1411 701 global_client_caps = IVAL(req->vwv+11, 0); 1412 702 … … 1475 765 lm_resp = data_blob(p, passlen1); 1476 766 nt_resp = data_blob(p+passlen1, passlen2); 1477 } else if (lp_security() != SEC_SHARE) { 1478 /* 1479 * In share level we should ignore any passwords, so 1480 * only read them if we're not. 1481 */ 767 } else { 1482 768 char *pass = NULL; 1483 769 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS; … … 1565 851 1566 852 if (*user) { 1567 if ( sconn->smb1.negprot.spnego) {853 if (xconn->smb1.negprot.spnego) { 1568 854 1569 855 /* This has to be here, because this is a perfectly … … 1580 866 fstrcpy(sub_user, user); 1581 867 } else { 1582 fstrcpy(sub_user, lp_guestaccount());868 fstrcpy(sub_user, ""); 1583 869 } 1584 870 1585 871 sub_set_smb_name(sub_user); 1586 872 1587 reload_services(sconn->msg_ctx, sconn->sock, True); 1588 1589 if (lp_security() == SEC_SHARE) { 1590 char *sub_user_mapped = NULL; 1591 /* In share level we should ignore any passwords */ 1592 1593 data_blob_free(&lm_resp); 1594 data_blob_free(&nt_resp); 1595 data_blob_clear_free(&plaintext_password); 1596 1597 (void)map_username(talloc_tos(), sub_user, &sub_user_mapped); 1598 if (!sub_user_mapped) { 1599 reply_nterror(req, NT_STATUS_NO_MEMORY); 1600 END_PROFILE(SMBsesssetupX); 1601 return; 1602 } 1603 fstrcpy(sub_user, sub_user_mapped); 1604 add_session_user(sconn, sub_user); 1605 add_session_workgroup(sconn, domain); 1606 /* Then force it to null for the benfit of the code below */ 1607 user = ""; 1608 } 873 reload_services(sconn, conn_snum_used, true); 1609 874 1610 875 if (!*user) { 1611 876 1612 nt_status = check_guest_password( &server_info);877 nt_status = check_guest_password(sconn->remote_address, req, &session_info); 1613 878 1614 879 } else if (doencrypt) { 1615 struct auth _context *negprot_auth_context = NULL;1616 negprot_auth_context = sconn->smb1.negprot.auth_context;880 struct auth4_context *negprot_auth_context = NULL; 881 negprot_auth_context = xconn->smb1.negprot.auth_context; 1617 882 if (!negprot_auth_context) { 1618 883 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted " … … 1623 888 return; 1624 889 } 1625 nt_status = make_user_info_for_reply_enc(&user_info, user, 1626 domain, 1627 lm_resp, nt_resp); 890 nt_status = make_user_info_for_reply_enc(talloc_tos(), 891 &user_info, user, 892 domain, 893 sconn->remote_address, 894 lm_resp, nt_resp); 1628 895 if (NT_STATUS_IS_OK(nt_status)) { 1629 nt_status = negprot_auth_context->check_ntlm_password( 1630 negprot_auth_context, 1631 user_info, 1632 &server_info); 896 nt_status = auth_check_password_session_info(negprot_auth_context, 897 req, user_info, &session_info); 1633 898 } 1634 899 } else { 1635 struct auth _context *plaintext_auth_context = NULL;1636 1637 nt_status = make_auth _context_subsystem(900 struct auth4_context *plaintext_auth_context = NULL; 901 902 nt_status = make_auth4_context( 1638 903 talloc_tos(), &plaintext_auth_context); 1639 904 … … 1644 909 plaintext_auth_context, chal); 1645 910 1646 if (!make_user_info_for_reply(&user_info, 1647 user, domain, chal, 911 if (!make_user_info_for_reply(talloc_tos(), 912 &user_info, 913 user, domain, 914 sconn->remote_address, 915 chal, 1648 916 plaintext_password)) { 1649 917 nt_status = NT_STATUS_NO_MEMORY; … … 1651 919 1652 920 if (NT_STATUS_IS_OK(nt_status)) { 1653 nt_status = plaintext_auth_context->check_ntlm_password( 1654 plaintext_auth_context, 1655 user_info, 1656 &server_info); 1657 1658 TALLOC_FREE(plaintext_auth_context); 921 nt_status = auth_check_password_session_info(plaintext_auth_context, 922 req, user_info, &session_info); 1659 923 } 1660 } 1661 } 1662 1663 free_user_info(&user_info); 1664 1665 if (!NT_STATUS_IS_OK(nt_status)) { 1666 nt_status = do_map_to_guest(nt_status, &server_info, 1667 user, domain); 1668 } 924 TALLOC_FREE(plaintext_auth_context); 925 } 926 } 927 928 TALLOC_FREE(user_info); 1669 929 1670 930 if (!NT_STATUS_IS_OK(nt_status)) { … … 1677 937 } 1678 938 1679 /* Ensure we can't possible take a code path leading to a1680 * null defref. */1681 if (!server_info) {1682 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));1683 END_PROFILE(SMBsesssetupX);1684 return;1685 }1686 1687 if (!server_info->security_token) {1688 nt_status = create_local_token(server_info);1689 1690 if (!NT_STATUS_IS_OK(nt_status)) {1691 DEBUG(10, ("create_local_token failed: %s\n",1692 nt_errstr(nt_status)));1693 data_blob_free(&nt_resp);1694 data_blob_free(&lm_resp);1695 data_blob_clear_free(&plaintext_password);1696 reply_nterror(req, nt_status_squash(nt_status));1697 END_PROFILE(SMBsesssetupX);1698 return;1699 }1700 }1701 1702 939 data_blob_clear_free(&plaintext_password); 1703 940 1704 941 /* it's ok - setup a reply */ 1705 942 reply_outbuf(req, 3, 0); 943 SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */ 944 SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */ 945 1706 946 if (get_Protocol() >= PROTOCOL_NT1) { 1707 947 push_signature(&req->outbuf); … … 1709 949 } 1710 950 1711 if (se rver_info->guest) {1712 SSVAL(req->outbuf,smb_vwv2,1);951 if (security_session_user_level(session_info, NULL) == SECURITY_GUEST) { 952 action |= SMB_SETUP_GUEST; 1713 953 } 1714 954 … … 1716 956 to a uid can get through without a password, on the same VC */ 1717 957 1718 if (lp_security() == SEC_SHARE) { 1719 sess_vuid = UID_FIELD_INVALID; 1720 TALLOC_FREE(server_info); 1721 } else { 1722 /* Ignore the initial vuid. */ 1723 sess_vuid = register_initial_vuid(sconn); 1724 if (sess_vuid == UID_FIELD_INVALID) { 958 nt_status = smbXsrv_session_create(xconn, 959 now, &session); 960 if (!NT_STATUS_IS_OK(nt_status)) { 961 data_blob_free(&nt_resp); 962 data_blob_free(&lm_resp); 963 reply_nterror(req, nt_status_squash(nt_status)); 964 END_PROFILE(SMBsesssetupX); 965 return; 966 } 967 968 if (session_info->session_key.length > 0) { 969 uint8_t session_key[16]; 970 971 /* 972 * Note: the SMB1 signing key is not truncated to 16 byte! 973 */ 974 session->global->signing_key = 975 data_blob_dup_talloc(session->global, 976 session_info->session_key); 977 if (session->global->signing_key.data == NULL) { 1725 978 data_blob_free(&nt_resp); 1726 979 data_blob_free(&lm_resp); 1727 reply_nterror(req, nt_status_squash(1728 NT_STATUS_LOGON_FAILURE));980 TALLOC_FREE(session); 981 reply_nterror(req, NT_STATUS_NO_MEMORY); 1729 982 END_PROFILE(SMBsesssetupX); 1730 983 return; 1731 984 } 1732 /* register_existing_vuid keeps the server info */ 1733 sess_vuid = register_existing_vuid(sconn, sess_vuid, 1734 server_info, 1735 nt_resp.data ? nt_resp : lm_resp, 1736 sub_user); 1737 if (sess_vuid == UID_FIELD_INVALID) { 985 986 /* 987 * The application key is truncated/padded to 16 bytes 988 */ 989 ZERO_STRUCT(session_key); 990 memcpy(session_key, session->global->signing_key.data, 991 MIN(session->global->signing_key.length, 992 sizeof(session_key))); 993 session->global->application_key = 994 data_blob_talloc(session->global, 995 session_key, 996 sizeof(session_key)); 997 ZERO_STRUCT(session_key); 998 if (session->global->application_key.data == NULL) { 1738 999 data_blob_free(&nt_resp); 1739 1000 data_blob_free(&lm_resp); 1740 reply_nterror(req, nt_status_squash(1741 NT_STATUS_LOGON_FAILURE));1001 TALLOC_FREE(session); 1002 reply_nterror(req, NT_STATUS_NO_MEMORY); 1742 1003 END_PROFILE(SMBsesssetupX); 1743 1004 return; 1744 1005 } 1745 1006 1746 /* current_user_info is changed on new vuid */ 1747 reload_services(sconn->msg_ctx, sconn->sock, True); 1748 } 1007 /* 1008 * Place the application key into the session_info 1009 */ 1010 data_blob_clear_free(&session_info->session_key); 1011 session_info->session_key = data_blob_dup_talloc(session_info, 1012 session->global->application_key); 1013 if (session_info->session_key.data == NULL) { 1014 data_blob_free(&nt_resp); 1015 data_blob_free(&lm_resp); 1016 TALLOC_FREE(session); 1017 reply_nterror(req, NT_STATUS_NO_MEMORY); 1018 END_PROFILE(SMBsesssetupX); 1019 return; 1020 } 1021 } 1022 1023 session->compat = talloc_zero(session, struct user_struct); 1024 if (session->compat == NULL) { 1025 data_blob_free(&nt_resp); 1026 data_blob_free(&lm_resp); 1027 TALLOC_FREE(session); 1028 reply_nterror(req, NT_STATUS_NO_MEMORY); 1029 END_PROFILE(SMBsesssetupX); 1030 return; 1031 } 1032 session->compat->session = session; 1033 session->compat->homes_snum = -1; 1034 session->compat->session_info = session_info; 1035 session->compat->session_keystr = NULL; 1036 session->compat->vuid = session->global->session_wire_id; 1037 DLIST_ADD(sconn->users, session->compat); 1038 sconn->num_users++; 1039 1040 if (security_session_user_level(session_info, NULL) >= SECURITY_USER) { 1041 session->compat->homes_snum = 1042 register_homes_share(session_info->unix_info->unix_name); 1043 } 1044 1045 if (srv_is_signing_negotiated(xconn) && 1046 action == 0 && 1047 session->global->signing_key.length > 0) 1048 { 1049 /* 1050 * Try and turn on server signing on the first non-guest 1051 * sessionsetup. 1052 */ 1053 srv_set_signing(xconn, 1054 session->global->signing_key, 1055 nt_resp.data ? nt_resp : lm_resp); 1056 } 1057 1058 set_current_user_info(session_info->unix_info->sanitized_username, 1059 session_info->unix_info->unix_name, 1060 session_info->info->domain_name); 1061 1062 session->status = NT_STATUS_OK; 1063 session->global->auth_session_info = talloc_move(session->global, 1064 &session_info); 1065 session->global->auth_session_info_seqnum += 1; 1066 session->global->channels[0].auth_session_info_seqnum = 1067 session->global->auth_session_info_seqnum; 1068 session->global->auth_time = now; 1069 session->global->expiration_time = GENSEC_EXPIRE_TIME_INFINITY; 1070 1071 nt_status = smbXsrv_session_update(session); 1072 if (!NT_STATUS_IS_OK(nt_status)) { 1073 DEBUG(0, ("smb1: Failed to update session for vuid=%llu - %s\n", 1074 (unsigned long long)session->compat->vuid, 1075 nt_errstr(nt_status))); 1076 data_blob_free(&nt_resp); 1077 data_blob_free(&lm_resp); 1078 TALLOC_FREE(session); 1079 reply_nterror(req, nt_status_squash(nt_status)); 1080 END_PROFILE(SMBsesssetupX); 1081 return; 1082 } 1083 1084 if (!session_claim(session)) { 1085 DEBUG(1, ("smb1: Failed to claim session for vuid=%llu\n", 1086 (unsigned long long)session->compat->vuid)); 1087 data_blob_free(&nt_resp); 1088 data_blob_free(&lm_resp); 1089 TALLOC_FREE(session); 1090 reply_nterror(req, NT_STATUS_LOGON_FAILURE); 1091 END_PROFILE(SMBsesssetupX); 1092 return; 1093 } 1094 1095 /* current_user_info is changed on new vuid */ 1096 reload_services(sconn, conn_snum_used, true); 1097 1098 sess_vuid = session->global->session_wire_id; 1749 1099 1750 1100 data_blob_free(&nt_resp); 1751 1101 data_blob_free(&lm_resp); 1752 1102 1103 SSVAL(req->outbuf,smb_vwv2,action); 1753 1104 SSVAL(req->outbuf,smb_uid,sess_vuid); 1754 SSVAL( req->inbuf,smb_uid,sess_vuid);1105 SSVAL(discard_const_p(char, req->inbuf),smb_uid,sess_vuid); 1755 1106 req->vuid = sess_vuid; 1756 1107 1757 if (!sconn->smb1.sessions.done_sesssetup) { 1758 sconn->smb1.sessions.max_send = 1759 MIN(sconn->smb1.sessions.max_send,smb_bufsize); 1760 } 1761 sconn->smb1.sessions.done_sesssetup = true; 1108 if (!xconn->smb1.sessions.done_sesssetup) { 1109 if (smb_bufsize < SMB_BUFFER_SIZE_MIN) { 1110 reply_force_doserror(req, ERRSRV, ERRerror); 1111 END_PROFILE(SMBsesssetupX); 1112 return; 1113 } 1114 xconn->smb1.sessions.max_send = smb_bufsize; 1115 xconn->smb1.sessions.done_sesssetup = true; 1116 } 1762 1117 1763 1118 END_PROFILE(SMBsesssetupX); 1764 chain_reply(req);1765 return;1766 1119 }
Note:
See TracChangeset
for help on using the changeset viewer.