X-Git-Url: http://git.samba.org/samba.git/?p=gd%2Fsamba%2F.git;a=blobdiff_plain;f=source%2Frpc_client%2Fcli_netlogon.c;h=91e27c5d85be0e58b74ebbe4807fe86ac95d6124;hp=831101ed81e4e7bb25d85dc0604e7befca8773ab;hb=bd6e2fcf3b3ab15736584edbbfb941b381988499;hpb=b47b930e0bcce54cc6eeced7e74b7cc38dc85735 diff --git a/source/rpc_client/cli_netlogon.c b/source/rpc_client/cli_netlogon.c index 831101ed81e..91e27c5d85b 100644 --- a/source/rpc_client/cli_netlogon.c +++ b/source/rpc_client/cli_netlogon.c @@ -1,759 +1,627 @@ -/* +/* Unix SMB/CIFS implementation. NT Domain Authentication SMB / MSRPC client Copyright (C) Andrew Tridgell 1992-2000 - Copyright (C) Luke Kenneth Casson Leighton 1996-2000 - Copyright (C) Tim Potter 2001 - Copyright (C) Paul Ashton 1997. Copyright (C) Jeremy Allison 1998. - Copyright (C) Andrew Bartlett 2001. - + Largely re-written by Jeremy Allison (C) 2005. + 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 + the Free Software Foundation; either version 3 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. + along with this program. If not, see . */ #include "includes.h" /* LSA Request Challenge. Sends our challenge to server, then gets - server response. These are used to generate the credentials. */ - -NTSTATUS cli_net_req_chal(struct cli_state *cli, DOM_CHAL *clnt_chal, - DOM_CHAL *srv_chal) -{ - prs_struct qbuf, rbuf; - NET_Q_REQ_CHAL q; - NET_R_REQ_CHAL r; - NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - - prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL); - prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL); - - /* create and send a MSRPC command with api NET_REQCHAL */ - - DEBUG(4,("cli_net_req_chal: LSA Request Challenge from %s to %s: %s\n", - global_myname(), cli->desthost, credstr(clnt_chal->data))); - - /* store the parameters */ - init_q_req_chal(&q, cli->srv_name_slash, global_myname(), clnt_chal); - - /* Marshall data and send request */ - - if (!net_io_q_req_chal("", &q, &qbuf, 0) || - !rpc_api_pipe_req(cli, NET_REQCHAL, &qbuf, &rbuf)) { - goto done; - } - - /* Unmarhall response */ - - if (!net_io_r_req_chal("", &r, &rbuf, 0)) { - goto done; - } - - result = r.status; - - /* Return result */ + server response. These are used to generate the credentials. + The sent and received challenges are stored in the netlog pipe + private data. Only call this via rpccli_netlogon_setup_creds(). JRA. +*/ - if (NT_STATUS_IS_OK(result)) { - memcpy(srv_chal, r.srv_chal.data, sizeof(srv_chal->data)); - } - - done: - prs_mem_free(&qbuf); - prs_mem_free(&rbuf); - - return result; -} +/* instead of rpccli_net_req_chal() we use rpccli_netr_ServerReqChallenge() now - gd */ +#if 0 /**************************************************************************** LSA Authenticate 2 Send the client credential, receive back a server credential. -Ensure that the server credential returned matches the session key +Ensure that the server credential returned matches the session key encrypt of the server challenge originally received. JRA. ****************************************************************************/ -NTSTATUS cli_net_auth2(struct cli_state *cli, - uint16 sec_chan, + NTSTATUS rpccli_net_auth2(struct rpc_pipe_client *cli, + uint16 sec_chan, uint32 *neg_flags, DOM_CHAL *srv_chal) { prs_struct qbuf, rbuf; NET_Q_AUTH_2 q; NET_R_AUTH_2 r; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + fstring machine_acct; - prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL); - prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL); + if ( sec_chan == SEC_CHAN_DOMAIN ) + fstr_sprintf( machine_acct, "%s$", lp_workgroup() ); + else + fstrcpy( machine_acct, cli->mach_acct ); /* create and send a MSRPC command with api NET_AUTH2 */ DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s chal %s neg: %x\n", - cli->srv_name_slash, cli->mach_acct, sec_chan, global_myname(), + cli->srv_name_slash, machine_acct, sec_chan, global_myname(), credstr(cli->clnt_cred.challenge.data), *neg_flags)); /* store the parameters */ - init_q_auth_2(&q, cli->srv_name_slash, cli->mach_acct, - sec_chan, global_myname(), &cli->clnt_cred.challenge, + + init_q_auth_2(&q, cli->srv_name_slash, machine_acct, + sec_chan, global_myname(), &cli->clnt_cred.challenge, *neg_flags); /* turn parameters into data stream */ - if (!net_io_q_auth_2("", &q, &qbuf, 0) || - !rpc_api_pipe_req(cli, NET_AUTH2, &qbuf, &rbuf)) { - goto done; - } - - /* Unmarshall response */ - - if (!net_io_r_auth_2("", &r, &rbuf, 0)) { - goto done; - } + CLI_DO_RPC(cli, mem_ctx, PI_NETLOGON, NET_AUTH2, + q, r, + qbuf, rbuf, + net_io_q_auth_2, + net_io_r_auth_2, + NT_STATUS_UNSUCCESSFUL); result = r.status; if (NT_STATUS_IS_OK(result)) { UTIME zerotime; - + /* * Check the returned value using the initial * server received challenge. */ zerotime.time = 0; - if (cred_assert( &r.srv_chal, cli->sess_key, srv_chal, - zerotime) == 0) { + if (cred_assert( &r.srv_chal, cli->sess_key, srv_chal, zerotime) == 0) { /* * Server replied with bad credential. Fail. */ DEBUG(0,("cli_net_auth2: server %s replied with bad credential (bad machine \ -password ?).\n", cli->desthost )); - result = NT_STATUS_ACCESS_DENIED; - goto done; +password ?).\n", cli->cli->desthost )); + return NT_STATUS_ACCESS_DENIED; } *neg_flags = r.srv_flgs.neg_flags; } - done: - prs_mem_free(&qbuf); - prs_mem_free(&rbuf); - return result; } +#endif /**************************************************************************** -LSA Authenticate 3 + LSA Authenticate 2 -Send the client credential, receive back a server credential. -Ensure that the server credential returned matches the session key -encrypt of the server challenge originally received. JRA. + Send the client credential, receive back a server credential. + The caller *must* ensure that the server credential returned matches the session key + encrypt of the server challenge originally received. JRA. ****************************************************************************/ -NTSTATUS cli_net_auth3(struct cli_state *cli, - uint16 sec_chan, - uint32 *neg_flags, DOM_CHAL *srv_chal) -{ - prs_struct qbuf, rbuf; - NET_Q_AUTH_3 q; - NET_R_AUTH_3 r; - NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - - prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL); - prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL); - - /* create and send a MSRPC command with api NET_AUTH2 */ - - DEBUG(4,("cli_net_auth3: srv:%s acct:%s sc:%x mc: %s chal %s neg: %x\n", - cli->srv_name_slash, cli->mach_acct, sec_chan, global_myname(), - credstr(cli->clnt_cred.challenge.data), *neg_flags)); - - /* store the parameters */ - init_q_auth_3(&q, cli->srv_name_slash, cli->mach_acct, - sec_chan, global_myname(), &cli->clnt_cred.challenge, - *neg_flags); +/* instead of rpccli_net_auth2() we use rpccli_netr_ServerAuthenticate2() now - gd */ - /* turn parameters into data stream */ - - if (!net_io_q_auth_3("", &q, &qbuf, 0) || - !rpc_api_pipe_req(cli, NET_AUTH3, &qbuf, &rbuf)) { - goto done; - } - - /* Unmarshall response */ - - if (!net_io_r_auth_3("", &r, &rbuf, 0)) { - goto done; - } - - result = r.status; - if (NT_STATUS_IS_OK(result)) { - UTIME zerotime; - - /* - * Check the returned value using the initial - * server received challenge. - */ - - zerotime.time = 0; - if (cred_assert( &r.srv_chal, cli->sess_key, srv_chal, - zerotime) == 0) { - - /* - * Server replied with bad credential. Fail. - */ - DEBUG(0,("cli_net_auth3: server %s replied with bad credential (bad machine \ -password ?).\n", cli->desthost )); - result = NT_STATUS_ACCESS_DENIED; - goto done; - } - *neg_flags = r.srv_flgs.neg_flags; - } - - done: - prs_mem_free(&qbuf); - prs_mem_free(&rbuf); - - return result; -} - -/* Initialize domain session credentials */ +/**************************************************************************** + Wrapper function that uses the auth and auth2 calls to set up a NETLOGON + credentials chain. Stores the credentials in the struct dcinfo in the + netlogon pipe struct. +****************************************************************************/ -NTSTATUS cli_nt_setup_creds(struct cli_state *cli, - uint16 sec_chan, - const unsigned char mach_pwd[16], uint32 *neg_flags, int level) +NTSTATUS rpccli_netlogon_setup_creds(struct rpc_pipe_client *cli, + const char *server_name, + const char *domain, + const char *clnt_name, + const char *machine_account, + const unsigned char machine_pwd[16], + enum netr_SchannelType sec_chan_type, + uint32_t *neg_flags_inout) { - DOM_CHAL clnt_chal; - DOM_CHAL srv_chal; - UTIME zerotime; - NTSTATUS result; - - /******************* Request Challenge ********************/ + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + struct netr_Credential clnt_chal_send; + struct netr_Credential srv_chal_recv; + struct dcinfo *dc; - generate_random_buffer(clnt_chal.data, 8, False); - - /* send a client challenge; receive a server challenge */ - result = cli_net_req_chal(cli, &clnt_chal, &srv_chal); + SMB_ASSERT(cli->pipe_idx == PI_NETLOGON); - if (!NT_STATUS_IS_OK(result)) { - DEBUG(0,("cli_nt_setup_creds: request challenge failed\n")); - return result; - } - - /**************** Long-term Session key **************/ - - /* calculate the session key */ - cred_session_key(&clnt_chal, &srv_chal, mach_pwd, - cli->sess_key); - memset((char *)cli->sess_key+8, '\0', 8); - - /******************* Authenticate 2/3 ********************/ - - /* calculate auth-2/3 credentials */ - zerotime.time = 0; - cred_create(cli->sess_key, &clnt_chal, zerotime, &cli->clnt_cred.challenge); - - /* - * Send client auth-2/3 challenge. - * Receive an auth-2/3 challenge response and check it. - */ - switch (level) { - case 2: - result = cli_net_auth2(cli, sec_chan, neg_flags, &srv_chal); - break; - case 3: - result = cli_net_auth3(cli, sec_chan, neg_flags, &srv_chal); - break; - default: - DEBUG(1,("cli_nt_setup_creds: unsupported auth level: %d\n", level)); - break; + dc = cli->dc; + if (!dc) { + return NT_STATUS_INVALID_PARAMETER; } - if (!NT_STATUS_IS_OK(result)) - DEBUG(3,("cli_nt_setup_creds: auth%d challenge failed %s\n", level, nt_errstr(result))); + /* Ensure we don't reuse any of this state. */ + ZERO_STRUCTP(dc); - return result; -} - -/* Logon Control 2 */ + /* Store the machine account password we're going to use. */ + memcpy(dc->mach_pw, machine_pwd, 16); -NTSTATUS cli_netlogon_logon_ctrl2(struct cli_state *cli, TALLOC_CTX *mem_ctx, - uint32 query_level) -{ - prs_struct qbuf, rbuf; - NET_Q_LOGON_CTRL2 q; - NET_R_LOGON_CTRL2 r; - NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + fstrcpy(dc->remote_machine, "\\\\"); + fstrcat(dc->remote_machine, server_name); - ZERO_STRUCT(q); - ZERO_STRUCT(r); + fstrcpy(dc->domain, domain); - /* Initialise parse structures */ + fstr_sprintf( dc->mach_acct, "%s$", machine_account); - prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); + /* Create the client challenge. */ + generate_random_buffer(clnt_chal_send.data, 8); - /* Initialise input parameters */ + /* Get the server challenge. */ + result = rpccli_netr_ServerReqChallenge(cli, cli->mem_ctx, + dc->remote_machine, + clnt_name, + &clnt_chal_send, + &srv_chal_recv); + if (!NT_STATUS_IS_OK(result)) { + return result; + } - init_net_q_logon_ctrl2(&q, cli->srv_name_slash, query_level); + /* Calculate the session key and client credentials */ + creds_client_init(*neg_flags_inout, + dc, + &clnt_chal_send, + &srv_chal_recv, + machine_pwd, + &clnt_chal_send); - /* Marshall data and send request */ + /* + * Send client auth-2 challenge and receive server repy. + */ - if (!net_io_q_logon_ctrl2("", &q, &qbuf, 0) || - !rpc_api_pipe_req(cli, NET_LOGON_CTRL2, &qbuf, &rbuf)) { - result = NT_STATUS_UNSUCCESSFUL; - goto done; + result = rpccli_netr_ServerAuthenticate2(cli, cli->mem_ctx, + dc->remote_machine, + dc->mach_acct, + sec_chan_type, + clnt_name, + &clnt_chal_send, /* input. */ + &srv_chal_recv, /* output. */ + neg_flags_inout); + if (!NT_STATUS_IS_OK(result)) { + return result; } - /* Unmarshall response */ + /* + * Check the returned value using the initial + * server received challenge. + */ - if (!net_io_r_logon_ctrl2("", &r, &rbuf, 0)) { - result = NT_STATUS_UNSUCCESSFUL; - goto done; + if (!netlogon_creds_client_check(dc, &srv_chal_recv)) { + /* + * Server replied with bad credential. Fail. + */ + DEBUG(0,("rpccli_netlogon_setup_creds: server %s " + "replied with bad credential\n", + cli->cli->desthost )); + return NT_STATUS_ACCESS_DENIED; } - result = r.status; + DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential " + "chain established.\n", + cli->cli->desthost )); - done: - prs_mem_free(&qbuf); - prs_mem_free(&rbuf); - - return result; + return NT_STATUS_OK; } -/**************************************************************************** -Generate the next creds to use. Yuck - this is a cut&paste from another -file. They should be combined at some stage. )-: -****************************************************************************/ - -static void gen_next_creds( struct cli_state *cli, DOM_CRED *new_clnt_cred) -{ - /* - * Create the new client credentials. - */ - - cli->clnt_cred.timestamp.time = time(NULL); - - memcpy(new_clnt_cred, &cli->clnt_cred, sizeof(*new_clnt_cred)); - - /* Calculate the new credentials. */ - cred_create(cli->sess_key, &(cli->clnt_cred.challenge), - new_clnt_cred->timestamp, &(new_clnt_cred->challenge)); -} - -/* Sam synchronisation */ +/* Logon domain user */ -NTSTATUS cli_netlogon_sam_sync(struct cli_state *cli, TALLOC_CTX *mem_ctx, DOM_CRED *ret_creds, - uint32 database_id, uint32 next_rid, uint32 *num_deltas, - SAM_DELTA_HDR **hdr_deltas, - SAM_DELTA_CTR **deltas) +NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + uint32 logon_parameters, + const char *domain, + const char *username, + const char *password, + const char *workstation, + int logon_type) { - prs_struct qbuf, rbuf; - NET_Q_SAM_SYNC q; - NET_R_SAM_SYNC r; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - DOM_CRED clnt_creds; - - ZERO_STRUCT(q); - ZERO_STRUCT(r); - - /* Initialise parse structures */ - - prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); - - /* Initialise input parameters */ - - gen_next_creds(cli, &clnt_creds); - - init_net_q_sam_sync(&q, cli->srv_name_slash, cli->clnt_name_slash + 2, - &clnt_creds, ret_creds, database_id, next_rid); + struct netr_Authenticator clnt_creds; + struct netr_Authenticator ret_creds; + union netr_LogonLevel *logon; + union netr_Validation validation; + uint8_t authoritative; + int validation_level = 3; + fstring clnt_name_slash; + uint8 zeros[16]; - /* Marshall data and send request */ + ZERO_STRUCT(ret_creds); + ZERO_STRUCT(zeros); - if (!net_io_q_sam_sync("", &q, &qbuf, 0) || - !rpc_api_pipe_req(cli, NET_SAM_SYNC, &qbuf, &rbuf)) { - result = NT_STATUS_UNSUCCESSFUL; - goto done; + logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel); + if (!logon) { + return NT_STATUS_NO_MEMORY; } - /* Unmarshall response */ - - if (!net_io_r_sam_sync("", cli->sess_key, &r, &rbuf, 0)) { - result = NT_STATUS_UNSUCCESSFUL; - goto done; + if (workstation) { + fstr_sprintf( clnt_name_slash, "\\\\%s", workstation ); + } else { + fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() ); } - /* Return results */ - - result = r.status; - *num_deltas = r.num_deltas2; - *hdr_deltas = r.hdr_deltas; - *deltas = r.deltas; + /* Initialise input parameters */ - memcpy(ret_creds, &r.srv_creds, sizeof(*ret_creds)); + netlogon_creds_client_step(cli->dc, &clnt_creds); - done: - prs_mem_free(&qbuf); - prs_mem_free(&rbuf); + switch (logon_type) { + case INTERACTIVE_LOGON_TYPE: { - return result; -} + struct netr_PasswordInfo *password_info; -/* Sam synchronisation */ + struct samr_Password lmpassword; + struct samr_Password ntpassword; -NTSTATUS cli_netlogon_sam_deltas(struct cli_state *cli, TALLOC_CTX *mem_ctx, - uint32 database_id, UINT64_S seqnum, - uint32 *num_deltas, - SAM_DELTA_HDR **hdr_deltas, - SAM_DELTA_CTR **deltas) -{ - prs_struct qbuf, rbuf; - NET_Q_SAM_DELTAS q; - NET_R_SAM_DELTAS r; - NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - DOM_CRED clnt_creds; + unsigned char lm_owf_user_pwd[16], nt_owf_user_pwd[16]; - ZERO_STRUCT(q); - ZERO_STRUCT(r); + unsigned char lm_owf[16]; + unsigned char nt_owf[16]; + unsigned char key[16]; - /* Initialise parse structures */ + password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo); + if (!password_info) { + return NT_STATUS_NO_MEMORY; + } - prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); + nt_lm_owf_gen(password, nt_owf_user_pwd, lm_owf_user_pwd); + +#ifdef DEBUG_PASSWORD + DEBUG(100,("lm cypher:")); + dump_data(100, lm_owf_user_pwd, 16); + + DEBUG(100,("nt cypher:")); + dump_data(100, nt_owf_user_pwd, 16); +#endif + memset(key, 0, 16); + memcpy(key, cli->dc->sess_key, 8); + + memcpy(lm_owf, lm_owf_user_pwd, 16); + SamOEMhash(lm_owf, key, 16); + memcpy(nt_owf, nt_owf_user_pwd, 16); + SamOEMhash(nt_owf, key, 16); + +#ifdef DEBUG_PASSWORD + DEBUG(100,("encrypt of lm owf password:")); + dump_data(100, lm_owf, 16); + + DEBUG(100,("encrypt of nt owf password:")); + dump_data(100, nt_owf, 16); +#endif + memcpy(lmpassword.hash, lm_owf, 16); + memcpy(ntpassword.hash, nt_owf, 16); + + init_netr_PasswordInfo(password_info, + domain, + logon_parameters, + 0xdead, + 0xbeef, + username, + clnt_name_slash, + lmpassword, + ntpassword); + + logon->password = password_info; + + break; + } + case NET_LOGON_TYPE: { + struct netr_NetworkInfo *network_info; + uint8 chal[8]; + unsigned char local_lm_response[24]; + unsigned char local_nt_response[24]; + struct netr_ChallengeResponse lm; + struct netr_ChallengeResponse nt; + + ZERO_STRUCT(lm); + ZERO_STRUCT(nt); + + network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo); + if (!network_info) { + return NT_STATUS_NO_MEMORY; + } - /* Initialise input parameters */ + generate_random_buffer(chal, 8); - gen_next_creds(cli, &clnt_creds); + SMBencrypt(password, chal, local_lm_response); + SMBNTencrypt(password, chal, local_nt_response); - init_net_q_sam_deltas(&q, cli->srv_name_slash, - cli->clnt_name_slash + 2, &clnt_creds, - database_id, seqnum); + lm.length = 24; + lm.data = local_lm_response; - /* Marshall data and send request */ + nt.length = 24; + nt.data = local_nt_response; - if (!net_io_q_sam_deltas("", &q, &qbuf, 0) || - !rpc_api_pipe_req(cli, NET_SAM_DELTAS, &qbuf, &rbuf)) { - result = NT_STATUS_UNSUCCESSFUL; - goto done; - } + init_netr_NetworkInfo(network_info, + domain, + logon_parameters, + 0xdead, + 0xbeef, + username, + clnt_name_slash, + chal, + nt, + lm); - /* Unmarshall response */ + logon->network = network_info; - if (!net_io_r_sam_deltas("", cli->sess_key, &r, &rbuf, 0)) { - result = NT_STATUS_UNSUCCESSFUL; - goto done; + break; + } + default: + DEBUG(0, ("switch value %d not supported\n", + logon_type)); + return NT_STATUS_INVALID_INFO_CLASS; } - /* Return results */ - - result = r.status; - *num_deltas = r.num_deltas2; - *hdr_deltas = r.hdr_deltas; - *deltas = r.deltas; - - done: - prs_mem_free(&qbuf); - prs_mem_free(&rbuf); + result = rpccli_netr_LogonSamLogon(cli, mem_ctx, + cli->dc->remote_machine, + global_myname(), + &clnt_creds, + &ret_creds, + logon_type, + logon, + validation_level, + &validation, + &authoritative); + + if (memcmp(zeros, &ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) { + /* Check returned credentials if present. */ + if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) { + DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n")); + return NT_STATUS_ACCESS_DENIED; + } + } return result; } -/* 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) +/** + * Logon domain user with an 'network' SAM logon + * + * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller. + **/ + +NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + uint32 logon_parameters, + const char *server, + const char *username, + const char *domain, + const char *workstation, + const uint8 chal[8], + DATA_BLOB lm_response, + DATA_BLOB nt_response, + struct netr_SamInfo3 **info3) { - prs_struct qbuf, rbuf; - NET_Q_SAM_LOGON q; - NET_R_SAM_LOGON r; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - DOM_CRED clnt_creds, dummy_rtn_creds; - NET_ID_INFO_CTR ctr; - NET_USER_INFO_3 user; - int validation_level = 3; - - ZERO_STRUCT(q); - ZERO_STRUCT(r); - ZERO_STRUCT(dummy_rtn_creds); - - /* Initialise parse structures */ + int validation_level = 3; + const char *workstation_name_slash; + const char *server_name_slash; + uint8 zeros[16]; + struct netr_Authenticator clnt_creds; + struct netr_Authenticator ret_creds; + union netr_LogonLevel *logon = NULL; + struct netr_NetworkInfo *network_info; + uint8_t authoritative; + union netr_Validation validation; + struct netr_ChallengeResponse lm; + struct netr_ChallengeResponse nt; + struct netr_UserSessionKey user_session_key; + struct netr_LMSessionKey lmsesskey; + + *info3 = NULL; + + ZERO_STRUCT(zeros); + ZERO_STRUCT(ret_creds); + + ZERO_STRUCT(lm); + ZERO_STRUCT(nt); + + logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel); + if (!logon) { + return NT_STATUS_NO_MEMORY; + } - prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); + network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo); + if (!network_info) { + return NT_STATUS_NO_MEMORY; + } - /* Initialise input parameters */ + netlogon_creds_client_step(cli->dc, &clnt_creds); - gen_next_creds(cli, &clnt_creds); + if (server[0] != '\\' && server[1] != '\\') { + server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server); + } else { + server_name_slash = server; + } - q.validation_level = validation_level; + if (workstation[0] != '\\' && workstation[1] != '\\') { + workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation); + } else { + workstation_name_slash = workstation; + } - if (ret_creds == NULL) - ret_creds = &dummy_rtn_creds; + if (!workstation_name_slash || !server_name_slash) { + DEBUG(0, ("talloc_asprintf failed!\n")); + return NT_STATUS_NO_MEMORY; + } - ctr.switch_value = logon_type; + /* Initialise input parameters */ - switch (logon_type) { - case INTERACTIVE_LOGON_TYPE: { - unsigned char lm_owf_user_pwd[16], nt_owf_user_pwd[16]; + lm.data = lm_response.data; + lm.length = lm_response.length; + nt.data = nt_response.data; + nt.length = nt_response.length; - nt_lm_owf_gen(password, nt_owf_user_pwd, lm_owf_user_pwd); + init_netr_NetworkInfo(network_info, + domain, + logon_parameters, + 0xdead, + 0xbeef, + username, + workstation_name_slash, + (uint8_t *) chal, + nt, + lm); - init_id_info1(&ctr.auth.id1, lp_workgroup(), - 0, /* param_ctrl */ - 0xdead, 0xbeef, /* LUID? */ - username, cli->clnt_name_slash, - cli->sess_key, lm_owf_user_pwd, - nt_owf_user_pwd); + logon->network = network_info; - break; - } - case NET_LOGON_TYPE: { - uint8 chal[8]; - unsigned char local_lm_response[24]; - unsigned char local_nt_response[24]; - - generate_random_buffer(chal, 8, False); - - SMBencrypt(password, chal, local_lm_response); - SMBNTencrypt(password, chal, local_nt_response); - - init_id_info2(&ctr.auth.id2, lp_workgroup(), - 0, /* param_ctrl */ - 0xdead, 0xbeef, /* LUID? */ - username, cli->clnt_name_slash, chal, - local_lm_response, 24, local_nt_response, 24); - break; - } - default: - DEBUG(0, ("switch value %d not supported\n", - ctr.switch_value)); - goto done; - } - - init_sam_info(&q.sam_id, cli->srv_name_slash, global_myname(), - &clnt_creds, ret_creds, logon_type, - &ctr); - - /* Marshall data and send request */ + /* Marshall data and send request */ - if (!net_io_q_sam_logon("", &q, &qbuf, 0) || - !rpc_api_pipe_req(cli, NET_SAMLOGON, &qbuf, &rbuf)) { - goto done; + result = rpccli_netr_LogonSamLogon(cli, mem_ctx, + server_name_slash, + global_myname(), + &clnt_creds, + &ret_creds, + NET_LOGON_TYPE, + logon, + validation_level, + &validation, + &authoritative); + if (!NT_STATUS_IS_OK(result)) { + return result; } - /* Unmarshall response */ - - r.user = &user; + user_session_key = validation.sam3->base.key; + lmsesskey = validation.sam3->base.LMSessKey; - if (!net_io_r_sam_logon("", &r, &rbuf, 0)) { - goto done; + if (memcmp(zeros, user_session_key.key, 16) != 0) { + SamOEMhash(user_session_key.key, cli->dc->sess_key, 16); } - /* Return results */ + if (memcmp(zeros, lmsesskey.key, 8) != 0) { + SamOEMhash(lmsesskey.key, cli->dc->sess_key, 8); + } - result = r.status; - memcpy(ret_creds, &r.srv_creds, sizeof(*ret_creds)); + if (memcmp(zeros, ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) { + /* Check returned credentials if present. */ + if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) { + DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n")); + return NT_STATUS_ACCESS_DENIED; + } + } - done: - prs_mem_free(&qbuf); - prs_mem_free(&rbuf); + *info3 = validation.sam3; - return result; + return result; } - -/** - * Logon domain user with an 'network' SAM logon - * - * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller. - **/ - -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, - NET_USER_INFO_3 *info3) - +NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + uint32 logon_parameters, + const char *server, + const char *username, + const char *domain, + const char *workstation, + const uint8 chal[8], + DATA_BLOB lm_response, + DATA_BLOB nt_response, + struct netr_SamInfo3 **info3) { - prs_struct qbuf, rbuf; - NET_Q_SAM_LOGON q; - NET_R_SAM_LOGON r; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - DOM_CRED clnt_creds, dummy_rtn_creds; - NET_ID_INFO_CTR ctr; int validation_level = 3; - char *workstation_name_slash; - uint8 netlogon_sess_key[16]; - static uint8 zeros[16]; - - ZERO_STRUCT(q); - ZERO_STRUCT(r); - ZERO_STRUCT(dummy_rtn_creds); - - workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation); - - if (!workstation_name_slash) { - DEBUG(0, ("talloc_asprintf failed!\n")); + const char *workstation_name_slash; + const char *server_name_slash; + uint8 zeros[16]; + union netr_LogonLevel *logon = NULL; + struct netr_NetworkInfo *network_info; + uint8_t authoritative; + union netr_Validation validation; + struct netr_ChallengeResponse lm; + struct netr_ChallengeResponse nt; + struct netr_UserSessionKey user_session_key; + struct netr_LMSessionKey lmsesskey; + uint32_t flags = 0; + + *info3 = NULL; + + ZERO_STRUCT(zeros); + + ZERO_STRUCT(lm); + ZERO_STRUCT(nt); + + logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel); + if (!logon) { return NT_STATUS_NO_MEMORY; } - /* Initialise parse structures */ + network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo); + if (!network_info) { + return NT_STATUS_NO_MEMORY; + } - prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); + if (server[0] != '\\' && server[1] != '\\') { + server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server); + } else { + server_name_slash = server; + } - /* Initialise input parameters */ + if (workstation[0] != '\\' && workstation[1] != '\\') { + workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation); + } else { + workstation_name_slash = workstation; + } - gen_next_creds(cli, &clnt_creds); + if (!workstation_name_slash || !server_name_slash) { + DEBUG(0, ("talloc_asprintf failed!\n")); + return NT_STATUS_NO_MEMORY; + } - q.validation_level = validation_level; + /* Initialise input parameters */ - if (ret_creds == NULL) - ret_creds = &dummy_rtn_creds; + lm.data = lm_response.data; + lm.length = lm_response.length; + nt.data = nt_response.data; + nt.length = nt_response.length; - ctr.switch_value = NET_LOGON_TYPE; + init_netr_NetworkInfo(network_info, + domain, + logon_parameters, + 0xdead, + 0xbeef, + username, + workstation_name_slash, + (uint8_t *) chal, + nt, + lm); - init_id_info2(&ctr.auth.id2, domain, - 0, /* param_ctrl */ - 0xdead, 0xbeef, /* LUID? */ - username, workstation_name_slash, (const uchar*)chal, - 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, ret_creds, NET_LOGON_TYPE, - &ctr); + logon->network = network_info; /* Marshall data and send request */ - if (!net_io_q_sam_logon("", &q, &qbuf, 0) || - !rpc_api_pipe_req(cli, NET_SAMLOGON, &qbuf, &rbuf)) { - goto done; + result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx, + server_name_slash, + global_myname(), + NET_LOGON_TYPE, + logon, + validation_level, + &validation, + &authoritative, + &flags); + if (!NT_STATUS_IS_OK(result)) { + return result; } - /* Unmarshall response */ + user_session_key = validation.sam3->base.key; + lmsesskey = validation.sam3->base.LMSessKey; - r.user = info3; - - if (!net_io_r_sam_logon("", &r, &rbuf, 0)) { - goto done; + if (memcmp(zeros, user_session_key.key, 16) != 0) { + SamOEMhash(user_session_key.key, cli->dc->sess_key, 16); } - ZERO_STRUCT(netlogon_sess_key); - memcpy(netlogon_sess_key, cli->sess_key, 8); - - if (memcmp(zeros, info3->user_sess_key, 16) != 0) - SamOEMhash(info3->user_sess_key, netlogon_sess_key, 16); - - if (memcmp(zeros, info3->padding, 16) != 0) - SamOEMhash(info3->padding, netlogon_sess_key, 16); - - /* Return results */ - - result = r.status; - memcpy(ret_creds, &r.srv_creds, sizeof(*ret_creds)); - - done: - prs_mem_free(&qbuf); - prs_mem_free(&rbuf); - - return result; -} - -/*************************************************************************** -LSA Server Password Set. -****************************************************************************/ - -NTSTATUS cli_net_srv_pwset(struct cli_state *cli, TALLOC_CTX *mem_ctx, - const char *machine_name, uint8 hashed_mach_pwd[16]) -{ - prs_struct rbuf; - prs_struct qbuf; - DOM_CRED new_clnt_cred; - NET_Q_SRV_PWSET q_s; - uint16 sec_chan_type = 2; - NTSTATUS nt_status; - char *mach_acct; - - gen_next_creds( cli, &new_clnt_cred); - - prs_init(&qbuf , 1024, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); - - /* create and send a MSRPC command with api NET_SRV_PWSET */ - - mach_acct = talloc_asprintf(mem_ctx, "%s$", machine_name); - - if (!mach_acct) { - DEBUG(0,("talloc_asprintf failed!\n")); - nt_status = NT_STATUS_NO_MEMORY; - goto done; + if (memcmp(zeros, lmsesskey.key, 8) != 0) { + SamOEMhash(lmsesskey.key, cli->dc->sess_key, 8); } - DEBUG(4,("cli_net_srv_pwset: srv:%s acct:%s sc: %d mc: %s clnt %s %x\n", - cli->srv_name_slash, mach_acct, sec_chan_type, machine_name, - credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time)); - - /* store the parameters */ - init_q_srv_pwset(&q_s, cli->srv_name_slash, cli->sess_key, - mach_acct, sec_chan_type, machine_name, - &new_clnt_cred, (char *)hashed_mach_pwd); - - /* turn parameters into data stream */ - if(!net_io_q_srv_pwset("", &q_s, &qbuf, 0)) { - DEBUG(0,("cli_net_srv_pwset: Error : failed to marshall NET_Q_SRV_PWSET struct.\n")); - nt_status = NT_STATUS_UNSUCCESSFUL; - goto done; - } - - /* send the data on \PIPE\ */ - if (rpc_api_pipe_req(cli, NET_SRVPWSET, &qbuf, &rbuf)) - { - NET_R_SRV_PWSET r_s; - - if (!net_io_r_srv_pwset("", &r_s, &rbuf, 0)) { - nt_status = NT_STATUS_UNSUCCESSFUL; - goto done; - } - - nt_status = r_s.status; - - if (!NT_STATUS_IS_OK(r_s.status)) - { - /* report error code */ - DEBUG(0,("cli_net_srv_pwset: %s\n", nt_errstr(nt_status))); - goto done; - } + *info3 = validation.sam3; - /* Update the credentials. */ - if (!clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &(r_s.srv_cred))) - { - /* - * Server replied with bad credential. Fail. - */ - DEBUG(0,("cli_net_srv_pwset: server %s replied with bad credential (bad machine \ -password ?).\n", cli->desthost )); - nt_status = NT_STATUS_UNSUCCESSFUL; - } - } + return result; - done: - prs_mem_free(&qbuf); - prs_mem_free(&rbuf); - - return nt_status; + return result; } -