From 96b4187963cedcfe158ff02868929b8cf81c6ebf Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 19 Aug 2003 22:47:10 +0000 Subject: [PATCH] - Make 'net' use a single funciton for setting the 'use machine account' code. - Make winbindd try to use kerberos for connections to DCs, so that it can access RA=2 servers, particularly for netlogon. - Make rpcclient follow the new flags for the NETLOGON pipe - Make all the code that uses schannel use the centralised functions for doing so. Andrew Bartlett --- source/libads/krb5_setpw.c | 15 +++----- source/libsmb/trusts_util.c | 9 ++--- source/nsswitch/winbindd_cm.c | 90 ++++++++++++++++++++++++++++++++++++++----- source/rpcclient/rpcclient.c | 2 + source/utils/net.c | 38 ++++++++++-------- source/utils/net_ads.c | 39 +++++++++++-------- 6 files changed, 138 insertions(+), 55 deletions(-) diff --git a/source/libads/krb5_setpw.c b/source/libads/krb5_setpw.c index d1da118bb87..9cf15221a8d 100644 --- a/source/libads/krb5_setpw.c +++ b/source/libads/krb5_setpw.c @@ -664,25 +664,22 @@ ADS_STATUS kerberos_set_password(const char *kpasswd_server, * @return status of password change **/ ADS_STATUS ads_set_machine_password(ADS_STRUCT *ads, - const char *hostname, + const char *machine_account, const char *password) { ADS_STATUS status; - char *host = strdup(hostname); - char *principal; - - strlower_m(host); + char *principal = NULL; /* - we need to use the '$' form of the name here, as otherwise the - server might end up setting the password for a user instead + we need to use the '$' form of the name here (the machine account name), + as otherwise the server might end up setting the password for a user + instead */ - asprintf(&principal, "%s$@%s", host, ads->config.realm); + asprintf(&principal, "%s@%s", machine_account, ads->config.realm); status = ads_krb5_set_password(ads->auth.kdc_server, principal, password, ads->auth.time_offset); - free(host); free(principal); return status; diff --git a/source/libsmb/trusts_util.c b/source/libsmb/trusts_util.c index 610f4b3c031..4e02b29f92c 100644 --- a/source/libsmb/trusts_util.c +++ b/source/libsmb/trusts_util.c @@ -35,16 +35,15 @@ static NTSTATUS just_change_the_password(struct cli_state *cli, TALLOC_CTX *mem_ uint32 sec_channel_type) { NTSTATUS result; - uint32 neg_flags = 0x000001ff; - result = cli_nt_setup_creds(cli, sec_channel_type, orig_trust_passwd_hash, &neg_flags, 2); - - if (!NT_STATUS_IS_OK(result)) { + /* ensure that schannel uses the right domain */ + fstrcpy(cli->domain, lp_workgroup()); + if (! NT_STATUS_IS_OK(result = cli_nt_establish_netlogon(cli, sec_channel_type, orig_trust_passwd_hash))) { DEBUG(3,("just_change_the_password: unable to setup creds (%s)!\n", nt_errstr(result))); return result; } - + result = cli_net_srv_pwset(cli, mem_ctx, global_myname(), new_trust_passwd_hash); if (!NT_STATUS_IS_OK(result)) { diff --git a/source/nsswitch/winbindd_cm.c b/source/nsswitch/winbindd_cm.c index f07117b5ab8..eaf10168db0 100644 --- a/source/nsswitch/winbindd_cm.c +++ b/source/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,75 @@ 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)) { + 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)); + + 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; + if (!NT_STATUS_IS_OK(result) + && new_conn->cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) { + DEBUG(5, ("connecting to %s from %s with username [%s]\\[%s]\n", + new_conn->controller, global_myname(), ipc_domain, ipc_username)); + + 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 kerberos session setup with %s\n", nt_errstr(result))); + if (NT_STATUS_IS_OK(result)) + result = NT_STATUS_UNSUCCESSFUL; + } + } + if (!NT_STATUS_IS_OK(result)) { + if (!cli_session_setup(new_conn->cli, "", NULL, 0, + NULL, 0, + "")) { + 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; + } + + } + 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 +233,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); diff --git a/source/rpcclient/rpcclient.c b/source/rpcclient/rpcclient.c index 6efa9874a06..515489292bc 100644 --- a/source/rpcclient/rpcclient.c +++ b/source/rpcclient/rpcclient.c @@ -522,6 +522,8 @@ static NTSTATUS do_cmd(struct cli_state *cli, /* some of the DsXXX commands use the netlogon pipe */ if (lp_client_schannel() && (cmd_entry->pipe_idx == PI_NETLOGON) && !(cli->pipe_auth_flags & AUTH_PIPE_NETSEC)) { + /* The 7 here seems to be required to get Win2k not to downgrade us + to NT4. Actually, anything other than 1ff would seem to do... */ uint32 neg_flags = 0x000001ff; uint32 sec_channel_type; diff --git a/source/utils/net.c b/source/utils/net.c index 8f6b09a3fa4..c49c77dd50c 100644 --- a/source/utils/net.c +++ b/source/utils/net.c @@ -181,6 +181,27 @@ NTSTATUS connect_to_ipc_anonymous(struct cli_state **c, } } +/**************************************************************************** + Use the local machine's password for this session +****************************************************************************/ +int net_use_machine_password(void) +{ + char *user_name = NULL; + + if (!secrets_init()) { + d_printf("ERROR: Unable to open secrets database\n"); + exit(1); + } + + user_name = NULL; + opt_password = secrets_fetch_machine_password(opt_target_workgroup, NULL, NULL); + if (asprintf(&user_name, "%s$@%s", global_myname(), lp_realm()) == -1) { + return -1; + } + opt_user_name = user_name; + return 0; +} + BOOL net_find_server(unsigned flags, struct in_addr *server_ip, char **server_name) { @@ -321,7 +342,7 @@ static int net_join(int argc, const char **argv) if (net_ads_join(argc, argv) == 0) return 0; else - d_printf("ADS join did not work, trying RPC...\n"); + d_printf("ADS join did not work, falling back to RPC...\n"); } return net_rpc_join(argc, argv); } @@ -649,23 +670,10 @@ static struct functable net_func[] = { sec_init(); if (opt_machine_pass) { - char *user = NULL; /* it is very useful to be able to make ads queries as the machine account for testing purposes and for domain leave */ - if (!secrets_init()) { - d_printf("ERROR: Unable to open secrets database\n"); - exit(1); - } - - opt_password = secrets_fetch_machine_password(opt_workgroup, NULL, NULL); - - asprintf(&user,"%s$", global_myname()); - opt_user_name = user; - if (!opt_password) { - d_printf("ERROR: Unable to fetch machine password\n"); - exit(1); - } + net_use_machine_password(); } if (!opt_password) { diff --git a/source/utils/net_ads.c b/source/utils/net_ads.c index 631e2351275..352431a9382 100644 --- a/source/utils/net_ads.c +++ b/source/utils/net_ads.c @@ -579,10 +579,7 @@ static int net_ads_leave(int argc, const char **argv) } if (!opt_password) { - char *user_name; - asprintf(&user_name, "%s$", global_myname()); - opt_password = secrets_fetch_machine_password(opt_target_workgroup, NULL, NULL); - opt_user_name = user_name; + net_use_machine_password(); } if (!(ads = ads_startup())) { @@ -603,7 +600,6 @@ static int net_ads_leave(int argc, const char **argv) static int net_ads_join_ok(void) { - char *user_name; ADS_STRUCT *ads = NULL; if (!secrets_init()) { @@ -611,9 +607,7 @@ static int net_ads_join_ok(void) return -1; } - asprintf(&user_name, "%s$", global_myname()); - opt_user_name = user_name; - opt_password = secrets_fetch_machine_password(opt_target_workgroup, NULL, NULL); + net_use_machine_password(); if (!(ads = ads_startup())) { return -1; @@ -648,6 +642,7 @@ int net_ads_join(int argc, const char **argv) ADS_STRUCT *ads; ADS_STATUS rc; char *password; + char *machine_account = NULL; char *tmp_password; const char *org_unit = "Computers"; char *dn; @@ -669,6 +664,16 @@ int net_ads_join(int argc, const char **argv) if (!(ads = ads_startup())) return -1; + if (!*lp_realm()) { + d_printf("realm must be set in in smb.conf for ADS join to succeed.\n"); + return -1; + } + + if (strcmp(ads->config.realm, lp_realm()) != 0) { + d_printf("realm of remote server (%s) and realm in smb.conf (%s) DO NOT match. Aborting join\n", ads->config.realm, lp_realm()); + return -1; + } + ou_str = ads_ou_string(org_unit); asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path); free(ou_str); @@ -696,11 +701,16 @@ int net_ads_join(int argc, const char **argv) rc = ads_domain_sid(ads, &dom_sid); if (!ADS_ERR_OK(rc)) { - d_printf("ads_domain_sid: %s\n", ads_errstr(rc)); + d_printf("ads_domain_sid: %s\n", ads_errstr(rc)); + return -1; + } + + if (asprintf(&machine_account, "%s$", global_myname()) == -1) { + d_printf("asprintf failed\n"); return -1; } - rc = ads_set_machine_password(ads, global_myname(), password); + rc = ads_set_machine_password(ads, machine_account, password); if (!ADS_ERR_OK(rc)) { d_printf("ads_set_machine_password: %s\n", ads_errstr(rc)); return -1; @@ -718,7 +728,8 @@ int net_ads_join(int argc, const char **argv) d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm); - free(password); + SAFE_FREE(password); + SAFE_FREE(machine_account); return 0; } @@ -1020,17 +1031,13 @@ int net_ads_changetrustpw(int argc, const char **argv) char *host_principal; char *hostname; ADS_STATUS ret; - char *user_name; if (!secrets_init()) { DEBUG(1,("Failed to initialise secrets database\n")); return -1; } - asprintf(&user_name, "%s$", global_myname()); - opt_user_name = user_name; - - opt_password = secrets_fetch_machine_password(opt_target_workgroup, NULL, NULL); + net_use_machine_password(); use_in_memory_ccache(); -- 2.11.4.GIT