diff options
Diffstat (limited to 'source3/nsswitch/winbindd_cm.c')
-rw-r--r-- | source3/nsswitch/winbindd_cm.c | 126 |
1 files changed, 116 insertions, 10 deletions
diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c index f07117b5ab..8513a46f8f 100644 --- a/source3/nsswitch/winbindd_cm.c +++ b/source3/nsswitch/winbindd_cm.c @@ -116,7 +116,8 @@ static NTSTATUS cm_open_connection(const char *domain, const int pipe_index, struct winbindd_cm_conn *new_conn) { NTSTATUS result; - char *ipc_username, *ipc_domain, *ipc_password; + char *machine_password; + char *machine_krb5_principal, *ipc_username, *ipc_domain, *ipc_password; struct in_addr dc_ip; int i; BOOL retry = True; @@ -137,10 +138,15 @@ static NTSTATUS cm_open_connection(const char *domain, const int pipe_index, /* Initialise SMB connection */ - cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password); + /* grab stored passwords */ + machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); + + if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(), lp_realm()) == -1) { + SAFE_FREE(machine_password); + return NT_STATUS_NO_MEMORY; + } - DEBUG(5, ("connecting to %s from %s with username [%s]\\[%s]\n", - new_conn->controller, global_myname(), ipc_domain, ipc_username)); + cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password); for (i = 0; retry && (i < 3); i++) { BOOL got_mutex; @@ -150,12 +156,99 @@ static NTSTATUS cm_open_connection(const char *domain, const int pipe_index, continue; } - result = cli_full_connection(&new_conn->cli, global_myname(), new_conn->controller, - &dc_ip, 0, "IPC$", "IPC", ipc_username, ipc_domain, - ipc_password, CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK, - Undefined, &retry); - - secrets_named_mutex_release(new_conn->controller); + new_conn->cli = NULL; + result = cli_start_connection(&new_conn->cli, global_myname(), + new_conn->controller, + &dc_ip, 0, Undefined, + CLI_FULL_CONNECTION_USE_KERBEROS, + &retry); + + if (NT_STATUS_IS_OK(result)) { + + /* reset the error code */ + result = NT_STATUS_UNSUCCESSFUL; + + /* Krb5 session */ + + if ((lp_security() == SEC_ADS) + && (new_conn->cli->protocol >= PROTOCOL_NT1 && new_conn->cli->capabilities & CAP_EXTENDED_SECURITY)) { + new_conn->cli->use_kerberos = True; + DEBUG(5, ("connecting to %s from %s with kerberos principal [%s]\n", + new_conn->controller, global_myname(), machine_krb5_principal)); + + result = NT_STATUS_OK; + + if (!cli_session_setup_spnego(new_conn->cli, machine_krb5_principal, + machine_password, + domain)) { + result = cli_nt_error(new_conn->cli); + DEBUG(4,("failed kerberos session setup with %s\n", nt_errstr(result))); + if (NT_STATUS_IS_OK(result)) + result = NT_STATUS_UNSUCCESSFUL; + } + } + new_conn->cli->use_kerberos = False; + + /* only do this is we have a username/password for thr IPC$ connection */ + + if ( !NT_STATUS_IS_OK(result) + && new_conn->cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE + && strlen(ipc_username) ) + { + DEBUG(5, ("connecting to %s from %s with username [%s]\\[%s]\n", + new_conn->controller, global_myname(), ipc_domain, ipc_username)); + + result = NT_STATUS_OK; + + if (!cli_session_setup(new_conn->cli, ipc_username, + ipc_password, strlen(ipc_password)+1, + ipc_password, strlen(ipc_password)+1, + domain)) { + result = cli_nt_error(new_conn->cli); + DEBUG(4,("failed authenticated session setup with %s\n", nt_errstr(result))); + if (NT_STATUS_IS_OK(result)) + result = NT_STATUS_UNSUCCESSFUL; + } + } + + /* anonymous is all that is left if we get to here */ + + if (!NT_STATUS_IS_OK(result)) { + + DEBUG(5, ("anonymous connection attempt to %s from %s\n", + new_conn->controller, global_myname())); + + result = NT_STATUS_OK; + + if (!cli_session_setup(new_conn->cli, "", NULL, 0, NULL, 0, "")) + { + result = cli_nt_error(new_conn->cli); + DEBUG(4,("failed anonymous session setup with %s\n", nt_errstr(result))); + if (NT_STATUS_IS_OK(result)) + result = NT_STATUS_UNSUCCESSFUL; + } + + } + + if (NT_STATUS_IS_OK(result) && !cli_send_tconX(new_conn->cli, "IPC$", "IPC", + "", 0)) { + result = cli_nt_error(new_conn->cli); + DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result))); + cli_shutdown(new_conn->cli); + if (NT_STATUS_IS_OK(result)) { + result = NT_STATUS_UNSUCCESSFUL; + } + } + } + + if (NT_STATUS_IS_OK(result)) { + struct ntuser_creds creds; + init_creds(&creds, ipc_username, ipc_domain, ipc_password); + cli_init_creds(new_conn->cli, &creds); + } + + if (got_mutex) + secrets_named_mutex_release(new_conn->controller); if (NT_STATUS_IS_OK(result)) break; @@ -164,6 +257,7 @@ static NTSTATUS cm_open_connection(const char *domain, const int pipe_index, SAFE_FREE(ipc_username); SAFE_FREE(ipc_domain); SAFE_FREE(ipc_password); + SAFE_FREE(machine_password); if (!NT_STATUS_IS_OK(result)) { add_failed_connection_entry(domain, new_conn->controller, result); @@ -479,6 +573,7 @@ NTSTATUS cm_get_netlogon_cli(const char *domain, struct winbindd_cm_conn *conn; fstring lock_name; BOOL got_mutex; + struct winbindd_domain *wb_domain = NULL; if (!cli) return NT_STATUS_INVALID_PARAMETER; @@ -520,6 +615,17 @@ NTSTATUS cm_get_netlogon_cli(const char *domain, if ( sec_channel_type == SEC_CHAN_DOMAIN ) fstr_sprintf(conn->cli->mach_acct, "%s$", lp_workgroup()); + /* we need the short form of the domain name for the schanel + rpc bind. What if we fail? I don't think we should ever get + a request for a domain name not in our list but I'm not bailing + out if we do since I'm not 10% certain about this --jerry */ + + if ( (wb_domain = find_domain_from_name( domain )) != NULL ) { + DEBUG(5,("cm_get_netlogon_cli: Using short for of domain name [%s] for netlogon rpc bind\n", + wb_domain->name)); + fstrcpy( conn->cli->domain, wb_domain->name); + } + result = cli_nt_establish_netlogon(conn->cli, sec_channel_type, trust_passwd); if (got_mutex) |