/* Unix SMB/Netbios implementation. Version 1.9. NT Domain Authentication SMB / MSRPC client Copyright (C) Andrew Tridgell 1994-2000 Copyright (C) Luke Kenneth Casson Leighton 1996-2000 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "includes.h" #include "rpc_parse.h" #include "rpc_client.h" #include "nterr.h" extern int DEBUGLEVEL; /**************************************************************************** Initialize domain session credentials. ****************************************************************************/ uint32 cli_nt_setup_creds(const char *srv_name, const char *domain, const char *cli_hostname, const char *trust_acct, const uchar trust_pwd[16], uint16 sec_chan, uint16 * validation_level) { DOM_CHAL clnt_chal; DOM_CHAL srv_chal; uint32 status; UTIME zerotime; uint8 sess_key[16]; DOM_CRED clnt_cred; uint32 neg_flags = !lp_client_schannel()? 0x000001ff : 0x400001ff; /******************* Request Challenge ********************/ generate_random_buffer(clnt_chal.data, 8, False); /* send a client challenge; receive a server challenge */ status = cli_net_req_chal(srv_name, cli_hostname, &clnt_chal, &srv_chal); if (status != 0) { DEBUG(1, ("cli_nt_setup_creds: request challenge failed\n")); return status; } /**************** Long-term Session key **************/ /* calculate the session key */ cred_session_key(&clnt_chal, &srv_chal, trust_pwd, sess_key); memset(sess_key + 8, 0, 8); /******************* Authenticate 2 ********************/ /* calculate auth-2 credentials */ zerotime.time = 0; cred_create(sess_key, &clnt_chal, zerotime, &clnt_cred.challenge); if (!cli_con_set_creds(srv_name, sess_key, &clnt_cred)) { return NT_STATUS_ACCESS_DENIED | 0xC0000000; } /* * Send client auth-2 challenge. * Receive an auth-2 challenge response and check it. */ status = cli_net_auth2(srv_name, trust_acct, cli_hostname, sec_chan, &neg_flags, &srv_chal); if (status != 0x0) { DEBUG(1, ("cli_nt_setup_creds: auth2 challenge failed. status: %x\n", status)); } /* check the client secure channel status */ if (status == 0x0 && lp_client_schannel() == True && IS_BITS_CLR_ALL(neg_flags, 0x40000000)) { /* netlogon secure channel was required, and not negotiated */ return NT_STATUS_ACCESS_DENIED | 0xC0000000; } if (status == 0x0 && IS_BITS_SET_ALL(neg_flags, 0x40000000)) { extern cli_auth_fns cli_netsec_fns; struct cli_connection *con = NULL; struct netsec_creds creds; safe_strcpy(creds.domain, domain, sizeof(creds.myname) - 1); safe_strcpy(creds.myname, cli_hostname, sizeof(creds.myname) - 1); memcpy(creds.sess_key, sess_key, sizeof(creds.sess_key)); if (!cli_connection_init_auth(srv_name, PIPE_NETLOGON, &con, &cli_netsec_fns, (void *)&creds)) { return NT_STATUS_ACCESS_DENIED | 0xC0000000; } if (!cli_con_set_creds(srv_name, sess_key, &clnt_cred)) { cli_connection_free(con); return NT_STATUS_ACCESS_DENIED | 0xC0000000; } } if (IS_BITS_SET_ALL(neg_flags, 0x40)) { (*validation_level) = 3; } else { (*validation_level) = 2; } return status; } /**************************************************************************** Set machine password. ****************************************************************************/ BOOL cli_nt_srv_pwset(const char *srv_name, const char *cli_hostname, const char *trust_acct, const uchar * new_hashof_trust_pwd, uint16 sec_chan) { DEBUG(5, ("cli_nt_srv_pwset: %d\n", __LINE__)); #ifdef DEBUG_PASSWORD dump_data(6, new_hashof_trust_pwd, 16); #endif /* send client srv_pwset challenge */ return cli_net_srv_pwset(srv_name, cli_hostname, trust_acct, new_hashof_trust_pwd, sec_chan); } /**************************************************************************** NT login - general. *NEVER* use this code. This method of doing a logon (sending the cleartext password equivalents, protected by the session key) is inherently insecure given the current design of the NT Domain system. JRA. ****************************************************************************/ BOOL cli_nt_login_general(const char *srv_name, const char *cli_hostname, const char *domain, const char *username, uint32 luid_low, const char *general, NET_ID_INFO_CTR * ctr, uint16 validation_level, NET_USER_INFO_3 * user_info3) { uint8 sess_key[16]; NET_USER_INFO_CTR user_ctr; uint32 status; ZERO_STRUCT(user_ctr); user_ctr.switch_value = validation_level; DEBUG(5, ("cli_nt_login_general: %d\n", __LINE__)); #ifdef DEBUG_PASSWORD DEBUG(100, ("\"general\" user password: ")); dump_data(100, general, strlen(general)); #endif if (!cli_get_sesskey_srv(srv_name, sess_key)) { DEBUG(1, ("could not obtain session key for %s\n", srv_name)); return NT_STATUS_ACCESS_DENIED; } /* indicate an "general" login */ ctr->switch_value = GENERAL_LOGON_TYPE; /* Create the structure needed for SAM logon. */ make_id_info4(&ctr->auth.id4, domain, 0, luid_low, 0, username, cli_hostname, general); /* Send client sam-logon request - update credentials on success. */ status = cli_net_sam_logon(srv_name, cli_hostname, ctr, &user_ctr); if (!net_user_info_3_copy_from_ctr(user_info3, &user_ctr)) { status = NT_STATUS_INVALID_PARAMETER; } free_net_user_info_ctr(&user_ctr); return status; } /**************************************************************************** NT login - interactive. *NEVER* use this code. This method of doing a logon (sending the cleartext password equivalents, protected by the session key) is inherently insecure given the current design of the NT Domain system. JRA. ****************************************************************************/ uint32 cli_nt_login_interactive(const char *srv_name, const char *cli_hostname, const char *domain, const char *username, uint32 luid_low, const uchar * lm_owf_user_pwd, const uchar * nt_owf_user_pwd, NET_ID_INFO_CTR * ctr, uint16 validation_level, NET_USER_INFO_3 * user_info3) { uint32 status; uint8 sess_key[16]; NET_USER_INFO_CTR user_ctr; ZERO_STRUCT(user_ctr); user_ctr.switch_value = validation_level; DEBUG(5, ("cli_nt_login_interactive: %d\n", __LINE__)); dump_data_pw("nt owf of user password:\n", lm_owf_user_pwd, 16); dump_data_pw("nt owf of user password:\n", nt_owf_user_pwd, 16); if (!cli_get_sesskey_srv(srv_name, sess_key)) { DEBUG(1, ("could not obtain session key for %s\n", srv_name)); return NT_STATUS_ACCESS_DENIED; } /* indicate an "interactive" login */ ctr->switch_value = INTERACTIVE_LOGON_TYPE; /* Create the structure needed for SAM logon. */ make_id_info1(&ctr->auth.id1, domain, 0, luid_low, 0, username, cli_hostname, (char *)sess_key, lm_owf_user_pwd, nt_owf_user_pwd); /* Send client sam-logon request - update credentials on success. */ status = cli_net_sam_logon(srv_name, cli_hostname, ctr, &user_ctr); if (!net_user_info_3_copy_from_ctr(user_info3, &user_ctr)) { status = NT_STATUS_INVALID_PARAMETER; } free_net_user_info_ctr(&user_ctr); memset(ctr->auth.id1.lm_owf.data, '\0', sizeof(ctr->auth.id1.lm_owf.data)); memset(ctr->auth.id1.nt_owf.data, '\0', sizeof(ctr->auth.id1.nt_owf.data)); return status; } /**************************************************************************** NT login - network. *ALWAYS* use this call to validate a user as it does not expose plaintext password equivalents over the network. JRA. ****************************************************************************/ uint32 cli_nt_login_network(const char *srv_name, const char *cli_hostname, const char *domain, const char *username, uint32 luid_low, const char lm_chal[8], const char *lm_chal_resp, int lm_chal_len, const char *nt_chal_resp, int nt_chal_len, NET_ID_INFO_CTR * ctr, uint16 validation_level, NET_USER_INFO_3 * user_info3) { uint8 sess_key[16]; uint32 status; NET_USER_INFO_CTR user_ctr; ZERO_STRUCT(user_ctr); user_ctr.switch_value = validation_level; DEBUG(5, ("cli_nt_login_network: %d\n", __LINE__)); if (!cli_get_sesskey_srv(srv_name, sess_key)) { DEBUG(1, ("could not obtain session key for %s\n", srv_name)); return NT_STATUS_ACCESS_DENIED; } /* indicate a "network" login */ ctr->switch_value = NETWORK_LOGON_TYPE; /* Create the structure needed for SAM logon. */ make_id_info2(&ctr->auth.id2, domain, 0, luid_low, 0, username, cli_hostname, lm_chal, lm_chal_resp, lm_chal_len, nt_chal_resp, nt_chal_len); /* Send client sam-logon request - update credentials on success. */ status = cli_net_sam_logon(srv_name, cli_hostname, ctr, &user_ctr); if (!net_user_info_3_copy_from_ctr(user_info3, &user_ctr)) { status = NT_STATUS_INVALID_PARAMETER; } free_net_user_info_ctr(&user_ctr); dump_data_pw("cli sess key:", sess_key, 8); dump_data_pw("enc padding:", user_info3->padding, 8); dump_data_pw("enc user sess key:", user_info3->user_sess_key, 16); SamOEMhash(user_info3->user_sess_key, sess_key, 0); SamOEMhash(user_info3->padding, sess_key, 3); dump_data_pw("dec padding:", user_info3->padding, 8); dump_data_pw("dec user sess key:", user_info3->user_sess_key, 16); return status; } /**************************************************************************** NT Logoff. ****************************************************************************/ BOOL cli_nt_logoff(const char *srv_name, const char *cli_hostname, NET_ID_INFO_CTR * ctr) { DEBUG(5, ("cli_nt_logoff: %d\n", __LINE__)); /* Send client sam-logoff request - update credentials on success. */ return cli_net_sam_logoff(srv_name, cli_hostname, ctr); } /**************************************************************************** NT SAM database sync ****************************************************************************/ BOOL net_sam_sync(const char *srv_name, const char *domain, const char *cli_hostname, const char *trust_acct, uchar trust_passwd[16], SAM_DELTA_HDR hdr_deltas[MAX_SAM_DELTAS], SAM_DELTA_CTR deltas[MAX_SAM_DELTAS], uint32 * num_deltas) { BOOL res = True; uint16 validation_level; *num_deltas = 0; DEBUG(5, ("Attempting SAM sync with PDC: %s\n", srv_name)); res = res ? cli_nt_setup_creds(srv_name, domain, cli_hostname, trust_acct, trust_passwd, SEC_CHAN_BDC, &validation_level) == 0x0 : False; memset(trust_passwd, 0, 16); res = res ? cli_net_sam_sync(srv_name, cli_hostname, 0, num_deltas, hdr_deltas, deltas) : False; if (!res) { DEBUG(5, ("SAM synchronisation FAILED\n")); return False; } DEBUG(5, ("SAM synchronisation returned %d entries\n", *num_deltas)); return True; }