NTSTATUS rpccli_connect_netlogon( struct cli_state *cli, enum dcerpc_transport_t transport, struct netlogon_creds_cli_context *creds_ctx, bool force_reauth, struct cli_credentials *trust_creds, struct rpc_pipe_client **_rpccli) { TALLOC_CTX *frame = talloc_stackframe(); struct netlogon_creds_CredentialState *creds = NULL; enum netlogon_creds_cli_lck_type lck_type; enum netr_SchannelType sec_chan_type; struct netlogon_creds_cli_lck *lck = NULL; uint32_t negotiate_flags; uint8_t found_session_key[16] = {0}; bool found_existing_creds = false; bool do_serverauth; struct rpc_pipe_client *rpccli; NTSTATUS status; bool retry = false; sec_chan_type = cli_credentials_get_secure_channel_type(trust_creds); if (sec_chan_type == SEC_CHAN_NULL) { DBG_ERR("secure_channel_type gave SEC_CHAN_NULL\n"); status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; goto fail; } again: /* * See whether we can use existing netlogon_creds or * whether we have to serverauthenticate. */ status = netlogon_creds_cli_get(creds_ctx, frame, &creds); if (NT_STATUS_IS_OK(status)) { int cmp = memcmp(found_session_key, creds->session_key, sizeof(found_session_key)); found_existing_creds = (cmp != 0); memcpy(found_session_key, creds->session_key, sizeof(found_session_key)); TALLOC_FREE(creds); } lck_type = (force_reauth || !found_existing_creds) ? NETLOGON_CREDS_CLI_LCK_EXCLUSIVE : NETLOGON_CREDS_CLI_LCK_SHARED; status = netlogon_creds_cli_lck(creds_ctx, lck_type, frame, &lck); if (!NT_STATUS_IS_OK(status)) { DBG_DEBUG("netlogon_creds_cli_lck failed: %s\n", nt_errstr(status)); goto fail; } if (!found_existing_creds) { /* * Try to find creds under the lock again. Someone * else might have done it for us. */ status = netlogon_creds_cli_get(creds_ctx, frame, &creds); if (NT_STATUS_IS_OK(status)) { int cmp = memcmp(found_session_key, creds->session_key, sizeof(found_session_key)); found_existing_creds = (cmp != 0); memcpy(found_session_key, creds->session_key, sizeof(found_session_key)); TALLOC_FREE(creds); } } do_serverauth = force_reauth || !found_existing_creds; if (!do_serverauth) { /* * Do the quick schannel bind without a reauth */ status = cli_rpc_pipe_open_bind_schannel( cli, &ndr_table_netlogon, transport, creds_ctx, &rpccli); if (!retry && NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) { DBG_DEBUG("Retrying with serverauthenticate\n"); TALLOC_FREE(lck); retry = true; goto again; } if (!NT_STATUS_IS_OK(status)) { DBG_DEBUG("cli_rpc_pipe_open_bind_schannel " "failed: %s\n", nt_errstr(status)); goto fail; } goto done; } if (cli_credentials_is_anonymous(trust_creds)) { DBG_WARNING("get_trust_credential for %s only gave anonymous," "unable to negotiate NETLOGON credentials\n", netlogon_creds_cli_debug_string( creds_ctx, frame)); status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; goto fail; } status = rpccli_setup_netlogon_creds_locked( cli, transport, creds_ctx, true, trust_creds, &negotiate_flags); if (!NT_STATUS_IS_OK(status)) { DBG_DEBUG("rpccli_setup_netlogon_creds failed for %s, " "unable to setup NETLOGON credentials: %s\n", netlogon_creds_cli_debug_string( creds_ctx, frame), nt_errstr(status)); goto fail; } if (!(negotiate_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) { if (lp_winbind_sealed_pipes() || lp_require_strong_key()) { status = NT_STATUS_DOWNGRADE_DETECTED; DBG_WARNING("Unwilling to make connection to %s" "without connection level security, " "must set 'winbind sealed pipes = false'" " and 'require strong key = false' " "to proceed: %s\n", netlogon_creds_cli_debug_string( creds_ctx, frame), nt_errstr(status)); goto fail; } status = cli_rpc_pipe_open_noauth_transport( cli, transport, &ndr_table_netlogon, &rpccli); if (!NT_STATUS_IS_OK(status)) { DBG_DEBUG("cli_rpc_pipe_open_noauth_transport " "failed: %s\n", nt_errstr(status)); goto fail; } goto done; } status = cli_rpc_pipe_open_bind_schannel( cli, &ndr_table_netlogon, transport, creds_ctx, &rpccli); if (!NT_STATUS_IS_OK(status)) { DBG_DEBUG("cli_rpc_pipe_open_bind_schannel " "failed: %s\n", nt_errstr(status)); goto fail; } status = netlogon_creds_cli_check(creds_ctx, rpccli->binding_handle, NULL); if (!NT_STATUS_IS_OK(status)) { DBG_WARNING("netlogon_creds_cli_check failed: %s\n", nt_errstr(status)); goto fail; } done: *_rpccli = rpccli; status = NT_STATUS_OK; fail: ZERO_STRUCT(found_session_key); TALLOC_FREE(lck); TALLOC_FREE(frame); return status; }
NTSTATUS rpccli_setup_netlogon_creds(struct cli_state *cli, enum dcerpc_transport_t transport, struct netlogon_creds_cli_context *netlogon_creds, bool force_reauth, struct samr_Password current_nt_hash, const struct samr_Password *previous_nt_hash) { TALLOC_CTX *frame = talloc_stackframe(); struct rpc_pipe_client *netlogon_pipe = NULL; struct netlogon_creds_CredentialState *creds = NULL; NTSTATUS status; status = netlogon_creds_cli_get(netlogon_creds, frame, &creds); if (NT_STATUS_IS_OK(status)) { const char *action = "using"; if (force_reauth) { action = "overwrite"; } DEBUG(5,("%s: %s cached netlogon_creds cli[%s/%s] to %s\n", __FUNCTION__, action, creds->account_name, creds->computer_name, smbXcli_conn_remote_name(cli->conn))); if (!force_reauth) { TALLOC_FREE(frame); return NT_STATUS_OK; } TALLOC_FREE(creds); } status = cli_rpc_pipe_open_noauth_transport(cli, transport, &ndr_table_netlogon, &netlogon_pipe); if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("%s: failed to open noauth netlogon connection to %s - %s\n", __FUNCTION__, smbXcli_conn_remote_name(cli->conn), nt_errstr(status))); TALLOC_FREE(frame); return status; } talloc_steal(frame, netlogon_pipe); status = netlogon_creds_cli_auth(netlogon_creds, netlogon_pipe->binding_handle, current_nt_hash, previous_nt_hash); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(frame); return status; } status = netlogon_creds_cli_get(netlogon_creds, frame, &creds); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(frame); return NT_STATUS_INTERNAL_ERROR; } DEBUG(5,("%s: using new netlogon_creds cli[%s/%s] to %s\n", __FUNCTION__, creds->account_name, creds->computer_name, smbXcli_conn_remote_name(cli->conn))); TALLOC_FREE(frame); return NT_STATUS_OK; }
NTSTATUS rpccli_setup_netlogon_creds_locked( struct cli_state *cli, enum dcerpc_transport_t transport, struct netlogon_creds_cli_context *creds_ctx, bool force_reauth, struct cli_credentials *cli_creds, uint32_t *negotiate_flags) { TALLOC_CTX *frame = talloc_stackframe(); struct rpc_pipe_client *netlogon_pipe = NULL; struct netlogon_creds_CredentialState *creds = NULL; uint8_t num_nt_hashes = 0; const struct samr_Password *nt_hashes[2] = { NULL, NULL }; uint8_t idx_nt_hashes = 0; NTSTATUS status; status = netlogon_creds_cli_get(creds_ctx, frame, &creds); if (NT_STATUS_IS_OK(status)) { const char *action = "using"; if (force_reauth) { action = "overwrite"; } DEBUG(5,("%s: %s cached netlogon_creds cli[%s/%s] to %s\n", __FUNCTION__, action, creds->account_name, creds->computer_name, smbXcli_conn_remote_name(cli->conn))); if (!force_reauth) { goto done; } TALLOC_FREE(creds); } nt_hashes[0] = cli_credentials_get_nt_hash(cli_creds, talloc_tos()); if (nt_hashes[0] == NULL) { TALLOC_FREE(frame); return NT_STATUS_NO_MEMORY; } num_nt_hashes = 1; nt_hashes[1] = cli_credentials_get_old_nt_hash(cli_creds, talloc_tos()); if (nt_hashes[1] != NULL) { num_nt_hashes = 2; } status = cli_rpc_pipe_open_noauth_transport(cli, transport, &ndr_table_netlogon, &netlogon_pipe); if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("%s: failed to open noauth netlogon connection to %s - %s\n", __FUNCTION__, smbXcli_conn_remote_name(cli->conn), nt_errstr(status))); TALLOC_FREE(frame); return status; } talloc_steal(frame, netlogon_pipe); status = netlogon_creds_cli_auth(creds_ctx, netlogon_pipe->binding_handle, num_nt_hashes, nt_hashes, &idx_nt_hashes); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(frame); return status; } status = netlogon_creds_cli_get(creds_ctx, frame, &creds); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(frame); return NT_STATUS_INTERNAL_ERROR; } DEBUG(5,("%s: using new netlogon_creds cli[%s/%s] to %s\n", __FUNCTION__, creds->account_name, creds->computer_name, smbXcli_conn_remote_name(cli->conn))); done: if (negotiate_flags != NULL) { *negotiate_flags = creds->negotiate_flags; } TALLOC_FREE(frame); return NT_STATUS_OK; }
static NTSTATUS connect_to_domain_password_server(struct cli_state **cli_ret, const char *domain, const char *dc_name, const struct sockaddr_storage *dc_ss, struct rpc_pipe_client **pipe_ret, TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_context **creds_ret) { TALLOC_CTX *frame = talloc_stackframe(); struct messaging_context *msg_ctx = server_messaging_context(); NTSTATUS result; struct cli_state *cli = NULL; struct rpc_pipe_client *netlogon_pipe = NULL; struct netlogon_creds_cli_context *netlogon_creds = NULL; struct netlogon_creds_CredentialState *creds = NULL; uint32_t netlogon_flags = 0; enum netr_SchannelType sec_chan_type = 0; const char *_account_name = NULL; const char *account_name = NULL; struct samr_Password current_nt_hash; struct samr_Password *previous_nt_hash = NULL; bool ok; *cli_ret = NULL; *pipe_ret = NULL; *creds_ret = NULL; /* TODO: Send a SAMLOGON request to determine whether this is a valid logonserver. We can avoid a 30-second timeout if the DC is down if the SAMLOGON request fails as it is only over UDP. */ /* we use a mutex to prevent two connections at once - when a Win2k PDC get two connections where one hasn't completed a session setup yet it will send a TCP reset to the first connection (tridge) */ /* * With NT4.x DC's *all* authentication must be serialized to avoid * ACCESS_DENIED errors if 2 auths are done from the same machine. JRA. */ mutex = grab_named_mutex(NULL, dc_name, 10); if (mutex == NULL) { TALLOC_FREE(frame); return NT_STATUS_NO_LOGON_SERVERS; } /* Attempt connection */ result = cli_full_connection(&cli, lp_netbios_name(), dc_name, dc_ss, 0, "IPC$", "IPC", "", "", "", 0, SMB_SIGNING_DEFAULT); if (!NT_STATUS_IS_OK(result)) { /* map to something more useful */ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) { result = NT_STATUS_NO_LOGON_SERVERS; } TALLOC_FREE(mutex); TALLOC_FREE(frame); return result; } /* * We now have an anonymous connection to IPC$ on the domain password server. */ ok = get_trust_pw_hash(domain, current_nt_hash.hash, &_account_name, &sec_chan_type); if (!ok) { cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } account_name = talloc_asprintf(talloc_tos(), "%s$", _account_name); if (account_name == NULL) { cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); return NT_STATUS_NO_MEMORY; } result = rpccli_create_netlogon_creds(dc_name, domain, account_name, sec_chan_type, msg_ctx, talloc_tos(), &netlogon_creds); if (!NT_STATUS_IS_OK(result)) { cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); SAFE_FREE(previous_nt_hash); return result; } result = rpccli_setup_netlogon_creds(cli, netlogon_creds, false, /* force_reauth */ current_nt_hash, previous_nt_hash); SAFE_FREE(previous_nt_hash); if (!NT_STATUS_IS_OK(result)) { cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); return result; } result = netlogon_creds_cli_get(netlogon_creds, talloc_tos(), &creds); if (!NT_STATUS_IS_OK(result)) { cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); return result; } netlogon_flags = creds->negotiate_flags; TALLOC_FREE(creds); if (netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC) { result = cli_rpc_pipe_open_schannel_with_key( cli, &ndr_table_netlogon, NCACN_NP, domain, netlogon_creds, &netlogon_pipe); } else { result = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon, &netlogon_pipe); } if (!NT_STATUS_IS_OK(result)) { DEBUG(0,("connect_to_domain_password_server: " "unable to open the domain client session to " "machine %s. Flags[0x%08X] Error was : %s.\n", dc_name, (unsigned)netlogon_flags, nt_errstr(result))); cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); return result; } if(!netlogon_pipe) { DEBUG(0, ("connect_to_domain_password_server: unable to open " "the domain client session to machine %s. Error " "was : %s.\n", dc_name, nt_errstr(result))); cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); return NT_STATUS_NO_LOGON_SERVERS; } /* We exit here with the mutex *locked*. JRA */ *cli_ret = cli; *pipe_ret = netlogon_pipe; *creds_ret = talloc_move(mem_ctx, &netlogon_creds); TALLOC_FREE(frame); return NT_STATUS_OK; }