/* * Unix SMB/CIFS implementation. * RPC Pipe client / server routines * Largely rewritten by Jeremy Allison 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 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, see . */ #include "includes.h" #include "../librpc/gen_ndr/ndr_schannel.h" #include "../librpc/gen_ndr/ndr_netlogon.h" #include "../libcli/auth/schannel.h" #include "rpc_client/cli_netlogon.h" #include "rpc_client/cli_pipe.h" #include "librpc/gen_ndr/ndr_dcerpc.h" #include "librpc/rpc/dcerpc.h" #include "passdb.h" #include "libsmb/libsmb.h" #include "auth/gensec/gensec.h" #include "../libcli/smb/smbXcli_base.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_RPC_CLI /**************************************************************************** Get a the schannel session key out of an already opened netlogon pipe. ****************************************************************************/ static NTSTATUS get_schannel_session_key_common(struct rpc_pipe_client *netlogon_pipe, struct cli_state *cli, const char *domain, uint32 *pneg_flags) { enum netr_SchannelType sec_chan_type = 0; unsigned char machine_pwd[16]; const char *machine_account; NTSTATUS status; /* Get the machine account credentials from secrets.tdb. */ if (!get_trust_pw_hash(domain, machine_pwd, &machine_account, &sec_chan_type)) { DEBUG(0, ("get_schannel_session_key: could not fetch " "trust account password for domain '%s'\n", domain)); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } status = rpccli_netlogon_setup_creds(netlogon_pipe, smbXcli_conn_remote_name(cli->conn), /* server name */ domain, /* domain */ lp_netbios_name(), /* client name */ machine_account, /* machine account name */ machine_pwd, sec_chan_type, pneg_flags); if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("get_schannel_session_key_common: " "rpccli_netlogon_setup_creds failed with result %s " "to server %s, domain %s, machine account %s.\n", nt_errstr(status), smbXcli_conn_remote_name(cli->conn), domain, machine_account )); return status; } if (((*pneg_flags) & NETLOGON_NEG_SCHANNEL) == 0) { DEBUG(3, ("get_schannel_session_key: Server %s did not offer schannel\n", smbXcli_conn_remote_name(cli->conn))); return NT_STATUS_INVALID_NETWORK_RESPONSE; } return NT_STATUS_OK; } /**************************************************************************** Open a named pipe to an SMB server and bind using schannel (bind type 68). Fetch the session key ourselves using a temporary netlogon pipe. ****************************************************************************/ NTSTATUS cli_rpc_pipe_open_schannel(struct cli_state *cli, const struct ndr_interface_table *table, enum dcerpc_transport_t transport, enum dcerpc_AuthLevel auth_level, const char *domain, struct rpc_pipe_client **presult) { uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES; struct rpc_pipe_client *netlogon_pipe = NULL; struct rpc_pipe_client *result = NULL; NTSTATUS status; status = get_schannel_session_key(cli, domain, &neg_flags, &netlogon_pipe); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("cli_rpc_pipe_open_schannel: failed to get schannel session " "key from server %s for domain %s.\n", smbXcli_conn_remote_name(cli->conn), domain )); return status; } status = cli_rpc_pipe_open_schannel_with_key( cli, table, transport, auth_level, domain, &netlogon_pipe->dc, &result); /* Now we've bound using the session key we can close the netlog pipe. */ TALLOC_FREE(netlogon_pipe); if (NT_STATUS_IS_OK(status)) { *presult = result; } return status; } /**************************************************************************** Open a netlogon pipe and get the schannel session key. Now exposed to external callers. ****************************************************************************/ NTSTATUS get_schannel_session_key(struct cli_state *cli, const char *domain, uint32 *pneg_flags, struct rpc_pipe_client **presult) { struct rpc_pipe_client *netlogon_pipe = NULL; NTSTATUS status; status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon, &netlogon_pipe); if (!NT_STATUS_IS_OK(status)) { return status; } status = get_schannel_session_key_common(netlogon_pipe, cli, domain, pneg_flags); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(netlogon_pipe); return status; } *presult = netlogon_pipe; return NT_STATUS_OK; }