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