Make Samba3 use the new common libcli/auth code
[kai/samba.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 #include "../libcli/auth/libcli_auth.h"
25
26 /****************************************************************************
27  Wrapper function that uses the auth and auth2 calls to set up a NETLOGON
28  credentials chain. Stores the credentials in the struct dcinfo in the
29  netlogon pipe struct.
30 ****************************************************************************/
31
32 NTSTATUS rpccli_netlogon_setup_creds(struct rpc_pipe_client *cli,
33                                      const char *server_name,
34                                      const char *domain,
35                                      const char *clnt_name,
36                                      const char *machine_account,
37                                      const unsigned char machine_pwd[16],
38                                      enum netr_SchannelType sec_chan_type,
39                                      uint32_t *neg_flags_inout)
40 {
41         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
42         struct netr_Credential clnt_chal_send;
43         struct netr_Credential srv_chal_recv;
44         struct samr_Password password;
45         bool retried = false;
46         fstring mach_acct;
47
48         SMB_ASSERT(ndr_syntax_id_equal(&cli->abstract_syntax,
49                                        &ndr_table_netlogon.syntax_id));
50
51         TALLOC_FREE(cli->dc);
52
53         /* Store the machine account password we're going to use. */
54         memcpy(password.hash, machine_pwd, 16);
55
56         fstr_sprintf( mach_acct, "%s$", machine_account);
57
58  again:
59         /* Create the client challenge. */
60         generate_random_buffer(clnt_chal_send.data, 8);
61
62         /* Get the server challenge. */
63         result = rpccli_netr_ServerReqChallenge(cli, talloc_tos(),
64                                                 cli->srv_name_slash,
65                                                 clnt_name,
66                                                 &clnt_chal_send,
67                                                 &srv_chal_recv);
68         if (!NT_STATUS_IS_OK(result)) {
69                 return result;
70         }
71
72         /* Calculate the session key and client credentials */
73         
74         cli->dc = netlogon_creds_client_init(cli,
75                                     clnt_name,
76                                     machine_account, 
77                                     &clnt_chal_send,
78                                     &srv_chal_recv,
79                                     &password,
80                                     &clnt_chal_send,
81                                     *neg_flags_inout);
82
83         if (!cli->dc) {
84                 return NT_STATUS_NO_MEMORY;
85         }
86
87         /*
88          * Send client auth-2 challenge and receive server repy.
89          */
90
91         result = rpccli_netr_ServerAuthenticate2(cli, talloc_tos(),
92                                                  cli->srv_name_slash,
93                                                  cli->dc->account_name,
94                                                  sec_chan_type,
95                                                  cli->dc->computer_name,
96                                                  &clnt_chal_send, /* input. */
97                                                  &srv_chal_recv, /* output. */
98                                                  neg_flags_inout);
99
100         /* we might be talking to NT4, so let's downgrade in that case and retry
101          * with the returned neg_flags - gd */
102
103         if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) {
104                 TALLOC_FREE(cli->dc);
105                 goto again;
106         }
107
108         if (!NT_STATUS_IS_OK(result)) {
109                 return result;
110         }
111
112         /*
113          * Check the returned value using the initial
114          * server received challenge.
115          */
116
117         if (!netlogon_creds_client_check(cli->dc, &srv_chal_recv)) {
118                 /*
119                  * Server replied with bad credential. Fail.
120                  */
121                 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
122                         "replied with bad credential\n",
123                         cli->desthost ));
124                 return NT_STATUS_ACCESS_DENIED;
125         }
126
127         DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
128                 "chain established.\n",
129                 cli->desthost ));
130
131         return NT_STATUS_OK;
132 }
133
134 /* Logon domain user */
135
136 NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
137                                    TALLOC_CTX *mem_ctx,
138                                    uint32 logon_parameters,
139                                    const char *domain,
140                                    const char *username,
141                                    const char *password,
142                                    const char *workstation,
143                                    int logon_type)
144 {
145         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
146         struct netr_Authenticator clnt_creds;
147         struct netr_Authenticator ret_creds;
148         union netr_LogonLevel *logon;
149         union netr_Validation validation;
150         uint8_t authoritative;
151         int validation_level = 3;
152         fstring clnt_name_slash;
153         uint8 zeros[16];
154
155         ZERO_STRUCT(ret_creds);
156         ZERO_STRUCT(zeros);
157
158         logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
159         if (!logon) {
160                 return NT_STATUS_NO_MEMORY;
161         }
162
163         if (workstation) {
164                 fstr_sprintf( clnt_name_slash, "\\\\%s", workstation );
165         } else {
166                 fstr_sprintf( clnt_name_slash, "\\\\%s", global_myname() );
167         }
168
169         /* Initialise input parameters */
170
171         netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
172
173         switch (logon_type) {
174         case NetlogonInteractiveInformation: {
175
176                 struct netr_PasswordInfo *password_info;
177
178                 struct samr_Password lmpassword;
179                 struct samr_Password ntpassword;
180
181                 password_info = TALLOC_ZERO_P(mem_ctx, struct netr_PasswordInfo);
182                 if (!password_info) {
183                         return NT_STATUS_NO_MEMORY;
184                 }
185
186                 nt_lm_owf_gen(password, ntpassword.hash, lmpassword.hash);
187
188                 if (cli->dc->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
189                         netlogon_creds_arcfour_crypt(cli->dc, lmpassword.hash, 16);
190                         netlogon_creds_arcfour_crypt(cli->dc, ntpassword.hash, 16);
191                 } else {
192                         netlogon_creds_des_encrypt(cli->dc, &lmpassword);
193                         netlogon_creds_des_encrypt(cli->dc, &ntpassword);
194                 }
195
196                 init_netr_PasswordInfo(password_info,
197                                        domain,
198                                        logon_parameters,
199                                        0xdead,
200                                        0xbeef,
201                                        username,
202                                        clnt_name_slash,
203                                        lmpassword,
204                                        ntpassword);
205
206                 logon->password = password_info;
207
208                 break;
209         }
210         case NetlogonNetworkInformation: {
211                 struct netr_NetworkInfo *network_info;
212                 uint8 chal[8];
213                 unsigned char local_lm_response[24];
214                 unsigned char local_nt_response[24];
215                 struct netr_ChallengeResponse lm;
216                 struct netr_ChallengeResponse nt;
217
218                 ZERO_STRUCT(lm);
219                 ZERO_STRUCT(nt);
220
221                 network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
222                 if (!network_info) {
223                         return NT_STATUS_NO_MEMORY;
224                 }
225
226                 generate_random_buffer(chal, 8);
227
228                 SMBencrypt(password, chal, local_lm_response);
229                 SMBNTencrypt(password, chal, local_nt_response);
230
231                 lm.length = 24;
232                 lm.data = local_lm_response;
233
234                 nt.length = 24;
235                 nt.data = local_nt_response;
236
237                 init_netr_NetworkInfo(network_info,
238                                       domain,
239                                       logon_parameters,
240                                       0xdead,
241                                       0xbeef,
242                                       username,
243                                       clnt_name_slash,
244                                       chal,
245                                       nt,
246                                       lm);
247
248                 logon->network = network_info;
249
250                 break;
251         }
252         default:
253                 DEBUG(0, ("switch value %d not supported\n",
254                         logon_type));
255                 return NT_STATUS_INVALID_INFO_CLASS;
256         }
257
258         result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
259                                            cli->srv_name_slash,
260                                            global_myname(),
261                                            &clnt_creds,
262                                            &ret_creds,
263                                            logon_type,
264                                            logon,
265                                            validation_level,
266                                            &validation,
267                                            &authoritative);
268
269         /* Always check returned credentials */
270         if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
271                 DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n"));
272                 return NT_STATUS_ACCESS_DENIED;
273         }
274
275         return result;
276 }
277
278
279 /**
280  * Logon domain user with an 'network' SAM logon
281  *
282  * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
283  **/
284
285 NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
286                                            TALLOC_CTX *mem_ctx,
287                                            uint32 logon_parameters,
288                                            const char *server,
289                                            const char *username,
290                                            const char *domain,
291                                            const char *workstation,
292                                            const uint8 chal[8],
293                                            DATA_BLOB lm_response,
294                                            DATA_BLOB nt_response,
295                                            struct netr_SamInfo3 **info3)
296 {
297         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
298         int validation_level = 3;
299         const char *workstation_name_slash;
300         const char *server_name_slash;
301         uint8 zeros[16];
302         struct netr_Authenticator clnt_creds;
303         struct netr_Authenticator ret_creds;
304         union netr_LogonLevel *logon = NULL;
305         struct netr_NetworkInfo *network_info;
306         uint8_t authoritative;
307         union netr_Validation validation;
308         struct netr_ChallengeResponse lm;
309         struct netr_ChallengeResponse nt;
310
311         *info3 = NULL;
312
313         ZERO_STRUCT(zeros);
314         ZERO_STRUCT(ret_creds);
315
316         ZERO_STRUCT(lm);
317         ZERO_STRUCT(nt);
318
319         logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
320         if (!logon) {
321                 return NT_STATUS_NO_MEMORY;
322         }
323
324         network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
325         if (!network_info) {
326                 return NT_STATUS_NO_MEMORY;
327         }
328
329         netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
330
331         if (server[0] != '\\' && server[1] != '\\') {
332                 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
333         } else {
334                 server_name_slash = server;
335         }
336
337         if (workstation[0] != '\\' && workstation[1] != '\\') {
338                 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
339         } else {
340                 workstation_name_slash = workstation;
341         }
342
343         if (!workstation_name_slash || !server_name_slash) {
344                 DEBUG(0, ("talloc_asprintf failed!\n"));
345                 return NT_STATUS_NO_MEMORY;
346         }
347
348         /* Initialise input parameters */
349
350         lm.data = lm_response.data;
351         lm.length = lm_response.length;
352         nt.data = nt_response.data;
353         nt.length = nt_response.length;
354
355         init_netr_NetworkInfo(network_info,
356                               domain,
357                               logon_parameters,
358                               0xdead,
359                               0xbeef,
360                               username,
361                               workstation_name_slash,
362                               (uint8_t *) chal,
363                               nt,
364                               lm);
365
366         logon->network = network_info;
367
368         /* Marshall data and send request */
369
370         result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
371                                            server_name_slash,
372                                            global_myname(),
373                                            &clnt_creds,
374                                            &ret_creds,
375                                            NetlogonNetworkInformation,
376                                            logon,
377                                            validation_level,
378                                            &validation,
379                                            &authoritative);
380         if (!NT_STATUS_IS_OK(result)) {
381                 return result;
382         }
383
384         /* Always check returned credentials. */
385         if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
386                 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
387                 return NT_STATUS_ACCESS_DENIED;
388         }
389
390         netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
391
392         *info3 = validation.sam3;
393
394         return result;
395 }
396
397 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
398                                               TALLOC_CTX *mem_ctx,
399                                               uint32 logon_parameters,
400                                               const char *server,
401                                               const char *username,
402                                               const char *domain,
403                                               const char *workstation,
404                                               const uint8 chal[8],
405                                               DATA_BLOB lm_response,
406                                               DATA_BLOB nt_response,
407                                               struct netr_SamInfo3 **info3)
408 {
409         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
410         int validation_level = 3;
411         const char *workstation_name_slash;
412         const char *server_name_slash;
413         uint8 zeros[16];
414         union netr_LogonLevel *logon = NULL;
415         struct netr_NetworkInfo *network_info;
416         uint8_t authoritative;
417         union netr_Validation validation;
418         struct netr_ChallengeResponse lm;
419         struct netr_ChallengeResponse nt;
420         uint32_t flags = 0;
421
422         *info3 = NULL;
423
424         ZERO_STRUCT(zeros);
425
426         ZERO_STRUCT(lm);
427         ZERO_STRUCT(nt);
428
429         logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
430         if (!logon) {
431                 return NT_STATUS_NO_MEMORY;
432         }
433
434         network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
435         if (!network_info) {
436                 return NT_STATUS_NO_MEMORY;
437         }
438
439         if (server[0] != '\\' && server[1] != '\\') {
440                 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
441         } else {
442                 server_name_slash = server;
443         }
444
445         if (workstation[0] != '\\' && workstation[1] != '\\') {
446                 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
447         } else {
448                 workstation_name_slash = workstation;
449         }
450
451         if (!workstation_name_slash || !server_name_slash) {
452                 DEBUG(0, ("talloc_asprintf failed!\n"));
453                 return NT_STATUS_NO_MEMORY;
454         }
455
456         /* Initialise input parameters */
457
458         lm.data = lm_response.data;
459         lm.length = lm_response.length;
460         nt.data = nt_response.data;
461         nt.length = nt_response.length;
462
463         init_netr_NetworkInfo(network_info,
464                               domain,
465                               logon_parameters,
466                               0xdead,
467                               0xbeef,
468                               username,
469                               workstation_name_slash,
470                               (uint8_t *) chal,
471                               nt,
472                               lm);
473
474         logon->network = network_info;
475
476         /* Marshall data and send request */
477
478         result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx,
479                                              server_name_slash,
480                                              global_myname(),
481                                              NetlogonNetworkInformation,
482                                              logon,
483                                              validation_level,
484                                              &validation,
485                                              &authoritative,
486                                              &flags);
487         if (!NT_STATUS_IS_OK(result)) {
488                 return result;
489         }
490
491         netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
492
493         *info3 = validation.sam3;
494
495         return result;
496 }
497
498 /*********************************************************
499  Change the domain password on the PDC.
500
501  Just changes the password betwen the two values specified.
502
503  Caller must have the cli connected to the netlogon pipe
504  already.
505 **********************************************************/
506
507 NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli,
508                                             TALLOC_CTX *mem_ctx,
509                                             const unsigned char orig_trust_passwd_hash[16],
510                                             const char *new_trust_pwd_cleartext,
511                                             const unsigned char new_trust_passwd_hash[16],
512                                             uint32_t sec_channel_type)
513 {
514         NTSTATUS result;
515         uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
516         struct netr_Authenticator clnt_creds, srv_cred;
517
518         result = rpccli_netlogon_setup_creds(cli,
519                                              cli->desthost, /* server name */
520                                              lp_workgroup(), /* domain */
521                                              global_myname(), /* client name */
522                                              global_myname(), /* machine account name */
523                                              orig_trust_passwd_hash,
524                                              sec_channel_type,
525                                              &neg_flags);
526
527         if (!NT_STATUS_IS_OK(result)) {
528                 DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n",
529                          nt_errstr(result)));
530                 return result;
531         }
532
533         netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
534
535         if (neg_flags & NETLOGON_NEG_PASSWORD_SET2) {
536
537                 struct netr_CryptPassword new_password;
538
539                 init_netr_CryptPassword(new_trust_pwd_cleartext,
540                                         cli->dc->session_key,
541                                         &new_password);
542
543                 result = rpccli_netr_ServerPasswordSet2(cli, mem_ctx,
544                                                         cli->srv_name_slash,
545                                                         cli->dc->account_name,
546                                                         sec_channel_type,
547                                                         cli->dc->computer_name,
548                                                         &clnt_creds,
549                                                         &srv_cred,
550                                                         &new_password);
551                 if (!NT_STATUS_IS_OK(result)) {
552                         DEBUG(0,("rpccli_netr_ServerPasswordSet2 failed: %s\n",
553                                 nt_errstr(result)));
554                         return result;
555                 }
556         } else {
557
558                 struct samr_Password new_password;
559                 memcpy(new_password.hash, new_trust_passwd_hash, sizeof(new_password.hash));
560                 netlogon_creds_des_encrypt(cli->dc, &new_password);
561
562                 result = rpccli_netr_ServerPasswordSet(cli, mem_ctx,
563                                                        cli->srv_name_slash,
564                                                        cli->dc->account_name,
565                                                        sec_channel_type,
566                                                        cli->dc->computer_name,
567                                                        &clnt_creds,
568                                                        &srv_cred,
569                                                        &new_password);
570                 if (!NT_STATUS_IS_OK(result)) {
571                         DEBUG(0,("rpccli_netr_ServerPasswordSet failed: %s\n",
572                                 nt_errstr(result)));
573                         return result;
574                 }
575         }
576
577         /* Always check returned credentials. */
578         if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
579                 DEBUG(0,("credentials chain check failed\n"));
580                 return NT_STATUS_ACCESS_DENIED;
581         }
582
583         return result;
584 }
585