static NTSTATUS smbd_smb2_reauth_generic_return(struct smbXsrv_session *session, struct smbd_smb2_request *smb2req, struct auth_session_info *session_info, uint16_t *out_session_flags, uint64_t *out_session_id) { NTSTATUS status; struct smbXsrv_session *x = session; data_blob_clear_free(&session_info->session_key); session_info->session_key = data_blob_dup_talloc(session_info, x->global->application_key); if (session_info->session_key.data == NULL) { return NT_STATUS_NO_MEMORY; } session->compat->session_info = session_info; session->compat->vuid = session->global->session_wire_id; session->compat->homes_snum = register_homes_share(session_info->unix_info->unix_name); set_current_user_info(session_info->unix_info->sanitized_username, session_info->unix_info->unix_name, session_info->info->domain_name); reload_services(smb2req->sconn, conn_snum_used, true); session->status = NT_STATUS_OK; TALLOC_FREE(session->global->auth_session_info); session->global->auth_session_info = session_info; session->global->auth_session_info_seqnum += 1; session->global->channels[0].auth_session_info_seqnum = session->global->auth_session_info_seqnum; session->global->auth_time = timeval_to_nttime(&smb2req->request_time); session->global->expiration_time = gensec_expire_time(session->gensec); status = smbXsrv_session_update(session); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n", (unsigned long long)session->compat->vuid, nt_errstr(status))); return NT_STATUS_LOGON_FAILURE; } conn_clear_vuid_caches(smb2req->sconn, session->compat->vuid); if (security_session_user_level(session_info, NULL) >= SECURITY_USER) { smb2req->do_signing = true; } *out_session_id = session->global->session_wire_id; return NT_STATUS_OK; }
bool pdb_set_nt_passwd(struct samu *sampass, const uint8 pwd[NT_HASH_LEN], enum pdb_value_state flag) { data_blob_clear_free(&sampass->nt_pw); if (pwd) { sampass->nt_pw = data_blob_talloc(sampass, pwd, NT_HASH_LEN); } else { sampass->nt_pw = data_blob_null; } return pdb_set_init_flags(sampass, PDB_NTPASSWD, flag); }
bool pdb_set_lanman_passwd(struct samu *sampass, const uint8 pwd[LM_HASH_LEN], enum pdb_value_state flag) { data_blob_clear_free(&sampass->lm_pw); /* on keep the password if we are allowing LANMAN authentication */ if (pwd && lp_lanman_auth() ) { sampass->lm_pw = data_blob_talloc(sampass, pwd, LM_HASH_LEN); } else { sampass->lm_pw = data_blob_null; } return pdb_set_init_flags(sampass, PDB_LMPASSWD, flag); }
static void reply_sesssetup_and_X_spnego(struct smb_request *req) { const uint8_t *p; DATA_BLOB in_blob; DATA_BLOB out_blob = data_blob_null; size_t bufrem; char *tmp; const char *native_os; const char *native_lanman; const char *primary_domain; uint16_t data_blob_len = SVAL(req->vwv+7, 0); enum remote_arch_types ra_type = get_remote_arch(); uint64_t vuid = req->vuid; NTSTATUS status = NT_STATUS_OK; struct smbXsrv_connection *xconn = req->xconn; struct smbd_server_connection *sconn = req->sconn; uint16_t action = 0; bool is_authenticated = false; NTTIME now = timeval_to_nttime(&req->request_time); struct smbXsrv_session *session = NULL; uint16_t smb_bufsize = SVAL(req->vwv+2, 0); uint32_t client_caps = IVAL(req->vwv+10, 0); struct smbXsrv_session_auth0 *auth; DEBUG(3,("Doing spnego session setup\n")); if (!xconn->smb1.sessions.done_sesssetup) { global_client_caps = client_caps; if (!(global_client_caps & CAP_STATUS32)) { remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES); } } p = req->buf; if (data_blob_len == 0) { /* an invalid request */ reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE)); return; } bufrem = smbreq_bufrem(req, p); /* pull the spnego blob */ in_blob = data_blob_const(p, MIN(bufrem, data_blob_len)); #if 0 file_save("negotiate.dat", in_blob.data, in_blob.length); #endif p = req->buf + in_blob.length; p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p, STR_TERMINATE); native_os = tmp ? tmp : ""; p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p, STR_TERMINATE); native_lanman = tmp ? tmp : ""; p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p, STR_TERMINATE); primary_domain = tmp ? tmp : ""; DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", native_os, native_lanman, primary_domain)); if ( ra_type == RA_WIN2K ) { /* Vista sets neither the OS or lanman strings */ if ( !strlen(native_os) && !strlen(native_lanman) ) set_remote_arch(RA_VISTA); /* Windows 2003 doesn't set the native lanman string, but does set primary domain which is a bug I think */ if ( !strlen(native_lanman) ) { ra_lanman_string( primary_domain ); } else { ra_lanman_string( native_lanman ); } } else if ( ra_type == RA_VISTA ) { if ( strncmp(native_os, "Mac OS X", 8) == 0 ) { set_remote_arch(RA_OSX); } } if (vuid != 0) { status = smb1srv_session_lookup(xconn, vuid, now, &session); if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) { reply_force_doserror(req, ERRSRV, ERRbaduid); return; } if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) { status = NT_STATUS_OK; } if (NT_STATUS_IS_OK(status)) { session->status = NT_STATUS_MORE_PROCESSING_REQUIRED; status = NT_STATUS_MORE_PROCESSING_REQUIRED; TALLOC_FREE(session->pending_auth); } if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { reply_nterror(req, nt_status_squash(status)); return; } } if (session == NULL) { /* create a new session */ status = smbXsrv_session_create(xconn, now, &session); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, nt_status_squash(status)); return; } } status = smbXsrv_session_find_auth(session, xconn, now, &auth); if (!NT_STATUS_IS_OK(status)) { status = smbXsrv_session_create_auth(session, xconn, now, 0, /* flags */ 0, /* security */ &auth); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, nt_status_squash(status)); return; } } if (auth->gensec == NULL) { status = auth_generic_prepare(session, xconn->remote_address, xconn->local_address, "SMB", &auth->gensec); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(session); reply_nterror(req, nt_status_squash(status)); return; } gensec_want_feature(auth->gensec, GENSEC_FEATURE_SESSION_KEY); gensec_want_feature(auth->gensec, GENSEC_FEATURE_UNIX_TOKEN); gensec_want_feature(auth->gensec, GENSEC_FEATURE_SMB_TRANSPORT); status = gensec_start_mech_by_oid(auth->gensec, GENSEC_OID_SPNEGO); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to start SPNEGO handler!\n")); TALLOC_FREE(session);; reply_nterror(req, nt_status_squash(status)); return; } } become_root(); status = gensec_update(auth->gensec, talloc_tos(), in_blob, &out_blob); unbecome_root(); if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { TALLOC_FREE(session); reply_nterror(req, nt_status_squash(status)); return; } if (NT_STATUS_IS_OK(status) && session->global->auth_session_info == NULL) { struct auth_session_info *session_info = NULL; status = gensec_session_info(auth->gensec, session, &session_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(1,("Failed to generate session_info " "(user and group token) for session setup: %s\n", nt_errstr(status))); data_blob_free(&out_blob); TALLOC_FREE(session); reply_nterror(req, nt_status_squash(status)); return; } if (security_session_user_level(session_info, NULL) == SECURITY_GUEST) { action |= SMB_SETUP_GUEST; } if (session_info->session_key.length > 0) { struct smbXsrv_session *x = session; /* * Note: the SMB1 signing key is not truncated to 16 byte! */ x->global->signing_key = data_blob_dup_talloc(x->global, session_info->session_key); if (x->global->signing_key.data == NULL) { data_blob_free(&out_blob); TALLOC_FREE(session); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } /* * clear the session key * the first tcon will add setup the application key */ data_blob_clear_free(&session_info->session_key); } session->compat = talloc_zero(session, struct user_struct); if (session->compat == NULL) { data_blob_free(&out_blob); TALLOC_FREE(session); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } session->compat->session = session; session->compat->homes_snum = -1; session->compat->session_info = session_info; session->compat->session_keystr = NULL; session->compat->vuid = session->global->session_wire_id; DLIST_ADD(sconn->users, session->compat); sconn->num_users++; if (security_session_user_level(session_info, NULL) >= SECURITY_USER) { is_authenticated = true; session->compat->homes_snum = register_homes_share(session_info->unix_info->unix_name); } if (srv_is_signing_negotiated(xconn) && is_authenticated && session->global->signing_key.length > 0) { /* * Try and turn on server signing on the first non-guest * sessionsetup. */ srv_set_signing(xconn, session->global->signing_key, data_blob_null); } set_current_user_info(session_info->unix_info->sanitized_username, session_info->unix_info->unix_name, session_info->info->domain_name); session->status = NT_STATUS_OK; session->global->auth_session_info = talloc_move(session->global, &session_info); session->global->auth_session_info_seqnum += 1; session->global->channels[0].auth_session_info_seqnum = session->global->auth_session_info_seqnum; session->global->auth_time = now; if (client_caps & CAP_DYNAMIC_REAUTH) { session->global->expiration_time = gensec_expire_time(auth->gensec); } else { session->global->expiration_time = GENSEC_EXPIRE_TIME_INFINITY; } if (!session_claim(session)) { DEBUG(1, ("smb1: Failed to claim session for vuid=%llu\n", (unsigned long long)session->compat->vuid)); data_blob_free(&out_blob); TALLOC_FREE(session); reply_nterror(req, NT_STATUS_LOGON_FAILURE); return; } status = smbXsrv_session_update(session); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("smb1: Failed to update session for vuid=%llu - %s\n", (unsigned long long)session->compat->vuid, nt_errstr(status))); data_blob_free(&out_blob); TALLOC_FREE(session); reply_nterror(req, NT_STATUS_LOGON_FAILURE); return; } if (!xconn->smb1.sessions.done_sesssetup) { if (smb_bufsize < SMB_BUFFER_SIZE_MIN) { reply_force_doserror(req, ERRSRV, ERRerror); return; } xconn->smb1.sessions.max_send = smb_bufsize; xconn->smb1.sessions.done_sesssetup = true; } /* current_user_info is changed on new vuid */ reload_services(sconn, conn_snum_used, true); } else if (NT_STATUS_IS_OK(status)) {
static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session, struct smbd_smb2_request *smb2req, uint8_t in_security_mode, struct auth_session_info *session_info, uint16_t *out_session_flags, uint64_t *out_session_id) { NTSTATUS status; bool guest = false; uint8_t session_key[16]; struct smbXsrv_session *x = session; struct smbXsrv_connection *xconn = smb2req->xconn; struct _derivation { DATA_BLOB label; DATA_BLOB context; }; struct { struct _derivation signing; struct _derivation encryption; struct _derivation decryption; struct _derivation application; } derivation = { }; if (xconn->protocol >= PROTOCOL_SMB3_10) { struct smbXsrv_preauth *preauth; struct _derivation *d; DATA_BLOB p; struct hc_sha512state sctx; size_t i; preauth = talloc_move(smb2req, &session->preauth); samba_SHA512_Init(&sctx); samba_SHA512_Update(&sctx, preauth->sha512_value, sizeof(preauth->sha512_value)); for (i = 1; i < smb2req->in.vector_count; i++) { samba_SHA512_Update(&sctx, smb2req->in.vector[i].iov_base, smb2req->in.vector[i].iov_len); } samba_SHA512_Final(preauth->sha512_value, &sctx); p = data_blob_const(preauth->sha512_value, sizeof(preauth->sha512_value)); d = &derivation.signing; d->label = data_blob_string_const_null("SMBSigningKey"); d->context = p; d = &derivation.decryption; d->label = data_blob_string_const_null("SMBC2SCipherKey"); d->context = p; d = &derivation.encryption; d->label = data_blob_string_const_null("SMBS2CCipherKey"); d->context = p; d = &derivation.application; d->label = data_blob_string_const_null("SMBAppKey"); d->context = p; } else if (xconn->protocol >= PROTOCOL_SMB2_24) { struct _derivation *d; d = &derivation.signing; d->label = data_blob_string_const_null("SMB2AESCMAC"); d->context = data_blob_string_const_null("SmbSign"); d = &derivation.decryption; d->label = data_blob_string_const_null("SMB2AESCCM"); d->context = data_blob_string_const_null("ServerIn "); d = &derivation.encryption; d->label = data_blob_string_const_null("SMB2AESCCM"); d->context = data_blob_string_const_null("ServerOut"); d = &derivation.application; d->label = data_blob_string_const_null("SMB2APP"); d->context = data_blob_string_const_null("SmbRpc"); } if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) || (xconn->smb2.server.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED)) { x->global->signing_required = true; } if ((lp_smb_encrypt(-1) >= SMB_SIGNING_DESIRED) && (xconn->smb2.client.capabilities & SMB2_CAP_ENCRYPTION)) { x->encryption_desired = true; } if (lp_smb_encrypt(-1) == SMB_SIGNING_REQUIRED) { x->encryption_desired = true; x->global->encryption_required = true; } if (security_session_user_level(session_info, NULL) < SECURITY_USER) { /* we map anonymous to guest internally */ *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST; *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL; /* force no signing */ x->global->signing_required = false; guest = true; } if (guest && x->global->encryption_required) { DEBUG(1,("reject guest session as encryption is required\n")); return NT_STATUS_ACCESS_DENIED; } if (xconn->smb2.server.cipher == 0) { if (x->global->encryption_required) { DEBUG(1,("reject session with dialect[0x%04X] " "as encryption is required\n", xconn->smb2.server.dialect)); return NT_STATUS_ACCESS_DENIED; } } if (x->encryption_desired) { *out_session_flags |= SMB2_SESSION_FLAG_ENCRYPT_DATA; } ZERO_STRUCT(session_key); memcpy(session_key, session_info->session_key.data, MIN(session_info->session_key.length, sizeof(session_key))); x->global->signing_key = data_blob_talloc(x->global, session_key, sizeof(session_key)); if (x->global->signing_key.data == NULL) { ZERO_STRUCT(session_key); return NT_STATUS_NO_MEMORY; } if (xconn->protocol >= PROTOCOL_SMB2_24) { struct _derivation *d = &derivation.signing; smb2_key_derivation(session_key, sizeof(session_key), d->label.data, d->label.length, d->context.data, d->context.length, x->global->signing_key.data); } if (xconn->protocol >= PROTOCOL_SMB2_24) { struct _derivation *d = &derivation.decryption; x->global->decryption_key = data_blob_talloc(x->global, session_key, sizeof(session_key)); if (x->global->decryption_key.data == NULL) { ZERO_STRUCT(session_key); return NT_STATUS_NO_MEMORY; } smb2_key_derivation(session_key, sizeof(session_key), d->label.data, d->label.length, d->context.data, d->context.length, x->global->decryption_key.data); } if (xconn->protocol >= PROTOCOL_SMB2_24) { struct _derivation *d = &derivation.encryption; size_t nonce_size; x->global->encryption_key = data_blob_talloc(x->global, session_key, sizeof(session_key)); if (x->global->encryption_key.data == NULL) { ZERO_STRUCT(session_key); return NT_STATUS_NO_MEMORY; } smb2_key_derivation(session_key, sizeof(session_key), d->label.data, d->label.length, d->context.data, d->context.length, x->global->encryption_key.data); /* * CCM and GCM algorithms must never have their * nonce wrap, or the security of the whole * communication and the keys is destroyed. * We must drop the connection once we have * transfered too much data. * * NOTE: We assume nonces greater than 8 bytes. */ generate_random_buffer((uint8_t *)&x->nonce_high_random, sizeof(x->nonce_high_random)); switch (xconn->smb2.server.cipher) { case SMB2_ENCRYPTION_AES128_CCM: nonce_size = AES_CCM_128_NONCE_SIZE; break; case SMB2_ENCRYPTION_AES128_GCM: nonce_size = AES_GCM_128_IV_SIZE; break; default: nonce_size = 0; break; } x->nonce_high_max = SMB2_NONCE_HIGH_MAX(nonce_size); x->nonce_high = 0; x->nonce_low = 0; } x->global->application_key = data_blob_dup_talloc(x->global, x->global->signing_key); if (x->global->application_key.data == NULL) { ZERO_STRUCT(session_key); return NT_STATUS_NO_MEMORY; } if (xconn->protocol >= PROTOCOL_SMB2_24) { struct _derivation *d = &derivation.application; smb2_key_derivation(session_key, sizeof(session_key), d->label.data, d->label.length, d->context.data, d->context.length, x->global->application_key.data); } ZERO_STRUCT(session_key); x->global->channels[0].signing_key = data_blob_dup_talloc(x->global->channels, x->global->signing_key); if (x->global->channels[0].signing_key.data == NULL) { return NT_STATUS_NO_MEMORY; } data_blob_clear_free(&session_info->session_key); session_info->session_key = data_blob_dup_talloc(session_info, x->global->application_key); if (session_info->session_key.data == NULL) { return NT_STATUS_NO_MEMORY; } session->compat = talloc_zero(session, struct user_struct); if (session->compat == NULL) { return NT_STATUS_NO_MEMORY; } session->compat->session = session; session->compat->homes_snum = -1; session->compat->session_info = session_info; session->compat->session_keystr = NULL; session->compat->vuid = session->global->session_wire_id; DLIST_ADD(smb2req->sconn->users, session->compat); smb2req->sconn->num_users++; if (security_session_user_level(session_info, NULL) >= SECURITY_USER) { session->compat->homes_snum = register_homes_share(session_info->unix_info->unix_name); } set_current_user_info(session_info->unix_info->sanitized_username, session_info->unix_info->unix_name, session_info->info->domain_name); reload_services(smb2req->sconn, conn_snum_used, true); session->status = NT_STATUS_OK; session->global->auth_session_info = session_info; session->global->auth_session_info_seqnum += 1; session->global->channels[0].auth_session_info_seqnum = session->global->auth_session_info_seqnum; session->global->auth_time = timeval_to_nttime(&smb2req->request_time); session->global->expiration_time = gensec_expire_time(session->gensec); if (!session_claim(session)) { DEBUG(1, ("smb2: Failed to claim session " "for vuid=%llu\n", (unsigned long long)session->compat->vuid)); return NT_STATUS_LOGON_FAILURE; } status = smbXsrv_session_update(session); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n", (unsigned long long)session->compat->vuid, nt_errstr(status))); return NT_STATUS_LOGON_FAILURE; } /* * we attach the session to the request * so that the response can be signed */ if (!guest) { smb2req->do_signing = true; } global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32); *out_session_id = session->global->session_wire_id; return NT_STATUS_OK; }
static bool smb_pwd_check_ntlmv2(TALLOC_CTX *mem_ctx, const DATA_BLOB *ntv2_response, const uint8_t *part_passwd, const DATA_BLOB *sec_blob, const char *user, const char *domain, DATA_BLOB *user_sess_key) { /* Finish the encryption of part_passwd. */ uint8_t kr[16]; uint8_t value_from_encryption[16]; DATA_BLOB client_key_data; if (part_passwd == NULL) { DEBUG(10,("No password set - DISALLOWING access\n")); /* No password set - always false */ return false; } if (sec_blob->length != 8) { DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect challenge size (%lu)\n", (unsigned long)sec_blob->length)); return false; } if (ntv2_response->length < 24) { /* We MUST have more than 16 bytes, or the stuff below will go crazy. No known implementation sends less than the 24 bytes for LMv2, let alone NTLMv2. */ DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect password length (%lu)\n", (unsigned long)ntv2_response->length)); return false; } client_key_data = data_blob_talloc(mem_ctx, ntv2_response->data+16, ntv2_response->length-16); /* todo: should we be checking this for anything? We can't for LMv2, but for NTLMv2 it is meant to contain the current time etc. */ if (!ntv2_owf_gen(part_passwd, user, domain, kr)) { return false; } SMBOWFencrypt_ntv2(kr, sec_blob, &client_key_data, value_from_encryption); #if DEBUG_PASSWORD DEBUG(100,("Part password (P16) was |\n")); dump_data(100, part_passwd, 16); DEBUGADD(100,("Password from client was |\n")); dump_data(100, ntv2_response->data, ntv2_response->length); DEBUGADD(100,("Variable data from client was |\n")); dump_data(100, client_key_data.data, client_key_data.length); DEBUGADD(100,("Given challenge was |\n")); dump_data(100, sec_blob->data, sec_blob->length); DEBUGADD(100,("Value from encryption was |\n")); dump_data(100, value_from_encryption, 16); #endif data_blob_clear_free(&client_key_data); if (memcmp(value_from_encryption, ntv2_response->data, 16) == 0) { if (user_sess_key != NULL) { *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16); SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key->data); } return true; } return false; }
int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, int length,int bufsize) { int sess_vuid; int smb_bufsize; DATA_BLOB lm_resp; DATA_BLOB nt_resp; DATA_BLOB plaintext_password; fstring user; fstring sub_user; /* Sainitised username for substituion */ fstring domain; fstring native_os; fstring native_lanman; fstring primary_domain; static BOOL done_sesssetup = False; auth_usersupplied_info *user_info = NULL; auth_serversupplied_info *server_info = NULL; NTSTATUS nt_status; BOOL doencrypt = global_encrypted_passwords_negotiated; DATA_BLOB session_key; START_PROFILE(SMBsesssetupX); ZERO_STRUCT(lm_resp); ZERO_STRUCT(nt_resp); ZERO_STRUCT(plaintext_password); DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2))); /* a SPNEGO session setup has 12 command words, whereas a normal NT1 session setup has 13. See the cifs spec. */ if (CVAL(inbuf, smb_wct) == 12 && (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) { if (!global_spnego_negotiated) { DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n")); return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE)); } if (SVAL(inbuf,smb_vwv4) == 0) { setup_new_vc_session(); } return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize); } smb_bufsize = SVAL(inbuf,smb_vwv2); if (Protocol < PROTOCOL_NT1) { uint16 passlen1 = SVAL(inbuf,smb_vwv7); /* Never do NT status codes with protocols before NT1 as we don't get client caps. */ remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES); if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) { return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER)); } if (doencrypt) { lm_resp = data_blob(smb_buf(inbuf), passlen1); } else { plaintext_password = data_blob(smb_buf(inbuf), passlen1+1); /* Ensure null termination */ plaintext_password.data[passlen1] = 0; } srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE); *domain = 0; } else { uint16 passlen1 = SVAL(inbuf,smb_vwv7); uint16 passlen2 = SVAL(inbuf,smb_vwv8); enum remote_arch_types ra_type = get_remote_arch(); char *p = smb_buf(inbuf); char *save_p = smb_buf(inbuf); uint16 byte_count; if(global_client_caps == 0) { global_client_caps = IVAL(inbuf,smb_vwv11); if (!(global_client_caps & CAP_STATUS32)) { remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES); } /* client_caps is used as final determination if client is NT or Win95. This is needed to return the correct error codes in some circumstances. */ if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) { if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) { set_remote_arch( RA_WIN95); } } } if (!doencrypt) { /* both Win95 and WinNT stuff up the password lengths for non-encrypting systems. Uggh. if passlen1==24 its a win95 system, and its setting the password length incorrectly. Luckily it still works with the default code because Win95 will null terminate the password anyway if passlen1>0 and passlen2>0 then maybe its a NT box and its setting passlen2 to some random value which really stuffs things up. we need to fix that one. */ if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1) passlen2 = 0; } /* check for nasty tricks */ if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) { return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER)); } if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) { return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER)); } /* Save the lanman2 password and the NT md4 password. */ if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) { doencrypt = False; } if (doencrypt) { lm_resp = data_blob(p, passlen1); nt_resp = data_blob(p+passlen1, passlen2); } else { pstring pass; BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS; #if 0 /* This was the previous fix. Not sure if it's still valid. JRA. */ if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) { /* NT4.0 stuffs up plaintext unicode password lengths... */ srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1, sizeof(pass), passlen1, STR_TERMINATE); #endif if (unic && (passlen2 == 0) && passlen1) { /* Only a ascii plaintext password was sent. */ srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass), passlen1, STR_TERMINATE|STR_ASCII); } else { srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass), unic ? passlen2 : passlen1, STR_TERMINATE); } plaintext_password = data_blob(pass, strlen(pass)+1); } p += passlen1 + passlen2; p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE); p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE); p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE); p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE); /* not documented or decoded by Ethereal but there is one more string in the extra bytes which is the same as the PrimaryDomain when using extended security. Windows NT 4 and 2003 use this string to store the native lanman string. Windows 9x does not include a string here at all so we have to check if we have any extra bytes left */ byte_count = SVAL(inbuf, smb_vwv13); if ( PTR_DIFF(p, save_p) < byte_count) p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE); else fstrcpy( primary_domain, "null" ); DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", domain, native_os, native_lanman, primary_domain)); if ( ra_type == RA_WIN2K ) { if ( strlen(native_lanman) == 0 ) ra_lanman_string( primary_domain ); else ra_lanman_string( native_lanman ); } } if (SVAL(inbuf,smb_vwv4) == 0) { setup_new_vc_session(); } DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name())); if (*user) { if (global_spnego_negotiated) { /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */ DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at 'normal' session setup after negotiating spnego.\n")); return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE)); } fstrcpy(sub_user, user); } else { fstrcpy(sub_user, lp_guestaccount()); } sub_set_smb_name(sub_user); reload_services(True); if (lp_security() == SEC_SHARE) { /* in share level we should ignore any passwords */ data_blob_free(&lm_resp); data_blob_free(&nt_resp); data_blob_clear_free(&plaintext_password); map_username(sub_user); add_session_user(sub_user); add_session_workgroup(domain); /* Then force it to null for the benfit of the code below */ *user = 0; } if (!*user) { nt_status = check_guest_password(&server_info); } else if (doencrypt) { if (!negprot_global_auth_context) { DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted session setup without negprot denied!\n")); return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE)); } nt_status = make_user_info_for_reply_enc(&user_info, user, domain, lm_resp, nt_resp); if (NT_STATUS_IS_OK(nt_status)) { nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, user_info, &server_info); } } else { struct auth_context *plaintext_auth_context = NULL; const uint8 *chal; nt_status = make_auth_context_subsystem(&plaintext_auth_context); if (NT_STATUS_IS_OK(nt_status)) { chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context); if (!make_user_info_for_reply(&user_info, user, domain, chal, plaintext_password)) { nt_status = NT_STATUS_NO_MEMORY; } if (NT_STATUS_IS_OK(nt_status)) { nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, user_info, &server_info); (plaintext_auth_context->free)(&plaintext_auth_context); } } } free_user_info(&user_info); if (!NT_STATUS_IS_OK(nt_status)) { nt_status = do_map_to_guest(nt_status, &server_info, user, domain); } if (!NT_STATUS_IS_OK(nt_status)) { data_blob_free(&nt_resp); data_blob_free(&lm_resp); data_blob_clear_free(&plaintext_password); return ERROR_NT(nt_status_squash(nt_status)); } /* Ensure we can't possible take a code path leading to a null defref. */ if (!server_info) { return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE)); } nt_status = create_local_token(server_info); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(10, ("create_local_token failed: %s\n", nt_errstr(nt_status))); data_blob_free(&nt_resp); data_blob_free(&lm_resp); data_blob_clear_free(&plaintext_password); return ERROR_NT(nt_status_squash(nt_status)); } if (server_info->user_session_key.data) { session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length); } else { session_key = data_blob(NULL, 0); } data_blob_clear_free(&plaintext_password); /* it's ok - setup a reply */ set_message(outbuf,3,0,True); if (Protocol >= PROTOCOL_NT1) { char *p = smb_buf( outbuf ); p += add_signature( outbuf, p ); set_message_end( outbuf, p ); /* perhaps grab OS version here?? */ } if (server_info->guest) { SSVAL(outbuf,smb_vwv2,1); } /* register the name and uid as being validated, so further connections to a uid can get through without a password, on the same VC */ if (lp_security() == SEC_SHARE) { sess_vuid = UID_FIELD_INVALID; data_blob_free(&session_key); TALLOC_FREE(server_info); } else { /* register_vuid keeps the server info */ sess_vuid = register_vuid(server_info, session_key, nt_resp.data ? nt_resp : lm_resp, sub_user); if (sess_vuid == UID_FIELD_INVALID) { data_blob_free(&nt_resp); data_blob_free(&lm_resp); return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE)); } /* current_user_info is changed on new vuid */ reload_services( True ); sessionsetup_start_signing_engine(server_info, inbuf); } data_blob_free(&nt_resp); data_blob_free(&lm_resp); SSVAL(outbuf,smb_uid,sess_vuid); SSVAL(inbuf,smb_uid,sess_vuid); if (!done_sesssetup) max_send = MIN(max_send,smb_bufsize); done_sesssetup = True; END_PROFILE(SMBsesssetupX); return chain_reply(inbuf,outbuf,length,bufsize); }
static BOOL smb_pwd_check_ntlmv2(const DATA_BLOB *ntv2_response, const uchar *part_passwd, const DATA_BLOB *sec_blob, const char *user, const char *domain, BOOL upper_case_domain, /* should the domain be transformed into upper case? */ DATA_BLOB *user_sess_key) { /* Finish the encryption of part_passwd. */ uchar kr[16]; uchar value_from_encryption[16]; uchar client_response[16]; DATA_BLOB client_key_data; BOOL res; if (part_passwd == NULL) { DEBUG(10,("No password set - DISALLOWING access\n")); /* No password set - always False */ return False; } if (sec_blob->length != 8) { DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect challenge size (%lu)\n", (unsigned long)sec_blob->length)); return False; } if (ntv2_response->length < 24) { /* We MUST have more than 16 bytes, or the stuff below will go crazy. No known implementation sends less than the 24 bytes for LMv2, let alone NTLMv2. */ DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect password length (%lu)\n", (unsigned long)ntv2_response->length)); return False; } client_key_data = data_blob(ntv2_response->data+16, ntv2_response->length-16); /* todo: should we be checking this for anything? We can't for LMv2, but for NTLMv2 it is meant to contain the current time etc. */ memcpy(client_response, ntv2_response->data, sizeof(client_response)); if (!ntv2_owf_gen(part_passwd, user, domain, upper_case_domain, kr)) { return False; } SMBOWFencrypt_ntv2(kr, sec_blob, &client_key_data, value_from_encryption); if (user_sess_key != NULL) { *user_sess_key = data_blob(NULL, 16); SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key->data); } #if DEBUG_PASSWORD DEBUG(100,("Part password (P16) was |\n")); dump_data(100, part_passwd, 16); DEBUGADD(100,("Password from client was |\n")); dump_data(100, ntv2_response->data, ntv2_response->length); DEBUGADD(100,("Variable data from client was |\n")); dump_data(100, client_key_data.data, client_key_data.length); DEBUGADD(100,("Given challenge was |\n")); dump_data(100, sec_blob->data, sec_blob->length); DEBUGADD(100,("Value from encryption was |\n")); dump_data(100, value_from_encryption, 16); #endif data_blob_clear_free(&client_key_data); res = (memcmp(value_from_encryption, client_response, 16) == 0); if ((!res) && (user_sess_key != NULL)) data_blob_clear_free(user_sess_key); return res; }
static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session, struct smbd_smb2_request *smb2req, uint8_t in_security_mode, struct auth_session_info *session_info, uint16_t *out_session_flags, uint64_t *out_session_id) { NTSTATUS status; bool guest = false; uint8_t session_key[16]; struct smbXsrv_session *x = session; struct smbXsrv_connection *xconn = smb2req->xconn; if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) || lp_server_signing() == SMB_SIGNING_REQUIRED) { x->global->signing_required = true; } if (lp_smb_encrypt(-1) == SMB_SIGNING_REQUIRED) { x->global->encryption_required = true; } if (security_session_user_level(session_info, NULL) < SECURITY_USER) { /* we map anonymous to guest internally */ *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST; *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL; /* force no signing */ x->global->signing_required = false; guest = true; } if (guest && x->global->encryption_required) { DEBUG(1,("reject guest session as encryption is required\n")); return NT_STATUS_ACCESS_DENIED; } if (xconn->smb2.server.cipher == 0) { if (x->global->encryption_required) { DEBUG(1,("reject session with dialect[0x%04X] " "as encryption is required\n", xconn->smb2.server.dialect)); return NT_STATUS_ACCESS_DENIED; } } if (x->global->encryption_required) { *out_session_flags |= SMB2_SESSION_FLAG_ENCRYPT_DATA; } ZERO_STRUCT(session_key); memcpy(session_key, session_info->session_key.data, MIN(session_info->session_key.length, sizeof(session_key))); x->global->signing_key = data_blob_talloc(x->global, session_key, sizeof(session_key)); if (x->global->signing_key.data == NULL) { ZERO_STRUCT(session_key); return NT_STATUS_NO_MEMORY; } if (xconn->protocol >= PROTOCOL_SMB2_24) { const DATA_BLOB label = data_blob_string_const_null("SMB2AESCMAC"); const DATA_BLOB context = data_blob_string_const_null("SmbSign"); smb2_key_derivation(session_key, sizeof(session_key), label.data, label.length, context.data, context.length, x->global->signing_key.data); } if (xconn->protocol >= PROTOCOL_SMB2_24) { const DATA_BLOB label = data_blob_string_const_null("SMB2AESCCM"); const DATA_BLOB context = data_blob_string_const_null("ServerIn "); x->global->decryption_key = data_blob_talloc(x->global, session_key, sizeof(session_key)); if (x->global->decryption_key.data == NULL) { ZERO_STRUCT(session_key); return NT_STATUS_NO_MEMORY; } smb2_key_derivation(session_key, sizeof(session_key), label.data, label.length, context.data, context.length, x->global->decryption_key.data); } if (xconn->protocol >= PROTOCOL_SMB2_24) { const DATA_BLOB label = data_blob_string_const_null("SMB2AESCCM"); const DATA_BLOB context = data_blob_string_const_null("ServerOut"); x->global->encryption_key = data_blob_talloc(x->global, session_key, sizeof(session_key)); if (x->global->encryption_key.data == NULL) { ZERO_STRUCT(session_key); return NT_STATUS_NO_MEMORY; } smb2_key_derivation(session_key, sizeof(session_key), label.data, label.length, context.data, context.length, x->global->encryption_key.data); generate_random_buffer((uint8_t *)&x->nonce_high, sizeof(x->nonce_high)); x->nonce_low = 1; } x->global->application_key = data_blob_dup_talloc(x->global, x->global->signing_key); if (x->global->application_key.data == NULL) { ZERO_STRUCT(session_key); return NT_STATUS_NO_MEMORY; } if (xconn->protocol >= PROTOCOL_SMB2_24) { const DATA_BLOB label = data_blob_string_const_null("SMB2APP"); const DATA_BLOB context = data_blob_string_const_null("SmbRpc"); smb2_key_derivation(session_key, sizeof(session_key), label.data, label.length, context.data, context.length, x->global->application_key.data); } ZERO_STRUCT(session_key); x->global->channels[0].signing_key = data_blob_dup_talloc(x->global->channels, x->global->signing_key); if (x->global->channels[0].signing_key.data == NULL) { return NT_STATUS_NO_MEMORY; } data_blob_clear_free(&session_info->session_key); session_info->session_key = data_blob_dup_talloc(session_info, x->global->application_key); if (session_info->session_key.data == NULL) { return NT_STATUS_NO_MEMORY; } session->compat = talloc_zero(session, struct user_struct); if (session->compat == NULL) { return NT_STATUS_NO_MEMORY; } session->compat->session = session; session->compat->homes_snum = -1; session->compat->session_info = session_info; session->compat->session_keystr = NULL; session->compat->vuid = session->global->session_wire_id; DLIST_ADD(smb2req->sconn->users, session->compat); smb2req->sconn->num_users++; if (security_session_user_level(session_info, NULL) >= SECURITY_USER) { session->compat->homes_snum = register_homes_share(session_info->unix_info->unix_name); } set_current_user_info(session_info->unix_info->sanitized_username, session_info->unix_info->unix_name, session_info->info->domain_name); reload_services(smb2req->sconn, conn_snum_used, true); session->status = NT_STATUS_OK; session->global->auth_session_info = session_info; session->global->auth_session_info_seqnum += 1; session->global->channels[0].auth_session_info_seqnum = session->global->auth_session_info_seqnum; session->global->auth_time = timeval_to_nttime(&smb2req->request_time); session->global->expiration_time = gensec_expire_time(session->gensec); if (!session_claim(session)) { DEBUG(1, ("smb2: Failed to claim session " "for vuid=%llu\n", (unsigned long long)session->compat->vuid)); return NT_STATUS_LOGON_FAILURE; } status = smbXsrv_session_update(session); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n", (unsigned long long)session->compat->vuid, nt_errstr(status))); return NT_STATUS_LOGON_FAILURE; } /* * we attach the session to the request * so that the response can be signed */ smb2req->session = session; if (!guest) { smb2req->do_signing = true; } global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32); *out_session_id = session->global->session_wire_id; return NT_STATUS_OK; }