Beispiel #1
0
static NTSTATUS cmd_netlogon_capabilities(struct rpc_pipe_client *cli,
					  TALLOC_CTX *mem_ctx, int argc,
					  const char **argv)
{
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
	NTSTATUS result;
	struct netr_Authenticator credential;
	struct netr_Authenticator return_authenticator;
	union netr_Capabilities capabilities;
	uint32_t level = 1;
	struct dcerpc_binding_handle *b = cli->binding_handle;

	if (argc > 2) {
		fprintf(stderr, "Usage: %s <level>\n", argv[0]);
		return NT_STATUS_OK;
	}

	if (argc == 2) {
		level = atoi(argv[1]);
	}

	ZERO_STRUCT(return_authenticator);

	netlogon_creds_client_authenticator(cli->dc, &credential);

	status = dcerpc_netr_LogonGetCapabilities(b, mem_ctx,
						  cli->desthost,
						  lp_netbios_name(),
						  &credential,
						  &return_authenticator,
						  level,
						  &capabilities,
						  &result);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	if (!netlogon_creds_client_check(cli->dc,
					 &return_authenticator.cred)) {
		DEBUG(0,("credentials chain check failed\n"));
		return NT_STATUS_ACCESS_DENIED;
	}

	printf("capabilities: 0x%08x\n", capabilities.server_capabilities);

	return result;
}
Beispiel #2
0
static NTSTATUS cmd_netlogon_sam_deltas(struct rpc_pipe_client *cli,
					TALLOC_CTX *mem_ctx, int argc,
					const char **argv)
{
	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
	NTSTATUS status;
	uint32_t tmp;
	const char *logon_server = cli->desthost;
	const char *computername = lp_netbios_name();
	struct netr_Authenticator credential;
	struct netr_Authenticator return_authenticator;
	enum netr_SamDatabaseID database_id = SAM_DATABASE_DOMAIN;
	uint64_t sequence_num;
	struct dcerpc_binding_handle *b = cli->binding_handle;

	if (argc != 3) {
		fprintf(stderr, "Usage: %s database_id seqnum\n", argv[0]);
		return NT_STATUS_OK;
	}

	database_id = atoi(argv[1]);
	tmp = atoi(argv[2]);

	sequence_num = tmp & 0xffff;

	do {
		struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
		struct netlogon_creds_CredentialState *creds = NULL;

		if (rpcclient_netlogon_creds == NULL) {
			return NT_STATUS_UNSUCCESSFUL;
		}

		status = netlogon_creds_cli_lock(rpcclient_netlogon_creds,
						 mem_ctx, &creds);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}

		netlogon_creds_client_authenticator(creds, &credential);

		status = dcerpc_netr_DatabaseDeltas(b, mem_ctx,
						    logon_server,
						    computername,
						    &credential,
						    &return_authenticator,
						    database_id,
						    &sequence_num,
						    &delta_enum_array,
						    0xffff,
						    &result);
		if (!NT_STATUS_IS_OK(status)) {
			TALLOC_FREE(creds);
			return status;
		}

		/* Check returned credentials. */
		if (!netlogon_creds_client_check(creds,
						 &return_authenticator.cred)) {
			DEBUG(0,("credentials chain check failed\n"));
			TALLOC_FREE(creds);
			return NT_STATUS_ACCESS_DENIED;
		}
		TALLOC_FREE(creds);

		if (NT_STATUS_IS_ERR(result)) {
			break;
		}

		/* Display results */

		display_sam_sync(delta_enum_array);

		TALLOC_FREE(delta_enum_array);

	} while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));

        return result;
}
Beispiel #3
0
static NTSTATUS cmd_netlogon_database_redo(struct rpc_pipe_client *cli,
					   TALLOC_CTX *mem_ctx, int argc,
					   const char **argv)
{
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
	NTSTATUS result;
	const char *server_name = cli->desthost;
	struct netr_Authenticator clnt_creds, srv_cred;
	struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
	struct netr_ChangeLogEntry e;
	uint32_t rid = 500;
	struct dcerpc_binding_handle *b = cli->binding_handle;
	struct netlogon_creds_CredentialState *creds = NULL;

	if (argc > 2) {
		fprintf(stderr, "Usage: %s <user rid>\n", argv[0]);
		return NT_STATUS_OK;
	}

	if (argc == 2) {
		sscanf(argv[1], "%d", &rid);
	}

	if (rpcclient_netlogon_creds == NULL) {
		return NT_STATUS_UNSUCCESSFUL;
	}

	status = netlogon_creds_cli_lock(rpcclient_netlogon_creds,
					 mem_ctx, &creds);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	netlogon_creds_client_authenticator(creds, &clnt_creds);

	ZERO_STRUCT(e);

	e.object_rid		= rid;
	e.db_index		= SAM_DATABASE_DOMAIN;
	e.delta_type		= NETR_DELTA_USER;

	status = dcerpc_netr_DatabaseRedo(b, mem_ctx,
					  server_name,
					  lp_netbios_name(),
					  &clnt_creds,
					  &srv_cred,
					  e,
					  0, /* is calculated automatically */
					  &delta_enum_array,
					  &result);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(creds);
		return status;
	}

	if (!netlogon_creds_client_check(creds, &srv_cred.cred)) {
		DEBUG(0,("credentials chain check failed\n"));
		TALLOC_FREE(creds);
		return NT_STATUS_ACCESS_DENIED;
	}
	TALLOC_FREE(creds);

	return result;
}
Beispiel #4
0
static NTSTATUS libnet_samsync_delta(TALLOC_CTX *mem_ctx,
				     enum netr_SamDatabaseID database_id,
				     uint64_t *sequence_num,
				     struct samsync_context *ctx,
				     struct netr_ChangeLogEntry *e)
{
	NTSTATUS result;
	NTSTATUS callback_status;
	const char *logon_server = ctx->cli->desthost;
	const char *computername = global_myname();
	struct netr_Authenticator credential;
	struct netr_Authenticator return_authenticator;
	uint16_t restart_state = 0;
	uint32_t sync_context = 0;

	ZERO_STRUCT(return_authenticator);

	do {
		struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;

		netlogon_creds_client_authenticator(ctx->cli->dc, &credential);

		if (ctx->single_object_replication &&
		    !ctx->force_full_replication) {
			result = rpccli_netr_DatabaseRedo(ctx->cli, mem_ctx,
							  logon_server,
							  computername,
							  &credential,
							  &return_authenticator,
							  *e,
							  0,
							  &delta_enum_array);
		} else if (!ctx->force_full_replication &&
		           sequence_num && (*sequence_num > 0)) {
			result = rpccli_netr_DatabaseDeltas(ctx->cli, mem_ctx,
							    logon_server,
							    computername,
							    &credential,
							    &return_authenticator,
							    database_id,
							    sequence_num,
							    &delta_enum_array,
							    0xffff);
		} else {
			result = rpccli_netr_DatabaseSync2(ctx->cli, mem_ctx,
							   logon_server,
							   computername,
							   &credential,
							   &return_authenticator,
							   database_id,
							   restart_state,
							   &sync_context,
							   &delta_enum_array,
							   0xffff);
		}

		if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) {
			return result;
		}

		/* Check returned credentials. */
		if (!netlogon_creds_client_check(ctx->cli->dc,
						 &return_authenticator.cred)) {
			DEBUG(0,("credentials chain check failed\n"));
			return NT_STATUS_ACCESS_DENIED;
		}

		if (NT_STATUS_IS_ERR(result)) {
			break;
		}

		samsync_fix_delta_array(mem_ctx,
					ctx->cli->dc,
					database_id,
					delta_enum_array);

		/* Process results */
		callback_status = ctx->ops->process_objects(mem_ctx, database_id,
							    delta_enum_array,
							    sequence_num,
							    ctx);
		if (!NT_STATUS_IS_OK(callback_status)) {
			result = callback_status;
			goto out;
		}

		TALLOC_FREE(delta_enum_array);

	} while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));

 out:

	return result;
}
Beispiel #5
0
static NTSTATUS cmd_netlogon_sam_sync(struct rpc_pipe_client *cli,
                                      TALLOC_CTX *mem_ctx, int argc,
                                      const char **argv)
{
	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
	NTSTATUS status;
	const char *logon_server = cli->desthost;
	const char *computername = lp_netbios_name();
	struct netr_Authenticator credential;
	struct netr_Authenticator return_authenticator;
	enum netr_SamDatabaseID database_id = SAM_DATABASE_DOMAIN;
	uint16_t restart_state = 0;
	uint32_t sync_context = 0;
	struct dcerpc_binding_handle *b = cli->binding_handle;

        if (argc > 2) {
                fprintf(stderr, "Usage: %s [database_id]\n", argv[0]);
                return NT_STATUS_OK;
        }

	if (argc == 2) {
		database_id = atoi(argv[1]);
	}

	/* Synchronise sam database */

	do {
		struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;

		netlogon_creds_client_authenticator(cli->dc, &credential);

		status = dcerpc_netr_DatabaseSync2(b, mem_ctx,
						   logon_server,
						   computername,
						   &credential,
						   &return_authenticator,
						   database_id,
						   restart_state,
						   &sync_context,
						   &delta_enum_array,
						   0xffff,
						   &result);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}

		/* Check returned credentials. */
		if (!netlogon_creds_client_check(cli->dc,
						 &return_authenticator.cred)) {
			DEBUG(0,("credentials chain check failed\n"));
			return NT_STATUS_ACCESS_DENIED;
		}

		if (NT_STATUS_IS_ERR(result)) {
			break;
		}

		/* Display results */

		display_sam_sync(delta_enum_array);

		TALLOC_FREE(delta_enum_array);

	} while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));

	return result;
}
Beispiel #6
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;
}
Beispiel #7
0
static NTSTATUS cmd_netlogon_database_redo(struct rpc_pipe_client *cli,
					   TALLOC_CTX *mem_ctx, int argc,
					   const char **argv)
{
	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
	NTSTATUS result;
	const char *server_name = cli->desthost;
	uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
	struct netr_Authenticator clnt_creds, srv_cred;
	struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
	unsigned char trust_passwd_hash[16];
	enum netr_SchannelType sec_channel_type = 0;
	struct netr_ChangeLogEntry e;
	uint32_t rid = 500;
	struct dcerpc_binding_handle *b = cli->binding_handle;

	if (argc > 2) {
		fprintf(stderr, "Usage: %s <user rid>\n", argv[0]);
		return NT_STATUS_OK;
	}

	if (argc == 2) {
		sscanf(argv[1], "%d", &rid);
	}

	if (!secrets_fetch_trust_account_password(lp_workgroup(),
						  trust_passwd_hash,
						  NULL, &sec_channel_type)) {
		return NT_STATUS_UNSUCCESSFUL;
	}

	status = rpccli_netlogon_setup_creds(cli,
					     server_name, /* server name */
					     lp_workgroup(), /* domain */
					     lp_netbios_name(), /* client name */
					     lp_netbios_name(), /* machine account name */
					     trust_passwd_hash,
					     sec_channel_type,
					     &neg_flags);

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

	netlogon_creds_client_authenticator(cli->dc, &clnt_creds);

	ZERO_STRUCT(e);

	e.object_rid		= rid;
	e.db_index		= SAM_DATABASE_DOMAIN;
	e.delta_type		= NETR_DELTA_USER;

	status = dcerpc_netr_DatabaseRedo(b, mem_ctx,
					  server_name,
					  lp_netbios_name(),
					  &clnt_creds,
					  &srv_cred,
					  e,
					  0, /* is calculated automatically */
					  &delta_enum_array,
					  &result);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
		DEBUG(0,("credentials chain check failed\n"));
		return NT_STATUS_ACCESS_DENIED;
	}

	return result;
}
NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli,
					    TALLOC_CTX *mem_ctx,
					    const char *account_name,
					    const unsigned char orig_trust_passwd_hash[16],
					    const char *new_trust_pwd_cleartext,
					    const unsigned char new_trust_passwd_hash[16],
					    enum netr_SchannelType sec_channel_type)
{
	NTSTATUS result, status;
	struct netr_Authenticator clnt_creds, srv_cred;
	struct dcerpc_binding_handle *b = cli->binding_handle;

	if (!cli->dc) {
		uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
		result = rpccli_netlogon_setup_creds(cli,
						     cli->desthost, /* server name */
						     lp_workgroup(), /* domain */
						     lp_netbios_name(), /* client name */
						     account_name, /* machine account name */
						     orig_trust_passwd_hash,
						     sec_channel_type,
						     &neg_flags);
		if (!NT_STATUS_IS_OK(result)) {
			DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n",
				 nt_errstr(result)));
			return result;
		}
	}

	netlogon_creds_client_authenticator(cli->dc, &clnt_creds);

	if (cli->dc->negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {

		struct netr_CryptPassword new_password;
		uint32_t old_timeout;

		init_netr_CryptPassword(new_trust_pwd_cleartext,
					cli->dc,
					&new_password);

		old_timeout = dcerpc_binding_handle_set_timeout(b, 600000);

		status = dcerpc_netr_ServerPasswordSet2(b, mem_ctx,
							cli->srv_name_slash,
							cli->dc->account_name,
							sec_channel_type,
							cli->dc->computer_name,
							&clnt_creds,
							&srv_cred,
							&new_password,
							&result);

		dcerpc_binding_handle_set_timeout(b, old_timeout);

		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(0,("dcerpc_netr_ServerPasswordSet2 failed: %s\n",
				nt_errstr(status)));
			return status;
		}
	} else {

		struct samr_Password new_password;
		uint32_t old_timeout;

		memcpy(new_password.hash, new_trust_passwd_hash, sizeof(new_password.hash));
		netlogon_creds_des_encrypt(cli->dc, &new_password);

		old_timeout = dcerpc_binding_handle_set_timeout(b, 600000);

		status = dcerpc_netr_ServerPasswordSet(b, mem_ctx,
						       cli->srv_name_slash,
						       cli->dc->account_name,
						       sec_channel_type,
						       cli->dc->computer_name,
						       &clnt_creds,
						       &srv_cred,
						       &new_password,
						       &result);

		dcerpc_binding_handle_set_timeout(b, old_timeout);

		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(0,("dcerpc_netr_ServerPasswordSet failed: %s\n",
				nt_errstr(status)));
			return status;
		}
	}

	/* Always check returned credentials. */
	if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
		DEBUG(0,("credentials chain check failed\n"));
		return NT_STATUS_ACCESS_DENIED;
	}

	if (!NT_STATUS_IS_OK(result)) {
		DEBUG(0,("dcerpc_netr_ServerPasswordSet{2} failed: %s\n",
			nt_errstr(result)));
		return result;
	}

	return result;
}
NTSTATUS rpccli_netlogon_setup_creds(struct rpc_pipe_client *cli,
				     const char *server_name,
				     const char *domain,
				     const char *clnt_name,
				     const char *machine_account,
				     const unsigned char machine_pwd[16],
				     enum netr_SchannelType sec_chan_type,
				     uint32_t *neg_flags_inout)
{
	NTSTATUS status;
	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
	struct netr_Credential clnt_chal_send;
	struct netr_Credential srv_chal_recv;
	struct samr_Password password;
	bool retried = false;
	fstring mach_acct;
	uint32_t neg_flags = *neg_flags_inout;
	struct dcerpc_binding_handle *b = cli->binding_handle;

	if (!ndr_syntax_id_equal(&cli->abstract_syntax,
				 &ndr_table_netlogon.syntax_id)) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	TALLOC_FREE(cli->dc);

	/* Store the machine account password we're going to use. */
	memcpy(password.hash, machine_pwd, 16);

	fstr_sprintf( mach_acct, "%s$", machine_account);

 again:
	/* Create the client challenge. */
	generate_random_buffer(clnt_chal_send.data, 8);

	/* Get the server challenge. */
	status = dcerpc_netr_ServerReqChallenge(b, talloc_tos(),
						cli->srv_name_slash,
						clnt_name,
						&clnt_chal_send,
						&srv_chal_recv,
						&result);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}
	if (!NT_STATUS_IS_OK(result)) {
		return result;
	}

	/* Calculate the session key and client credentials */

	cli->dc = netlogon_creds_client_init(cli,
				    mach_acct,
				    clnt_name,
				    &clnt_chal_send,
				    &srv_chal_recv,
				    &password,
				    &clnt_chal_send,
				    neg_flags);

	if (!cli->dc) {
		return NT_STATUS_NO_MEMORY;
	}

	/*
	 * Send client auth-2 challenge and receive server repy.
	 */

	status = dcerpc_netr_ServerAuthenticate2(b, talloc_tos(),
						 cli->srv_name_slash,
						 cli->dc->account_name,
						 sec_chan_type,
						 cli->dc->computer_name,
						 &clnt_chal_send, /* input. */
						 &srv_chal_recv, /* output. */
						 &neg_flags,
						 &result);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}
	/* we might be talking to NT4, so let's downgrade in that case and retry
	 * with the returned neg_flags - gd */

	if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) {
		retried = true;
		TALLOC_FREE(cli->dc);
		goto again;
	}

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

	/*
	 * Check the returned value using the initial
	 * server received challenge.
	 */

	if (!netlogon_creds_client_check(cli->dc, &srv_chal_recv)) {
		/*
		 * Server replied with bad credential. Fail.
		 */
		DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
			"replied with bad credential\n",
			cli->desthost ));
		return NT_STATUS_ACCESS_DENIED;
	}

	DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
		"chain established.\n",
		cli->desthost ));

	cli->dc->negotiate_flags = neg_flags;
	*neg_flags_inout = neg_flags;

	return NT_STATUS_OK;
}
NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
					   TALLOC_CTX *mem_ctx,
					   uint32 logon_parameters,
					   const char *server,
					   const char *username,
					   const char *domain,
					   const char *workstation,
					   const uint8 chal[8],
					   uint16_t validation_level,
					   DATA_BLOB lm_response,
					   DATA_BLOB nt_response,
					   struct netr_SamInfo3 **info3)
{
	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
	NTSTATUS status;
	const char *workstation_name_slash;
	const char *server_name_slash;
	struct netr_Authenticator clnt_creds;
	struct netr_Authenticator ret_creds;
	union netr_LogonLevel *logon = NULL;
	struct netr_NetworkInfo *network_info;
	uint8_t authoritative;
	union netr_Validation validation;
	struct netr_ChallengeResponse lm;
	struct netr_ChallengeResponse nt;
	struct dcerpc_binding_handle *b = cli->binding_handle;

	*info3 = NULL;

	ZERO_STRUCT(ret_creds);

	ZERO_STRUCT(lm);
	ZERO_STRUCT(nt);

	logon = talloc_zero(mem_ctx, union netr_LogonLevel);
	if (!logon) {
		return NT_STATUS_NO_MEMORY;
	}

	network_info = talloc_zero(mem_ctx, struct netr_NetworkInfo);
	if (!network_info) {
		return NT_STATUS_NO_MEMORY;
	}

	netlogon_creds_client_authenticator(cli->dc, &clnt_creds);

	if (server[0] != '\\' && server[1] != '\\') {
		server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
	} else {
		server_name_slash = server;
	}

	if (workstation[0] != '\\' && workstation[1] != '\\') {
		workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
	} else {
		workstation_name_slash = workstation;
	}

	if (!workstation_name_slash || !server_name_slash) {
		DEBUG(0, ("talloc_asprintf failed!\n"));
		return NT_STATUS_NO_MEMORY;
	}

	/* Initialise input parameters */

	lm.data = lm_response.data;
	lm.length = lm_response.length;
	nt.data = nt_response.data;
	nt.length = nt_response.length;

	network_info->identity_info.domain_name.string		= domain;
	network_info->identity_info.parameter_control		= logon_parameters;
	network_info->identity_info.logon_id_low		= 0xdead;
	network_info->identity_info.logon_id_high		= 0xbeef;
	network_info->identity_info.account_name.string		= username;
	network_info->identity_info.workstation.string		= workstation_name_slash;

	memcpy(network_info->challenge, chal, 8);
	network_info->nt = nt;
	network_info->lm = lm;

	logon->network = network_info;

	/* Marshall data and send request */

	status = dcerpc_netr_LogonSamLogon(b, mem_ctx,
					   server_name_slash,
					   lp_netbios_name(),
					   &clnt_creds,
					   &ret_creds,
					   NetlogonNetworkInformation,
					   logon,
					   validation_level,
					   &validation,
					   &authoritative,
					   &result);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	/* Always check returned credentials. */
	if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
		DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
		return NT_STATUS_ACCESS_DENIED;
	}

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

	netlogon_creds_decrypt_samlogon_validation(cli->dc, validation_level,
						   &validation);

	result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
	if (!NT_STATUS_IS_OK(result)) {
		return result;
	}

	return result;
}
NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
				   TALLOC_CTX *mem_ctx,
				   uint32 logon_parameters,
				   const char *domain,
				   const char *username,
				   const char *password,
				   const char *workstation,
				   uint16_t validation_level,
				   int logon_type)
{
	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
	NTSTATUS status;
	struct netr_Authenticator clnt_creds;
	struct netr_Authenticator ret_creds;
	union netr_LogonLevel *logon;
	union netr_Validation validation;
	uint8_t authoritative;
	fstring clnt_name_slash;
	struct dcerpc_binding_handle *b = cli->binding_handle;

	ZERO_STRUCT(ret_creds);

	logon = talloc_zero(mem_ctx, union netr_LogonLevel);
	if (!logon) {
		return NT_STATUS_NO_MEMORY;
	}

	if (workstation) {
		fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
	} else {
		fstr_sprintf( clnt_name_slash, "\\\\%s", lp_netbios_name() );
	}

	/* Initialise input parameters */

	netlogon_creds_client_authenticator(cli->dc, &clnt_creds);

	switch (logon_type) {
	case NetlogonInteractiveInformation: {

		struct netr_PasswordInfo *password_info;

		struct samr_Password lmpassword;
		struct samr_Password ntpassword;

		password_info = talloc_zero(mem_ctx, struct netr_PasswordInfo);
		if (!password_info) {
			return NT_STATUS_NO_MEMORY;
		}

		nt_lm_owf_gen(password, ntpassword.hash, lmpassword.hash);

		if (cli->dc->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
			netlogon_creds_aes_encrypt(cli->dc, lmpassword.hash, 16);
			netlogon_creds_aes_encrypt(cli->dc, ntpassword.hash, 16);
		} else if (cli->dc->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
			netlogon_creds_arcfour_crypt(cli->dc, lmpassword.hash, 16);
			netlogon_creds_arcfour_crypt(cli->dc, ntpassword.hash, 16);
		} else {
			netlogon_creds_des_encrypt(cli->dc, &lmpassword);
			netlogon_creds_des_encrypt(cli->dc, &ntpassword);
		}

		password_info->identity_info.domain_name.string		= domain;
		password_info->identity_info.parameter_control		= logon_parameters;
		password_info->identity_info.logon_id_low		= 0xdead;
		password_info->identity_info.logon_id_high		= 0xbeef;
		password_info->identity_info.account_name.string	= username;
		password_info->identity_info.workstation.string		= clnt_name_slash;

		password_info->lmpassword = lmpassword;
		password_info->ntpassword = ntpassword;

		logon->password = password_info;

		break;
	}
	case NetlogonNetworkInformation: {
		struct netr_NetworkInfo *network_info;
		uint8 chal[8];
		unsigned char local_lm_response[24];
		unsigned char local_nt_response[24];
		struct netr_ChallengeResponse lm;
		struct netr_ChallengeResponse nt;

		ZERO_STRUCT(lm);
		ZERO_STRUCT(nt);

		network_info = talloc_zero(mem_ctx, struct netr_NetworkInfo);
		if (!network_info) {
			return NT_STATUS_NO_MEMORY;
		}

		generate_random_buffer(chal, 8);

		SMBencrypt(password, chal, local_lm_response);
		SMBNTencrypt(password, chal, local_nt_response);

		lm.length = 24;
		lm.data = local_lm_response;

		nt.length = 24;
		nt.data = local_nt_response;

		network_info->identity_info.domain_name.string		= domain;
		network_info->identity_info.parameter_control		= logon_parameters;
		network_info->identity_info.logon_id_low		= 0xdead;
		network_info->identity_info.logon_id_high		= 0xbeef;
		network_info->identity_info.account_name.string		= username;
		network_info->identity_info.workstation.string		= clnt_name_slash;

		memcpy(network_info->challenge, chal, 8);
		network_info->nt = nt;
		network_info->lm = lm;

		logon->network = network_info;

		break;
	}
	default:
		DEBUG(0, ("switch value %d not supported\n",
			logon_type));
		return NT_STATUS_INVALID_INFO_CLASS;
	}

	status = dcerpc_netr_LogonSamLogon(b, mem_ctx,
					   cli->srv_name_slash,
					   lp_netbios_name(),
					   &clnt_creds,
					   &ret_creds,
					   logon_type,
					   logon,
					   validation_level,
					   &validation,
					   &authoritative,
					   &result);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	/* Always check returned credentials */
	if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
		DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
		return NT_STATUS_ACCESS_DENIED;
	}

	return result;
}
Beispiel #12
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;
}