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