Esempio n. 1
0
bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
                             const char *old_password)
{
	char param[1024];
	unsigned char data[532];
	char *p = param;
	unsigned char old_pw_hash[16];
	unsigned char new_pw_hash[16];
	unsigned int data_len;
	unsigned int param_len = 0;
	char *rparam = NULL;
	char *rdata = NULL;
	unsigned int rprcnt, rdrcnt;

	if (strlen(user) >= sizeof(fstring)-1) {
		DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
		return False;
	}

	SSVAL(p,0,214); /* SamOEMChangePassword command. */
	p += 2;
	strlcpy(p, "zsT", sizeof(param)-PTR_DIFF(p,param));
	p = skip_string(param,sizeof(param),p);
	strlcpy(p, "B516B16", sizeof(param)-PTR_DIFF(p,param));
	p = skip_string(param,sizeof(param),p);
	strlcpy(p,user, sizeof(param)-PTR_DIFF(p,param));
	p = skip_string(param,sizeof(param),p);
	SSVAL(p,0,532);
	p += 2;

	param_len = PTR_DIFF(p,param);

	/*
	 * Get the Lanman hash of the old password, we
	 * use this as the key to make_oem_passwd_hash().
	 */
	E_deshash(old_password, old_pw_hash);

	encode_pw_buffer(data, new_password, STR_ASCII);

#ifdef DEBUG_PASSWORD
	DEBUG(100,("make_oem_passwd_hash\n"));
	dump_data(100, data, 516);
#endif
	arcfour_crypt( (unsigned char *)data, (unsigned char *)old_pw_hash, 516);

	/*
	 * Now place the old password hash in the data.
	 */
	E_deshash(new_password, new_pw_hash);

	E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);

	data_len = 532;

	if (!cli_api(cli,
		     param, param_len, 4,		/* param, length, max */
		     (char *)data, data_len, 0,		/* data, length, max */
		     &rparam, &rprcnt,
		     &rdata, &rdrcnt)) {
		DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
			user ));
		return False;
	}

	if (rparam) {
		cli->rap_error = SVAL(rparam,0);
	}

	SAFE_FREE(rparam);
	SAFE_FREE(rdata);

	return (cli->rap_error == 0);
}
Esempio n. 2
0
static bool test_wbc_change_password(struct torture_context *tctx)
{
	wbcErr ret;
	const char *oldpass = getenv("PASSWORD");
	const char *newpass = "******";

	struct samr_CryptPassword new_nt_password;
	struct samr_CryptPassword new_lm_password;
	struct samr_Password old_nt_hash_enc;
	struct samr_Password old_lanman_hash_enc;

	uint8_t old_nt_hash[16];
	uint8_t old_lanman_hash[16];
	uint8_t new_nt_hash[16];
	uint8_t new_lanman_hash[16];

	struct wbcChangePasswordParams params;

	if (oldpass == NULL) {
		torture_skip(tctx,
			"skipping wbcChangeUserPassword test as old password cannot be retrieved\n");
	}

	ZERO_STRUCT(params);

	E_md4hash(oldpass, old_nt_hash);
	E_md4hash(newpass, new_nt_hash);

	if (lpcfg_client_lanman_auth(tctx->lp_ctx) &&
	    E_deshash(newpass, new_lanman_hash) &&
	    E_deshash(oldpass, old_lanman_hash)) {

		/* E_deshash returns false for 'long' passwords (> 14
		   DOS chars).  This allows us to match Win2k, which
		   does not store a LM hash for these passwords (which
		   would reduce the effective password length to 14) */

		encode_pw_buffer(new_lm_password.data, newpass, STR_UNICODE);
		arcfour_crypt(new_lm_password.data, old_nt_hash, 516);
		E_old_pw_hash(new_nt_hash, old_lanman_hash,
			      old_lanman_hash_enc.hash);

		params.old_password.response.old_lm_hash_enc_length =
			sizeof(old_lanman_hash_enc.hash);
		params.old_password.response.old_lm_hash_enc_data =
			old_lanman_hash_enc.hash;
		params.new_password.response.lm_length =
			sizeof(new_lm_password.data);
		params.new_password.response.lm_data =
			new_lm_password.data;
	} else {
		ZERO_STRUCT(new_lm_password);
		ZERO_STRUCT(old_lanman_hash_enc);
	}

	encode_pw_buffer(new_nt_password.data, newpass, STR_UNICODE);

	arcfour_crypt(new_nt_password.data, old_nt_hash, 516);
	E_old_pw_hash(new_nt_hash, old_nt_hash, old_nt_hash_enc.hash);

	params.old_password.response.old_nt_hash_enc_length =
		sizeof(old_nt_hash_enc.hash);
	params.old_password.response.old_nt_hash_enc_data =
		old_nt_hash_enc.hash;
	params.new_password.response.nt_length = sizeof(new_nt_password.data);
	params.new_password.response.nt_data = new_nt_password.data;

	params.level = WBC_CHANGE_PASSWORD_LEVEL_RESPONSE;
	params.account_name = getenv("USERNAME");
	params.domain_name = "SAMBA-TEST";

	ret = wbcChangeUserPasswordEx(&params, NULL, NULL, NULL);
	torture_assert_wbc_equal(tctx, ret, WBC_ERR_SUCCESS,
				 "wbcChangeUserPassword failed");

	if (!test_wbc_authenticate_user_int(tctx, "Koo8irei")) {
		return false;
	}

	ret = wbcChangeUserPassword(getenv("USERNAME"), "Koo8irei",
				    getenv("PASSWORD"));
	torture_assert_wbc_equal(tctx, ret, WBC_ERR_SUCCESS,
				 "wbcChangeUserPassword failed");

	return test_wbc_authenticate_user_int(tctx, getenv("PASSWORD"));
}
Esempio n. 3
0
bool make_user_info_netlogon_interactive(struct auth_usersupplied_info **user_info,
					 const char *smb_name, 
					 const char *client_domain, 
					 const char *workstation_name,
					 uint32 logon_parameters,
					 const uchar chal[8], 
					 const uchar lm_interactive_pwd[16], 
					 const uchar nt_interactive_pwd[16], 
					 const uchar *dc_sess_key)
{
	struct samr_Password lm_pwd;
	struct samr_Password nt_pwd;
	unsigned char local_lm_response[24];
	unsigned char local_nt_response[24];
	unsigned char key[16];

	memcpy(key, dc_sess_key, 16);

	if (lm_interactive_pwd)
		memcpy(lm_pwd.hash, lm_interactive_pwd, sizeof(lm_pwd.hash));

	if (nt_interactive_pwd)
		memcpy(nt_pwd.hash, nt_interactive_pwd, sizeof(nt_pwd.hash));

#ifdef DEBUG_PASSWORD
	DEBUG(100,("key:"));
	dump_data(100, key, sizeof(key));

	DEBUG(100,("lm owf password:"******"nt owf password:"******"decrypt of lm owf password:"******"decrypt of nt owf password:"));
	dump_data(100, nt_pwd.hash, sizeof(nt_pwd));
#endif

	if (lm_interactive_pwd)
		SMBOWFencrypt(lm_pwd.hash, chal,
			      local_lm_response);

	if (nt_interactive_pwd)
		SMBOWFencrypt(nt_pwd.hash, chal,
			      local_nt_response);

	/* Password info paranoia */
	ZERO_STRUCT(key);

	{
		bool ret;
		NTSTATUS nt_status;
		DATA_BLOB local_lm_blob;
		DATA_BLOB local_nt_blob;

		if (lm_interactive_pwd) {
			local_lm_blob = data_blob(local_lm_response,
						  sizeof(local_lm_response));
		}

		if (nt_interactive_pwd) {
			local_nt_blob = data_blob(local_nt_response,
						  sizeof(local_nt_response));
		}

		nt_status = make_user_info_map(
			user_info, 
			smb_name, client_domain, workstation_name,
			lm_interactive_pwd ? &local_lm_blob : NULL,
			nt_interactive_pwd ? &local_nt_blob : NULL,
			lm_interactive_pwd ? &lm_pwd : NULL,
			nt_interactive_pwd ? &nt_pwd : NULL,
			NULL, AUTH_PASSWORD_HASH);

		if (NT_STATUS_IS_OK(nt_status)) {
			(*user_info)->logon_parameters = logon_parameters;
		}

		ret = NT_STATUS_IS_OK(nt_status) ? True : False;
		data_blob_free(&local_lm_blob);
		data_blob_free(&local_nt_blob);
		return ret;
	}
}
Esempio n. 4
0
static void
test_arcfour(const struct tstring *key,
	     const struct tstring *cleartext,
	     const struct tstring *ciphertext)
{
  size_t block;
  struct arcfour_ctx ctx;

  uint8_t *data;
  size_t length;

  ASSERT (cleartext->length == ciphertext->length);
  length = cleartext->length;

  data = xalloc(length + 1);

  for (block = 1; block <= length; block++)
    {
      size_t i;

      memset(data, 0x17, length + 1);
      arcfour_set_key(&ctx, key->length, key->data);

      for (i = 0; i + block < length; i += block)
	{
	  arcfour_crypt(&ctx, block, data + i, cleartext->data + i);
	  ASSERT (data[i + block] == 0x17);
	}

      arcfour_crypt(&ctx, length - i, data + i, cleartext->data + i);
      ASSERT (data[length] == 0x17);

      if (!MEMEQ(length, data, ciphertext->data))
	{
	  fprintf(stderr, "Encrypt failed, block size %lu\nInput:",
		  (unsigned long) block);
	  tstring_print_hex(cleartext);
	  fprintf(stderr, "\nOutput: ");
	  print_hex(length, data);
	  fprintf(stderr, "\nExpected:");
	  tstring_print_hex(ciphertext);
	  fprintf(stderr, "\n");
	  FAIL();
	}
    }

  arcfour_set_key(&ctx, key->length, key->data);
  arcfour_crypt(&ctx, length, data, data);

  ASSERT (data[length] == 0x17);

  if (!MEMEQ(length, data, cleartext->data))
    {
      fprintf(stderr, "Decrypt failed\nInput:");
      tstring_print_hex(ciphertext);
      fprintf(stderr, "\nOutput: ");
      print_hex(length, data);
      fprintf(stderr, "\nExpected:");
      tstring_print_hex(cleartext);
      fprintf(stderr, "\n");
      FAIL();
    }

  free(data);
}
Esempio n. 5
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;
}
Esempio n. 6
0
/*
 * do a password change using DCERPC/SAMR calls
 * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
 * 2. try samr_ChangePasswordUser3
 * 3. try samr_ChangePasswordUser2
 * 4. try samr_OemChangePasswordUser2
 * (not yet: 5. try samr_ChangePasswordUser)
 */
static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
{
        NTSTATUS status;
	struct libnet_RpcConnect c;
#if 0
	struct policy_handle user_handle;
	struct samr_Password hash1, hash2, hash3, hash4, hash5, hash6;
	struct samr_ChangePasswordUser pw;
#endif
	struct samr_OemChangePasswordUser2 oe2;
	struct samr_ChangePasswordUser2 pw2;
	struct samr_ChangePasswordUser3 pw3;
	struct lsa_String server, account;
	struct lsa_AsciiString a_server, a_account;
	struct samr_CryptPassword nt_pass, lm_pass;
	struct samr_Password nt_verifier, lm_verifier;
	uint8_t old_nt_hash[16], new_nt_hash[16];
	uint8_t old_lm_hash[16], new_lm_hash[16];
	struct samr_DomInfo1 *dominfo = NULL;
	struct userPwdChangeFailureInformation *reject = NULL;

	ZERO_STRUCT(c);

	/* prepare connect to the SAMR pipe of the users domain PDC */
	c.level                    = LIBNET_RPC_CONNECT_PDC;
	c.in.name                  = r->samr.in.domain_name;
	c.in.dcerpc_iface     	   = &ndr_table_samr;
	c.in.dcerpc_flags          = DCERPC_ANON_FALLBACK;

	/* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
	status = libnet_RpcConnect(ctx, mem_ctx, &c);
	if (!NT_STATUS_IS_OK(status)) {
		r->samr.out.error_string = talloc_asprintf(mem_ctx,
						"Connection to SAMR pipe of PDC of domain '%s' failed: %s",
						r->samr.in.domain_name, nt_errstr(status));
		return status;
	}

	/* prepare password change for account */
	server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.out.dcerpc_pipe));
	account.string = r->samr.in.account_name;

	E_md4hash(r->samr.in.oldpassword, old_nt_hash);
	E_md4hash(r->samr.in.newpassword, new_nt_hash);

	E_deshash(r->samr.in.oldpassword, old_lm_hash);
	E_deshash(r->samr.in.newpassword, new_lm_hash);

	/* prepare samr_ChangePasswordUser3 */
	encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_UNICODE);
	arcfour_crypt(lm_pass.data, old_nt_hash, 516);
	E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);

	encode_pw_buffer(nt_pass.data,  r->samr.in.newpassword, STR_UNICODE);
	arcfour_crypt(nt_pass.data, old_nt_hash, 516);
	E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);

	pw3.in.server = &server;
	pw3.in.account = &account;
	pw3.in.nt_password = &nt_pass;
	pw3.in.nt_verifier = &nt_verifier;
	pw3.in.lm_change = 1;
	pw3.in.lm_password = &lm_pass;
	pw3.in.lm_verifier = &lm_verifier;
	pw3.in.password3 = NULL;
	pw3.out.dominfo = &dominfo;
	pw3.out.reject = &reject;

	/* 2. try samr_ChangePasswordUser3 */
	status = dcerpc_samr_ChangePasswordUser3(c.out.dcerpc_pipe, mem_ctx, &pw3);
	if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
		if (!NT_STATUS_IS_OK(status)) {
			r->samr.out.error_string = talloc_asprintf(mem_ctx,
								   "samr_ChangePasswordUser3 failed: %s",
								   nt_errstr(status));
			r->samr.out.error_string = talloc_asprintf(mem_ctx,
								   "samr_ChangePasswordUser3 for '%s\\%s' failed: %s",
								   r->samr.in.domain_name, r->samr.in.account_name, 
								   nt_errstr(status));
		}
		goto disconnect;
	} 

	/* prepare samr_ChangePasswordUser2 */
	encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII|STR_TERMINATE);
	arcfour_crypt(lm_pass.data, old_lm_hash, 516);
	E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);

	encode_pw_buffer(nt_pass.data, r->samr.in.newpassword, STR_UNICODE);
	arcfour_crypt(nt_pass.data, old_nt_hash, 516);
	E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);

	pw2.in.server = &server;
	pw2.in.account = &account;
	pw2.in.nt_password = &nt_pass;
	pw2.in.nt_verifier = &nt_verifier;
	pw2.in.lm_change = 1;
	pw2.in.lm_password = &lm_pass;
	pw2.in.lm_verifier = &lm_verifier;

	/* 3. try samr_ChangePasswordUser2 */
	status = dcerpc_samr_ChangePasswordUser2(c.out.dcerpc_pipe, mem_ctx, &pw2);
	if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
		if (!NT_STATUS_IS_OK(status)) {
			r->samr.out.error_string = talloc_asprintf(mem_ctx,
								   "samr_ChangePasswordUser2 for '%s\\%s' failed: %s",
								   r->samr.in.domain_name, r->samr.in.account_name, 
								   nt_errstr(status));
		}
		goto disconnect;
	}


	/* prepare samr_OemChangePasswordUser2 */
	a_server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.out.dcerpc_pipe));
	a_account.string = r->samr.in.account_name;

	encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII);
	arcfour_crypt(lm_pass.data, old_lm_hash, 516);
	E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);

	oe2.in.server = &a_server;
	oe2.in.account = &a_account;
	oe2.in.password = &lm_pass;
	oe2.in.hash = &lm_verifier;

	/* 4. try samr_OemChangePasswordUser2 */
	status = dcerpc_samr_OemChangePasswordUser2(c.out.dcerpc_pipe, mem_ctx, &oe2);
	if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
		if (!NT_STATUS_IS_OK(oe2.out.result)) {
			r->samr.out.error_string = talloc_asprintf(mem_ctx,
								   "samr_OemChangePasswordUser2 for '%s\\%s' failed: %s",
								   r->samr.in.domain_name, r->samr.in.account_name, 
								   nt_errstr(status));
		}
		goto disconnect;
	}

#if 0
	/* prepare samr_ChangePasswordUser */
	E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash);
	E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash);
	E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash);
	E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash);
	E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash);
	E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash);

	/* TODO: ask for a user_handle */
	pw.in.handle = &user_handle;
	pw.in.lm_present = 1;
	pw.in.old_lm_crypted = &hash1;
	pw.in.new_lm_crypted = &hash2;
	pw.in.nt_present = 1;
	pw.in.old_nt_crypted = &hash3;
	pw.in.new_nt_crypted = &hash4;
	pw.in.cross1_present = 1;
	pw.in.nt_cross = &hash5;
	pw.in.cross2_present = 1;
	pw.in.lm_cross = &hash6;

	/* 5. try samr_ChangePasswordUser */
	status = dcerpc_samr_ChangePasswordUser(c.pdc.out.dcerpc_pipe, mem_ctx, &pw);
	if (!NT_STATUS_IS_OK(status)) {
		r->samr.out.error_string = talloc_asprintf(mem_ctx,
						"samr_ChangePasswordUser failed: %s",
						nt_errstr(status));
		goto disconnect;
	}

	/* check result of samr_ChangePasswordUser */
	if (!NT_STATUS_IS_OK(pw.out.result)) {
		r->samr.out.error_string = talloc_asprintf(mem_ctx,
						"samr_ChangePasswordUser for '%s\\%s' failed: %s",
						r->samr.in.domain_name, r->samr.in.account_name, 
						nt_errstr(pw.out.result));
		if (NT_STATUS_EQUAL(pw.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
			status = pw.out.result;
			goto disconnect;
		}
		goto disconnect;
	}
#endif
disconnect:
	/* close connection */
	talloc_free(c.out.dcerpc_pipe);

	return status;
}
Esempio n. 7
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->chal = challenge_blob;
	ntlmssp_state->lm_resp = lm_response;
	talloc_steal(ntlmssp_state->lm_resp.data, lm_response.data);
	ntlmssp_state->nt_resp = nt_response;
	talloc_steal(ntlmssp_state->nt_resp.data, nt_response.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;
}