Beispiel #1
0
/*
  try a netlogon SamLogon
*/
bool test_netlogon_ex_ops(struct dcerpc_pipe *p, struct torture_context *tctx,
			  struct cli_credentials *credentials,
			  struct netlogon_creds_CredentialState *creds)
{
	NTSTATUS status;
	struct netr_LogonSamLogonEx r;
	struct netr_NetworkInfo ninfo;
	union netr_LogonLevel logon;
	union netr_Validation validation;
	uint8_t authoritative = 0;
	uint32_t _flags = 0;
	DATA_BLOB names_blob, chal, lm_resp, nt_resp;
	int i;
	int flags = CLI_CRED_NTLM_AUTH;
	struct dcerpc_binding_handle *b = p->binding_handle;

	struct netr_UserSessionKey key;
	struct netr_LMSessionKey LMSessKey;
	uint32_t validation_levels[] = { 2, 3 };
	struct netr_SamBaseInfo *base = NULL;
	const char *crypto_alg = "";
	bool can_do_validation_6 = true;
	enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;

	if (lpcfg_client_lanman_auth(tctx->lp_ctx)) {
		flags |= CLI_CRED_LANMAN_AUTH;
	}

	if (lpcfg_client_ntlmv2_auth(tctx->lp_ctx)) {
		flags |= CLI_CRED_NTLMv2_AUTH;
	}

	cli_credentials_get_ntlm_username_domain(cmdline_credentials, tctx,
						 &ninfo.identity_info.account_name.string,
						 &ninfo.identity_info.domain_name.string);

	generate_random_buffer(ninfo.challenge,
			       sizeof(ninfo.challenge));
	chal = data_blob_const(ninfo.challenge,
			       sizeof(ninfo.challenge));

	names_blob = NTLMv2_generate_names_blob(tctx, cli_credentials_get_workstation(credentials),
						cli_credentials_get_domain(credentials));

	status = cli_credentials_get_ntlm_response(cmdline_credentials, tctx,
						   &flags,
						   chal,
						   names_blob,
						   &lm_resp, &nt_resp,
						   NULL, NULL);
	torture_assert_ntstatus_ok(tctx, status,
				   "cli_credentials_get_ntlm_response failed");

	ninfo.lm.data = lm_resp.data;
	ninfo.lm.length = lm_resp.length;

	ninfo.nt.data = nt_resp.data;
	ninfo.nt.length = nt_resp.length;

	ninfo.identity_info.parameter_control = 0;
	ninfo.identity_info.logon_id_low = 0;
	ninfo.identity_info.logon_id_high = 0;
	ninfo.identity_info.workstation.string = cli_credentials_get_workstation(credentials);

	logon.network = &ninfo;

	r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
	r.in.computer_name = cli_credentials_get_workstation(credentials);
	r.in.logon_level = NetlogonNetworkInformation;
	r.in.logon= &logon;
	r.in.flags = &_flags;
	r.out.validation = &validation;
	r.out.authoritative = &authoritative;
	r.out.flags = &_flags;

	/*
	- retrieve level6
	- save usrsession and lmsession key
	- retrieve level 2
	- calculate, compare
	- retrieve level 3
	- calculate, compare
	*/

	if (creds) {
		if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
			crypto_alg = "AES";
		} else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
			crypto_alg = "ARCFOUR";
		}
	}

	dcerpc_binding_handle_auth_info(b, NULL, &auth_level);
	if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
		r.in.validation_level = 6;

		torture_comment(tctx,
				"Testing LogonSamLogonEx with name %s using %s and validation_level: %d\n",
				ninfo.identity_info.account_name.string, crypto_alg,
				r.in.validation_level);

		torture_assert_ntstatus_ok(tctx,
			dcerpc_netr_LogonSamLogonEx_r(b, tctx, &r),
			"LogonSamLogonEx failed");
	} else {
		torture_comment(tctx,
				"Skip auth_level[%u] Testing LogonSamLogonEx with name %s using %s and validation_level: %d\n",
				auth_level, ninfo.identity_info.account_name.string, crypto_alg,
				r.in.validation_level);
		r.out.result = NT_STATUS_INVALID_INFO_CLASS;
	}

	if (NT_STATUS_EQUAL(r.out.result, NT_STATUS_INVALID_INFO_CLASS)) {
		can_do_validation_6 = false;
	} else {
		torture_assert_ntstatus_ok(tctx, r.out.result,
			"LogonSamLogonEx failed");

		key = r.out.validation->sam6->base.key;
		LMSessKey = r.out.validation->sam6->base.LMSessKey;

		DEBUG(1,("unencrypted session keys from validation_level 6:\n"));
		dump_data(1, r.out.validation->sam6->base.key.key, 16);
		dump_data(1, r.out.validation->sam6->base.LMSessKey.key, 8);
	}

	for (i=0; i < ARRAY_SIZE(validation_levels); i++) {

		r.in.validation_level = validation_levels[i];

		torture_comment(tctx,
			"Testing LogonSamLogonEx with name %s using %s and validation_level: %d\n",
			ninfo.identity_info.account_name.string, crypto_alg,
			r.in.validation_level);

		torture_assert_ntstatus_ok(tctx,
			dcerpc_netr_LogonSamLogonEx_r(b, tctx, &r),
			"LogonSamLogonEx failed");
		torture_assert_ntstatus_ok(tctx, r.out.result,
			"LogonSamLogonEx failed");

		if (creds == NULL) {
			/* when this test is called without creds no point in
			 * testing the session keys */
			continue;
		}

		switch (validation_levels[i]) {
		case 2:
			base = &r.out.validation->sam2->base;
			break;
		case 3:
			base = &r.out.validation->sam3->base;
			break;
		default:
			break;
		}

		DEBUG(1,("encrypted keys validation_level %d:\n",
			validation_levels[i]));
		dump_data(1, base->key.key, 16);
		dump_data(1, base->LMSessKey.key, 8);

		if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
			netlogon_creds_aes_decrypt(creds, base->key.key, 16);
			netlogon_creds_aes_decrypt(creds, base->LMSessKey.key, 8);
		} else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
			netlogon_creds_arcfour_crypt(creds, base->key.key, 16);
			netlogon_creds_arcfour_crypt(creds, base->LMSessKey.key, 8);
		}

		DEBUG(1,("decryped keys validation_level %d\n",
			validation_levels[i]));

		dump_data(1, base->key.key, 16);
		dump_data(1, base->LMSessKey.key, 8);

		if (!can_do_validation_6) {
			/* we cant compare against unencrypted keys */
			continue;
		}

		torture_assert_mem_equal(tctx,
					 base->key.key,
					 key.key,
					 16,
					 "unexpected user session key\n");
		torture_assert_mem_equal(tctx,
					 base->LMSessKey.key,
					 LMSessKey.key,
					 8,
					 "unexpected LM session key\n");
	}

	return true;
}
Beispiel #2
0
NTSTATUS libnet_SamSync_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_SamSync *r)
{
	NTSTATUS nt_status, dbsync_nt_status;
	TALLOC_CTX *samsync_ctx, *loop_ctx, *delta_ctx;
	struct netlogon_creds_CredentialState *creds;
	struct netr_DatabaseSync dbsync;
	struct netr_Authenticator credential, return_authenticator;
	struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
	struct cli_credentials *machine_account;
	struct dcerpc_pipe *p;
	struct libnet_context *machine_net_ctx;
	struct libnet_RpcConnect *c;
	struct libnet_SamSync_state *state;
	const enum netr_SamDatabaseID database_ids[] = {SAM_DATABASE_DOMAIN, SAM_DATABASE_BUILTIN, SAM_DATABASE_PRIVS}; 
	unsigned int i;

	samsync_ctx = talloc_named(mem_ctx, 0, "SamSync top context");

	if (!r->in.machine_account) { 
		machine_account = cli_credentials_init(samsync_ctx);
		if (!machine_account) {
			talloc_free(samsync_ctx);
			return NT_STATUS_NO_MEMORY;
		}
		cli_credentials_set_conf(machine_account, ctx->lp_ctx);
		nt_status = cli_credentials_set_machine_account(machine_account, ctx->lp_ctx);
		if (!NT_STATUS_IS_OK(nt_status)) {
			r->out.error_string = talloc_strdup(mem_ctx, "Could not obtain machine account password - are we joined to the domain?");
			talloc_free(samsync_ctx);
			return nt_status;
		}
	} else {
		machine_account = r->in.machine_account;
	}

	/* We cannot do this unless we are a BDC.  Check, before we get odd errors later */
	if (cli_credentials_get_secure_channel_type(machine_account) != SEC_CHAN_BDC) {
		r->out.error_string
			= talloc_asprintf(mem_ctx, 
					  "Our join to domain %s is not as a BDC (%d), please rejoin as a BDC",
					  cli_credentials_get_domain(machine_account),
					  cli_credentials_get_secure_channel_type(machine_account));
		talloc_free(samsync_ctx);
		return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
	}

	c = talloc_zero(samsync_ctx, struct libnet_RpcConnect);
	if (!c) {
		r->out.error_string = NULL;
		talloc_free(samsync_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	c->level              = LIBNET_RPC_CONNECT_DC_INFO;
	if (r->in.binding_string) {
		c->in.binding = r->in.binding_string;
		c->in.name    = NULL;
	} else {
		c->in.binding = NULL;
		c->in.name    = cli_credentials_get_domain(machine_account);
	}
	
	/* prepare connect to the NETLOGON pipe of PDC */
	c->in.dcerpc_iface      = &ndr_table_netlogon;

	/* We must do this as the machine, not as any command-line
	 * user.  So we override the credentials in the
	 * libnet_context */
	machine_net_ctx = talloc(samsync_ctx, struct libnet_context);
	if (!machine_net_ctx) {
		r->out.error_string = NULL;
		talloc_free(samsync_ctx);
		return NT_STATUS_NO_MEMORY;
	}
	*machine_net_ctx = *ctx;
	machine_net_ctx->cred = machine_account;

	/* connect to the NETLOGON pipe of the PDC */
	nt_status = libnet_RpcConnect(machine_net_ctx, samsync_ctx, c);
	if (!NT_STATUS_IS_OK(nt_status)) {
		if (r->in.binding_string) {
			r->out.error_string = talloc_asprintf(mem_ctx,
							      "Connection to NETLOGON pipe of DC %s failed: %s",
							      r->in.binding_string, c->out.error_string);
		} else {
			r->out.error_string = talloc_asprintf(mem_ctx,
							      "Connection to NETLOGON pipe of DC for %s failed: %s",
							      c->in.name, c->out.error_string);
		}
		talloc_free(samsync_ctx);
		return nt_status;
	}

	/* This makes a new pipe, on which we can do schannel.  We
	 * should do this in the RpcConnect code, but the abstaction
	 * layers do not suit yet */

	nt_status = dcerpc_secondary_connection(c->out.dcerpc_pipe, &p,
						c->out.dcerpc_pipe->binding);

	if (!NT_STATUS_IS_OK(nt_status)) {
		r->out.error_string = talloc_asprintf(mem_ctx,
						      "Secondary connection to NETLOGON pipe of DC %s failed: %s",
						      dcerpc_server_name(p), nt_errstr(nt_status));
		talloc_free(samsync_ctx);
		return nt_status;
	}

	nt_status = dcerpc_bind_auth_schannel(samsync_ctx, p, &ndr_table_netlogon,
					      machine_account, ctx->lp_ctx, DCERPC_AUTH_LEVEL_PRIVACY);

	if (!NT_STATUS_IS_OK(nt_status)) {
		r->out.error_string = talloc_asprintf(mem_ctx,
						      "SCHANNEL authentication to NETLOGON pipe of DC %s failed: %s",
						      dcerpc_server_name(p), nt_errstr(nt_status));
		talloc_free(samsync_ctx);
		return nt_status;
	}

	state = talloc(samsync_ctx, struct libnet_SamSync_state);
	if (!state) {
		r->out.error_string = NULL;
		talloc_free(samsync_ctx);
		return nt_status;
	}		

	state->domain_name     = c->out.domain_name;
	state->domain_sid      = c->out.domain_sid;
	state->realm           = c->out.realm;
	state->domain_guid     = c->out.guid;
	state->machine_net_ctx = machine_net_ctx;
	state->netlogon_pipe   = p;

	/* initialise the callback layer.  It may wish to contact the
	 * server with ldap, now we know the name */
	
	if (r->in.init_fn) {
		char *error_string;
		nt_status = r->in.init_fn(samsync_ctx, 
					  r->in.fn_ctx,
					  state, 
					  &error_string); 
		if (!NT_STATUS_IS_OK(nt_status)) {
			r->out.error_string = talloc_steal(mem_ctx, error_string);
			talloc_free(samsync_ctx);
			return nt_status;
		}
	}

	/* get NETLOGON credentials */

	nt_status = dcerpc_schannel_creds(p->conn->security_state.generic_state, samsync_ctx, &creds);
	if (!NT_STATUS_IS_OK(nt_status)) {
		r->out.error_string = talloc_strdup(mem_ctx, "Could not obtain NETLOGON credentials from DCERPC/GENSEC layer");
		talloc_free(samsync_ctx);
		return nt_status;
	}

	/* Setup details for the synchronisation */

	ZERO_STRUCT(return_authenticator);

	dbsync.in.logon_server = talloc_asprintf(samsync_ctx, "\\\\%s", dcerpc_server_name(p));
	dbsync.in.computername = cli_credentials_get_workstation(machine_account);
	dbsync.in.preferredmaximumlength = (uint32_t)-1;
	dbsync.in.return_authenticator = &return_authenticator;
	dbsync.out.return_authenticator = &return_authenticator;
	dbsync.out.delta_enum_array = &delta_enum_array;

	for (i=0;i< ARRAY_SIZE(database_ids); i++) {

		uint32_t sync_context = 0;

		dbsync.in.database_id = database_ids[i];
		dbsync.in.sync_context = &sync_context;
		dbsync.out.sync_context = &sync_context;
		
		do {
			uint32_t d;
			loop_ctx = talloc_named(samsync_ctx, 0, "DatabaseSync loop context");
			netlogon_creds_client_authenticator(creds, &credential);

			dbsync.in.credential = &credential;
			
			dbsync_nt_status = dcerpc_netr_DatabaseSync_r(p->binding_handle, loop_ctx, &dbsync);
			if (NT_STATUS_IS_OK(dbsync_nt_status) && !NT_STATUS_IS_OK(dbsync.out.result)) {
				dbsync_nt_status = dbsync.out.result;
			}
			if (!NT_STATUS_IS_OK(dbsync_nt_status) &&
			    !NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES)) {
				r->out.error_string = talloc_asprintf(mem_ctx, "DatabaseSync failed - %s", nt_errstr(nt_status));
				talloc_free(samsync_ctx);
				return nt_status;
			}
			
			if (!netlogon_creds_client_check(creds, &dbsync.out.return_authenticator->cred)) {
				r->out.error_string = talloc_strdup(mem_ctx, "Credential chaining on incoming DatabaseSync failed");
				talloc_free(samsync_ctx);
				return NT_STATUS_ACCESS_DENIED;
			}
			
			dbsync.in.sync_context = dbsync.out.sync_context;
			
			/* For every single remote 'delta' entry: */
			for (d=0; d < delta_enum_array->num_deltas; d++) {
				char *error_string = NULL;
				delta_ctx = talloc_named(loop_ctx, 0, "DatabaseSync delta context");
				/* 'Fix' elements, by decrypting and
				 * de-obfuscating the data */
				nt_status = samsync_fix_delta(delta_ctx, 
							      creds, 
							      dbsync.in.database_id,
							      &delta_enum_array->delta_enum[d]);
				if (!NT_STATUS_IS_OK(nt_status)) {
					r->out.error_string = talloc_steal(mem_ctx, error_string);
					talloc_free(samsync_ctx);
					return nt_status;
				}

				/* Now call the callback.  This will
				 * do something like print the data or
				 * write to an ldb */
				nt_status = r->in.delta_fn(delta_ctx, 
							   r->in.fn_ctx,
							   dbsync.in.database_id,
							   &delta_enum_array->delta_enum[d],
							   &error_string);
				if (!NT_STATUS_IS_OK(nt_status)) {
					r->out.error_string = talloc_steal(mem_ctx, error_string);
					talloc_free(samsync_ctx);
					return nt_status;
				}
				talloc_free(delta_ctx);
			}
			talloc_free(loop_ctx);
		} while (NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES));
		
		if (!NT_STATUS_IS_OK(dbsync_nt_status)) {
			r->out.error_string = talloc_asprintf(mem_ctx, "libnet_SamSync_netlogon failed: unexpected inconsistancy. Should not get error %s here", nt_errstr(nt_status));
			talloc_free(samsync_ctx);
			return dbsync_nt_status;
		}
		nt_status = NT_STATUS_OK;
	}
	talloc_free(samsync_ctx);
	return nt_status;
}
static NTSTATUS schannel_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
				struct tevent_context *ev,
				const DATA_BLOB in, DATA_BLOB *out)
{
	struct schannel_state *state = (struct schannel_state *)gensec_security->private_data;
	NTSTATUS status;
	enum ndr_err_code ndr_err;
	struct NL_AUTH_MESSAGE bind_schannel;
	struct NL_AUTH_MESSAGE bind_schannel_ack;
	struct netlogon_creds_CredentialState *creds;
	const char *workstation;
	const char *domain;

	*out = data_blob(NULL, 0);

	switch (gensec_security->gensec_role) {
	case GENSEC_CLIENT:
		if (state->state != SCHANNEL_STATE_START) {
			/* we could parse the bind ack, but we don't know what it is yet */
			return NT_STATUS_OK;
		}

		state->creds = cli_credentials_get_netlogon_creds(gensec_security->credentials);
		if (state->creds == NULL) {
			return NT_STATUS_INVALID_PARAMETER_MIX;
		}
		/*
		 * We need to create a reference here or we don't get
		 * updates performed on the credentials if we create a
		 * copy.
		 */
		state->creds = talloc_reference(state, state->creds);
		if (state->creds == NULL) {
			return NT_STATUS_NO_MEMORY;
		}

		bind_schannel.MessageType = NL_NEGOTIATE_REQUEST;
#if 0
		/* to support this we'd need to have access to the full domain name */
		/* 0x17, 23 */
		bind_schannel.Flags = NL_FLAG_OEM_NETBIOS_DOMAIN_NAME |
				      NL_FLAG_OEM_NETBIOS_COMPUTER_NAME |
				      NL_FLAG_UTF8_DNS_DOMAIN_NAME |
				      NL_FLAG_UTF8_NETBIOS_COMPUTER_NAME;
		bind_schannel.oem_netbios_domain.a = cli_credentials_get_domain(gensec_security->credentials);
		bind_schannel.oem_netbios_computer.a = cli_credentials_get_workstation(gensec_security->credentials);
		bind_schannel.utf8_dns_domain = cli_credentials_get_realm(gensec_security->credentials);
		/* w2k3 refuses us if we use the full DNS workstation?
		 why? perhaps because we don't fill in the dNSHostName
		 attribute in the machine account? */
		bind_schannel.utf8_netbios_computer = cli_credentials_get_workstation(gensec_security->credentials);
#else
		bind_schannel.Flags = NL_FLAG_OEM_NETBIOS_DOMAIN_NAME |
				      NL_FLAG_OEM_NETBIOS_COMPUTER_NAME;
		bind_schannel.oem_netbios_domain.a = cli_credentials_get_domain(gensec_security->credentials);
		bind_schannel.oem_netbios_computer.a = cli_credentials_get_workstation(gensec_security->credentials);
#endif

		ndr_err = ndr_push_struct_blob(out, out_mem_ctx, &bind_schannel,
					       (ndr_push_flags_fn_t)ndr_push_NL_AUTH_MESSAGE);
		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
			status = ndr_map_error2ntstatus(ndr_err);
			DEBUG(3, ("Could not create schannel bind: %s\n",
				  nt_errstr(status)));
			return status;
		}

		state->state = SCHANNEL_STATE_UPDATE_1;

		return NT_STATUS_MORE_PROCESSING_REQUIRED;
	case GENSEC_SERVER:

		if (state->state != SCHANNEL_STATE_START) {
			/* no third leg on this protocol */
			return NT_STATUS_INVALID_PARAMETER;
		}

		/* parse the schannel startup blob */
		ndr_err = ndr_pull_struct_blob(&in, out_mem_ctx, &bind_schannel,
			(ndr_pull_flags_fn_t)ndr_pull_NL_AUTH_MESSAGE);
		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
			status = ndr_map_error2ntstatus(ndr_err);
			DEBUG(3, ("Could not parse incoming schannel bind: %s\n",
				  nt_errstr(status)));
			return status;
		}

		if (bind_schannel.Flags & NL_FLAG_OEM_NETBIOS_DOMAIN_NAME) {
			domain = bind_schannel.oem_netbios_domain.a;
			if (strcasecmp_m(domain, lpcfg_workgroup(gensec_security->settings->lp_ctx)) != 0) {
				DEBUG(3, ("Request for schannel to incorrect domain: %s != our domain %s\n",
					  domain, lpcfg_workgroup(gensec_security->settings->lp_ctx)));
				return NT_STATUS_LOGON_FAILURE;
			}
		} else if (bind_schannel.Flags & NL_FLAG_UTF8_DNS_DOMAIN_NAME) {
			domain = bind_schannel.utf8_dns_domain.u;
			if (strcasecmp_m(domain, lpcfg_dnsdomain(gensec_security->settings->lp_ctx)) != 0) {
				DEBUG(3, ("Request for schannel to incorrect domain: %s != our domain %s\n",
					  domain, lpcfg_dnsdomain(gensec_security->settings->lp_ctx)));
				return NT_STATUS_LOGON_FAILURE;
			}
		} else {
			DEBUG(3, ("Request for schannel to without domain\n"));
			return NT_STATUS_LOGON_FAILURE;
		}

		if (bind_schannel.Flags & NL_FLAG_OEM_NETBIOS_COMPUTER_NAME) {
			workstation = bind_schannel.oem_netbios_computer.a;
		} else if (bind_schannel.Flags & NL_FLAG_UTF8_NETBIOS_COMPUTER_NAME) {
			workstation = bind_schannel.utf8_netbios_computer.u;
		} else {
			DEBUG(3, ("Request for schannel to without netbios workstation\n"));
			return NT_STATUS_LOGON_FAILURE;
		}

		status = schannel_get_creds_state(out_mem_ctx,
						  gensec_security->settings->lp_ctx,
						  workstation, &creds);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(3, ("Could not find session key for attempted schannel connection from %s: %s\n",
				  workstation, nt_errstr(status)));
			if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
				return NT_STATUS_LOGON_FAILURE;
			}
			return status;
		}

		state->creds = talloc_steal(state, creds);

		bind_schannel_ack.MessageType = NL_NEGOTIATE_RESPONSE;
		bind_schannel_ack.Flags = 0;
		bind_schannel_ack.Buffer.dummy = 0x6c0000; /* actually I think
							    * this does not have
							    * any meaning here
							    * - gd */

		ndr_err = ndr_push_struct_blob(out, out_mem_ctx, &bind_schannel_ack,
					       (ndr_push_flags_fn_t)ndr_push_NL_AUTH_MESSAGE);
		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
			status = ndr_map_error2ntstatus(ndr_err);
			DEBUG(3, ("Could not return schannel bind ack for client %s: %s\n",
				  workstation, nt_errstr(status)));
			return status;
		}

		state->state = SCHANNEL_STATE_UPDATE_1;

		return NT_STATUS_OK;
	}
	return NT_STATUS_INVALID_PARAMETER;
}
Beispiel #4
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;
}
Beispiel #5
0
NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
{
	struct gensec_ntlmssp_context *gensec_ntlmssp;
	struct ntlmssp_state *ntlmssp_state;
	NTSTATUS nt_status;

	nt_status = gensec_ntlmssp_start(gensec_security);
	NT_STATUS_NOT_OK_RETURN(nt_status);

	gensec_ntlmssp =
		talloc_get_type_abort(gensec_security->private_data,
				      struct gensec_ntlmssp_context);

	ntlmssp_state = talloc_zero(gensec_ntlmssp,
				    struct ntlmssp_state);
	if (!ntlmssp_state) {
		return NT_STATUS_NO_MEMORY;
	}

	gensec_ntlmssp->ntlmssp_state = ntlmssp_state;

	ntlmssp_state = gensec_ntlmssp->ntlmssp_state;

	ntlmssp_state->role = NTLMSSP_CLIENT;

	ntlmssp_state->client.netbios_domain = lpcfg_workgroup(gensec_security->settings->lp_ctx);
	ntlmssp_state->client.netbios_name = cli_credentials_get_workstation(gensec_security->credentials);

	ntlmssp_state->unicode = gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "unicode", true);

	ntlmssp_state->use_nt_response = gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "send_nt_reponse", true);

	ntlmssp_state->allow_lm_key = (lpcfg_client_lanman_auth(gensec_security->settings->lp_ctx)
					      && (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "allow_lm_key", false)
						  || gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "lm_key", false)));

	ntlmssp_state->use_ntlmv2 = lpcfg_client_ntlmv2_auth(gensec_security->settings->lp_ctx);

	ntlmssp_state->expected_state = NTLMSSP_INITIAL;

	ntlmssp_state->neg_flags =
		NTLMSSP_NEGOTIATE_NTLM |
		NTLMSSP_REQUEST_TARGET;

	if (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "128bit", true)) {
		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_128;
	}

	if (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "56bit", false)) {
		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_56;
	}

	if (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "lm_key", false)) {
		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
	}

	if (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "keyexchange", true)) {
		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_KEY_EXCH;
	}

	if (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "alwayssign", true)) {
		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
	}

	if (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "ntlm2", true)) {
		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;
	} else {
		/* apparently we can't do ntlmv2 if we don't do ntlm2 */
		ntlmssp_state->use_ntlmv2 = false;
	}

	if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) {
		/*
		 * We need to set this to allow a later SetPassword
		 * via the SAMR pipe to succeed. Strange.... We could
		 * also add  NTLMSSP_NEGOTIATE_SEAL here. JRA.
		 *
		 * Without this, Windows will not create the master key
		 * that it thinks is only used for NTLMSSP signing and
		 * sealing.  (It is actually pulled out and used directly)
		 */
		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
	}
	if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
	}
	if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
		ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
	}

	return NT_STATUS_OK;
}
Beispiel #6
0
/*
  try a netlogon SamLogon
*/
bool test_netlogon_ex_ops(struct dcerpc_pipe *p, struct torture_context *tctx, 
			  struct cli_credentials *credentials, 
			  struct netlogon_creds_CredentialState *creds)
{
	NTSTATUS status;
	struct netr_LogonSamLogonEx r;
	struct netr_NetworkInfo ninfo;
	union netr_LogonLevel logon;
	union netr_Validation validation;
	uint8_t authoritative = 0;
	uint32_t _flags = 0;
	DATA_BLOB names_blob, chal, lm_resp, nt_resp;
	int i;
	int flags = CLI_CRED_NTLM_AUTH;
	struct dcerpc_binding_handle *b = p->binding_handle;

	if (lpcfg_client_lanman_auth(tctx->lp_ctx)) {
		flags |= CLI_CRED_LANMAN_AUTH;
	}

	if (lpcfg_client_ntlmv2_auth(tctx->lp_ctx)) {
		flags |= CLI_CRED_NTLMv2_AUTH;
	}

	cli_credentials_get_ntlm_username_domain(cmdline_credentials, tctx, 
						 &ninfo.identity_info.account_name.string,
						 &ninfo.identity_info.domain_name.string);
	
	generate_random_buffer(ninfo.challenge, 
			       sizeof(ninfo.challenge));
	chal = data_blob_const(ninfo.challenge, 
			       sizeof(ninfo.challenge));

	names_blob = NTLMv2_generate_names_blob(tctx, cli_credentials_get_workstation(credentials), 
						cli_credentials_get_domain(credentials));

	status = cli_credentials_get_ntlm_response(cmdline_credentials, tctx, 
						   &flags, 
						   chal,
						   names_blob,
						   &lm_resp, &nt_resp,
						   NULL, NULL);
	torture_assert_ntstatus_ok(tctx, status, 
				   "cli_credentials_get_ntlm_response failed");

	ninfo.lm.data = lm_resp.data;
	ninfo.lm.length = lm_resp.length;

	ninfo.nt.data = nt_resp.data;
	ninfo.nt.length = nt_resp.length;

	ninfo.identity_info.parameter_control = 0;
	ninfo.identity_info.logon_id_low = 0;
	ninfo.identity_info.logon_id_high = 0;
	ninfo.identity_info.workstation.string = cli_credentials_get_workstation(credentials);

	logon.network = &ninfo;

	r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
	r.in.computer_name = cli_credentials_get_workstation(credentials);
	r.in.logon_level = 2;
	r.in.logon= &logon;
	r.in.flags = &_flags;
	r.out.validation = &validation;
	r.out.authoritative = &authoritative;
	r.out.flags = &_flags;

	torture_comment(tctx, 
			"Testing LogonSamLogonEx with name %s\n", 
			ninfo.identity_info.account_name.string);
	
	for (i=2;i<3;i++) {
		r.in.validation_level = i;
		
		torture_assert_ntstatus_ok(tctx, dcerpc_netr_LogonSamLogonEx_r(b, tctx, &r),
			"LogonSamLogon failed");
		torture_assert_ntstatus_ok(tctx, r.out.result, "LogonSamLogon failed");
	}

	return true;
}
Beispiel #7
0
static PyObject *py_creds_get_workstation(PyObject *self, PyObject *unused)
{
	return PyString_FromStringOrNULL(cli_credentials_get_workstation(PyCredentials_AsCliCredentials(self)));
}
Beispiel #8
0
static bool test_PACVerify(struct torture_context *tctx,
                           struct dcerpc_pipe *p,
                           struct cli_credentials *credentials)
{
    NTSTATUS status;

    struct netr_LogonSamLogon r;

    union netr_LogonLevel logon;
    union netr_Validation validation;
    uint8_t authoritative;
    struct netr_Authenticator return_authenticator;

    struct netr_GenericInfo generic;
    struct netr_Authenticator auth, auth2;


    struct netlogon_creds_CredentialState *creds;
    struct gensec_security *gensec_client_context;
    struct gensec_security *gensec_server_context;

    DATA_BLOB client_to_server, server_to_client, pac_wrapped, payload;
    struct PAC_Validate pac_wrapped_struct;

    enum ndr_err_code ndr_err;

    struct auth_session_info *session_info;

    char *tmp_dir;

    TALLOC_CTX *tmp_ctx = talloc_new(tctx);

    torture_assert(tctx, tmp_ctx != NULL, "talloc_new() failed");

    if (!test_SetupCredentials2(p, tctx, NETLOGON_NEG_AUTH2_ADS_FLAGS,
                                credentials, SEC_CHAN_BDC,
                                &creds)) {
        return false;
    }

    status = torture_temp_dir(tctx, "PACVerify", &tmp_dir);
    torture_assert_ntstatus_ok(tctx, status, "torture_temp_dir failed");

    status = gensec_client_start(tctx, &gensec_client_context, tctx->ev,
                                 lp_gensec_settings(tctx, tctx->lp_ctx));
    torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed");

    status = gensec_set_target_hostname(gensec_client_context, TEST_MACHINE_NAME);

    status = gensec_set_credentials(gensec_client_context, cmdline_credentials);
    torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");

    status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSSAPI");
    torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed");

    status = gensec_server_start(tctx, tctx->ev,
                                 lp_gensec_settings(tctx, tctx->lp_ctx),
                                 NULL, &gensec_server_context);
    torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed");

    status = gensec_set_credentials(gensec_server_context, credentials);
    torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed");

    status = gensec_start_mech_by_sasl_name(gensec_server_context, "GSSAPI");
    torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (server) failed");

    server_to_client = data_blob(NULL, 0);

    do {
        /* Do a client-server update dance */
        status = gensec_update(gensec_client_context, tmp_ctx, server_to_client, &client_to_server);
        if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
            ;
            torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed");
        }

        status = gensec_update(gensec_server_context, tmp_ctx, client_to_server, &server_to_client);
        if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
            ;
            torture_assert_ntstatus_ok(tctx, status, "gensec_update (server) failed");
        }

        if (NT_STATUS_IS_OK(status)) {
            break;
        }
    } while (1);

    /* Extract the PAC using Samba's code */

    status = gensec_session_info(gensec_server_context, &session_info);
    torture_assert_ntstatus_ok(tctx, status, "gensec_session_info failed");

    pac_wrapped_struct.ChecksumLength = session_info->server_info->pac_srv_sig.signature.length;
    pac_wrapped_struct.SignatureType = session_info->server_info->pac_kdc_sig.type;
    pac_wrapped_struct.SignatureLength = session_info->server_info->pac_kdc_sig.signature.length;
    pac_wrapped_struct.ChecksumAndSignature = payload
            = data_blob_talloc(tmp_ctx, NULL,
                               pac_wrapped_struct.ChecksumLength
                               + pac_wrapped_struct.SignatureLength);
    memcpy(&payload.data[0],
           session_info->server_info->pac_srv_sig.signature.data,
           pac_wrapped_struct.ChecksumLength);
    memcpy(&payload.data[pac_wrapped_struct.ChecksumLength],
           session_info->server_info->pac_kdc_sig.signature.data,
           pac_wrapped_struct.SignatureLength);

    ndr_err = ndr_push_struct_blob(&pac_wrapped, tmp_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_wrapped_struct,
                                   (ndr_push_flags_fn_t)ndr_push_PAC_Validate);
    torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_push_struct_blob of PACValidate structure failed");

    torture_assert(tctx, (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR), "not willing to even try a PACValidate without RC4 encryption");
    netlogon_creds_arcfour_crypt(creds, pac_wrapped.data, pac_wrapped.length);

    generic.length = pac_wrapped.length;
    generic.data = pac_wrapped.data;

    /* Validate it over the netlogon pipe */

    generic.identity_info.parameter_control = 0;
    generic.identity_info.logon_id_high = 0;
    generic.identity_info.logon_id_low = 0;
    generic.identity_info.domain_name.string = session_info->server_info->domain_name;
    generic.identity_info.account_name.string = session_info->server_info->account_name;
    generic.identity_info.workstation.string = TEST_MACHINE_NAME;

    generic.package_name.string = "Kerberos";

    logon.generic = &generic;

    ZERO_STRUCT(auth2);
    netlogon_creds_client_authenticator(creds, &auth);
    r.in.credential = &auth;
    r.in.return_authenticator = &auth2;
    r.in.logon = &logon;
    r.in.logon_level = NetlogonGenericInformation;
    r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
    r.in.computer_name = cli_credentials_get_workstation(credentials);
    r.in.validation_level = NetlogonValidationGenericInfo2;
    r.out.validation = &validation;
    r.out.authoritative = &authoritative;
    r.out.return_authenticator = &return_authenticator;

    status = dcerpc_netr_LogonSamLogon(p, tctx, &r);

    torture_assert_ntstatus_ok(tctx, status, "LogonSamLogon failed");

    /* This will break the signature nicely (even in the crypto wrapping), check we get a logon failure */
    generic.data[generic.length-1]++;

    logon.generic = &generic;

    ZERO_STRUCT(auth2);
    netlogon_creds_client_authenticator(creds, &auth);
    r.in.credential = &auth;
    r.in.return_authenticator = &auth2;
    r.in.logon_level = NetlogonGenericInformation;
    r.in.logon = &logon;
    r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
    r.in.computer_name = cli_credentials_get_workstation(credentials);
    r.in.validation_level = NetlogonValidationGenericInfo2;

    status = dcerpc_netr_LogonSamLogon(p, tctx, &r);

    torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOGON_FAILURE, "LogonSamLogon failed");

    torture_assert(tctx, netlogon_creds_client_check(creds, &r.out.return_authenticator->cred),
                   "Credential chaining failed");

    /* This will break the parsing nicely (even in the crypto wrapping), check we get INVALID_PARAMETER */
    generic.length--;

    logon.generic = &generic;

    ZERO_STRUCT(auth2);
    netlogon_creds_client_authenticator(creds, &auth);
    r.in.credential = &auth;
    r.in.return_authenticator = &auth2;
    r.in.logon_level = NetlogonGenericInformation;
    r.in.logon = &logon;
    r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
    r.in.computer_name = cli_credentials_get_workstation(credentials);
    r.in.validation_level = NetlogonValidationGenericInfo2;

    status = dcerpc_netr_LogonSamLogon(p, tctx, &r);

    torture_assert_ntstatus_equal(tctx, status, NT_STATUS_INVALID_PARAMETER, "LogonSamLogon failed");

    torture_assert(tctx, netlogon_creds_client_check(creds,
                   &r.out.return_authenticator->cred),
                   "Credential chaining failed");

    pac_wrapped_struct.ChecksumLength = session_info->server_info->pac_srv_sig.signature.length;
    pac_wrapped_struct.SignatureType = session_info->server_info->pac_kdc_sig.type;

    /* Break the SignatureType */
    pac_wrapped_struct.SignatureType++;

    pac_wrapped_struct.SignatureLength = session_info->server_info->pac_kdc_sig.signature.length;
    pac_wrapped_struct.ChecksumAndSignature = payload
            = data_blob_talloc(tmp_ctx, NULL,
                               pac_wrapped_struct.ChecksumLength
                               + pac_wrapped_struct.SignatureLength);
    memcpy(&payload.data[0],
           session_info->server_info->pac_srv_sig.signature.data,
           pac_wrapped_struct.ChecksumLength);
    memcpy(&payload.data[pac_wrapped_struct.ChecksumLength],
           session_info->server_info->pac_kdc_sig.signature.data,
           pac_wrapped_struct.SignatureLength);

    ndr_err = ndr_push_struct_blob(&pac_wrapped, tmp_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_wrapped_struct,
                                   (ndr_push_flags_fn_t)ndr_push_PAC_Validate);
    torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_push_struct_blob of PACValidate structure failed");

    torture_assert(tctx, (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR), "not willing to even try a PACValidate without RC4 encryption");
    netlogon_creds_arcfour_crypt(creds, pac_wrapped.data, pac_wrapped.length);

    generic.length = pac_wrapped.length;
    generic.data = pac_wrapped.data;

    logon.generic = &generic;

    ZERO_STRUCT(auth2);
    netlogon_creds_client_authenticator(creds, &auth);
    r.in.credential = &auth;
    r.in.return_authenticator = &auth2;
    r.in.logon_level = NetlogonGenericInformation;
    r.in.logon = &logon;
    r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
    r.in.computer_name = cli_credentials_get_workstation(credentials);
    r.in.validation_level = NetlogonValidationGenericInfo2;

    status = dcerpc_netr_LogonSamLogon(p, tctx, &r);

    torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOGON_FAILURE, "LogonSamLogon failed");

    torture_assert(tctx, netlogon_creds_client_check(creds, &r.out.return_authenticator->cred),
                   "Credential chaining failed");

    pac_wrapped_struct.ChecksumLength = session_info->server_info->pac_srv_sig.signature.length;
    pac_wrapped_struct.SignatureType = session_info->server_info->pac_kdc_sig.type;
    pac_wrapped_struct.SignatureLength = session_info->server_info->pac_kdc_sig.signature.length;

    pac_wrapped_struct.ChecksumAndSignature = payload
            = data_blob_talloc(tmp_ctx, NULL,
                               pac_wrapped_struct.ChecksumLength
                               + pac_wrapped_struct.SignatureLength);
    memcpy(&payload.data[0],
           session_info->server_info->pac_srv_sig.signature.data,
           pac_wrapped_struct.ChecksumLength);
    memcpy(&payload.data[pac_wrapped_struct.ChecksumLength],
           session_info->server_info->pac_kdc_sig.signature.data,
           pac_wrapped_struct.SignatureLength);

    /* Break the signature length */
    pac_wrapped_struct.SignatureLength++;

    ndr_err = ndr_push_struct_blob(&pac_wrapped, tmp_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_wrapped_struct,
                                   (ndr_push_flags_fn_t)ndr_push_PAC_Validate);
    torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_push_struct_blob of PACValidate structure failed");

    torture_assert(tctx, (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR), "not willing to even try a PACValidate without RC4 encryption");
    netlogon_creds_arcfour_crypt(creds, pac_wrapped.data, pac_wrapped.length);

    generic.length = pac_wrapped.length;
    generic.data = pac_wrapped.data;

    logon.generic = &generic;

    ZERO_STRUCT(auth2);
    netlogon_creds_client_authenticator(creds, &auth);
    r.in.credential = &auth;
    r.in.return_authenticator = &auth2;
    r.in.logon_level = NetlogonGenericInformation;
    r.in.logon = &logon;
    r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
    r.in.computer_name = cli_credentials_get_workstation(credentials);
    r.in.validation_level = NetlogonValidationGenericInfo2;

    status = dcerpc_netr_LogonSamLogon(p, tctx, &r);

    torture_assert_ntstatus_equal(tctx, status, NT_STATUS_INVALID_PARAMETER, "LogonSamLogon failed");

    torture_assert(tctx, netlogon_creds_client_check(creds, &r.out.return_authenticator->cred),
                   "Credential chaining failed");
    return true;
}
Beispiel #9
0
/*
  try a netlogon SamLogon
*/
BOOL test_netlogon_ex_ops(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
			  struct cli_credentials *credentials, 
			  struct creds_CredentialState *creds)
{
	NTSTATUS status;
	struct netr_LogonSamLogonEx r;
	struct netr_NetworkInfo ninfo;
	DATA_BLOB names_blob, chal, lm_resp, nt_resp;
	int i;
	BOOL ret = True;
	int flags = CLI_CRED_NTLM_AUTH;
	if (lp_client_lanman_auth()) {
		flags |= CLI_CRED_LANMAN_AUTH;
	}

	if (lp_client_ntlmv2_auth()) {
		flags |= CLI_CRED_NTLMv2_AUTH;
	}

	cli_credentials_get_ntlm_username_domain(cmdline_credentials, mem_ctx, 
						 &ninfo.identity_info.account_name.string,
						 &ninfo.identity_info.domain_name.string);
	
	generate_random_buffer(ninfo.challenge, 
			       sizeof(ninfo.challenge));
	chal = data_blob_const(ninfo.challenge, 
			       sizeof(ninfo.challenge));

	names_blob = NTLMv2_generate_names_blob(mem_ctx, cli_credentials_get_workstation(credentials), 
						cli_credentials_get_domain(credentials));

	status = cli_credentials_get_ntlm_response(cmdline_credentials, mem_ctx, 
						   &flags, 
						   chal,
						   names_blob,
						   &lm_resp, &nt_resp,
						   NULL, NULL);
	if (!NT_STATUS_IS_OK(status)) {
		printf("cli_credentials_get_ntlm_response failed: %s\n", 
		       nt_errstr(status));
		return False;
	}

	ninfo.lm.data = lm_resp.data;
	ninfo.lm.length = lm_resp.length;

	ninfo.nt.data = nt_resp.data;
	ninfo.nt.length = nt_resp.length;

	ninfo.identity_info.parameter_control = 0;
	ninfo.identity_info.logon_id_low = 0;
	ninfo.identity_info.logon_id_high = 0;
	ninfo.identity_info.workstation.string = cli_credentials_get_workstation(credentials);

	r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
	r.in.computer_name = cli_credentials_get_workstation(credentials);
	r.in.logon_level = 2;
	r.in.logon.network = &ninfo;
	r.in.flags = 0;

	printf("Testing LogonSamLogonEx with name %s\n", ninfo.identity_info.account_name.string);
	
	for (i=2;i<3;i++) {
		r.in.validation_level = i;
		
		status = dcerpc_netr_LogonSamLogonEx(p, mem_ctx, &r);
		if (!NT_STATUS_IS_OK(status)) {
			printf("LogonSamLogon failed: %s\n", 
			       nt_errstr(status));
			return False;
		}
	}

	return ret;
}
Beispiel #10
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;
}