Merge commit 'release-4-0-0alpha15' into master4-tmp
[nivanova/samba-autobuild/.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 "client.h"
30
31 #undef DBGC_CLASS
32 #define DBGC_CLASS DBGC_RPC_CLI
33
34
35 /****************************************************************************
36   Get a the schannel session key out of an already opened netlogon pipe.
37  ****************************************************************************/
38 static NTSTATUS get_schannel_session_key_common(struct rpc_pipe_client *netlogon_pipe,
39                                                 struct cli_state *cli,
40                                                 const char *domain,
41                                                 uint32 *pneg_flags)
42 {
43         enum netr_SchannelType sec_chan_type = 0;
44         unsigned char machine_pwd[16];
45         const char *machine_account;
46         NTSTATUS status;
47
48         /* Get the machine account credentials from secrets.tdb. */
49         if (!get_trust_pw_hash(domain, machine_pwd, &machine_account,
50                                &sec_chan_type))
51         {
52                 DEBUG(0, ("get_schannel_session_key: could not fetch "
53                         "trust account password for domain '%s'\n",
54                         domain));
55                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
56         }
57
58         status = rpccli_netlogon_setup_creds(netlogon_pipe,
59                                         cli->desthost, /* server name */
60                                         domain,        /* domain */
61                                         lp_netbios_name(), /* client name */
62                                         machine_account, /* machine account name */
63                                         machine_pwd,
64                                         sec_chan_type,
65                                         pneg_flags);
66
67         if (!NT_STATUS_IS_OK(status)) {
68                 DEBUG(3, ("get_schannel_session_key_common: "
69                           "rpccli_netlogon_setup_creds failed with result %s "
70                           "to server %s, domain %s, machine account %s.\n",
71                           nt_errstr(status), cli->desthost, domain,
72                           machine_account ));
73                 return status;
74         }
75
76         if (((*pneg_flags) & NETLOGON_NEG_SCHANNEL) == 0) {
77                 DEBUG(3, ("get_schannel_session_key: Server %s did not offer schannel\n",
78                         cli->desthost));
79                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
80         }
81
82         return NT_STATUS_OK;
83 }
84
85 /****************************************************************************
86  Open a named pipe to an SMB server and bind using schannel (bind type 68).
87  Fetch the session key ourselves using a temporary netlogon pipe. This
88  version uses an ntlmssp auth bound netlogon pipe to get the key.
89  ****************************************************************************/
90
91 static NTSTATUS get_schannel_session_key_auth_ntlmssp(struct cli_state *cli,
92                                                       const char *domain,
93                                                       const char *username,
94                                                       const char *password,
95                                                       uint32 *pneg_flags,
96                                                       struct rpc_pipe_client **presult)
97 {
98         struct rpc_pipe_client *netlogon_pipe = NULL;
99         NTSTATUS status;
100
101         status = cli_rpc_pipe_open_spnego_ntlmssp(
102                 cli, &ndr_table_netlogon.syntax_id, NCACN_NP,
103                 DCERPC_AUTH_LEVEL_PRIVACY,
104                 domain, username, password, &netlogon_pipe);
105         if (!NT_STATUS_IS_OK(status)) {
106                 return status;
107         }
108
109         status = get_schannel_session_key_common(netlogon_pipe, cli, domain,
110                                                  pneg_flags);
111         if (!NT_STATUS_IS_OK(status)) {
112                 TALLOC_FREE(netlogon_pipe);
113                 return status;
114         }
115
116         *presult = netlogon_pipe;
117         return NT_STATUS_OK;
118 }
119
120 /****************************************************************************
121  Open a named pipe to an SMB server and bind using schannel (bind type 68).
122  Fetch the session key ourselves using a temporary netlogon pipe. This version
123  uses an ntlmssp bind to get the session key.
124  ****************************************************************************/
125
126 NTSTATUS cli_rpc_pipe_open_ntlmssp_auth_schannel(struct cli_state *cli,
127                                                  const struct ndr_syntax_id *interface,
128                                                  enum dcerpc_transport_t transport,
129                                                  enum dcerpc_AuthLevel auth_level,
130                                                  const char *domain,
131                                                  const char *username,
132                                                  const char *password,
133                                                  struct rpc_pipe_client **presult)
134 {
135         uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
136         struct rpc_pipe_client *netlogon_pipe = NULL;
137         struct rpc_pipe_client *result = NULL;
138         NTSTATUS status;
139
140         status = get_schannel_session_key_auth_ntlmssp(
141                 cli, domain, username, password, &neg_flags, &netlogon_pipe);
142         if (!NT_STATUS_IS_OK(status)) {
143                 DEBUG(0,("cli_rpc_pipe_open_ntlmssp_auth_schannel: failed to get schannel session "
144                         "key from server %s for domain %s.\n",
145                         cli->desthost, domain ));
146                 return status;
147         }
148
149         status = cli_rpc_pipe_open_schannel_with_key(
150                 cli, interface, transport, auth_level, domain, &netlogon_pipe->dc,
151                 &result);
152
153         /* Now we've bound using the session key we can close the netlog pipe. */
154         TALLOC_FREE(netlogon_pipe);
155
156         if (NT_STATUS_IS_OK(status)) {
157                 *presult = result;
158         }
159         return status;
160 }
161
162 /****************************************************************************
163  Open a named pipe to an SMB server and bind using schannel (bind type 68).
164  Fetch the session key ourselves using a temporary netlogon pipe.
165  ****************************************************************************/
166
167 NTSTATUS cli_rpc_pipe_open_schannel(struct cli_state *cli,
168                                     const struct ndr_syntax_id *interface,
169                                     enum dcerpc_transport_t transport,
170                                     enum dcerpc_AuthLevel auth_level,
171                                     const char *domain,
172                                     struct rpc_pipe_client **presult)
173 {
174         uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
175         struct rpc_pipe_client *netlogon_pipe = NULL;
176         struct rpc_pipe_client *result = NULL;
177         NTSTATUS status;
178
179         status = get_schannel_session_key(cli, domain, &neg_flags,
180                                           &netlogon_pipe);
181         if (!NT_STATUS_IS_OK(status)) {
182                 DEBUG(0,("cli_rpc_pipe_open_schannel: failed to get schannel session "
183                         "key from server %s for domain %s.\n",
184                         cli->desthost, domain ));
185                 return status;
186         }
187
188         status = cli_rpc_pipe_open_schannel_with_key(
189                 cli, interface, transport, auth_level, domain, &netlogon_pipe->dc,
190                 &result);
191
192         /* Now we've bound using the session key we can close the netlog pipe. */
193         TALLOC_FREE(netlogon_pipe);
194
195         if (NT_STATUS_IS_OK(status)) {
196                 *presult = result;
197         }
198
199         return status;
200 }
201
202 /****************************************************************************
203  Open a netlogon pipe and get the schannel session key.
204  Now exposed to external callers.
205  ****************************************************************************/
206
207
208 NTSTATUS get_schannel_session_key(struct cli_state *cli,
209                                   const char *domain,
210                                   uint32 *pneg_flags,
211                                   struct rpc_pipe_client **presult)
212 {
213         struct rpc_pipe_client *netlogon_pipe = NULL;
214         NTSTATUS status;
215
216         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id,
217                                           &netlogon_pipe);
218         if (!NT_STATUS_IS_OK(status)) {
219                 return status;
220         }
221
222         status = get_schannel_session_key_common(netlogon_pipe, cli, domain,
223                                                  pneg_flags);
224         if (!NT_STATUS_IS_OK(status)) {
225                 TALLOC_FREE(netlogon_pipe);
226                 return status;
227         }
228
229         *presult = netlogon_pipe;
230         return NT_STATUS_OK;
231 }