VERSION: Bump version up to 3.5.18.
[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
27 /****************************************************************************
28  Wrapper function that uses the auth and auth2 calls to set up a NETLOGON
29  credentials chain. Stores the credentials in the struct dcinfo in the
30  netlogon pipe struct.
31 ****************************************************************************/
32
33 NTSTATUS rpccli_netlogon_setup_creds(struct rpc_pipe_client *cli,
34                                      const char *server_name,
35                                      const char *domain,
36                                      const char *clnt_name,
37                                      const char *machine_account,
38                                      const unsigned char machine_pwd[16],
39                                      enum netr_SchannelType sec_chan_type,
40                                      uint32_t *neg_flags_inout)
41 {
42         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
43         struct netr_Credential clnt_chal_send;
44         struct netr_Credential srv_chal_recv;
45         struct samr_Password password;
46         bool retried = false;
47         fstring mach_acct;
48         uint32_t neg_flags = *neg_flags_inout;
49
50         if (!ndr_syntax_id_equal(&cli->abstract_syntax,
51                                  &ndr_table_netlogon.syntax_id)) {
52                 return NT_STATUS_INVALID_PARAMETER;
53         }
54
55         TALLOC_FREE(cli->dc);
56
57         /* Store the machine account password we're going to use. */
58         memcpy(password.hash, machine_pwd, 16);
59
60         fstr_sprintf( mach_acct, "%s$", machine_account);
61
62  again:
63         /* Create the client challenge. */
64         generate_random_buffer(clnt_chal_send.data, 8);
65
66         /* Get the server challenge. */
67         result = rpccli_netr_ServerReqChallenge(cli, talloc_tos(),
68                                                 cli->srv_name_slash,
69                                                 clnt_name,
70                                                 &clnt_chal_send,
71                                                 &srv_chal_recv);
72         if (!NT_STATUS_IS_OK(result)) {
73                 return result;
74         }
75
76         /* Calculate the session key and client credentials */
77         
78         cli->dc = netlogon_creds_client_init(cli,
79                                     mach_acct,
80                                     clnt_name,
81                                     &clnt_chal_send,
82                                     &srv_chal_recv,
83                                     &password,
84                                     &clnt_chal_send,
85                                     neg_flags);
86
87         if (!cli->dc) {
88                 return NT_STATUS_NO_MEMORY;
89         }
90
91         /*
92          * Send client auth-2 challenge and receive server repy.
93          */
94
95         result = rpccli_netr_ServerAuthenticate2(cli, talloc_tos(),
96                                                  cli->srv_name_slash,
97                                                  cli->dc->account_name,
98                                                  sec_chan_type,
99                                                  cli->dc->computer_name,
100                                                  &clnt_chal_send, /* input. */
101                                                  &srv_chal_recv, /* output. */
102                                                  &neg_flags);
103
104         /* we might be talking to NT4, so let's downgrade in that case and retry
105          * with the returned neg_flags - gd */
106
107         if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) {
108                 retried = true;
109                 TALLOC_FREE(cli->dc);
110                 goto again;
111         }
112
113         if (!NT_STATUS_IS_OK(result)) {
114                 return result;
115         }
116
117         /*
118          * Check the returned value using the initial
119          * server received challenge.
120          */
121
122         if (!netlogon_creds_client_check(cli->dc, &srv_chal_recv)) {
123                 /*
124                  * Server replied with bad credential. Fail.
125                  */
126                 DEBUG(0,("rpccli_netlogon_setup_creds: server %s "
127                         "replied with bad credential\n",
128                         cli->desthost ));
129                 return NT_STATUS_ACCESS_DENIED;
130         }
131
132         DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential "
133                 "chain established.\n",
134                 cli->desthost ));
135
136         cli->dc->negotiate_flags = neg_flags;
137         *neg_flags_inout = neg_flags;
138
139         return NT_STATUS_OK;
140 }
141
142 /* Logon domain user */
143
144 NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli,
145                                    TALLOC_CTX *mem_ctx,
146                                    uint32 logon_parameters,
147                                    const char *domain,
148                                    const char *username,
149                                    const char *password,
150                                    const char *workstation,
151                                    int logon_type)
152 {
153         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
154         struct netr_Authenticator clnt_creds;
155         struct netr_Authenticator ret_creds;
156         union netr_LogonLevel *logon;
157         union netr_Validation validation;
158         uint8_t authoritative;
159         int validation_level = 3;
160         fstring clnt_name_slash;
161         uint8 zeros[16];
162
163         ZERO_STRUCT(ret_creds);
164         ZERO_STRUCT(zeros);
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 #define COPY_LSA_STRING(mem_ctx, in, out, name) do { \
287         if (in->name.string) { \
288                 out->name.string = talloc_strdup(mem_ctx, in->name.string); \
289                 NT_STATUS_HAVE_NO_MEMORY(out->name.string); \
290         } \
291 } while (0)
292
293 static NTSTATUS copy_netr_SamBaseInfo(TALLOC_CTX *mem_ctx,
294                                       const struct netr_SamBaseInfo *in,
295                                       struct netr_SamBaseInfo *out)
296 {
297         /* first copy all, then realloc pointers */
298         *out = *in;
299
300         COPY_LSA_STRING(mem_ctx, in, out, account_name);
301         COPY_LSA_STRING(mem_ctx, in, out, full_name);
302         COPY_LSA_STRING(mem_ctx, in, out, logon_script);
303         COPY_LSA_STRING(mem_ctx, in, out, profile_path);
304         COPY_LSA_STRING(mem_ctx, in, out, home_directory);
305         COPY_LSA_STRING(mem_ctx, in, out, home_drive);
306
307         if (in->groups.count) {
308                 out->groups.rids = (struct samr_RidWithAttribute *)
309                         talloc_memdup(mem_ctx, in->groups.rids,
310                                 (sizeof(struct samr_RidWithAttribute) *
311                                         in->groups.count));
312                 NT_STATUS_HAVE_NO_MEMORY(out->groups.rids);
313         }
314
315         COPY_LSA_STRING(mem_ctx, in, out, logon_server);
316         COPY_LSA_STRING(mem_ctx, in, out, domain);
317
318         if (in->domain_sid) {
319                 out->domain_sid = sid_dup_talloc(mem_ctx, in->domain_sid);
320                 NT_STATUS_HAVE_NO_MEMORY(out->domain_sid);
321         }
322
323         return NT_STATUS_OK;
324 }
325
326 static NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
327                                         uint16_t validation_level,
328                                         union netr_Validation *validation,
329                                         struct netr_SamInfo3 **info3_p)
330 {
331         struct netr_SamInfo3 *info3;
332         NTSTATUS status;
333
334         if (validation == NULL) {
335                 return NT_STATUS_INVALID_PARAMETER;
336         }
337
338         switch (validation_level) {
339         case 3:
340                 if (validation->sam3 == NULL) {
341                         return NT_STATUS_INVALID_PARAMETER;
342                 }
343
344                 info3 = talloc_move(mem_ctx, &validation->sam3);
345                 break;
346         case 6:
347                 if (validation->sam6 == NULL) {
348                         return NT_STATUS_INVALID_PARAMETER;
349                 }
350
351                 info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
352                 if (info3 == NULL) {
353                         return NT_STATUS_NO_MEMORY;
354                 }
355                 status = copy_netr_SamBaseInfo(info3, &validation->sam6->base, &info3->base);
356                 if (!NT_STATUS_IS_OK(status)) {
357                         TALLOC_FREE(info3);
358                         return status;
359                 }
360
361                 info3->sidcount = validation->sam6->sidcount;
362                 info3->sids = talloc_move(info3, &validation->sam6->sids);
363                 break;
364         default:
365                 return NT_STATUS_BAD_VALIDATION_CLASS;
366         }
367
368         *info3_p = info3;
369
370         return NT_STATUS_OK;
371 }
372
373 /**
374  * Logon domain user with an 'network' SAM logon
375  *
376  * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
377  **/
378
379 NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli,
380                                            TALLOC_CTX *mem_ctx,
381                                            uint32 logon_parameters,
382                                            const char *server,
383                                            const char *username,
384                                            const char *domain,
385                                            const char *workstation,
386                                            const uint8 chal[8],
387                                            uint16_t validation_level,
388                                            DATA_BLOB lm_response,
389                                            DATA_BLOB nt_response,
390                                            struct netr_SamInfo3 **info3)
391 {
392         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
393         const char *workstation_name_slash;
394         const char *server_name_slash;
395         uint8 zeros[16];
396         struct netr_Authenticator clnt_creds;
397         struct netr_Authenticator ret_creds;
398         union netr_LogonLevel *logon = NULL;
399         struct netr_NetworkInfo *network_info;
400         uint8_t authoritative;
401         union netr_Validation validation;
402         struct netr_ChallengeResponse lm;
403         struct netr_ChallengeResponse nt;
404
405         *info3 = NULL;
406
407         ZERO_STRUCT(zeros);
408         ZERO_STRUCT(ret_creds);
409
410         ZERO_STRUCT(lm);
411         ZERO_STRUCT(nt);
412
413         logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
414         if (!logon) {
415                 return NT_STATUS_NO_MEMORY;
416         }
417
418         network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
419         if (!network_info) {
420                 return NT_STATUS_NO_MEMORY;
421         }
422
423         netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
424
425         if (server[0] != '\\' && server[1] != '\\') {
426                 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
427         } else {
428                 server_name_slash = server;
429         }
430
431         if (workstation[0] != '\\' && workstation[1] != '\\') {
432                 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
433         } else {
434                 workstation_name_slash = workstation;
435         }
436
437         if (!workstation_name_slash || !server_name_slash) {
438                 DEBUG(0, ("talloc_asprintf failed!\n"));
439                 return NT_STATUS_NO_MEMORY;
440         }
441
442         /* Initialise input parameters */
443
444         lm.data = lm_response.data;
445         lm.length = lm_response.length;
446         nt.data = nt_response.data;
447         nt.length = nt_response.length;
448
449         network_info->identity_info.domain_name.string          = domain;
450         network_info->identity_info.parameter_control           = logon_parameters;
451         network_info->identity_info.logon_id_low                = 0xdead;
452         network_info->identity_info.logon_id_high               = 0xbeef;
453         network_info->identity_info.account_name.string         = username;
454         network_info->identity_info.workstation.string          = workstation_name_slash;
455
456         memcpy(network_info->challenge, chal, 8);
457         network_info->nt = nt;
458         network_info->lm = lm;
459
460         logon->network = network_info;
461
462         /* Marshall data and send request */
463
464         result = rpccli_netr_LogonSamLogon(cli, mem_ctx,
465                                            server_name_slash,
466                                            global_myname(),
467                                            &clnt_creds,
468                                            &ret_creds,
469                                            NetlogonNetworkInformation,
470                                            logon,
471                                            validation_level,
472                                            &validation,
473                                            &authoritative);
474         if (!NT_STATUS_IS_OK(result)) {
475                 return result;
476         }
477
478         /* Always check returned credentials. */
479         if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) {
480                 DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n"));
481                 return NT_STATUS_ACCESS_DENIED;
482         }
483
484         netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
485
486         result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
487         if (!NT_STATUS_IS_OK(result)) {
488                 return result;
489         }
490
491         return result;
492 }
493
494 NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli,
495                                               TALLOC_CTX *mem_ctx,
496                                               uint32 logon_parameters,
497                                               const char *server,
498                                               const char *username,
499                                               const char *domain,
500                                               const char *workstation,
501                                               const uint8 chal[8],
502                                               uint16_t validation_level,
503                                               DATA_BLOB lm_response,
504                                               DATA_BLOB nt_response,
505                                               struct netr_SamInfo3 **info3)
506 {
507         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
508         const char *workstation_name_slash;
509         const char *server_name_slash;
510         uint8 zeros[16];
511         union netr_LogonLevel *logon = NULL;
512         struct netr_NetworkInfo *network_info;
513         uint8_t authoritative;
514         union netr_Validation validation;
515         struct netr_ChallengeResponse lm;
516         struct netr_ChallengeResponse nt;
517         uint32_t flags = 0;
518
519         *info3 = NULL;
520
521         ZERO_STRUCT(zeros);
522
523         ZERO_STRUCT(lm);
524         ZERO_STRUCT(nt);
525
526         logon = TALLOC_ZERO_P(mem_ctx, union netr_LogonLevel);
527         if (!logon) {
528                 return NT_STATUS_NO_MEMORY;
529         }
530
531         network_info = TALLOC_ZERO_P(mem_ctx, struct netr_NetworkInfo);
532         if (!network_info) {
533                 return NT_STATUS_NO_MEMORY;
534         }
535
536         if (server[0] != '\\' && server[1] != '\\') {
537                 server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server);
538         } else {
539                 server_name_slash = server;
540         }
541
542         if (workstation[0] != '\\' && workstation[1] != '\\') {
543                 workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
544         } else {
545                 workstation_name_slash = workstation;
546         }
547
548         if (!workstation_name_slash || !server_name_slash) {
549                 DEBUG(0, ("talloc_asprintf failed!\n"));
550                 return NT_STATUS_NO_MEMORY;
551         }
552
553         /* Initialise input parameters */
554
555         lm.data = lm_response.data;
556         lm.length = lm_response.length;
557         nt.data = nt_response.data;
558         nt.length = nt_response.length;
559
560         network_info->identity_info.domain_name.string          = domain;
561         network_info->identity_info.parameter_control           = logon_parameters;
562         network_info->identity_info.logon_id_low                = 0xdead;
563         network_info->identity_info.logon_id_high               = 0xbeef;
564         network_info->identity_info.account_name.string         = username;
565         network_info->identity_info.workstation.string          = workstation_name_slash;
566
567         memcpy(network_info->challenge, chal, 8);
568         network_info->nt = nt;
569         network_info->lm = lm;
570
571         logon->network = network_info;
572
573         /* Marshall data and send request */
574
575         result = rpccli_netr_LogonSamLogonEx(cli, mem_ctx,
576                                              server_name_slash,
577                                              global_myname(),
578                                              NetlogonNetworkInformation,
579                                              logon,
580                                              validation_level,
581                                              &validation,
582                                              &authoritative,
583                                              &flags);
584         if (!NT_STATUS_IS_OK(result)) {
585                 return result;
586         }
587
588         netlogon_creds_decrypt_samlogon(cli->dc, validation_level, &validation);
589
590         result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3);
591         if (!NT_STATUS_IS_OK(result)) {
592                 return result;
593         }
594
595         return result;
596 }
597
598 /*********************************************************
599  Change the domain password on the PDC.
600
601  Just changes the password betwen the two values specified.
602
603  Caller must have the cli connected to the netlogon pipe
604  already.
605 **********************************************************/
606
607 NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli,
608                                             TALLOC_CTX *mem_ctx,
609                                             const char *account_name,
610                                             const unsigned char orig_trust_passwd_hash[16],
611                                             const char *new_trust_pwd_cleartext,
612                                             const unsigned char new_trust_passwd_hash[16],
613                                             enum netr_SchannelType sec_channel_type)
614 {
615         NTSTATUS result;
616         struct netr_Authenticator clnt_creds, srv_cred;
617
618         if (!cli->dc) {
619                 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
620                 result = rpccli_netlogon_setup_creds(cli,
621                                                      cli->desthost, /* server name */
622                                                      lp_workgroup(), /* domain */
623                                                      global_myname(), /* client name */
624                                                      account_name, /* machine account name */
625                                                      orig_trust_passwd_hash,
626                                                      sec_channel_type,
627                                                      &neg_flags);
628                 if (!NT_STATUS_IS_OK(result)) {
629                         DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n",
630                                  nt_errstr(result)));
631                         return result;
632                 }
633         }
634
635         netlogon_creds_client_authenticator(cli->dc, &clnt_creds);
636
637         if (cli->dc->negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
638
639                 struct netr_CryptPassword new_password;
640
641                 init_netr_CryptPassword(new_trust_pwd_cleartext,
642                                         cli->dc->session_key,
643                                         &new_password);
644
645                 result = rpccli_netr_ServerPasswordSet2(cli, mem_ctx,
646                                                         cli->srv_name_slash,
647                                                         cli->dc->account_name,
648                                                         sec_channel_type,
649                                                         cli->dc->computer_name,
650                                                         &clnt_creds,
651                                                         &srv_cred,
652                                                         &new_password);
653                 if (!NT_STATUS_IS_OK(result)) {
654                         DEBUG(0,("rpccli_netr_ServerPasswordSet2 failed: %s\n",
655                                 nt_errstr(result)));
656                         return result;
657                 }
658         } else {
659
660                 struct samr_Password new_password;
661                 memcpy(new_password.hash, new_trust_passwd_hash, sizeof(new_password.hash));
662                 netlogon_creds_des_encrypt(cli->dc, &new_password);
663
664                 result = rpccli_netr_ServerPasswordSet(cli, mem_ctx,
665                                                        cli->srv_name_slash,
666                                                        cli->dc->account_name,
667                                                        sec_channel_type,
668                                                        cli->dc->computer_name,
669                                                        &clnt_creds,
670                                                        &srv_cred,
671                                                        &new_password);
672                 if (!NT_STATUS_IS_OK(result)) {
673                         DEBUG(0,("rpccli_netr_ServerPasswordSet failed: %s\n",
674                                 nt_errstr(result)));
675                         return result;
676                 }
677         }
678
679         /* Always check returned credentials. */
680         if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) {
681                 DEBUG(0,("credentials chain check failed\n"));
682                 return NT_STATUS_ACCESS_DENIED;
683         }
684
685         return result;
686 }
687