Example #1
0
static DATA_BLOB NTLMv2_generate_client_data(TALLOC_CTX *mem_ctx, const DATA_BLOB *names_blob)
{
	uint8_t client_chal[8];
	DATA_BLOB response = data_blob(NULL, 0);
	uint8_t long_date[8];
	NTTIME nttime;

	unix_to_nt_time(&nttime, time(NULL));

	generate_random_buffer(client_chal, sizeof(client_chal));

	push_nttime(long_date, 0, nttime);

	/* See http://www.ubiqx.org/cifs/SMB.html#SMB.8.5 */

	/* Deliberately ignore return here.. */
	(void)msrpc_gen(mem_ctx, &response, "ddbbdb",
		  0x00000101,     /* Header  */
		  0,              /* 'Reserved'  */
		  long_date, 8,	  /* Timestamp */
		  client_chal, 8, /* client challenge */
		  0,		  /* Unknown */
		  names_blob->data, names_blob->length);	/* End of name list */

	return response;
}
Example #2
0
static NTSTATUS ntlmssp3_client_initial(struct ntlmssp_state *ntlmssp_state,
				       TALLOC_CTX *out_mem_ctx,
				       DATA_BLOB in, DATA_BLOB *out)
{
	const char *domain = ntlmssp_state->client.netbios_domain;
	const char *workstation = ntlmssp_state->client.netbios_name;
	NTSTATUS status;

	/* These don't really matter in the initial packet, so don't panic if they are not set */
	if (!domain) {
		domain = "";
	}

	if (!workstation) {
		workstation = "";
	}

	if (ntlmssp_state->unicode) {
		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
	} else {
		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
	}

	if (ntlmssp_state->use_ntlmv2) {
		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;
	}

	/* generate the ntlmssp negotiate packet */
	status = msrpc_gen(out_mem_ctx,
		  out, "CddAA",
		  "NTLMSSP",
		  NTLMSSP_NEGOTIATE,
		  ntlmssp_state->neg_flags,
		  domain,
		  workstation);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("ntlmssp_client_initial: failed to generate "
			  "ntlmssp negotiate packet\n"));
		return status;
	}

	if (DEBUGLEVEL >= 10) {
		struct NEGOTIATE_MESSAGE *negotiate = talloc(
			talloc_tos(), struct NEGOTIATE_MESSAGE);
		if (negotiate != NULL) {
			status = ntlmssp_pull_NEGOTIATE_MESSAGE(
				out, negotiate, negotiate);
			if (NT_STATUS_IS_OK(status)) {
				NDR_PRINT_DEBUG(NEGOTIATE_MESSAGE,
						negotiate);
			}
			TALLOC_FREE(negotiate);
		}
	}

	ntlmssp_state->expected_state = NTLMSSP_CHALLENGE;

	return NT_STATUS_MORE_PROCESSING_REQUIRED;
}
Example #3
0
NTSTATUS ntlmssp_seal_packet(NTLMSSP_STATE *ntlmssp_state,
			     uchar *data, size_t length,
			     uchar *whole_pdu, size_t pdu_length,
			     DATA_BLOB *sig)
{	
	if (!(ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL)) {
		DEBUG(3, ("NTLMSSP Sealing not negotiated - cannot seal packet!\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (!ntlmssp_state->session_key.length) {
		DEBUG(3, ("NO session key, cannot seal packet\n"));
		return NT_STATUS_NO_USER_SESSION_KEY;
	}

	DEBUG(10,("ntlmssp_seal_data: seal\n"));
	dump_data_pw("ntlmssp clear data\n", data, length);
	if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
		/* The order of these two operations matters - we must first seal the packet,
		   then seal the sequence number - this is becouse the send_seal_hash is not
		   constant, but is is rather updated with each iteration */
		NTSTATUS nt_status = ntlmssp_make_packet_signature(ntlmssp_state,
							data, length,
							whole_pdu, pdu_length,
							NTLMSSP_SEND, sig, False);
		if (!NT_STATUS_IS_OK(nt_status)) {
			return nt_status;
		}

		arcfour_crypt_sbox(&ntlmssp_state->send_seal_arc4_state, data, length);
		if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
			arcfour_crypt_sbox(&ntlmssp_state->send_seal_arc4_state, sig->data+4, 8);
		}
	} else {
		uint32 crc;
		crc = crc32_calc_buffer(data, length);
		if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmv1_seq_num)) {
			return NT_STATUS_NO_MEMORY;
		}

		/* The order of these two operations matters - we must first seal the packet,
		   then seal the sequence number - this is becouse the ntlmv1_arc4_state is not
		   constant, but is is rather updated with each iteration */
		
		dump_arc4_state("ntlmv1 arc4 state:\n", 
						&ntlmssp_state->ntlmv1_arc4_state);
		arcfour_crypt_sbox(&ntlmssp_state->ntlmv1_arc4_state, data, length);

		dump_arc4_state("ntlmv1 arc4 state:\n", 
						&ntlmssp_state->ntlmv1_arc4_state);

		arcfour_crypt_sbox(&ntlmssp_state->ntlmv1_arc4_state, sig->data+4, sig->length-4);

		ntlmssp_state->ntlmv1_seq_num++;
	}
	dump_data_pw("ntlmssp signature\n", sig->data, sig->length);
	dump_data_pw("ntlmssp sealed data\n", data, length);

	return NT_STATUS_OK;
}
Example #4
0
static NTSTATUS ntlmssp_client_initial(struct ntlmssp_state *ntlmssp_state, 
				  DATA_BLOB reply, DATA_BLOB *next_request) 
{
	if (ntlmssp_state->unicode) {
		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
	} else {
		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
	}
	
	if (ntlmssp_state->use_ntlmv2) {
		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;
	}

	/* generate the ntlmssp negotiate packet */
	msrpc_gen(next_request, "CddAA",
		  "NTLMSSP",
		  NTLMSSP_NEGOTIATE,
		  ntlmssp_state->neg_flags,
		  ntlmssp_state->get_domain(), 
		  ntlmssp_state->get_global_myname());

	ntlmssp_state->expected_state = NTLMSSP_CHALLENGE;

	return NT_STATUS_MORE_PROCESSING_REQUIRED;
}
Example #5
0
static NTSTATUS ntlmssp_make_packet_signature(NTLMSSP_STATE *ntlmssp_state,
        const uchar *data, size_t length,
        enum ntlmssp_direction direction,
        DATA_BLOB *sig)
{
    if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
        HMACMD5Context ctx;
        uchar seq_num[4];
        uchar digest[16];
        SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);

        hmac_md5_init_limK_to_64((const unsigned char *)(ntlmssp_state->send_sign_const), 16, &ctx);
        hmac_md5_update(seq_num, 4, &ctx);
        hmac_md5_update(data, length, &ctx);
        hmac_md5_final(digest, &ctx);

        if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */
                       , ntlmssp_state->ntlmssp_seq_num)) {
            return NT_STATUS_NO_MEMORY;
        }

        if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
            switch (direction) {
            case NTLMSSP_SEND:
                NTLMSSPcalc_ap(ntlmssp_state->send_sign_hash,  sig->data+4, sig->length-4);
                break;
            case NTLMSSP_RECEIVE:
                NTLMSSPcalc_ap(ntlmssp_state->recv_sign_hash,  sig->data+4, sig->length-4);
                break;
            }
        }
    } else {
        uint32 crc;
        crc = crc32_calc_buffer((const char *)data, length);
        if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
            return NT_STATUS_NO_MEMORY;
        }

        dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
                     sizeof(ntlmssp_state->ntlmssp_hash));
        NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
    }
    return NT_STATUS_OK;
}
Example #6
0
DATA_BLOB NTLMv2_generate_names_blob(const char *hostname, 
				     const char *domain)
{
	DATA_BLOB names_blob = data_blob(NULL, 0);
	
	msrpc_gen(&names_blob, "aaa", 
		  NTLMSSP_NAME_TYPE_DOMAIN, domain,
		  NTLMSSP_NAME_TYPE_SERVER, hostname,
		  0, "");
	return names_blob;
}
Example #7
0
DATA_BLOB NTLMv2_generate_names_blob(TALLOC_CTX *mem_ctx,
				     const char *hostname,
				     const char *domain)
{
	DATA_BLOB names_blob = data_blob_talloc(mem_ctx, NULL, 0);

	/* Deliberately ignore return here.. */
	if (hostname != NULL) {
		(void)msrpc_gen(mem_ctx, &names_blob,
			  "aaa",
			  MsvAvNbDomainName, domain,
			  MsvAvNbComputerName, hostname,
			  MsvAvEOL, "");
	} else {
		(void)msrpc_gen(mem_ctx, &names_blob,
			  "aa",
			  MsvAvNbDomainName, domain,
			  MsvAvEOL, "");
	}
	return names_blob;
}
Example #8
0
NTSTATUS ntlmssp_client_initial(struct gensec_security *gensec_security,
				TALLOC_CTX *out_mem_ctx,
				DATA_BLOB in, DATA_BLOB *out)
{
	struct gensec_ntlmssp_context *gensec_ntlmssp =
		talloc_get_type_abort(gensec_security->private_data,
				      struct gensec_ntlmssp_context);
	struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state;
	NTSTATUS status;
	const DATA_BLOB version_blob = ntlmssp_version_blob();

	/* generate the ntlmssp negotiate packet */
	status = msrpc_gen(out_mem_ctx,
		  out, "CddAAb",
		  "NTLMSSP",
		  NTLMSSP_NEGOTIATE,
		  ntlmssp_state->neg_flags,
		  "", /* domain */
		  "", /* workstation */
		  version_blob.data, version_blob.length);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("ntlmssp_client_initial: failed to generate "
			  "ntlmssp negotiate packet\n"));
		return status;
	}

	if (DEBUGLEVEL >= 10) {
		struct NEGOTIATE_MESSAGE *negotiate = talloc(
			ntlmssp_state, struct NEGOTIATE_MESSAGE);
		if (negotiate != NULL) {
			status = ntlmssp_pull_NEGOTIATE_MESSAGE(
				out, negotiate, negotiate);
			if (NT_STATUS_IS_OK(status)) {
				NDR_PRINT_DEBUG(NEGOTIATE_MESSAGE,
						negotiate);
			}
			TALLOC_FREE(negotiate);
		}
	}

	ntlmssp_state->expected_state = NTLMSSP_CHALLENGE;

	return NT_STATUS_MORE_PROCESSING_REQUIRED;
}
Example #9
0
static DATA_BLOB NTLMv2_generate_client_data(const DATA_BLOB *names_blob) 
{
	uchar client_chal[8];
	DATA_BLOB response = data_blob(NULL, 0);
	char long_date[8];

	generate_random_buffer(client_chal, sizeof(client_chal));

	put_long_date(long_date, time(NULL));

	/* See http://www.ubiqx.org/cifs/SMB.html#SMB.8.5 */

	msrpc_gen(&response, "ddbbdb", 
		  0x00000101,     /* Header  */
		  0,              /* 'Reserved'  */
		  long_date, 8,	  /* Timestamp */
		  client_chal, 8, /* client challenge */
		  0,		  /* Unknown */
		  names_blob->data, names_blob->length);	/* End of name list */

	return response;
}
Example #10
0
static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
					 const DATA_BLOB request, DATA_BLOB *reply) 
{
	DATA_BLOB struct_blob;
	const char *dnsname;
	char *dnsdomname = NULL;
	uint32 neg_flags = 0;
	uint32 ntlmssp_command, chal_flags;
	const uint8 *cryptkey;
	const char *target_name;

	/* parse the NTLMSSP packet */
#if 0
	file_save("ntlmssp_negotiate.dat", request.data, request.length);
#endif

	if (request.length) {
		if ((request.length < 16) || !msrpc_parse(&request, "Cdd",
							"NTLMSSP",
							&ntlmssp_command,
							&neg_flags)) {
			DEBUG(1, ("ntlmssp_server_negotiate: failed to parse NTLMSSP Negotiate of length %u\n",
				(unsigned int)request.length));
			dump_data(2, request.data, request.length);
			return NT_STATUS_INVALID_PARAMETER;
		}
		debug_ntlmssp_flags(neg_flags);
	}

	ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, lp_lanman_auth());

	/* Ask our caller what challenge they would like in the packet */
	cryptkey = ntlmssp_state->get_challenge(ntlmssp_state);

	/* Check if we may set the challenge */
	if (!ntlmssp_state->may_set_challenge(ntlmssp_state)) {
		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
	}

	/* The flags we send back are not just the negotiated flags,
	 * they are also 'what is in this packet'.  Therfore, we
	 * operate on 'chal_flags' from here on
	 */

	chal_flags = ntlmssp_state->neg_flags;

	/* get the right name to fill in as 'target' */
	target_name = ntlmssp_target_name(ntlmssp_state,
					  neg_flags, &chal_flags);
	if (target_name == NULL) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	ntlmssp_state->chal = data_blob_talloc(ntlmssp_state->mem_ctx, cryptkey, 8);
	ntlmssp_state->internal_chal = data_blob_talloc(ntlmssp_state->mem_ctx, cryptkey, 8);

	/* This should be a 'netbios domain -> DNS domain' mapping */
	dnsdomname = get_mydnsdomname(ntlmssp_state->mem_ctx);
	if (!dnsdomname) {
		dnsdomname = talloc_strdup(ntlmssp_state->mem_ctx, "");
	}
	if (!dnsdomname) {
		return NT_STATUS_NO_MEMORY;
	}
	strlower_m(dnsdomname);

	dnsname = get_mydnsfullname();
	if (!dnsname) {
		dnsname = "";
	}

	/* This creates the 'blob' of names that appears at the end of the packet */
	if (chal_flags & NTLMSSP_CHAL_TARGET_INFO)
	{
		msrpc_gen(&struct_blob, "aaaaa",
			  NTLMSSP_NAME_TYPE_DOMAIN, target_name,
			  NTLMSSP_NAME_TYPE_SERVER, ntlmssp_state->get_global_myname(),
			  NTLMSSP_NAME_TYPE_DOMAIN_DNS, dnsdomname,
			  NTLMSSP_NAME_TYPE_SERVER_DNS, dnsname,
			  0, "");
	} else {
		struct_blob = data_blob_null;
	}

	{
		/* Marshel the packet in the right format, be it unicode or ASCII */
		const char *gen_string;
		if (ntlmssp_state->unicode) {
			gen_string = "CdUdbddB";
		} else {
			gen_string = "CdAdbddB";
		}

		msrpc_gen(reply, gen_string,
			  "NTLMSSP",
			  NTLMSSP_CHALLENGE,
			  target_name,
			  chal_flags,
			  cryptkey, 8,
			  0, 0,
			  struct_blob.data, struct_blob.length);
	}

	data_blob_free(&struct_blob);

	ntlmssp_state->expected_state = NTLMSSP_AUTH;

	return NT_STATUS_MORE_PROCESSING_REQUIRED;
}
Example #11
0
NTSTATUS ntlmssp_seal_packet(NTLMSSP_STATE *ntlmssp_state,
                             uchar *data, size_t length,
                             DATA_BLOB *sig)
{
    if (!ntlmssp_state->session_key.length) {
        DEBUG(3, ("NO session key, cannot seal packet\n"));
        return NT_STATUS_NO_USER_SESSION_KEY;
    }

    DEBUG(10,("ntlmssp_seal_data: seal\n"));
    dump_data_pw("ntlmssp clear data\n", data, length);
    if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
        HMACMD5Context ctx;
        char seq_num[4];
        uchar digest[16];
        SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);

        hmac_md5_init_limK_to_64((const unsigned char *)(ntlmssp_state->send_sign_const), 16, &ctx);
        hmac_md5_update((const unsigned char *)seq_num, 4, &ctx);
        hmac_md5_update(data, length, &ctx);
        hmac_md5_final(digest, &ctx);

        if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */
                       , ntlmssp_state->ntlmssp_seq_num)) {
            return NT_STATUS_NO_MEMORY;
        }

        dump_data_pw("ntlmssp client sealing hash:\n",
                     ntlmssp_state->send_seal_hash,
                     sizeof(ntlmssp_state->send_seal_hash));
        NTLMSSPcalc_ap(ntlmssp_state->send_seal_hash, data, length);
        dump_data_pw("ntlmssp client signing hash:\n",
                     ntlmssp_state->send_sign_hash,
                     sizeof(ntlmssp_state->send_sign_hash));
        NTLMSSPcalc_ap(ntlmssp_state->send_sign_hash,  sig->data+4, sig->length-4);
    } else {
        uint32 crc;
        crc = crc32_calc_buffer((const char *)data, length);
        if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
            return NT_STATUS_NO_MEMORY;
        }

        /* The order of these two operations matters - we must first seal the packet,
           then seal the sequence number - this is becouse the ntlmssp_hash is not
           constant, but is is rather updated with each iteration */

        dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
                     sizeof(ntlmssp_state->ntlmssp_hash));
        NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, data, length);

        dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
                     sizeof(ntlmssp_state->ntlmssp_hash));
        NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
    }
    dump_data_pw("ntlmssp sealed data\n", data, length);

    /* increment counter on send */
    ntlmssp_state->ntlmssp_seq_num++;

    return NT_STATUS_OK;
}
Example #12
0
NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
				  TALLOC_CTX *out_mem_ctx,
				  const DATA_BLOB in, DATA_BLOB *out)
{
	struct gensec_ntlmssp_context *gensec_ntlmssp =
		talloc_get_type_abort(gensec_security->private_data,
				      struct gensec_ntlmssp_context);
	struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state;
	uint32_t chal_flags, ntlmssp_command, unkn1, unkn2;
	DATA_BLOB server_domain_blob;
	DATA_BLOB challenge_blob;
	DATA_BLOB target_info = data_blob(NULL, 0);
	char *server_domain;
	const char *chal_parse_string;
	const char *auth_gen_string;
	DATA_BLOB lm_response = data_blob(NULL, 0);
	DATA_BLOB nt_response = data_blob(NULL, 0);
	DATA_BLOB session_key = data_blob(NULL, 0);
	DATA_BLOB lm_session_key = data_blob(NULL, 0);
	DATA_BLOB encrypted_session_key = data_blob(NULL, 0);
	NTSTATUS nt_status;
	int flags = 0;
	const char *user, *domain;

	TALLOC_CTX *mem_ctx = talloc_new(out_mem_ctx);
	if (!mem_ctx) {
		return NT_STATUS_NO_MEMORY;
	}

	if (!msrpc_parse(mem_ctx,
			 &in, "CdBd",
			 "NTLMSSP",
			 &ntlmssp_command,
			 &server_domain_blob,
			 &chal_flags)) {
		DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
		dump_data(2, in.data, in.length);
		talloc_free(mem_ctx);

		return NT_STATUS_INVALID_PARAMETER;
	}

	data_blob_free(&server_domain_blob);

	DEBUG(3, ("Got challenge flags:\n"));
	debug_ntlmssp_flags(chal_flags);

	ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, ntlmssp_state->allow_lm_key);

	if (ntlmssp_state->unicode) {
		if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
			chal_parse_string = "CdUdbddB";
		} else {
			chal_parse_string = "CdUdbdd";
		}
		auth_gen_string = "CdBBUUUBd";
	} else {
		if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
			chal_parse_string = "CdAdbddB";
		} else {
			chal_parse_string = "CdAdbdd";
		}

		auth_gen_string = "CdBBAAABd";
	}

	if (!msrpc_parse(mem_ctx,
			 &in, chal_parse_string,
			 "NTLMSSP",
			 &ntlmssp_command,
			 &server_domain,
			 &chal_flags,
			 &challenge_blob, 8,
			 &unkn1, &unkn2,
			 &target_info)) {
		DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n"));
		dump_data(2, in.data, in.length);
		talloc_free(mem_ctx);
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (chal_flags & NTLMSSP_TARGET_TYPE_SERVER) {
		ntlmssp_state->server.is_standalone = true;
	} else {
		ntlmssp_state->server.is_standalone = false;
	}
	/* TODO: parse struct_blob and fill in the rest */
	ntlmssp_state->server.netbios_name = "";
	ntlmssp_state->server.netbios_domain = server_domain;
	ntlmssp_state->server.dns_name = "";
	ntlmssp_state->server.dns_domain = "";

	if (challenge_blob.length != 8) {
		talloc_free(mem_ctx);
		return NT_STATUS_INVALID_PARAMETER;
	}

	cli_credentials_get_ntlm_username_domain(gensec_security->credentials, mem_ctx,
						 &user, &domain);

	if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
		flags |= CLI_CRED_NTLM2;
	}
	if (ntlmssp_state->use_ntlmv2) {
		flags |= CLI_CRED_NTLMv2_AUTH;
	}
	if (ntlmssp_state->use_nt_response) {
		flags |= CLI_CRED_NTLM_AUTH;
	}
	if (lpcfg_client_lanman_auth(gensec_security->settings->lp_ctx)) {
		flags |= CLI_CRED_LANMAN_AUTH;
	}

	nt_status = cli_credentials_get_ntlm_response(gensec_security->credentials, mem_ctx,
						      &flags, challenge_blob, target_info,
						      &lm_response, &nt_response,
						      &lm_session_key, &session_key);

	if (!NT_STATUS_IS_OK(nt_status)) {
		return nt_status;
	}

	if (!(flags & CLI_CRED_LANMAN_AUTH)) {
		/* LM Key is still possible, just silly, so we do not
		 * allow it. Fortunetly all LM crypto is off by
		 * default and we require command line options to end
		 * up here */
		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
	}

	if (!(flags & CLI_CRED_NTLM2)) {
		/* NTLM2 is incompatible... */
		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
	}

	if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY)
	    && lpcfg_client_lanman_auth(gensec_security->settings->lp_ctx) && lm_session_key.length == 16) {
		DATA_BLOB new_session_key = data_blob_talloc(mem_ctx, NULL, 16);
		if (lm_response.length == 24) {
			SMBsesskeygen_lm_sess_key(lm_session_key.data, lm_response.data,
						  new_session_key.data);
		} else {
			static const uint8_t zeros[24];
			SMBsesskeygen_lm_sess_key(lm_session_key.data, zeros,
						  new_session_key.data);
		}
		session_key = new_session_key;
		dump_data_pw("LM session key\n", session_key.data, session_key.length);
	}


	/* Key exchange encryptes a new client-generated session key with
	   the password-derived key */
	if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
		/* Make up a new session key */
		uint8_t client_session_key[16];
		generate_secret_buffer(client_session_key, sizeof(client_session_key));

		/* Encrypt the new session key with the old one */
		encrypted_session_key = data_blob_talloc(ntlmssp_state,
							 client_session_key, sizeof(client_session_key));
		dump_data_pw("KEY_EXCH session key:\n", encrypted_session_key.data, encrypted_session_key.length);
		arcfour_crypt(encrypted_session_key.data, session_key.data, encrypted_session_key.length);
		dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length);

		/* Mark the new session key as the 'real' session key */
		session_key = data_blob_talloc(mem_ctx, client_session_key, sizeof(client_session_key));
	}

	DEBUG(3, ("NTLMSSP: Set final flags:\n"));
	debug_ntlmssp_flags(ntlmssp_state->neg_flags);

	/* this generates the actual auth packet */
	nt_status = msrpc_gen(mem_ctx,
		       out, auth_gen_string,
		       "NTLMSSP",
		       NTLMSSP_AUTH,
		       lm_response.data, lm_response.length,
		       nt_response.data, nt_response.length,
		       domain,
		       user,
		       cli_credentials_get_workstation(gensec_security->credentials),
		       encrypted_session_key.data, encrypted_session_key.length,
		       ntlmssp_state->neg_flags);
	if (!NT_STATUS_IS_OK(nt_status)) {
		talloc_free(mem_ctx);
		return nt_status;
	}

	ntlmssp_state->session_key = session_key;
	talloc_steal(ntlmssp_state, session_key.data);

	talloc_steal(out_mem_ctx, out->data);

	ntlmssp_state->expected_state = NTLMSSP_DONE;

	if (gensec_security->want_features & (GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL)) {
		nt_status = ntlmssp_sign_init(ntlmssp_state);
		if (!NT_STATUS_IS_OK(nt_status)) {
			DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n",
				  nt_errstr(nt_status)));
			talloc_free(mem_ctx);
			return nt_status;
		}
	}

	talloc_free(mem_ctx);
	return NT_STATUS_OK;
}
Example #13
0
NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security,
					 TALLOC_CTX *out_mem_ctx,
					 const DATA_BLOB request, DATA_BLOB *reply)
{
	struct gensec_ntlmssp_context *gensec_ntlmssp =
		talloc_get_type_abort(gensec_security->private_data,
				      struct gensec_ntlmssp_context);
	struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state;
	struct auth4_context *auth_context = gensec_security->auth_context;
	DATA_BLOB struct_blob;
	uint32_t neg_flags = 0;
	uint32_t ntlmssp_command, chal_flags;
	uint8_t cryptkey[8];
	const char *target_name;
	NTSTATUS status;

	/* parse the NTLMSSP packet */
#if 0
	file_save("ntlmssp_negotiate.dat", request.data, request.length);
#endif

	if (request.length) {
		if ((request.length < 16) || !msrpc_parse(ntlmssp_state, &request, "Cdd",
							  "NTLMSSP",
							  &ntlmssp_command,
							  &neg_flags)) {
			DEBUG(1, ("ntlmssp_server_negotiate: failed to parse NTLMSSP Negotiate of length %u\n",
				(unsigned int)request.length));
			dump_data(2, request.data, request.length);
			return NT_STATUS_INVALID_PARAMETER;
		}
		debug_ntlmssp_flags(neg_flags);

		if (DEBUGLEVEL >= 10) {
			struct NEGOTIATE_MESSAGE *negotiate = talloc(
				ntlmssp_state, struct NEGOTIATE_MESSAGE);
			if (negotiate != NULL) {
				status = ntlmssp_pull_NEGOTIATE_MESSAGE(
					&request, negotiate, negotiate);
				if (NT_STATUS_IS_OK(status)) {
					NDR_PRINT_DEBUG(NEGOTIATE_MESSAGE,
							negotiate);
				}
				TALLOC_FREE(negotiate);
			}
		}
	}

	ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, ntlmssp_state->allow_lm_key);

	/* Ask our caller what challenge they would like in the packet */
	if (auth_context->get_ntlm_challenge) {
		status = auth_context->get_ntlm_challenge(auth_context, cryptkey);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(1, ("gensec_ntlmssp_server_negotiate: failed to get challenge: %s\n",
				  nt_errstr(status)));
			return status;
		}
	} else {
		DEBUG(1, ("gensec_ntlmssp_server_negotiate: backend doesn't give a challenge\n"));
		return NT_STATUS_NOT_IMPLEMENTED;
	}

	/* The flags we send back are not just the negotiated flags,
	 * they are also 'what is in this packet'.  Therfore, we
	 * operate on 'chal_flags' from here on
	 */

	chal_flags = ntlmssp_state->neg_flags;

	/* get the right name to fill in as 'target' */
	target_name = ntlmssp_target_name(ntlmssp_state,
					  neg_flags, &chal_flags);
	if (target_name == NULL)
		return NT_STATUS_INVALID_PARAMETER;

	ntlmssp_state->chal = data_blob_talloc(ntlmssp_state, cryptkey, 8);
	ntlmssp_state->internal_chal = data_blob_talloc(ntlmssp_state,
							cryptkey, 8);

	/* This creates the 'blob' of names that appears at the end of the packet */
	if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO)
	{
		status = msrpc_gen(ntlmssp_state, &struct_blob, "aaaaa",
			  MsvAvNbDomainName, target_name,
			  MsvAvNbComputerName, ntlmssp_state->server.netbios_name,
			  MsvAvDnsDomainName, ntlmssp_state->server.dns_domain,
			  MsvAvDnsComputerName, ntlmssp_state->server.dns_name,
			  MsvAvEOL, "");
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}
	} else {
		struct_blob = data_blob_null;
	}

	{
		/* Marshal the packet in the right format, be it unicode or ASCII */
		const char *gen_string;
		DATA_BLOB version_blob = data_blob_null;

		if (chal_flags & NTLMSSP_NEGOTIATE_VERSION) {
			enum ndr_err_code err;
			struct ntlmssp_VERSION vers;

			/* "What Windows returns" as a version number. */
			ZERO_STRUCT(vers);
			vers.ProductMajorVersion = NTLMSSP_WINDOWS_MAJOR_VERSION_6;
			vers.ProductMinorVersion = NTLMSSP_WINDOWS_MINOR_VERSION_1;
			vers.ProductBuild = 0;
			vers.NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3;

			err = ndr_push_struct_blob(&version_blob,
						ntlmssp_state,
						&vers,
						(ndr_push_flags_fn_t)ndr_push_ntlmssp_VERSION);

			if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
				data_blob_free(&struct_blob);
				return NT_STATUS_NO_MEMORY;
			}
		}

		if (ntlmssp_state->unicode) {
			gen_string = "CdUdbddBb";
		} else {
			gen_string = "CdAdbddBb";
		}

		status = msrpc_gen(out_mem_ctx, reply, gen_string,
			"NTLMSSP",
			NTLMSSP_CHALLENGE,
			target_name,
			chal_flags,
			cryptkey, 8,
			0, 0,
			struct_blob.data, struct_blob.length,
			version_blob.data, version_blob.length);

		if (!NT_STATUS_IS_OK(status)) {
			data_blob_free(&version_blob);
			data_blob_free(&struct_blob);
			return status;
		}

		data_blob_free(&version_blob);

		if (DEBUGLEVEL >= 10) {
			struct CHALLENGE_MESSAGE *challenge = talloc(
				ntlmssp_state, struct CHALLENGE_MESSAGE);
			if (challenge != NULL) {
				challenge->NegotiateFlags = chal_flags;
				status = ntlmssp_pull_CHALLENGE_MESSAGE(
					reply, challenge, challenge);
				if (NT_STATUS_IS_OK(status)) {
					NDR_PRINT_DEBUG(CHALLENGE_MESSAGE,
							challenge);
				}
				TALLOC_FREE(challenge);
			}
		}
	}

	data_blob_free(&struct_blob);

	ntlmssp_state->expected_state = NTLMSSP_AUTH;

	return NT_STATUS_MORE_PROCESSING_REQUIRED;
}
Example #14
0
static NTSTATUS ntlmssp3_client_challenge(struct ntlmssp_state *ntlmssp_state,
				         TALLOC_CTX *out_mem_ctx, /* Unused at this time */
					 const DATA_BLOB reply, DATA_BLOB *next_request)
{
	uint32_t chal_flags, ntlmssp_command, unkn1, unkn2;
	DATA_BLOB server_domain_blob;
	DATA_BLOB challenge_blob;
	DATA_BLOB struct_blob = data_blob_null;
	char *server_domain;
	const char *chal_parse_string;
	const char *auth_gen_string;
	DATA_BLOB lm_response = data_blob_null;
	DATA_BLOB nt_response = data_blob_null;
	DATA_BLOB session_key = data_blob_null;
	DATA_BLOB encrypted_session_key = data_blob_null;
	NTSTATUS nt_status = NT_STATUS_OK;
	bool anon = ntlmssp_is_anonymous(ntlmssp_state);

	if (!anon && ntlmssp_state->use_ccache) {
		struct wbcCredentialCacheParams params;
		struct wbcCredentialCacheInfo *info = NULL;
		struct wbcAuthErrorInfo *error = NULL;
		struct wbcNamedBlob auth_blob;
		struct wbcBlob *wbc_next = NULL;
		struct wbcBlob *wbc_session_key = NULL;
		wbcErr wbc_status;
		int i;

		/*
		 * We need to set the netbios name or we are not able to connect
		 *  a Windows DC.
		 */
		if (ntlmssp_state->server.netbios_domain == NULL ||
		    ntlmssp_state->server.netbios_domain[0] == '\0') {
			ntlmssp_state->server.netbios_domain = ntlmssp_state->domain;
		}

		params.account_name = ntlmssp_state->user;
		params.domain_name = ntlmssp_state->domain;
		params.level = WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP;

		auth_blob.name = "challenge_blob";
		auth_blob.flags = 0;
		auth_blob.blob.data = reply.data;
		auth_blob.blob.length = reply.length;
		params.num_blobs = 1;
		params.blobs = &auth_blob;

		wbc_status = wbcCredentialCache(&params, &info, &error);
		wbcFreeMemory(error);
		if (!WBC_ERROR_IS_OK(wbc_status)) {
			goto noccache;
		}

		for (i=0; i<info->num_blobs; i++) {
			if (strequal(info->blobs[i].name, "auth_blob")) {
				wbc_next = &info->blobs[i].blob;
			}
			if (strequal(info->blobs[i].name, "session_key")) {
				wbc_session_key = &info->blobs[i].blob;
			}
		}
		if ((wbc_next == NULL) || (wbc_session_key == NULL)) {
			wbcFreeMemory(info);
			goto noccache;
		}

		*next_request = data_blob_talloc(ntlmssp_state,
						 wbc_next->data,
						 wbc_next->length);
		ntlmssp_state->session_key = data_blob_talloc(ntlmssp_state,
							      wbc_session_key->data,
							      wbc_session_key->length);

		wbcFreeMemory(info);
		goto done;
	}

noccache:

	if (!msrpc_parse(ntlmssp_state, &reply, "CdBd",
			 "NTLMSSP",
			 &ntlmssp_command,
			 &server_domain_blob,
			 &chal_flags)) {
		DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
		dump_data(2, reply.data, reply.length);

		return NT_STATUS_INVALID_PARAMETER;
	}

	if (DEBUGLEVEL >= 10) {
		struct CHALLENGE_MESSAGE *challenge = talloc(
			talloc_tos(), struct CHALLENGE_MESSAGE);
		if (challenge != NULL) {
			NTSTATUS status;
			challenge->NegotiateFlags = chal_flags;
			status = ntlmssp_pull_CHALLENGE_MESSAGE(
				&reply, challenge, challenge);
			if (NT_STATUS_IS_OK(status)) {
				NDR_PRINT_DEBUG(CHALLENGE_MESSAGE,
						challenge);
			}
			TALLOC_FREE(challenge);
		}
	}

	data_blob_free(&server_domain_blob);

	DEBUG(3, ("Got challenge flags:\n"));
	debug_ntlmssp_flags(chal_flags);

	ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, lp_client_lanman_auth());

	if (ntlmssp_state->unicode) {
		if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
			chal_parse_string = "CdUdbddB";
		} else {
			chal_parse_string = "CdUdbdd";
		}
		auth_gen_string = "CdBBUUUBd";
	} else {
		if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
			chal_parse_string = "CdAdbddB";
		} else {
			chal_parse_string = "CdAdbdd";
		}

		auth_gen_string = "CdBBAAABd";
	}

	DEBUG(3, ("NTLMSSP: Set final flags:\n"));
	debug_ntlmssp_flags(ntlmssp_state->neg_flags);

	if (!msrpc_parse(ntlmssp_state, &reply, chal_parse_string,
			 "NTLMSSP",
			 &ntlmssp_command,
			 &server_domain,
			 &chal_flags,
			 &challenge_blob, 8,
			 &unkn1, &unkn2,
			 &struct_blob)) {
		DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n"));
		dump_data(2, reply.data, reply.length);
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (chal_flags & NTLMSSP_TARGET_TYPE_SERVER) {
		ntlmssp_state->server.is_standalone = true;
	} else {
		ntlmssp_state->server.is_standalone = false;
	}
	/* TODO: parse struct_blob and fill in the rest */
	ntlmssp_state->server.netbios_name = "";
	ntlmssp_state->server.netbios_domain = server_domain;
	ntlmssp_state->server.dns_name = "";
	ntlmssp_state->server.dns_domain = "";

	if (challenge_blob.length != 8) {
		data_blob_free(&struct_blob);
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (anon || !ntlmssp_state->nt_hash) {
		static const uint8_t zeros[16] = {0, };
		/* do nothing - blobs are zero length */

		/* session key is all zeros */
		session_key = data_blob_talloc(ntlmssp_state, zeros, 16);

		/* not doing NLTM2 without a password */
		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
	} else if (ntlmssp_state->use_ntlmv2) {
		if (!struct_blob.length) {
			/* be lazy, match win2k - we can't do NTLMv2 without it */
			DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
			return NT_STATUS_INVALID_PARAMETER;
		}

		/* TODO: if the remote server is standalone, then we should replace 'domain'
		   with the server name as supplied above */

		if (!SMBNTLMv2encrypt_hash(ntlmssp_state,
					   ntlmssp_state->user,
					   ntlmssp_state->domain,
					   ntlmssp_state->nt_hash, &challenge_blob,
					   &struct_blob,
					   &lm_response, &nt_response, NULL,
					   &session_key)) {
			data_blob_free(&challenge_blob);
			data_blob_free(&struct_blob);
			return NT_STATUS_NO_MEMORY;
		}
	} else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
		MD5_CTX md5_session_nonce_ctx;
		uint8_t session_nonce[16];
		uint8_t session_nonce_hash[16];
		uint8_t user_session_key[16];

		lm_response = data_blob_talloc(ntlmssp_state, NULL, 24);
		generate_random_buffer(lm_response.data, 8);
		memset(lm_response.data+8, 0, 16);

		memcpy(session_nonce, challenge_blob.data, 8);
		memcpy(&session_nonce[8], lm_response.data, 8);

		MD5Init(&md5_session_nonce_ctx);
		MD5Update(&md5_session_nonce_ctx, challenge_blob.data, 8);
		MD5Update(&md5_session_nonce_ctx, lm_response.data, 8);
		MD5Final(session_nonce_hash, &md5_session_nonce_ctx);

		DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
		DEBUG(5, ("challenge is: \n"));
		dump_data(5, session_nonce_hash, 8);

		nt_response = data_blob_talloc(ntlmssp_state, NULL, 24);
		SMBNTencrypt_hash(ntlmssp_state->nt_hash,
				  session_nonce_hash,
				  nt_response.data);

		session_key = data_blob_talloc(ntlmssp_state, NULL, 16);

		SMBsesskeygen_ntv1(ntlmssp_state->nt_hash, user_session_key);
		hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data);
		dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
	} else {
		/* lanman auth is insecure, it may be disabled */
		if (lp_client_lanman_auth() && ntlmssp_state->lm_hash) {
			lm_response = data_blob_talloc(ntlmssp_state,
						       NULL, 24);
			SMBencrypt_hash(ntlmssp_state->lm_hash,challenge_blob.data,
				   lm_response.data);
		}

		nt_response = data_blob_talloc(ntlmssp_state, NULL, 24);
		SMBNTencrypt_hash(ntlmssp_state->nt_hash,challenge_blob.data,
			     nt_response.data);

		session_key = data_blob_talloc(ntlmssp_state, NULL, 16);
		if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY)
		    && lp_client_lanman_auth() && ntlmssp_state->lm_hash) {
			SMBsesskeygen_lm_sess_key(ntlmssp_state->lm_hash, lm_response.data,
					session_key.data);
			dump_data_pw("LM session key\n", session_key.data, session_key.length);
		} else {
			SMBsesskeygen_ntv1(ntlmssp_state->nt_hash, session_key.data);
			dump_data_pw("NT session key:\n", session_key.data, session_key.length);
		}
	}
	data_blob_free(&struct_blob);

	/* Key exchange encryptes a new client-generated session key with
	   the password-derived key */
	if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
		/* Make up a new session key */
		uint8_t client_session_key[16];
		generate_random_buffer(client_session_key, sizeof(client_session_key));

		/* Encrypt the new session key with the old one */
		encrypted_session_key = data_blob(client_session_key, sizeof(client_session_key));
		dump_data_pw("KEY_EXCH session key:\n", encrypted_session_key.data, encrypted_session_key.length);
		arcfour_crypt_blob(encrypted_session_key.data, encrypted_session_key.length, &session_key);
		dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length);

		/* Mark the new session key as the 'real' session key */
		data_blob_free(&session_key);
		session_key = data_blob_talloc(ntlmssp_state,
					       client_session_key,
					       sizeof(client_session_key));
	}

	/* this generates the actual auth packet */
	nt_status = msrpc_gen(ntlmssp_state, next_request, auth_gen_string,
		       "NTLMSSP",
		       NTLMSSP_AUTH,
		       lm_response.data, lm_response.length,
		       nt_response.data, nt_response.length,
		       ntlmssp_state->domain,
		       ntlmssp_state->user,
		       ntlmssp_state->client.netbios_name,
		       encrypted_session_key.data, encrypted_session_key.length,
		       ntlmssp_state->neg_flags);

	if (!NT_STATUS_IS_OK(nt_status)) {
		return NT_STATUS_NO_MEMORY;
	}

	if (DEBUGLEVEL >= 10) {
		struct AUTHENTICATE_MESSAGE *authenticate = talloc(
			talloc_tos(), struct AUTHENTICATE_MESSAGE);
		if (authenticate != NULL) {
			NTSTATUS status;
			authenticate->NegotiateFlags =
				ntlmssp_state->neg_flags;
			status = ntlmssp_pull_AUTHENTICATE_MESSAGE(
				next_request, authenticate, authenticate);
			if (NT_STATUS_IS_OK(status)) {
				NDR_PRINT_DEBUG(AUTHENTICATE_MESSAGE,
						authenticate);
			}
			TALLOC_FREE(authenticate);
		}
	}

	data_blob_free(&encrypted_session_key);

	data_blob_free(&ntlmssp_state->chal);

	ntlmssp_state->session_key = session_key;

	ntlmssp_state->chal = challenge_blob;
	ntlmssp_state->lm_resp = lm_response;
	ntlmssp_state->nt_resp = nt_response;

done:

	ntlmssp_state->expected_state = NTLMSSP_DONE;

	if (!NT_STATUS_IS_OK(nt_status = ntlmssp_sign_init(ntlmssp_state))) {
		DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n", nt_errstr(nt_status)));
	}

	return nt_status;
}
Example #15
0
static NTSTATUS ntlmssp_make_packet_signature(NTLMSSP_STATE *ntlmssp_state,
						const uchar *data, size_t length, 
						const uchar *whole_pdu, size_t pdu_length,
						enum ntlmssp_direction direction,
						DATA_BLOB *sig,
						bool encrypt_sig)
{
	if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
		HMACMD5Context ctx;
		uchar seq_num[4];
		uchar digest[16];

		*sig = data_blob(NULL, NTLMSSP_SIG_SIZE);
		if (!sig->data) {
			return NT_STATUS_NO_MEMORY;
		}

		switch (direction) {
			case NTLMSSP_SEND:
	                        DEBUG(100,("ntlmssp_make_packet_signature: SEND seq = %u, len = %u, pdu_len = %u\n",
					ntlmssp_state->ntlm2_send_seq_num,
					(unsigned int)length,
					(unsigned int)pdu_length));

				SIVAL(seq_num, 0, ntlmssp_state->ntlm2_send_seq_num);
				ntlmssp_state->ntlm2_send_seq_num++;
				hmac_md5_init_limK_to_64(ntlmssp_state->send_sign_key, 16, &ctx);
				break;
			case NTLMSSP_RECEIVE:

				DEBUG(100,("ntlmssp_make_packet_signature: RECV seq = %u, len = %u, pdu_len = %u\n",
					ntlmssp_state->ntlm2_recv_seq_num,
					(unsigned int)length,
					(unsigned int)pdu_length));

				SIVAL(seq_num, 0, ntlmssp_state->ntlm2_recv_seq_num);
				ntlmssp_state->ntlm2_recv_seq_num++;
				hmac_md5_init_limK_to_64(ntlmssp_state->recv_sign_key, 16, &ctx);
				break;
                }

		dump_data_pw("pdu data ", whole_pdu, pdu_length);

		hmac_md5_update(seq_num, 4, &ctx);
		hmac_md5_update(whole_pdu, pdu_length, &ctx);
		hmac_md5_final(digest, &ctx);

		if (encrypt_sig && (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) {
			switch (direction) {
			case NTLMSSP_SEND:
				arcfour_crypt_sbox(&ntlmssp_state->send_seal_arc4_state, digest, 8);
				break;
			case NTLMSSP_RECEIVE:
				arcfour_crypt_sbox(&ntlmssp_state->recv_seal_arc4_state, digest, 8);
				break;
			}
		}

		SIVAL(sig->data, 0, NTLMSSP_SIGN_VERSION);
		memcpy(sig->data + 4, digest, 8);
		memcpy(sig->data + 12, seq_num, 4);

		dump_data_pw("ntlmssp v2 sig ", sig->data, sig->length);

	} else {
		uint32 crc;
		crc = crc32_calc_buffer(data, length);
		if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmv1_seq_num)) {
			return NT_STATUS_NO_MEMORY;
		}
		
		ntlmssp_state->ntlmv1_seq_num++;

		dump_arc4_state("ntlmssp hash: \n", &ntlmssp_state->ntlmv1_arc4_state);
		arcfour_crypt_sbox(&ntlmssp_state->ntlmv1_arc4_state, sig->data+4, sig->length-4);
	}
	return NT_STATUS_OK;
}
Example #16
0
static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, 
					 const DATA_BLOB reply, DATA_BLOB *next_request) 
{
	uint32 chal_flags, ntlmssp_command, unkn1, unkn2;
	DATA_BLOB server_domain_blob;
	DATA_BLOB challenge_blob;
	DATA_BLOB struct_blob = data_blob_null;
	char *server_domain;
	const char *chal_parse_string;
	const char *auth_gen_string;
	DATA_BLOB lm_response = data_blob_null;
	DATA_BLOB nt_response = data_blob_null;
	DATA_BLOB session_key = data_blob_null;
	DATA_BLOB encrypted_session_key = data_blob_null;
	NTSTATUS nt_status = NT_STATUS_OK;

	if (!msrpc_parse(&reply, "CdBd",
			 "NTLMSSP",
			 &ntlmssp_command, 
			 &server_domain_blob,
			 &chal_flags)) {
		DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
		dump_data(2, reply.data, reply.length);

		return NT_STATUS_INVALID_PARAMETER;
	}
	
	data_blob_free(&server_domain_blob);

	DEBUG(3, ("Got challenge flags:\n"));
	debug_ntlmssp_flags(chal_flags);

	ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, lp_client_lanman_auth());

	if (ntlmssp_state->unicode) {
		if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
			chal_parse_string = "CdUdbddB";
		} else {
			chal_parse_string = "CdUdbdd";
		}
		auth_gen_string = "CdBBUUUBd";
	} else {
		if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
			chal_parse_string = "CdAdbddB";
		} else {
			chal_parse_string = "CdAdbdd";
		}

		auth_gen_string = "CdBBAAABd";
	}

	DEBUG(3, ("NTLMSSP: Set final flags:\n"));
	debug_ntlmssp_flags(ntlmssp_state->neg_flags);

	if (!msrpc_parse(&reply, chal_parse_string,
			 "NTLMSSP",
			 &ntlmssp_command, 
			 &server_domain,
			 &chal_flags,
			 &challenge_blob, 8,
			 &unkn1, &unkn2,
			 &struct_blob)) {
		DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n"));
		dump_data(2, reply.data, reply.length);
		return NT_STATUS_INVALID_PARAMETER;
	}

	ntlmssp_state->server_domain = talloc_strdup(ntlmssp_state->mem_ctx,
						     server_domain);

	SAFE_FREE(server_domain);
	if (challenge_blob.length != 8) {
		data_blob_free(&struct_blob);
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (!ntlmssp_state->nt_hash || !ntlmssp_state->lm_hash) {
		uchar zeros[16];
		/* do nothing - blobs are zero length */

		ZERO_STRUCT(zeros);

		/* session key is all zeros */
		session_key = data_blob_talloc(ntlmssp_state->mem_ctx, zeros, 16);
		
		/* not doing NLTM2 without a password */
		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
	} else if (ntlmssp_state->use_ntlmv2) {

		if (!struct_blob.length) {
			/* be lazy, match win2k - we can't do NTLMv2 without it */
			DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
			return NT_STATUS_INVALID_PARAMETER;
		}

		/* TODO: if the remote server is standalone, then we should replace 'domain'
		   with the server name as supplied above */
		
		if (!SMBNTLMv2encrypt_hash(ntlmssp_state->user, 
				      ntlmssp_state->domain, 
				      ntlmssp_state->nt_hash, &challenge_blob, 
				      &struct_blob, 
				      &lm_response, &nt_response, &session_key)) {
			data_blob_free(&challenge_blob);
			data_blob_free(&struct_blob);
			return NT_STATUS_NO_MEMORY;
		}
	} else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
		struct MD5Context md5_session_nonce_ctx;
		uchar session_nonce[16];
		uchar session_nonce_hash[16];
		uchar user_session_key[16];
		
		lm_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
		generate_random_buffer(lm_response.data, 8);
		memset(lm_response.data+8, 0, 16);

		memcpy(session_nonce, challenge_blob.data, 8);
		memcpy(&session_nonce[8], lm_response.data, 8);
	
		MD5Init(&md5_session_nonce_ctx);
		MD5Update(&md5_session_nonce_ctx, challenge_blob.data, 8);
		MD5Update(&md5_session_nonce_ctx, lm_response.data, 8);
		MD5Final(session_nonce_hash, &md5_session_nonce_ctx);

		DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
		DEBUG(5, ("challenge is: \n"));
		dump_data(5, session_nonce_hash, 8);
		
		nt_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
		SMBNTencrypt_hash(ntlmssp_state->nt_hash,
			     session_nonce_hash,
			     nt_response.data);

		session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);

		SMBsesskeygen_ntv1(ntlmssp_state->nt_hash, NULL, user_session_key);
		hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data);
		dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
	} else {
		/* lanman auth is insecure, it may be disabled */
		if (lp_client_lanman_auth()) {
			lm_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
			SMBencrypt_hash(ntlmssp_state->lm_hash,challenge_blob.data,
				   lm_response.data);
		}
		
		nt_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
		SMBNTencrypt_hash(ntlmssp_state->nt_hash,challenge_blob.data,
			     nt_response.data);
		
		session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);
		if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) 
		    && lp_client_lanman_auth()) {
			SMBsesskeygen_lm_sess_key(ntlmssp_state->lm_hash, lm_response.data,
					session_key.data);
			dump_data_pw("LM session key\n", session_key.data, session_key.length);
		} else {
			SMBsesskeygen_ntv1(ntlmssp_state->nt_hash, NULL, session_key.data);
			dump_data_pw("NT session key:\n", session_key.data, session_key.length);
		}
	}
	data_blob_free(&struct_blob);

	/* Key exchange encryptes a new client-generated session key with
	   the password-derived key */
	if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
		/* Make up a new session key */
		uint8 client_session_key[16];
		generate_random_buffer(client_session_key, sizeof(client_session_key));

		/* Encrypt the new session key with the old one */
		encrypted_session_key = data_blob(client_session_key, sizeof(client_session_key));
		dump_data_pw("KEY_EXCH session key:\n", encrypted_session_key.data, encrypted_session_key.length);
		SamOEMhash(encrypted_session_key.data, session_key.data, encrypted_session_key.length);
		dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length);

		/* Mark the new session key as the 'real' session key */
		data_blob_free(&session_key);
		session_key = data_blob_talloc(ntlmssp_state->mem_ctx, client_session_key, sizeof(client_session_key));
	}

	/* this generates the actual auth packet */
	if (!msrpc_gen(next_request, auth_gen_string, 
		       "NTLMSSP", 
		       NTLMSSP_AUTH, 
		       lm_response.data, lm_response.length,
		       nt_response.data, nt_response.length,
		       ntlmssp_state->domain, 
		       ntlmssp_state->user, 
		       ntlmssp_state->get_global_myname(), 
		       encrypted_session_key.data, encrypted_session_key.length,
		       ntlmssp_state->neg_flags)) {
		
		return NT_STATUS_NO_MEMORY;
	}

	data_blob_free(&encrypted_session_key);

	data_blob_free(&ntlmssp_state->chal);

	ntlmssp_state->session_key = session_key;

	ntlmssp_state->chal = challenge_blob;
	ntlmssp_state->lm_resp = lm_response;
	ntlmssp_state->nt_resp = nt_response;

	ntlmssp_state->expected_state = NTLMSSP_DONE;

	if (!NT_STATUS_IS_OK(nt_status = ntlmssp_sign_init(ntlmssp_state))) {
		DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n", nt_errstr(nt_status)));
	}

	return nt_status;
}
Example #17
0
NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
				  TALLOC_CTX *out_mem_ctx,
				  const DATA_BLOB in, DATA_BLOB *out)
{
	struct gensec_ntlmssp_context *gensec_ntlmssp =
		talloc_get_type_abort(gensec_security->private_data,
				      struct gensec_ntlmssp_context);
	struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state;
	uint32_t chal_flags, ntlmssp_command, unkn1 = 0, unkn2 = 0;
	DATA_BLOB server_domain_blob;
	DATA_BLOB challenge_blob;
	DATA_BLOB target_info = data_blob(NULL, 0);
	char *server_domain;
	const char *chal_parse_string;
	const char *chal_parse_string_short = NULL;
	const char *auth_gen_string;
	DATA_BLOB lm_response = data_blob(NULL, 0);
	DATA_BLOB nt_response = data_blob(NULL, 0);
	DATA_BLOB session_key = data_blob(NULL, 0);
	DATA_BLOB lm_session_key = data_blob(NULL, 0);
	DATA_BLOB encrypted_session_key = data_blob(NULL, 0);
	NTSTATUS nt_status;
	int flags = 0;
	const char *user = NULL, *domain = NULL, *workstation = NULL;
	bool is_anonymous = false;
	const DATA_BLOB version_blob = ntlmssp_version_blob();

	TALLOC_CTX *mem_ctx = talloc_new(out_mem_ctx);
	if (!mem_ctx) {
		return NT_STATUS_NO_MEMORY;
	}

	if (!msrpc_parse(mem_ctx,
			 &in, "CdBd",
			 "NTLMSSP",
			 &ntlmssp_command,
			 &server_domain_blob,
			 &chal_flags)) {
		DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
		dump_data(2, in.data, in.length);
		talloc_free(mem_ctx);

		return NT_STATUS_INVALID_PARAMETER;
	}

	data_blob_free(&server_domain_blob);

	DEBUG(3, ("Got challenge flags:\n"));
	debug_ntlmssp_flags(chal_flags);

	ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, ntlmssp_state->allow_lm_key);

	if (ntlmssp_state->unicode) {
		if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
			chal_parse_string = "CdUdbddB";
		} else {
			chal_parse_string = "CdUdbdd";
			chal_parse_string_short = "CdUdb";
		}
		auth_gen_string = "CdBBUUUBdb";
	} else {
		if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
			chal_parse_string = "CdAdbddB";
		} else {
			chal_parse_string = "CdAdbdd";
			chal_parse_string_short = "CdAdb";
		}

		auth_gen_string = "CdBBAAABdb";
	}

	if (!msrpc_parse(mem_ctx,
			 &in, chal_parse_string,
			 "NTLMSSP",
			 &ntlmssp_command,
			 &server_domain,
			 &chal_flags,
			 &challenge_blob, 8,
			 &unkn1, &unkn2,
			 &target_info)) {

		bool ok = false;

		DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n"));

		if (chal_parse_string_short != NULL) {
			/*
			 * In the case where NTLMSSP_NEGOTIATE_TARGET_INFO
			 * is not used, some NTLMSSP servers don't return
			 * the unused unkn1 and unkn2 fields.
			 * See bug:
			 * https://bugzilla.samba.org/show_bug.cgi?id=10016
			 * for packet traces.
			 * Try and parse again without them.
			 */
			ok = msrpc_parse(mem_ctx,
				&in, chal_parse_string_short,
				"NTLMSSP",
				&ntlmssp_command,
				&server_domain,
				&chal_flags,
				&challenge_blob, 8);
			if (!ok) {
				DEBUG(1, ("Failed to short parse "
					"the NTLMSSP Challenge: (#2)\n"));
			}
		}

		if (!ok) {
			dump_data(2, in.data, in.length);
			talloc_free(mem_ctx);
			return NT_STATUS_INVALID_PARAMETER;
		}
	}

	if (chal_flags & NTLMSSP_TARGET_TYPE_SERVER) {
		ntlmssp_state->server.is_standalone = true;
	} else {
		ntlmssp_state->server.is_standalone = false;
	}
	/* TODO: parse struct_blob and fill in the rest */
	ntlmssp_state->server.netbios_name = "";
	ntlmssp_state->server.netbios_domain = talloc_move(ntlmssp_state, &server_domain);
	ntlmssp_state->server.dns_name = "";
	ntlmssp_state->server.dns_domain = "";

	if (challenge_blob.length != 8) {
		talloc_free(mem_ctx);
		return NT_STATUS_INVALID_PARAMETER;
	}

	is_anonymous = cli_credentials_is_anonymous(gensec_security->credentials);
	cli_credentials_get_ntlm_username_domain(gensec_security->credentials, mem_ctx,
						 &user, &domain);

	workstation = cli_credentials_get_workstation(gensec_security->credentials);

	if (user == NULL) {
		DEBUG(10, ("User is NULL, returning INVALID_PARAMETER\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (domain == NULL) {
		DEBUG(10, ("Domain is NULL, returning INVALID_PARAMETER\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (workstation == NULL) {
		DEBUG(10, ("Workstation is NULL, returning INVALID_PARAMETER\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (is_anonymous) {
		ntlmssp_state->neg_flags |= NTLMSSP_ANONYMOUS;
		/*
		 * don't use the ccache for anonymous auth
		 */
		ntlmssp_state->use_ccache = false;
	}
	if (ntlmssp_state->use_ccache) {
		struct samr_Password *nt_hash = NULL;

		/*
		 * If we have a password given we don't
		 * use the ccache
		 */
		nt_hash = cli_credentials_get_nt_hash(gensec_security->credentials,
						      mem_ctx);
		if (nt_hash != NULL) {
			ZERO_STRUCTP(nt_hash);
			TALLOC_FREE(nt_hash);
			ntlmssp_state->use_ccache = false;
		}
	}

	if (ntlmssp_state->use_ccache) {
		struct wbcCredentialCacheParams params;
		struct wbcCredentialCacheInfo *info = NULL;
		struct wbcAuthErrorInfo *error = NULL;
		struct wbcNamedBlob auth_blobs[1];
		const struct wbcBlob *wbc_auth_blob = NULL;
		const struct wbcBlob *wbc_session_key = NULL;
		wbcErr wbc_status;
		int i;

		params.account_name = user;
		params.domain_name = domain;
		params.level = WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP;

		auth_blobs[0].name = "challenge_blob";
		auth_blobs[0].flags = 0;
		auth_blobs[0].blob.data = in.data;
		auth_blobs[0].blob.length = in.length;
		params.num_blobs = ARRAY_SIZE(auth_blobs);
		params.blobs = auth_blobs;

		wbc_status = wbcCredentialCache(&params, &info, &error);
		wbcFreeMemory(error);
		if (!WBC_ERROR_IS_OK(wbc_status)) {
			return NT_STATUS_WRONG_CREDENTIAL_HANDLE;
		}

		for (i=0; i<info->num_blobs; i++) {
			if (strequal(info->blobs[i].name, "auth_blob")) {
				wbc_auth_blob = &info->blobs[i].blob;
			}
			if (strequal(info->blobs[i].name, "session_key")) {
				wbc_session_key = &info->blobs[i].blob;
			}
		}
		if ((wbc_auth_blob == NULL) || (wbc_session_key == NULL)) {
			wbcFreeMemory(info);
			return NT_STATUS_WRONG_CREDENTIAL_HANDLE;
		}

		session_key = data_blob_talloc(mem_ctx,
					       wbc_session_key->data,
					       wbc_session_key->length);
		if (session_key.length != wbc_session_key->length) {
			wbcFreeMemory(info);
			return NT_STATUS_NO_MEMORY;
		}
		*out = data_blob_talloc(mem_ctx,
					wbc_auth_blob->data,
					wbc_auth_blob->length);
		if (out->length != wbc_auth_blob->length) {
			wbcFreeMemory(info);
			return NT_STATUS_NO_MEMORY;
		}

		wbcFreeMemory(info);
		goto done;
	}

	if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
		flags |= CLI_CRED_NTLM2;
	}
	if (ntlmssp_state->use_ntlmv2) {
		flags |= CLI_CRED_NTLMv2_AUTH;
	}
	if (ntlmssp_state->use_nt_response) {
		flags |= CLI_CRED_NTLM_AUTH;
	}
	if (lpcfg_client_lanman_auth(gensec_security->settings->lp_ctx)) {
		flags |= CLI_CRED_LANMAN_AUTH;
	}

	nt_status = cli_credentials_get_ntlm_response(gensec_security->credentials, mem_ctx,
						      &flags, challenge_blob, target_info,
						      &lm_response, &nt_response,
						      &lm_session_key, &session_key);

	if (!NT_STATUS_IS_OK(nt_status)) {
		return nt_status;
	}

	if (!(flags & CLI_CRED_LANMAN_AUTH)) {
		/* LM Key is still possible, just silly, so we do not
		 * allow it. Fortunetly all LM crypto is off by
		 * default and we require command line options to end
		 * up here */
		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
	}

	if (!(flags & CLI_CRED_NTLM2)) {
		/* NTLM2 is incompatible... */
		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
	}

	if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY)
	    && lpcfg_client_lanman_auth(gensec_security->settings->lp_ctx) && lm_session_key.length == 16) {
		DATA_BLOB new_session_key = data_blob_talloc(mem_ctx, NULL, 16);
		if (lm_response.length == 24) {
			SMBsesskeygen_lm_sess_key(lm_session_key.data, lm_response.data,
						  new_session_key.data);
		} else {
			static const uint8_t zeros[24];
			SMBsesskeygen_lm_sess_key(lm_session_key.data, zeros,
						  new_session_key.data);
		}
		session_key = new_session_key;
		dump_data_pw("LM session key\n", session_key.data, session_key.length);
	}


	/* Key exchange encryptes a new client-generated session key with
	   the password-derived key */
	if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
		/* Make up a new session key */
		uint8_t client_session_key[16];
		generate_secret_buffer(client_session_key, sizeof(client_session_key));

		/* Encrypt the new session key with the old one */
		encrypted_session_key = data_blob_talloc(ntlmssp_state,
							 client_session_key, sizeof(client_session_key));
		dump_data_pw("KEY_EXCH session key:\n", encrypted_session_key.data, encrypted_session_key.length);
		arcfour_crypt(encrypted_session_key.data, session_key.data, encrypted_session_key.length);
		dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length);

		/* Mark the new session key as the 'real' session key */
		session_key = data_blob_talloc(mem_ctx, client_session_key, sizeof(client_session_key));
	}

	/* this generates the actual auth packet */
	nt_status = msrpc_gen(mem_ctx,
		       out, auth_gen_string,
		       "NTLMSSP",
		       NTLMSSP_AUTH,
		       lm_response.data, lm_response.length,
		       nt_response.data, nt_response.length,
		       domain,
		       user,
		       workstation,
		       encrypted_session_key.data, encrypted_session_key.length,
		       ntlmssp_state->neg_flags,
		       version_blob.data, version_blob.length);
	if (!NT_STATUS_IS_OK(nt_status)) {
		talloc_free(mem_ctx);
		return nt_status;
	}

done:
	ntlmssp_state->session_key = session_key;
	talloc_steal(ntlmssp_state, session_key.data);

	DEBUG(3, ("NTLMSSP: Set final flags:\n"));
	debug_ntlmssp_flags(ntlmssp_state->neg_flags);

	talloc_steal(out_mem_ctx, out->data);

	ntlmssp_state->expected_state = NTLMSSP_DONE;

	if (gensec_security->want_features & (GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL)) {
		nt_status = ntlmssp_sign_init(ntlmssp_state);
		if (!NT_STATUS_IS_OK(nt_status)) {
			DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n",
				  nt_errstr(nt_status)));
			talloc_free(mem_ctx);
			return nt_status;
		}
	}

	talloc_free(mem_ctx);
	return NT_STATUS_OK;
}