s3-librpc: pass struct ndr_interface_table down to cli_pipe_open_generic/spnego()
[samba.git] / source3 / rpc_client / cli_pipe_schannel.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *  Largely rewritten by Jeremy Allison             2005.
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "../librpc/gen_ndr/ndr_schannel.h"
22 #include "../librpc/gen_ndr/ndr_netlogon.h"
23 #include "../libcli/auth/schannel.h"
24 #include "rpc_client/cli_netlogon.h"
25 #include "rpc_client/cli_pipe.h"
26 #include "librpc/gen_ndr/ndr_dcerpc.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "passdb.h"
29 #include "libsmb/libsmb.h"
30 #include "auth/gensec/gensec.h"
31
32 #undef DBGC_CLASS
33 #define DBGC_CLASS DBGC_RPC_CLI
34
35
36 /****************************************************************************
37   Get a the schannel session key out of an already opened netlogon pipe.
38  ****************************************************************************/
39 static NTSTATUS get_schannel_session_key_common(struct rpc_pipe_client *netlogon_pipe,
40                                                 struct cli_state *cli,
41                                                 const char *domain,
42                                                 uint32 *pneg_flags)
43 {
44         enum netr_SchannelType sec_chan_type = 0;
45         unsigned char machine_pwd[16];
46         const char *machine_account;
47         NTSTATUS status;
48
49         /* Get the machine account credentials from secrets.tdb. */
50         if (!get_trust_pw_hash(domain, machine_pwd, &machine_account,
51                                &sec_chan_type))
52         {
53                 DEBUG(0, ("get_schannel_session_key: could not fetch "
54                         "trust account password for domain '%s'\n",
55                         domain));
56                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
57         }
58
59         status = rpccli_netlogon_setup_creds(netlogon_pipe,
60                                         cli_state_remote_name(cli), /* server name */
61                                         domain,        /* domain */
62                                         lp_netbios_name(), /* client name */
63                                         machine_account, /* machine account name */
64                                         machine_pwd,
65                                         sec_chan_type,
66                                         pneg_flags);
67
68         if (!NT_STATUS_IS_OK(status)) {
69                 DEBUG(3, ("get_schannel_session_key_common: "
70                           "rpccli_netlogon_setup_creds failed with result %s "
71                           "to server %s, domain %s, machine account %s.\n",
72                           nt_errstr(status), cli_state_remote_name(cli), domain,
73                           machine_account ));
74                 return status;
75         }
76
77         if (((*pneg_flags) & NETLOGON_NEG_SCHANNEL) == 0) {
78                 DEBUG(3, ("get_schannel_session_key: Server %s did not offer schannel\n",
79                         cli_state_remote_name(cli)));
80                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
81         }
82
83         return NT_STATUS_OK;
84 }
85
86 /****************************************************************************
87  Open a named pipe to an SMB server and bind using schannel (bind type 68).
88  Fetch the session key ourselves using a temporary netlogon pipe. This
89  version uses an ntlmssp auth bound netlogon pipe to get the key.
90  ****************************************************************************/
91
92 static NTSTATUS get_schannel_session_key_auth_ntlmssp(struct cli_state *cli,
93                                                       const char *domain,
94                                                       const char *username,
95                                                       const char *password,
96                                                       uint32 *pneg_flags,
97                                                       struct rpc_pipe_client **presult)
98 {
99         struct rpc_pipe_client *netlogon_pipe = NULL;
100         NTSTATUS status;
101
102         status = cli_rpc_pipe_open_spnego(
103                 cli, &ndr_table_netlogon, NCACN_NP,
104                 GENSEC_OID_NTLMSSP,
105                 DCERPC_AUTH_LEVEL_PRIVACY,
106                 cli_state_remote_name(cli),
107                 domain, username, password, &netlogon_pipe);
108         if (!NT_STATUS_IS_OK(status)) {
109                 return status;
110         }
111
112         status = get_schannel_session_key_common(netlogon_pipe, cli, domain,
113                                                  pneg_flags);
114         if (!NT_STATUS_IS_OK(status)) {
115                 TALLOC_FREE(netlogon_pipe);
116                 return status;
117         }
118
119         *presult = netlogon_pipe;
120         return NT_STATUS_OK;
121 }
122
123 /****************************************************************************
124  Open a named pipe to an SMB server and bind using schannel (bind type 68).
125  Fetch the session key ourselves using a temporary netlogon pipe. This version
126  uses an ntlmssp bind to get the session key.
127  ****************************************************************************/
128
129 NTSTATUS cli_rpc_pipe_open_ntlmssp_auth_schannel(struct cli_state *cli,
130                                                  const struct ndr_syntax_id *interface,
131                                                  enum dcerpc_transport_t transport,
132                                                  enum dcerpc_AuthLevel auth_level,
133                                                  const char *domain,
134                                                  const char *username,
135                                                  const char *password,
136                                                  struct rpc_pipe_client **presult)
137 {
138         uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
139         struct rpc_pipe_client *netlogon_pipe = NULL;
140         struct rpc_pipe_client *result = NULL;
141         NTSTATUS status;
142
143         status = get_schannel_session_key_auth_ntlmssp(
144                 cli, domain, username, password, &neg_flags, &netlogon_pipe);
145         if (!NT_STATUS_IS_OK(status)) {
146                 DEBUG(0,("cli_rpc_pipe_open_ntlmssp_auth_schannel: failed to get schannel session "
147                         "key from server %s for domain %s.\n",
148                         cli_state_remote_name(cli), domain ));
149                 return status;
150         }
151
152         status = cli_rpc_pipe_open_schannel_with_key(
153                 cli, interface, transport, auth_level, domain, &netlogon_pipe->dc,
154                 &result);
155
156         /* Now we've bound using the session key we can close the netlog pipe. */
157         TALLOC_FREE(netlogon_pipe);
158
159         if (NT_STATUS_IS_OK(status)) {
160                 *presult = result;
161         }
162         return status;
163 }
164
165 /****************************************************************************
166  Open a named pipe to an SMB server and bind using schannel (bind type 68).
167  Fetch the session key ourselves using a temporary netlogon pipe.
168  ****************************************************************************/
169
170 NTSTATUS cli_rpc_pipe_open_schannel(struct cli_state *cli,
171                                     const struct ndr_syntax_id *interface,
172                                     enum dcerpc_transport_t transport,
173                                     enum dcerpc_AuthLevel auth_level,
174                                     const char *domain,
175                                     struct rpc_pipe_client **presult)
176 {
177         uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
178         struct rpc_pipe_client *netlogon_pipe = NULL;
179         struct rpc_pipe_client *result = NULL;
180         NTSTATUS status;
181
182         status = get_schannel_session_key(cli, domain, &neg_flags,
183                                           &netlogon_pipe);
184         if (!NT_STATUS_IS_OK(status)) {
185                 DEBUG(0,("cli_rpc_pipe_open_schannel: failed to get schannel session "
186                         "key from server %s for domain %s.\n",
187                         cli_state_remote_name(cli), domain ));
188                 return status;
189         }
190
191         status = cli_rpc_pipe_open_schannel_with_key(
192                 cli, interface, transport, auth_level, domain, &netlogon_pipe->dc,
193                 &result);
194
195         /* Now we've bound using the session key we can close the netlog pipe. */
196         TALLOC_FREE(netlogon_pipe);
197
198         if (NT_STATUS_IS_OK(status)) {
199                 *presult = result;
200         }
201
202         return status;
203 }
204
205 /****************************************************************************
206  Open a netlogon pipe and get the schannel session key.
207  Now exposed to external callers.
208  ****************************************************************************/
209
210
211 NTSTATUS get_schannel_session_key(struct cli_state *cli,
212                                   const char *domain,
213                                   uint32 *pneg_flags,
214                                   struct rpc_pipe_client **presult)
215 {
216         struct rpc_pipe_client *netlogon_pipe = NULL;
217         NTSTATUS status;
218
219         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id,
220                                           &netlogon_pipe);
221         if (!NT_STATUS_IS_OK(status)) {
222                 return status;
223         }
224
225         status = get_schannel_session_key_common(netlogon_pipe, cli, domain,
226                                                  pneg_flags);
227         if (!NT_STATUS_IS_OK(status)) {
228                 TALLOC_FREE(netlogon_pipe);
229                 return status;
230         }
231
232         *presult = netlogon_pipe;
233         return NT_STATUS_OK;
234 }