Attempt to fix bug 5616
[metze/samba/wip.git] / source3 / rpc_client / cli_netlogon.c
1 /*
2    Unix SMB/CIFS implementation.
3    NT Domain Authentication SMB / MSRPC client
4    Copyright (C) Andrew Tridgell 1992-2000
5    Copyright (C) Jeremy Allison                    1998.
6    Largely re-written by Jeremy Allison (C)        2005.
7    Copyright (C) Guenther Deschner                 2008.
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24
25 /****************************************************************************
26  Wrapper function that uses the auth and auth2 calls to set up a NETLOGON
27  credentials chain. Stores the credentials in the struct dcinfo in the
28  netlogon pipe struct.
29 ****************************************************************************/
30
31 NTSTATUS rpccli_netlogon_setup_creds(struct rpc_pipe_client *cli,
32                                      const char *server_name,
33                                      const char *domain,
34                                      const char *clnt_name,
35                                      const char *machine_account,
36                                      const unsigned char machine_pwd[16],
37                                      enum netr_SchannelType sec_chan_type,
38                                      uint32_t *neg_flags_inout)
39 {
40         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
41         struct netr_Credential clnt_chal_send;
42         struct netr_Credential srv_chal_recv;
43         struct dcinfo *dc;
44         bool retried = false;
45
46         SMB_ASSERT(ndr_syntax_id_equal(&cli->abstract_syntax,
47                                        &ndr_table_netlogon.syntax_id));
48
49         TALLOC_FREE(cli->dc);
50         cli->dc = talloc_zero(cli, struct dcinfo);
51         if (cli->dc == NULL) {
52                 return NT_STATUS_NO_MEMORY;
53         }
54         dc = cli->dc;
55
56         /* Store the machine account password we're going to use. */
57         memcpy(dc->mach_pw, machine_pwd, 16);
58
59         fstrcpy(dc->remote_machine, "\\\\");
60         fstrcat(dc->remote_machine, server_name);
61
62         fstrcpy(dc->domain, domain);
63
64         fstr_sprintf( dc->mach_acct, "%s$", machine_account);
65
66  again:
67         /* Create the client challenge. */
68         generate_random_buffer(clnt_chal_send.data, 8);
69
70         /* Get the server challenge. */
71         result = rpccli_netr_ServerReqChallenge(cli, talloc_tos(),
72                                                 dc->remote_machine,
73                                                 clnt_name,
74                                                 &clnt_chal_send,
75                                                 &srv_chal_recv);
76         if (!NT_STATUS_IS_OK(result)) {
77                 return result;
78         }
79
80         /* Calculate the session key and client credentials */
81         creds_client_init(*neg_flags_inout,
82                         dc,
83                         &clnt_chal_send,
84                         &srv_chal_recv,
85                         machine_pwd,
86                         &clnt_chal_send);
87
88         /*
89          * Send client auth-2 challenge and receive server repy.
90          */
91
92         result = rpccli_netr_ServerAuthenticate2(cli, talloc_tos(),
93                                                  dc->remote_machine,
94                                                  dc->mach_acct,
95                                                  sec_chan_type,
96                                                  clnt_name,
97                                                  &clnt_chal_send, /* input. */
98                                                  &srv_chal_recv, /* output. */
99                                                  neg_flags_inout);
100
101         /* we might be talking to NT4, so let's downgrade in that case and retry
102          * with the returned neg_flags - gd */
103
104         if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) {
105                 retried = true;
106                 goto again;
107         }
108
109         if (!NT_STATUS_IS_OK(result)) {
110                 return result;
111         }
112
113         /*
114          * Check the returned value using the initial
115          * server received challenge.
116          */
117
118         if (!netlogon_creds_client_check(dc, &srv_chal_recv)) {
119                 /*
120                  * Server replied with bad credential. Fail.
121                  */
122                 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
123                         "replied with bad credential\n",
124                         cli->desthost ));
125                 return NT_STATUS_ACCESS_DENIED;
126         }
127
128         DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
129                 "chain established.\n",
130                 cli->desthost ));
131
132         return NT_STATUS_OK;
133 }
134
135 /* Logon domain user */
136
137 NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
138                                    TALLOC_CTX *mem_ctx,
139                                    uint32 logon_parameters,
140                                    const char *domain,
141                                    const char *username,
142                                    const char *password,
143                                    const char *workstation,
144                                    int logon_type)
145 {
146         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
147         struct netr_Authenticator clnt_creds;
148         struct netr_Authenticator ret_creds;
149         union netr_LogonInfo *logon;
150         union netr_Validation validation;
151         uint8_t authoritative;
152         int validation_level = 3;
153         fstring clnt_name_slash;
154         uint8 zeros[16];
155
156         ZERO_STRUCT(ret_creds);
157         ZERO_STRUCT(zeros);
158
159         logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
160         if (!logon) {
161                 return NT_STATUS_NO_MEMORY;
162         }
163
164         if (workstation) {
165                 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
166         } else {
167                 fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() );
168         }
169
170         /* Initialise input parameters */
171
172         netlogon_creds_client_step(cli->dc, &clnt_creds);
173
174         switch (logon_type) {
175         case INTERACTIVE_LOGON_TYPE: {
176
177                 struct netr_PasswordInfo *password_info;
178
179                 struct samr_Password lmpassword;
180                 struct samr_Password ntpassword;
181
182                 unsigned char lm_owf_user_pwd[16], nt_owf_user_pwd[16];
183
184                 unsigned char lm_owf[16];
185                 unsigned char nt_owf[16];
186                 unsigned char key[16];
187
188                 password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo);
189                 if (!password_info) {
190                         return NT_STATUS_NO_MEMORY;
191                 }
192
193                 nt_lm_owf_gen(password, nt_owf_user_pwd, lm_owf_user_pwd);
194
195 #ifdef DEBUG_PASSWORD
196                 DEBUG(100,("lm cypher:"));
197                 dump_data(100, lm_owf_user_pwd, 16);
198
199                 DEBUG(100,("nt cypher:"));
200                 dump_data(100, nt_owf_user_pwd, 16);
201 #endif
202                 memset(key, 0, 16);
203                 memcpy(key, cli->dc->sess_key, 8);
204
205                 memcpy(lm_owf, lm_owf_user_pwd, 16);
206                 SamOEMhash(lm_owf, key, 16);
207                 memcpy(nt_owf, nt_owf_user_pwd, 16);
208                 SamOEMhash(nt_owf, key, 16);
209
210 #ifdef DEBUG_PASSWORD
211                 DEBUG(100,("encrypt of lm owf password:"));
212                 dump_data(100, lm_owf, 16);
213
214                 DEBUG(100,("encrypt of nt owf password:"));
215                 dump_data(100, nt_owf, 16);
216 #endif
217                 memcpy(lmpassword.hash, lm_owf, 16);
218                 memcpy(ntpassword.hash, nt_owf, 16);
219
220                 init_netr_PasswordInfo(password_info,
221                                        domain,
222                                        logon_parameters,
223                                        0xdead,
224                                        0xbeef,
225                                        username,
226                                        clnt_name_slash,
227                                        lmpassword,
228                                        ntpassword);
229
230                 logon->password = password_info;
231
232                 break;
233         }
234         case NET_LOGON_TYPE: {
235                 struct netr_NetworkInfo *network_info;
236                 uint8 chal[8];
237                 unsigned char local_lm_response[24];
238                 unsigned char local_nt_response[24];
239                 struct netr_ChallengeResponse lm;
240                 struct netr_ChallengeResponse nt;
241
242                 ZERO_STRUCT(lm);
243                 ZERO_STRUCT(nt);
244
245                 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
246                 if (!network_info) {
247                         return NT_STATUS_NO_MEMORY;
248                 }
249
250                 generate_random_buffer(chal, 8);
251
252                 SMBencrypt(password, chal, local_lm_response);
253                 SMBNTencrypt(password, chal, local_nt_response);
254
255                 lm.length = 24;
256                 lm.data = local_lm_response;
257
258                 nt.length = 24;
259                 nt.data = local_nt_response;
260
261                 init_netr_NetworkInfo(network_info,
262                                       domain,
263                                       logon_parameters,
264                                       0xdead,
265                                       0xbeef,
266                                       username,
267                                       clnt_name_slash,
268                                       chal,
269                                       nt,
270                                       lm);
271
272                 logon->network = network_info;
273
274                 break;
275         }
276         default:
277                 DEBUG(0, ("switch value %d not supported\n",
278                         logon_type));
279                 return NT_STATUS_INVALID_INFO_CLASS;
280         }
281
282         result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
283                                            cli->dc->remote_machine,
284                                            global_myname(),
285                                            &clnt_creds,
286                                            &ret_creds,
287                                            logon_type,
288                                            logon,
289                                            validation_level,
290                                            &validation,
291                                            &authoritative);
292
293         if (memcmp(zeros, &ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
294                 /* Check returned credentials if present. */
295                 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
296                         DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
297                         return NT_STATUS_ACCESS_DENIED;
298                 }
299         }
300
301         return result;
302 }
303
304
305 /**
306  * Logon domain user with an 'network' SAM logon
307  *
308  * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
309  **/
310
311 NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
312                                            TALLOC_CTX *mem_ctx,
313                                            uint32 logon_parameters,
314                                            const char *server,
315                                            const char *username,
316                                            const char *domain,
317                                            const char *workstation,
318                                            const uint8 chal[8],
319                                            DATA_BLOB lm_response,
320                                            DATA_BLOB nt_response,
321                                            struct netr_SamInfo3 **info3)
322 {
323         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
324         int validation_level = 3;
325         const char *workstation_name_slash;
326         const char *server_name_slash;
327         uint8 zeros[16];
328         struct netr_Authenticator clnt_creds;
329         struct netr_Authenticator ret_creds;
330         union netr_LogonInfo *logon = NULL;
331         struct netr_NetworkInfo *network_info;
332         uint8_t authoritative;
333         union netr_Validation validation;
334         struct netr_ChallengeResponse lm;
335         struct netr_ChallengeResponse nt;
336
337         *info3 = NULL;
338
339         ZERO_STRUCT(zeros);
340         ZERO_STRUCT(ret_creds);
341
342         ZERO_STRUCT(lm);
343         ZERO_STRUCT(nt);
344
345         logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
346         if (!logon) {
347                 return NT_STATUS_NO_MEMORY;
348         }
349
350         network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
351         if (!network_info) {
352                 return NT_STATUS_NO_MEMORY;
353         }
354
355         netlogon_creds_client_step(cli->dc, &clnt_creds);
356
357         if (server[0] != '\\' && server[1] != '\\') {
358                 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
359         } else {
360                 server_name_slash = server;
361         }
362
363         if (workstation[0] != '\\' && workstation[1] != '\\') {
364                 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
365         } else {
366                 workstation_name_slash = workstation;
367         }
368
369         if (!workstation_name_slash || !server_name_slash) {
370                 DEBUG(0, ("talloc_asprintf failed!\n"));
371                 return NT_STATUS_NO_MEMORY;
372         }
373
374         /* Initialise input parameters */
375
376         lm.data = lm_response.data;
377         lm.length = lm_response.length;
378         nt.data = nt_response.data;
379         nt.length = nt_response.length;
380
381         init_netr_NetworkInfo(network_info,
382                               domain,
383                               logon_parameters,
384                               0xdead,
385                               0xbeef,
386                               username,
387                               workstation_name_slash,
388                               (uint8_t *) chal,
389                               nt,
390                               lm);
391
392         logon->network = network_info;
393
394         /* Marshall data and send request */
395
396         result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
397                                            server_name_slash,
398                                            global_myname(),
399                                            &clnt_creds,
400                                            &ret_creds,
401                                            NET_LOGON_TYPE,
402                                            logon,
403                                            validation_level,
404                                            &validation,
405                                            &authoritative);
406         if (!NT_STATUS_IS_OK(result)) {
407                 return result;
408         }
409
410         if (memcmp(zeros, validation.sam3->base.key.key, 16) != 0) {
411                 SamOEMhash(validation.sam3->base.key.key,
412                            cli->dc->sess_key, 16);
413         }
414
415         if (memcmp(zeros, validation.sam3->base.LMSessKey.key, 8) != 0) {
416                 SamOEMhash(validation.sam3->base.LMSessKey.key,
417                            cli->dc->sess_key, 8);
418         }
419
420         if (memcmp(zeros, ret_creds.cred.data, sizeof(ret_creds.cred.data)) != 0) {
421                 /* Check returned credentials if present. */
422                 if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
423                         DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
424                         return NT_STATUS_ACCESS_DENIED;
425                 }
426         }
427
428         *info3 = validation.sam3;
429
430         return result;
431 }
432
433 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
434                                               TALLOC_CTX *mem_ctx,
435                                               uint32 logon_parameters,
436                                               const char *server,
437                                               const char *username,
438                                               const char *domain,
439                                               const char *workstation,
440                                               const uint8 chal[8],
441                                               DATA_BLOB lm_response,
442                                               DATA_BLOB nt_response,
443                                               struct netr_SamInfo3 **info3)
444 {
445         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
446         int validation_level = 3;
447         const char *workstation_name_slash;
448         const char *server_name_slash;
449         uint8 zeros[16];
450         union netr_LogonInfo *logon = NULL;
451         struct netr_NetworkInfo *network_info;
452         uint8_t authoritative;
453         union netr_Validation validation;
454         struct netr_ChallengeResponse lm;
455         struct netr_ChallengeResponse nt;
456         struct netr_UserSessionKey user_session_key;
457         struct netr_LMSessionKey lmsesskey;
458         uint32_t flags = 0;
459
460         *info3 = NULL;
461
462         ZERO_STRUCT(zeros);
463
464         ZERO_STRUCT(lm);
465         ZERO_STRUCT(nt);
466
467         logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonInfo);
468         if (!logon) {
469                 return NT_STATUS_NO_MEMORY;
470         }
471
472         network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
473         if (!network_info) {
474                 return NT_STATUS_NO_MEMORY;
475         }
476
477         if (server[0] != '\\' && server[1] != '\\') {
478                 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
479         } else {
480                 server_name_slash = server;
481         }
482
483         if (workstation[0] != '\\' && workstation[1] != '\\') {
484                 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
485         } else {
486                 workstation_name_slash = workstation;
487         }
488
489         if (!workstation_name_slash || !server_name_slash) {
490                 DEBUG(0, ("talloc_asprintf failed!\n"));
491                 return NT_STATUS_NO_MEMORY;
492         }
493
494         /* Initialise input parameters */
495
496         lm.data = lm_response.data;
497         lm.length = lm_response.length;
498         nt.data = nt_response.data;
499         nt.length = nt_response.length;
500
501         init_netr_NetworkInfo(network_info,
502                               domain,
503                               logon_parameters,
504                               0xdead,
505                               0xbeef,
506                               username,
507                               workstation_name_slash,
508                               (uint8_t *) chal,
509                               nt,
510                               lm);
511
512         logon->network = network_info;
513
514         /* Marshall data and send request */
515
516         result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx,
517                                              server_name_slash,
518                                              global_myname(),
519                                              NET_LOGON_TYPE,
520                                              logon,
521                                              validation_level,
522                                              &validation,
523                                              &authoritative,
524                                              &flags);
525         if (!NT_STATUS_IS_OK(result)) {
526                 return result;
527         }
528
529         user_session_key = validation.sam3->base.key;
530         lmsesskey = validation.sam3->base.LMSessKey;
531
532         if (memcmp(zeros, user_session_key.key, 16) != 0) {
533                 SamOEMhash(user_session_key.key, cli->dc->sess_key, 16);
534         }
535
536         if (memcmp(zeros, lmsesskey.key, 8) != 0) {
537                 SamOEMhash(lmsesskey.key, cli->dc->sess_key, 8);
538         }
539
540         *info3 = validation.sam3;
541
542         return result;
543 }