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; }
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; }
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; }
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; }
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; }
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 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; }
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; }