1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-24 21:34:56 +03:00

This puts real netlogon connection caching to winbind. This becomes

important once we start doing schannel, as there would be a lot more
roundtrips for the second PIPE open and bind. With this patch logging
in to a member server is a matter of two (three if you count the
ack...) packets between us and the DC.

Volker
This commit is contained in:
Volker Lendecke 0001-01-01 00:00:00 +00:00
parent 9abe3b2383
commit 5b3cb7725a
10 changed files with 184 additions and 121 deletions

View File

@ -130,7 +130,6 @@ static NTSTATUS connect_to_domain_password_server(struct cli_state **cli,
struct in_addr dest_ip;
fstring remote_machine;
NTSTATUS result;
uint32 neg_flags = 0x000001ff;
*retry = False;
@ -214,7 +213,7 @@ machine %s. Error was : %s.\n", remote_machine, cli_errstr(*cli)));
return NT_STATUS_NO_MEMORY;
}
result = cli_nt_setup_creds(*cli, sec_chan, trust_passwd, &neg_flags, 2);
result = cli_nt_establish_netlogon(*cli, sec_chan, trust_passwd);
if (!NT_STATUS_IS_OK(result)) {
DEBUG(0,("connect_to_domain_password_server: unable to setup the NETLOGON credentials to machine \
@ -341,6 +340,7 @@ static NTSTATUS domain_client_validate(TALLOC_CTX *mem_ctx,
*/
nt_status = cli_netlogon_sam_network_logon(cli, mem_ctx,
NULL,
user_info->smb_name.str, user_info->domain.str,
user_info->wksta_name.str, chal,
user_info->lm_resp, user_info->nt_resp,

View File

@ -704,8 +704,8 @@ success:
Resolve via "lmhosts" method.
*********************************************************/
static BOOL resolve_lmhosts(const char *name, int name_type,
struct in_addr **return_iplist, int *return_count)
BOOL resolve_lmhosts(const char *name, int name_type,
struct in_addr **return_iplist, int *return_count)
{
/*
* "lmhosts" means parse the local lmhosts file.

View File

@ -415,21 +415,19 @@ static NTSTATUS cm_open_connection(const char *domain, const int pipe_index,
static BOOL connection_ok(struct winbindd_cm_conn *conn)
{
if (!conn) {
smb_panic("Invalid paramater passed to conneciton_ok(): conn was NULL!\n");
smb_panic("Invalid parameter passed to connection_ok(): conn was NULL!\n");
return False;
}
if (!conn->cli) {
DEBUG(0, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n",
DEBUG(3, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n",
conn->controller, conn->domain, conn->pipe_name));
smb_panic("connection_ok: conn->cli was null!");
return False;
}
if (!conn->cli->initialised) {
DEBUG(0, ("Connection to %s for domain %s (pipe %s) was never initialised!\n",
DEBUG(3, ("Connection to %s for domain %s (pipe %s) was never initialised!\n",
conn->controller, conn->domain, conn->pipe_name));
smb_panic("connection_ok: conn->cli->initialised is False!");
return False;
}
@ -442,13 +440,13 @@ static BOOL connection_ok(struct winbindd_cm_conn *conn)
return True;
}
/* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */
/* Search the cache for a connection. If there is a broken one,
shut it down properly and return NULL. */
static NTSTATUS get_connection_from_cache(const char *domain, const char *pipe_name,
struct winbindd_cm_conn **conn_out)
static void find_cm_connection(const char *domain, const char *pipe_name,
struct winbindd_cm_conn **conn_out)
{
struct winbindd_cm_conn *conn, conn_temp;
NTSTATUS result;
for (conn = cm_conns; conn; conn = conn->next) {
if (strequal(conn->domain, domain) &&
@ -467,25 +465,46 @@ static NTSTATUS get_connection_from_cache(const char *domain, const char *pipe_n
}
}
if (!conn) {
if (!(conn = malloc(sizeof(*conn))))
return NT_STATUS_NO_MEMORY;
*conn_out = conn;
}
ZERO_STRUCTP(conn);
/* Initialize a new connection up to the RPC BIND. */
if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, get_pipe_index(pipe_name), conn))) {
DEBUG(3, ("Could not open a connection to %s for %s (%s)\n",
domain, pipe_name, nt_errstr(result)));
SAFE_FREE(conn);
return result;
}
DLIST_ADD(cm_conns, conn);
static NTSTATUS new_cm_connection(const char *domain, const char *pipe_name,
struct winbindd_cm_conn **conn_out)
{
struct winbindd_cm_conn *conn;
NTSTATUS result;
if (!(conn = malloc(sizeof(*conn))))
return NT_STATUS_NO_MEMORY;
ZERO_STRUCTP(conn);
if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, get_pipe_index(pipe_name), conn))) {
DEBUG(3, ("Could not open a connection to %s for %s (%s)\n",
domain, pipe_name, nt_errstr(result)));
SAFE_FREE(conn);
return result;
}
DLIST_ADD(cm_conns, conn);
*conn_out = conn;
return NT_STATUS_OK;
}
/* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */
static NTSTATUS get_connection_from_cache(const char *domain, const char *pipe_name,
struct winbindd_cm_conn **conn_out)
{
find_cm_connection(domain, pipe_name, conn_out);
if (conn_out != NULL)
return NT_STATUS_OK;
return new_cm_connection(domain, pipe_name, conn_out);
}
/**********************************************************************************
**********************************************************************************/
@ -856,11 +875,11 @@ CLI_POLICY_HND *cm_get_sam_group_handle(char *domain, DOM_SID *domain_sid,
NTSTATUS cm_get_netlogon_cli(const char *domain,
const unsigned char *trust_passwd,
uint32 sec_channel_type,
BOOL fresh,
struct cli_state **cli)
{
NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
struct winbindd_cm_conn *conn;
uint32 neg_flags = 0x000001ff;
fstring lock_name;
BOOL got_mutex;
@ -869,7 +888,30 @@ NTSTATUS cm_get_netlogon_cli(const char *domain,
/* Open an initial conection - keep the mutex. */
if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_NETLOGON, &conn)))
find_cm_connection(domain, PIPE_NETLOGON, &conn);
if ( fresh && (conn != NULL) ) {
cli_shutdown(conn->cli);
conn->cli = NULL;
conn = NULL;
/* purge connection from cache */
find_cm_connection(domain, PIPE_NETLOGON, &conn);
if (conn != NULL) {
DEBUG(0,("Could not purge connection\n"));
return NT_STATUS_UNSUCCESSFUL;
}
}
if (conn != NULL) {
*cli = conn->cli;
return NT_STATUS_OK;
}
result = new_cm_connection(domain, PIPE_NETLOGON, &conn);
if (!NT_STATUS_IS_OK(result))
return result;
snprintf(lock_name, sizeof(lock_name), "NETLOGON\\%s", conn->controller);
@ -878,38 +920,16 @@ NTSTATUS cm_get_netlogon_cli(const char *domain,
DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", conn->controller));
}
result = cli_nt_setup_creds(conn->cli, sec_channel_type, trust_passwd, &neg_flags, 2);
result = cli_nt_establish_netlogon(conn->cli, sec_channel_type, trust_passwd);
if (got_mutex)
secrets_named_mutex_release(lock_name);
if (!NT_STATUS_IS_OK(result)) {
DEBUG(0, ("error connecting to domain password server: %s\n",
nt_errstr(result)));
/* Hit the cache code again. This cleans out the old connection and gets a new one */
if (conn->cli->fd == -1) {
if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_NETLOGON, &conn)))
return result;
snprintf(lock_name, sizeof(lock_name), "NETLOGON\\%s", conn->controller);
if (!(got_mutex = secrets_named_mutex(lock_name, WINBIND_SERVER_MUTEX_WAIT_TIME))) {
DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", conn->controller));
}
/* Try again */
result = cli_nt_setup_creds( conn->cli, sec_channel_type,trust_passwd, &neg_flags, 2);
if (got_mutex)
secrets_named_mutex_release(lock_name);
}
if (!NT_STATUS_IS_OK(result)) {
cli_shutdown(conn->cli);
DLIST_REMOVE(cm_conns, conn);
SAFE_FREE(conn);
return result;
}
cli_shutdown(conn->cli);
DLIST_REMOVE(cm_conns, conn);
SAFE_FREE(conn);
return result;
}
*cli = conn->cli;

View File

@ -50,7 +50,9 @@ enum winbindd_result winbindd_check_machine_acct(struct winbindd_cli_state *stat
the trust account password. */
/* Don't shut this down - it belongs to the connection cache code */
result = cm_get_netlogon_cli(lp_workgroup(), trust_passwd, sec_channel_type, &cli);
result = cm_get_netlogon_cli(lp_workgroup(),
trust_passwd, sec_channel_type,
True, &cli);
if (!NT_STATUS_IS_OK(result)) {
DEBUG(3, ("could not open handle to NETLOGON pipe\n"));

View File

@ -68,6 +68,8 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
TALLOC_CTX *mem_ctx = NULL;
DATA_BLOB lm_resp;
DATA_BLOB nt_resp;
DOM_CRED ret_creds;
int attempts = 0;
/* Ensure null termination */
state->request.data.auth.user[sizeof(state->request.data.auth.user)-1]='\0';
@ -119,23 +121,35 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
goto done;
}
ZERO_STRUCT(info3);
do {
ZERO_STRUCT(info3);
ZERO_STRUCT(ret_creds);
/* Don't shut this down - it belongs to the connection cache code */
result = cm_get_netlogon_cli(lp_workgroup(), trust_passwd,
sec_channel_type,
&cli);
/* Don't shut this down - it belongs to the connection cache code */
result = cm_get_netlogon_cli(lp_workgroup(), trust_passwd,
sec_channel_type, False, &cli);
if (!NT_STATUS_IS_OK(result)) {
DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
goto done;
}
if (!NT_STATUS_IS_OK(result)) {
DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
goto done;
}
result = cli_netlogon_sam_network_logon(cli, mem_ctx,
name_user, name_domain,
global_myname(), chal,
lm_resp, nt_resp,
&info3);
result = cli_netlogon_sam_network_logon(cli, mem_ctx,
&ret_creds,
name_user, name_domain,
global_myname(), chal,
lm_resp, nt_resp,
&info3);
attempts += 1;
/* We have to try a second time as cm_get_netlogon_cli
might not yet have noticed that the DC has killed
our connection. */
} while ( (attempts < 2) && (cli->fd == -1) );
clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &ret_creds);
uni_group_cache_store_netlogon(mem_ctx, &info3);
done:
@ -176,6 +190,8 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
const char *domain = NULL;
const char *contact_domain;
const char *workstation;
DOM_CRED ret_creds;
int attempts = 0;
DATA_BLOB lm_resp, nt_resp;
@ -264,21 +280,37 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
goto done;
}
ZERO_STRUCT(info3);
do {
ZERO_STRUCT(info3);
ZERO_STRUCT(ret_creds);
/* Don't shut this down - it belongs to the connection cache code */
result = cm_get_netlogon_cli(contact_domain, trust_passwd, sec_channel_type, &cli);
/* Don't shut this down - it belongs to the connection cache code */
result = cm_get_netlogon_cli(contact_domain, trust_passwd,
sec_channel_type, False, &cli);
if (!NT_STATUS_IS_OK(result)) {
DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n", nt_errstr(result)));
goto done;
}
if (!NT_STATUS_IS_OK(result)) {
DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n",
nt_errstr(result)));
goto done;
}
result = cli_netlogon_sam_network_logon(cli, mem_ctx,
user, domain,
workstation, state->request.data.auth_crap.chal,
lm_resp, nt_resp,
&info3);
result = cli_netlogon_sam_network_logon(cli, mem_ctx,
&ret_creds,
user, domain,
workstation,
state->request.data.auth_crap.chal,
lm_resp, nt_resp,
&info3);
attempts += 1;
/* We have to try a second time as cm_get_netlogon_cli
might not yet have noticed that the DC has killed
our connection. */
} while ( (attempts < 2) && (cli->fd == -1) );
clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &ret_creds);
if (NT_STATUS_IS_OK(result)) {
uni_group_cache_store_netlogon(mem_ctx, &info3);

View File

@ -472,6 +472,7 @@ NTSTATUS cli_netlogon_sam_deltas(struct cli_state *cli, TALLOC_CTX *mem_ctx,
/* Logon domain user */
NTSTATUS cli_netlogon_sam_logon(struct cli_state *cli, TALLOC_CTX *mem_ctx,
DOM_CRED *ret_creds,
const char *username, const char *password,
int logon_type)
{
@ -486,6 +487,7 @@ NTSTATUS cli_netlogon_sam_logon(struct cli_state *cli, TALLOC_CTX *mem_ctx,
ZERO_STRUCT(q);
ZERO_STRUCT(r);
ZERO_STRUCT(dummy_rtn_creds);
/* Initialise parse structures */
@ -498,8 +500,8 @@ NTSTATUS cli_netlogon_sam_logon(struct cli_state *cli, TALLOC_CTX *mem_ctx,
q.validation_level = validation_level;
memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
dummy_rtn_creds.timestamp.time = time(NULL);
if (ret_creds == NULL)
ret_creds = &dummy_rtn_creds;
ctr.switch_value = logon_type;
@ -542,7 +544,7 @@ NTSTATUS cli_netlogon_sam_logon(struct cli_state *cli, TALLOC_CTX *mem_ctx,
}
init_sam_info(&q.sam_id, cli->srv_name_slash, global_myname(),
&clnt_creds, &dummy_rtn_creds, logon_type,
&clnt_creds, ret_creds, logon_type,
&ctr);
/* Marshall data and send request */
@ -563,6 +565,7 @@ NTSTATUS cli_netlogon_sam_logon(struct cli_state *cli, TALLOC_CTX *mem_ctx,
/* Return results */
result = r.status;
memcpy(ret_creds, &r.srv_creds, sizeof(*ret_creds));
done:
prs_mem_free(&qbuf);
@ -579,6 +582,7 @@ NTSTATUS cli_netlogon_sam_logon(struct cli_state *cli, TALLOC_CTX *mem_ctx,
**/
NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_ctx,
DOM_CRED *ret_creds,
const char *username, const char *domain, const char *workstation,
const uint8 chal[8],
DATA_BLOB lm_response, DATA_BLOB nt_response,
@ -598,6 +602,7 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
ZERO_STRUCT(q);
ZERO_STRUCT(r);
ZERO_STRUCT(dummy_rtn_creds);
workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
@ -617,8 +622,8 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
q.validation_level = validation_level;
memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
dummy_rtn_creds.timestamp.time = time(NULL);
if (ret_creds == NULL)
ret_creds = &dummy_rtn_creds;
ctr.switch_value = NET_LOGON_TYPE;
@ -629,7 +634,7 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
lm_response.data, lm_response.length, nt_response.data, nt_response.length);
init_sam_info(&q.sam_id, cli->srv_name_slash, global_myname(),
&clnt_creds, &dummy_rtn_creds, NET_LOGON_TYPE,
&clnt_creds, ret_creds, NET_LOGON_TYPE,
&ctr);
/* Marshall data and send request */
@ -659,6 +664,7 @@ NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_c
/* Return results */
result = r.status;
memcpy(ret_creds, &r.srv_creds, sizeof(*ret_creds));
done:
prs_mem_free(&qbuf);

View File

@ -1563,8 +1563,8 @@ BOOL cli_nt_session_open(struct cli_state *cli, const int pipe_idx)
Open a session to the NETLOGON pipe using schannel.
****************************************************************************/
BOOL cli_nt_open_netlogon(struct cli_state *cli, const char *trust_password,
int sec_chan)
NTSTATUS cli_nt_establish_netlogon(struct cli_state *cli, int sec_chan,
const char *trust_password)
{
NTSTATUS result;
uint32 neg_flags = 0x000001ff;
@ -1573,22 +1573,12 @@ BOOL cli_nt_open_netlogon(struct cli_state *cli, const char *trust_password,
if (lp_client_schannel() != False)
neg_flags |= NETLOGON_NEG_SCHANNEL;
if (!cli_nt_session_open(cli, PI_NETLOGON)) {
return False;
}
if (!secrets_init()) {
DEBUG(3,("Failed to init secrets.tdb\n"));
return False;
}
result = cli_nt_setup_creds(cli, sec_chan, trust_password,
&neg_flags, 2);
if (!NT_STATUS_IS_OK(result)) {
cli_nt_session_close(cli);
return False;
return result;
}
if ((lp_client_schannel() == True) &&
@ -1596,12 +1586,12 @@ BOOL cli_nt_open_netlogon(struct cli_state *cli, const char *trust_password,
DEBUG(3, ("Server did not offer schannel\n"));
cli_nt_session_close(cli);
return False;
return NT_STATUS_UNSUCCESSFUL;
}
if ((lp_client_schannel() == False) ||
((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
return True;
return NT_STATUS_OK;
}
/* Server offered schannel, so try it. */
@ -1624,7 +1614,7 @@ BOOL cli_nt_open_netlogon(struct cli_state *cli, const char *trust_password,
"Error was %s\n",
PIPE_NETLOGON, cli->desthost,
cli_errstr(cli)));
return False;
return NT_STATUS_UNSUCCESSFUL;
}
cli->nt_pipe_fnum = (uint16)fnum;
@ -1635,7 +1625,7 @@ BOOL cli_nt_open_netlogon(struct cli_state *cli, const char *trust_password,
"Error was %s\n",
PIPE_NETLOGON, cli->desthost,
cli_errstr(cli)));
return False;
return NT_STATUS_UNSUCCESSFUL;
}
cli->nt_pipe_fnum = (uint16)fnum;
@ -1645,17 +1635,17 @@ BOOL cli_nt_open_netlogon(struct cli_state *cli, const char *trust_password,
DEBUG(0,("Pipe hnd state failed. Error was %s\n",
cli_errstr(cli)));
cli_close(cli, cli->nt_pipe_fnum);
return False;
return NT_STATUS_UNSUCCESSFUL;
}
}
if (!rpc_pipe_bind(cli, PI_NETLOGON, global_myname(), True)) {
DEBUG(2,("rpc bind to %s failed\n", PIPE_NETLOGON));
cli_close(cli, cli->nt_pipe_fnum);
return False;
return NT_STATUS_UNSUCCESSFUL;
}
return True;
return NT_STATUS_OK;
}

View File

@ -275,6 +275,7 @@ static NTSTATUS cmd_netlogon_sam_logon(struct cli_state *cli,
const char *username, *password;
uint32 neg_flags = 0x000001ff;
int auth_level = 2;
DOM_CRED ret_creds;
/* Check arguments */
@ -299,7 +300,13 @@ static NTSTATUS cmd_netlogon_sam_logon(struct cli_state *cli,
/* Perform the sam logon */
result = cli_netlogon_sam_logon(cli, mem_ctx, username, password, logon_type);
ZERO_STRUCT(ret_creds);
result = cli_netlogon_sam_logon(cli, mem_ctx, &ret_creds, username, password, logon_type);
clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &ret_creds);
result = cli_netlogon_sam_logon(cli, mem_ctx, &ret_creds, username, password, logon_type);
if (!NT_STATUS_IS_OK(result))
goto done;

View File

@ -391,6 +391,14 @@ static NTSTATUS do_cmd(struct cli_state *cli,
/* Open pipe */
if (cmd_entry->pipe_idx != -1) {
if (!cli_nt_session_open(cli, cmd_entry->pipe_idx)) {
DEBUG(0, ("Could not initialise %s\n",
get_pipe_name_from_index(cmd_entry->pipe_idx)));
return NT_STATUS_UNSUCCESSFUL;
}
}
if (cmd_entry->pipe_idx == PI_NETLOGON) {
uchar trust_password[16];
uint32 sec_channel_type;
@ -401,19 +409,11 @@ static NTSTATUS do_cmd(struct cli_state *cli,
return NT_STATUS_UNSUCCESSFUL;
}
if (!cli_nt_open_netlogon(cli, trust_password,
sec_channel_type)) {
if (!NT_STATUS_IS_OK(cli_nt_establish_netlogon(cli, sec_channel_type,
trust_password))) {
DEBUG(0, ("Could not initialise NETLOGON pipe\n"));
return NT_STATUS_UNSUCCESSFUL;
}
} else {
if (cmd_entry->pipe_idx != -1) {
if (!cli_nt_session_open(cli, cmd_entry->pipe_idx)) {
DEBUG(0, ("Could not initialise %s\n",
get_pipe_name_from_index(cmd_entry->pipe_idx)));
return NT_STATUS_UNSUCCESSFUL;
}
}
}
/* Run command */

View File

@ -209,6 +209,11 @@ int rpc_samdump(int argc, const char **argv)
fstrcpy(cli->domain, lp_workgroup());
if (!cli_nt_session_open(cli, PI_NETLOGON)) {
DEBUG(0,("Could not open connection to NETLOGON pipe\n"));
goto fail;
}
if (!secrets_fetch_trust_account_password(lp_workgroup(),
trust_password,
NULL, &sec_channel)) {
@ -216,7 +221,8 @@ int rpc_samdump(int argc, const char **argv)
goto fail;
}
if (!cli_nt_open_netlogon(cli, trust_password, sec_channel)) {
if (!NT_STATUS_IS_OK(cli_nt_establish_netlogon(cli, sec_channel,
trust_password))) {
DEBUG(0,("Error connecting to NETLOGON pipe\n"));
goto fail;
}