winbindd: make reset_cm_connection_on_error() public
[metze/samba/wip.git] / source3 / winbindd / winbindd_dual_srv.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    In-Child server implementation of the routines defined in wbint.idl
5
6    Copyright (C) Volker Lendecke 2009
7    Copyright (C) Guenther Deschner 2009
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 "winbindd/winbindd.h"
25 #include "winbindd/winbindd_proto.h"
26 #include "rpc_client/cli_pipe.h"
27 #include "ntdomain.h"
28 #include "librpc/gen_ndr/srv_winbind.h"
29 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
30 #include "../librpc/gen_ndr/ndr_lsa_c.h"
31 #include "idmap.h"
32 #include "../libcli/security/security.h"
33 #include "../libcli/auth/netlogon_creds_cli.h"
34 #include "passdb.h"
35 #include "../source4/dsdb/samdb/samdb.h"
36 #include "rpc_client/cli_netlogon.h"
37 #include "rpc_client/util_netlogon.h"
38
39 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
40 {
41         *r->out.out_data = r->in.in_data;
42 }
43
44 bool reset_cm_connection_on_error(struct winbindd_domain *domain,
45                                   NTSTATUS status)
46 {
47         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
48             NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR))
49         {
50                 invalidate_cm_connection(domain);
51                 /* We invalidated the connection. */
52                 return true;
53         }
54         return false;
55 }
56
57 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
58 {
59         struct winbindd_domain *domain = wb_child_domain();
60         char *dom_name;
61         char *name;
62         enum lsa_SidType type;
63         NTSTATUS status;
64
65         if (domain == NULL) {
66                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
67         }
68
69         status = wb_cache_sid_to_name(domain, p->mem_ctx, r->in.sid,
70                                       &dom_name, &name, &type);
71         reset_cm_connection_on_error(domain, status);
72         if (!NT_STATUS_IS_OK(status)) {
73                 return status;
74         }
75
76         *r->out.domain = dom_name;
77         *r->out.name = name;
78         *r->out.type = type;
79         return NT_STATUS_OK;
80 }
81
82 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
83 {
84         struct winbindd_domain *domain = wb_child_domain();
85         struct lsa_RefDomainList *domains = r->out.domains;
86         NTSTATUS status;
87
88         if (domain == NULL) {
89                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
90         }
91
92         /*
93          * This breaks the winbindd_domain->methods abstraction: This
94          * is only called for remote domains, and both winbindd_msrpc
95          * and winbindd_ad call into lsa_lookupsids anyway. Caching is
96          * done at the wbint RPC layer.
97          */
98         status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
99                                  &domains, &r->out.names);
100
101         if (domains != NULL) {
102                 r->out.domains = domains;
103         }
104
105         reset_cm_connection_on_error(domain, status);
106         return status;
107 }
108
109 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
110 {
111         struct winbindd_domain *domain = wb_child_domain();
112         NTSTATUS status;
113
114         if (domain == NULL) {
115                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
116         }
117
118         status = wb_cache_name_to_sid(domain, p->mem_ctx, r->in.domain,
119                                       r->in.name, r->in.flags,
120                                       r->out.sid, r->out.type);
121         reset_cm_connection_on_error(domain, status);
122         return status;
123 }
124
125 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
126                              struct wbint_Sids2UnixIDs *r)
127 {
128         uint32_t i;
129
130         struct lsa_DomainInfo *d;
131         struct wbint_TransID *ids;
132         uint32_t num_ids;
133
134         struct id_map **id_map_ptrs = NULL;
135         struct idmap_domain *dom;
136         NTSTATUS status = NT_STATUS_NO_MEMORY;
137
138         if (r->in.domains->count != 1) {
139                 return NT_STATUS_INVALID_PARAMETER;
140         }
141
142         d = &r->in.domains->domains[0];
143         ids = r->in.ids->ids;
144         num_ids = r->in.ids->num_ids;
145
146         dom = idmap_find_domain_with_sid(d->name.string, d->sid);
147         if (dom == NULL) {
148                 DEBUG(10, ("idmap domain %s:%s not found\n",
149                            d->name.string, sid_string_dbg(d->sid)));
150
151                 for (i=0; i<num_ids; i++) {
152
153                         ids[i].xid = (struct unixid) {
154                                 .id = UINT32_MAX,
155                                 .type = ID_TYPE_NOT_SPECIFIED
156                         };
157                 }
158
159                 return NT_STATUS_OK;
160         }
161
162         id_map_ptrs = id_map_ptrs_init(talloc_tos(), num_ids);
163         if (id_map_ptrs == NULL) {
164                 goto nomem;
165         }
166
167         /*
168          * Convert the input data into a list of id_map structs
169          * suitable for handing in to the idmap sids_to_unixids
170          * method.
171          */
172
173         for (i=0; i<num_ids; i++) {
174                 struct id_map *m = id_map_ptrs[i];
175
176                 sid_compose(m->sid, d->sid, ids[i].rid);
177                 m->status = ID_UNKNOWN;
178                 m->xid = (struct unixid) { .type = ids[i].type };
179         }
180
181         status = dom->methods->sids_to_unixids(dom, id_map_ptrs);
182
183         if (!NT_STATUS_IS_OK(status)) {
184                 DEBUG(10, ("sids_to_unixids returned %s\n",
185                            nt_errstr(status)));
186                 goto done;
187         }
188
189         /*
190          * Extract the results for handing them back to the caller.
191          */
192
193         for (i=0; i<num_ids; i++) {
194                 struct id_map *m = id_map_ptrs[i];
195
196                 if (!idmap_unix_id_is_in_range(m->xid.id, dom)) {
197                         DBG_DEBUG("id %"PRIu32" is out of range "
198                                   "%"PRIu32"-%"PRIu32" for domain %s\n",
199                                   m->xid.id, dom->low_id, dom->high_id,
200                                   dom->name);
201                         m->status = ID_UNMAPPED;
202                 }
203
204                 if (m->status == ID_MAPPED) {
205                         ids[i].xid = m->xid;
206                 } else {
207                         ids[i].xid.id = UINT32_MAX;
208                         ids[i].xid.type = ID_TYPE_NOT_SPECIFIED;
209                 }
210         }
211
212         goto done;
213 nomem:
214         status = NT_STATUS_NO_MEMORY;
215 done:
216         TALLOC_FREE(id_map_ptrs);
217         return status;
218 }
219
220 NTSTATUS _wbint_UnixIDs2Sids(struct pipes_struct *p,
221                              struct wbint_UnixIDs2Sids *r)
222 {
223         struct id_map **maps;
224         NTSTATUS status;
225         uint32_t i;
226
227         maps = id_map_ptrs_init(talloc_tos(), r->in.num_ids);
228         if (maps == NULL) {
229                 return NT_STATUS_NO_MEMORY;
230         }
231
232         for (i=0; i<r->in.num_ids; i++) {
233                 maps[i]->status = ID_UNKNOWN;
234                 maps[i]->xid = r->in.xids[i];
235         }
236
237         status = idmap_backend_unixids_to_sids(maps, r->in.domain_name,
238                                                r->in.domain_sid);
239         if (!NT_STATUS_IS_OK(status)) {
240                 TALLOC_FREE(maps);
241                 return status;
242         }
243
244         for (i=0; i<r->in.num_ids; i++) {
245                 r->out.xids[i] = maps[i]->xid;
246                 sid_copy(&r->out.sids[i], maps[i]->sid);
247         }
248
249         TALLOC_FREE(maps);
250
251         return NT_STATUS_OK;
252 }
253
254 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
255 {
256         struct unixid xid;
257         NTSTATUS status;
258
259         status = idmap_allocate_uid(&xid);
260         if (!NT_STATUS_IS_OK(status)) {
261                 return status;
262         }
263         *r->out.uid = xid.id;
264         return NT_STATUS_OK;
265 }
266
267 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
268 {
269         struct unixid xid;
270         NTSTATUS status;
271
272         status = idmap_allocate_gid(&xid);
273         if (!NT_STATUS_IS_OK(status)) {
274                 return status;
275         }
276         *r->out.gid = xid.id;
277         return NT_STATUS_OK;
278 }
279
280 NTSTATUS _wbint_GetNssInfo(struct pipes_struct *p, struct wbint_GetNssInfo *r)
281 {
282         struct idmap_domain *domain;
283         NTSTATUS status;
284
285         domain = idmap_find_domain(r->in.info->domain_name);
286         if ((domain == NULL) || (domain->query_user == NULL)) {
287                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
288         }
289
290         status = domain->query_user(domain, r->in.info);
291         return status;
292 }
293
294 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
295                                   struct wbint_LookupUserAliases *r)
296 {
297         struct winbindd_domain *domain = wb_child_domain();
298         NTSTATUS status;
299
300         if (domain == NULL) {
301                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
302         }
303
304         status = wb_cache_lookup_useraliases(domain, p->mem_ctx,
305                                              r->in.sids->num_sids,
306                                              r->in.sids->sids,
307                                              &r->out.rids->num_rids,
308                                              &r->out.rids->rids);
309         reset_cm_connection_on_error(domain, status);
310         return status;
311 }
312
313 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
314                                  struct wbint_LookupUserGroups *r)
315 {
316         struct winbindd_domain *domain = wb_child_domain();
317         NTSTATUS status;
318
319         if (domain == NULL) {
320                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
321         }
322
323         status = wb_cache_lookup_usergroups(domain, p->mem_ctx, r->in.sid,
324                                             &r->out.sids->num_sids,
325                                             &r->out.sids->sids);
326         reset_cm_connection_on_error(domain, status);
327         return status;
328 }
329
330 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
331                                     struct wbint_QuerySequenceNumber *r)
332 {
333         struct winbindd_domain *domain = wb_child_domain();
334         NTSTATUS status;
335
336         if (domain == NULL) {
337                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
338         }
339
340         status = wb_cache_sequence_number(domain, r->out.sequence);
341         reset_cm_connection_on_error(domain, status);
342         return status;
343 }
344
345 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
346                                    struct wbint_LookupGroupMembers *r)
347 {
348         struct winbindd_domain *domain = wb_child_domain();
349         uint32_t i, num_names;
350         struct dom_sid *sid_mem;
351         char **names;
352         uint32_t *name_types;
353         NTSTATUS status;
354
355         if (domain == NULL) {
356                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
357         }
358
359         status = wb_cache_lookup_groupmem(domain, p->mem_ctx, r->in.sid,
360                                           r->in.type, &num_names, &sid_mem,
361                                           &names, &name_types);
362         reset_cm_connection_on_error(domain, status);
363         if (!NT_STATUS_IS_OK(status)) {
364                 return status;
365         }
366
367         r->out.members->num_principals = num_names;
368         r->out.members->principals = talloc_array(
369                 r->out.members, struct wbint_Principal, num_names);
370         if (r->out.members->principals == NULL) {
371                 return NT_STATUS_NO_MEMORY;
372         }
373
374         for (i=0; i<num_names; i++) {
375                 struct wbint_Principal *m = &r->out.members->principals[i];
376                 sid_copy(&m->sid, &sid_mem[i]);
377                 m->name = talloc_move(r->out.members->principals, &names[i]);
378                 m->type = (enum lsa_SidType)name_types[i];
379         }
380
381         return NT_STATUS_OK;
382 }
383
384 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
385                                struct wbint_QueryGroupList *r)
386 {
387         TALLOC_CTX *frame = NULL;
388         struct winbindd_domain *domain = wb_child_domain();
389         uint32_t i;
390         uint32_t num_local_groups = 0;
391         struct wb_acct_info *local_groups = NULL;
392         uint32_t num_dom_groups = 0;
393         struct wb_acct_info *dom_groups = NULL;
394         uint32_t ti = 0;
395         uint64_t num_total = 0;
396         struct wbint_Principal *result;
397         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
398         bool include_local_groups = false;
399
400         if (domain == NULL) {
401                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
402         }
403
404         frame = talloc_stackframe();
405
406         switch (lp_server_role()) {
407         case ROLE_ACTIVE_DIRECTORY_DC:
408                 if (domain->internal) {
409                         /*
410                          * we want to include local groups
411                          * for BUILTIN and WORKGROUP
412                          */
413                         include_local_groups = true;
414                 }
415                 break;
416         default:
417                 /*
418                  * We might include local groups in more
419                  * setups later, but that requires more work
420                  * elsewhere.
421                  */
422                 break;
423         }
424
425         if (include_local_groups) {
426                 status = wb_cache_enum_local_groups(domain, frame,
427                                                     &num_local_groups,
428                                                     &local_groups);
429                 reset_cm_connection_on_error(domain, status);
430                 if (!NT_STATUS_IS_OK(status)) {
431                         goto out;
432                 }
433         }
434
435         status = wb_cache_enum_dom_groups(domain, frame,
436                                           &num_dom_groups,
437                                           &dom_groups);
438         reset_cm_connection_on_error(domain, status);
439         if (!NT_STATUS_IS_OK(status)) {
440                 goto out;
441         }
442
443         num_total = num_local_groups + num_dom_groups;
444         if (num_total > UINT32_MAX) {
445                 status = NT_STATUS_INTERNAL_ERROR;
446                 goto out;
447         }
448
449         result = talloc_array(frame, struct wbint_Principal, num_total);
450         if (result == NULL) {
451                 status = NT_STATUS_NO_MEMORY;
452                 goto out;
453         }
454
455         for (i = 0; i < num_local_groups; i++) {
456                 struct wb_acct_info *lg = &local_groups[i];
457                 struct wbint_Principal *rg = &result[ti++];
458
459                 sid_compose(&rg->sid, &domain->sid, lg->rid);
460                 rg->type = SID_NAME_ALIAS;
461                 rg->name = talloc_strdup(result, lg->acct_name);
462                 if (rg->name == NULL) {
463                         status = NT_STATUS_NO_MEMORY;
464                         goto out;
465                 }
466         }
467         num_local_groups = 0;
468
469         for (i = 0; i < num_dom_groups; i++) {
470                 struct wb_acct_info *dg = &dom_groups[i];
471                 struct wbint_Principal *rg = &result[ti++];
472
473                 sid_compose(&rg->sid, &domain->sid, dg->rid);
474                 rg->type = SID_NAME_DOM_GRP;
475                 rg->name = talloc_strdup(result, dg->acct_name);
476                 if (rg->name == NULL) {
477                         status = NT_STATUS_NO_MEMORY;
478                         goto out;
479                 }
480         }
481         num_dom_groups = 0;
482
483         r->out.groups->num_principals = ti;
484         r->out.groups->principals = talloc_move(r->out.groups, &result);
485
486         status = NT_STATUS_OK;
487 out:
488         TALLOC_FREE(frame);
489         return status;
490 }
491
492 NTSTATUS _wbint_QueryUserRidList(struct pipes_struct *p,
493                                  struct wbint_QueryUserRidList *r)
494 {
495         struct winbindd_domain *domain = wb_child_domain();
496         NTSTATUS status;
497
498         if (domain == NULL) {
499                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
500         }
501
502         /*
503          * Right now this is overkill. We should add a backend call
504          * just querying the rids.
505          */
506
507         status = wb_cache_query_user_list(domain, p->mem_ctx,
508                                           &r->out.rids->rids);
509         reset_cm_connection_on_error(domain, status);
510
511         if (!NT_STATUS_IS_OK(status)) {
512                 return status;
513         }
514
515         r->out.rids->num_rids = talloc_array_length(r->out.rids->rids);
516
517         return NT_STATUS_OK;
518 }
519
520 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
521 {
522         struct winbindd_domain *domain = wb_child_domain();
523         struct rpc_pipe_client *netlogon_pipe;
524         struct netr_DsRGetDCNameInfo *dc_info;
525         NTSTATUS status;
526         WERROR werr;
527         unsigned int orig_timeout;
528         struct dcerpc_binding_handle *b;
529
530         if (domain == NULL) {
531                 return dsgetdcname(p->mem_ctx, server_messaging_context(),
532                                    r->in.domain_name, r->in.domain_guid,
533                                    r->in.site_name ? r->in.site_name : "",
534                                    r->in.flags,
535                                    r->out.dc_info);
536         }
537
538         status = cm_connect_netlogon(domain, &netlogon_pipe);
539
540         reset_cm_connection_on_error(domain, status);
541         if (!NT_STATUS_IS_OK(status)) {
542                 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
543                 return status;
544         }
545
546         b = netlogon_pipe->binding_handle;
547
548         /* This call can take a long time - allow the server to time out.
549            35 seconds should do it. */
550
551         orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
552
553         if (domain->active_directory) {
554                 status = dcerpc_netr_DsRGetDCName(b,
555                         p->mem_ctx, domain->dcname,
556                         r->in.domain_name, NULL, r->in.domain_guid,
557                         r->in.flags, r->out.dc_info, &werr);
558                 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
559                         goto done;
560                 }
561                 if (reset_cm_connection_on_error(domain, status)) {
562                         /* Re-initialize. */
563                         status = cm_connect_netlogon(domain, &netlogon_pipe);
564
565                         reset_cm_connection_on_error(domain, status);
566                         if (!NT_STATUS_IS_OK(status)) {
567                                 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
568                                 return status;
569                         }
570
571                         b = netlogon_pipe->binding_handle;
572
573                         /* This call can take a long time - allow the server to time out.
574                            35 seconds should do it. */
575
576                         orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
577                 }
578         }
579
580         /*
581          * Fallback to less capable methods
582          */
583
584         dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
585         if (dc_info == NULL) {
586                 status = NT_STATUS_NO_MEMORY;
587                 goto done;
588         }
589
590         if (r->in.flags & DS_PDC_REQUIRED) {
591                 status = dcerpc_netr_GetDcName(b,
592                         p->mem_ctx, domain->dcname,
593                         r->in.domain_name, &dc_info->dc_unc, &werr);
594         } else {
595                 status = dcerpc_netr_GetAnyDCName(b,
596                         p->mem_ctx, domain->dcname,
597                         r->in.domain_name, &dc_info->dc_unc, &werr);
598         }
599
600         reset_cm_connection_on_error(domain, status);
601         if (!NT_STATUS_IS_OK(status)) {
602                 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
603                            nt_errstr(status)));
604                 goto done;
605         }
606         if (!W_ERROR_IS_OK(werr)) {
607                 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
608                            win_errstr(werr)));
609                 status = werror_to_ntstatus(werr);
610                 goto done;
611         }
612
613         *r->out.dc_info = dc_info;
614         status = NT_STATUS_OK;
615
616 done:
617         /* And restore our original timeout. */
618         rpccli_set_timeout(netlogon_pipe, orig_timeout);
619
620         return status;
621 }
622
623 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
624 {
625         struct winbindd_domain *domain = wb_child_domain();
626         char *domain_name;
627         char **names;
628         enum lsa_SidType *types;
629         struct wbint_Principal *result;
630         NTSTATUS status;
631         uint32_t i;
632
633         if (domain == NULL) {
634                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
635         }
636
637         status = wb_cache_rids_to_names(domain, talloc_tos(), r->in.domain_sid,
638                                         r->in.rids->rids, r->in.rids->num_rids,
639                                         &domain_name, &names, &types);
640         reset_cm_connection_on_error(domain, status);
641         if (!NT_STATUS_IS_OK(status)) {
642                 return status;
643         }
644
645         *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
646
647         result = talloc_array(p->mem_ctx, struct wbint_Principal,
648                               r->in.rids->num_rids);
649         if (result == NULL) {
650                 return NT_STATUS_NO_MEMORY;
651         }
652
653         for (i=0; i<r->in.rids->num_rids; i++) {
654                 sid_compose(&result[i].sid, r->in.domain_sid,
655                             r->in.rids->rids[i]);
656                 result[i].type = types[i];
657                 result[i].name = talloc_move(result, &names[i]);
658         }
659         TALLOC_FREE(types);
660         TALLOC_FREE(names);
661
662         r->out.names->num_principals = r->in.rids->num_rids;
663         r->out.names->principals = result;
664         return NT_STATUS_OK;
665 }
666
667 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
668                                     struct wbint_CheckMachineAccount *r)
669 {
670         struct winbindd_domain *domain;
671         int num_retries = 0;
672         NTSTATUS status;
673
674         domain = wb_child_domain();
675         if (domain == NULL) {
676                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
677         }
678
679 again:
680         invalidate_cm_connection(domain);
681         domain->conn.netlogon_force_reauth = true;
682
683         {
684                 struct rpc_pipe_client *netlogon_pipe = NULL;
685                 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
686                 status = cm_connect_netlogon_secure(domain,
687                                                     &netlogon_pipe,
688                                                     &netlogon_creds_ctx);
689         }
690
691         /* There is a race condition between fetching the trust account
692            password and the periodic machine password change.  So it's
693            possible that the trust account password has been changed on us.
694            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
695
696 #define MAX_RETRIES 3
697
698         if ((num_retries < MAX_RETRIES)
699             && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
700                 num_retries++;
701                 goto again;
702         }
703
704         if (!NT_STATUS_IS_OK(status)) {
705                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
706                 goto done;
707         }
708
709         /* Pass back result code - zero for success, other values for
710            specific failures. */
711
712         DEBUG(3,("domain %s secret is %s\n", domain->name,
713                 NT_STATUS_IS_OK(status) ? "good" : "bad"));
714
715  done:
716         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
717               ("Checking the trust account password for domain %s returned %s\n",
718                domain->name, nt_errstr(status)));
719
720         return status;
721 }
722
723 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
724                                      struct wbint_ChangeMachineAccount *r)
725 {
726         struct messaging_context *msg_ctx = server_messaging_context();
727         struct winbindd_domain *domain;
728         NTSTATUS status;
729         struct rpc_pipe_client *netlogon_pipe = NULL;
730         struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
731
732         domain = wb_child_domain();
733         if (domain == NULL) {
734                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
735         }
736
737         status = cm_connect_netlogon_secure(domain,
738                                             &netlogon_pipe,
739                                             &netlogon_creds_ctx);
740         if (!NT_STATUS_IS_OK(status)) {
741                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
742                 goto done;
743         }
744
745         status = trust_pw_change(netlogon_creds_ctx,
746                                  msg_ctx,
747                                  netlogon_pipe->binding_handle,
748                                  domain->name,
749                                  domain->dcname,
750                                  true); /* force */
751
752         /* Pass back result code - zero for success, other values for
753            specific failures. */
754
755         DEBUG(3,("domain %s secret %s\n", domain->name,
756                 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
757
758  done:
759         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
760               ("Changing the trust account password for domain %s returned %s\n",
761                domain->name, nt_errstr(status)));
762
763         return status;
764 }
765
766 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
767 {
768         NTSTATUS status;
769         struct winbindd_domain *domain;
770         struct rpc_pipe_client *netlogon_pipe;
771         union netr_CONTROL_QUERY_INFORMATION info;
772         WERROR werr;
773         fstring logon_server;
774         struct dcerpc_binding_handle *b;
775         bool retry = false;
776
777         domain = wb_child_domain();
778         if (domain == NULL) {
779                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
780         }
781
782 reconnect:
783         status = cm_connect_netlogon(domain, &netlogon_pipe);
784         reset_cm_connection_on_error(domain, status);
785         if (!NT_STATUS_IS_OK(status)) {
786                 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
787                           nt_errstr(status)));
788                 return status;
789         }
790
791         b = netlogon_pipe->binding_handle;
792
793         fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
794         *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
795         if (*r->out.dcname == NULL) {
796                 DEBUG(2, ("Could not allocate memory\n"));
797                 return NT_STATUS_NO_MEMORY;
798         }
799
800         /*
801          * This provokes a WERR_NOT_SUPPORTED error message. This is
802          * documented in the wspp docs. I could not get a successful
803          * call to work, but the main point here is testing that the
804          * netlogon pipe works.
805          */
806         status = dcerpc_netr_LogonControl(b, p->mem_ctx,
807                                           logon_server, NETLOGON_CONTROL_QUERY,
808                                           2, &info, &werr);
809
810         if (!dcerpc_binding_handle_is_connected(b) && !retry) {
811                 DEBUG(10, ("Session might have expired. "
812                            "Reconnect and retry once.\n"));
813                 invalidate_cm_connection(domain);
814                 retry = true;
815                 goto reconnect;
816         }
817
818         reset_cm_connection_on_error(domain, status);
819         if (!NT_STATUS_IS_OK(status)) {
820                 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
821                         nt_errstr(status)));
822                 return status;
823         }
824
825         if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
826                 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
827                           "WERR_NOT_SUPPORTED\n",
828                           win_errstr(werr)));
829                 return werror_to_ntstatus(werr);
830         }
831
832         DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
833         return NT_STATUS_OK;
834 }
835
836 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
837                                                     struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
838 {
839         struct winbindd_domain *domain;
840         NTSTATUS status;
841         struct rpc_pipe_client *netlogon_pipe = NULL;
842         struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
843
844         domain = wb_child_domain();
845         if (domain == NULL) {
846                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
847         }
848
849         status = cm_connect_netlogon_secure(domain,
850                                             &netlogon_pipe,
851                                             &netlogon_creds_ctx);
852         if (!NT_STATUS_IS_OK(status)) {
853                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
854                 goto done;
855         }
856
857         status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(netlogon_creds_ctx,
858                                                                       netlogon_pipe->binding_handle,
859                                                                       r->in.site_name,
860                                                                       r->in.dns_ttl,
861                                                                       r->in.dns_names);
862
863         /* Pass back result code - zero for success, other values for
864            specific failures. */
865
866         DEBUG(3,("DNS records for domain %s %s\n", domain->name,
867                 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
868
869  done:
870         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
871               ("Update of DNS records via RW DC %s returned %s\n",
872                domain->name, nt_errstr(status)));
873
874         return status;
875 }
876
877 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
878                         struct winbind_SamLogon *r)
879 {
880         struct winbindd_domain *domain;
881         NTSTATUS status;
882         struct netr_IdentityInfo *identity_info = NULL;
883         const uint8_t chal_zero[8] = {0, };
884         const uint8_t *challenge = chal_zero;
885         DATA_BLOB lm_response, nt_response;
886         uint32_t flags = 0;
887         uint16_t validation_level;
888         union netr_Validation *validation = NULL;
889         bool interactive = false;
890
891         domain = wb_child_domain();
892         if (domain == NULL) {
893                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
894         }
895
896         switch (r->in.validation_level) {
897         case 3:
898         case 6:
899                 break;
900         default:
901                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
902         }
903
904         switch (r->in.logon_level) {
905         case NetlogonInteractiveInformation:
906         case NetlogonServiceInformation:
907         case NetlogonInteractiveTransitiveInformation:
908         case NetlogonServiceTransitiveInformation:
909                 if (r->in.logon.password == NULL) {
910                         return NT_STATUS_REQUEST_NOT_ACCEPTED;
911                 }
912
913                 interactive = true;
914                 identity_info = &r->in.logon.password->identity_info;
915
916                 challenge = chal_zero;
917                 lm_response = data_blob_talloc(p->mem_ctx,
918                                         r->in.logon.password->lmpassword.hash,
919                                         sizeof(r->in.logon.password->lmpassword.hash));
920                 nt_response = data_blob_talloc(p->mem_ctx,
921                                         r->in.logon.password->ntpassword.hash,
922                                         sizeof(r->in.logon.password->ntpassword.hash));
923                 break;
924
925         case NetlogonNetworkInformation:
926         case NetlogonNetworkTransitiveInformation:
927                 if (r->in.logon.network == NULL) {
928                         return NT_STATUS_REQUEST_NOT_ACCEPTED;
929                 }
930
931                 interactive = false;
932                 identity_info = &r->in.logon.network->identity_info;
933
934                 challenge = r->in.logon.network->challenge;
935                 lm_response = data_blob_talloc(p->mem_ctx,
936                                         r->in.logon.network->lm.data,
937                                         r->in.logon.network->lm.length);
938                 nt_response = data_blob_talloc(p->mem_ctx,
939                                         r->in.logon.network->nt.data,
940                                         r->in.logon.network->nt.length);
941                 break;
942
943         case NetlogonGenericInformation:
944                 if (r->in.logon.generic == NULL) {
945                         return NT_STATUS_REQUEST_NOT_ACCEPTED;
946                 }
947
948                 identity_info = &r->in.logon.generic->identity_info;
949                 /*
950                  * Not implemented here...
951                  */
952                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
953
954         default:
955                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
956         }
957
958         status = winbind_dual_SamLogon(domain, p->mem_ctx,
959                                        interactive,
960                                        identity_info->parameter_control,
961                                        identity_info->account_name.string,
962                                        identity_info->domain_name.string,
963                                        identity_info->workstation.string,
964                                        challenge,
965                                        lm_response, nt_response,
966                                        &r->out.authoritative,
967                                        true, /* skip_sam */
968                                        &flags,
969                                        &validation_level,
970                                        &validation);
971         if (!NT_STATUS_IS_OK(status)) {
972                 return status;
973         }
974         switch (r->in.validation_level) {
975         case 3:
976                 status = map_validation_to_info3(p->mem_ctx,
977                                                  validation_level,
978                                                  validation,
979                                                  &r->out.validation.sam3);
980                 TALLOC_FREE(validation);
981                 if (!NT_STATUS_IS_OK(status)) {
982                         return status;
983                 }
984                 return NT_STATUS_OK;
985         case 6:
986                 status = map_validation_to_info6(p->mem_ctx,
987                                                  validation_level,
988                                                  validation,
989                                                  &r->out.validation.sam6);
990                 TALLOC_FREE(validation);
991                 if (!NT_STATUS_IS_OK(status)) {
992                         return status;
993                 }
994                 return NT_STATUS_OK;
995         }
996
997         smb_panic(__location__);
998         return NT_STATUS_INTERNAL_ERROR;
999 }
1000
1001 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
1002                              struct winbindd_domain *domain,
1003                              struct winbind_LogonControl *r)
1004 {
1005         NTSTATUS status;
1006         struct rpc_pipe_client *netlogon_pipe = NULL;
1007         struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1008         struct netr_NETLOGON_INFO_2 *info2 = NULL;
1009         WERROR check_result = WERR_INTERNAL_ERROR;
1010
1011         info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1012         if (info2 == NULL) {
1013                 return WERR_NOT_ENOUGH_MEMORY;
1014         }
1015
1016         if (domain->internal) {
1017                 check_result = WERR_OK;
1018                 goto check_return;
1019         }
1020
1021         /*
1022          * For now we just force a reconnect
1023          *
1024          * TODO: take care of the optional '\dcname'
1025          */
1026         invalidate_cm_connection(domain);
1027         domain->conn.netlogon_force_reauth = true;
1028         status = cm_connect_netlogon_secure(domain,
1029                                             &netlogon_pipe,
1030                                             &netlogon_creds_ctx);
1031         reset_cm_connection_on_error(domain, status);
1032         if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1033                 status = NT_STATUS_NO_LOGON_SERVERS;
1034         }
1035         if (!NT_STATUS_IS_OK(status)) {
1036                 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1037                           __func__, domain->name, domain->alt_name,
1038                           nt_errstr(status)));
1039                 /*
1040                  * Here we return a top level error!
1041                  * This is different than TC_QUERY or TC_VERIFY.
1042                  */
1043                 return ntstatus_to_werror(status);
1044         }
1045         check_result = WERR_OK;
1046
1047 check_return:
1048         info2->pdc_connection_status = WERR_OK;
1049         if (domain->dcname != NULL) {
1050                 info2->flags |= NETLOGON_HAS_IP;
1051                 info2->flags |= NETLOGON_HAS_TIMESERV;
1052                 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1053                                                          domain->dcname);
1054                 if (info2->trusted_dc_name == NULL) {
1055                         return WERR_NOT_ENOUGH_MEMORY;
1056                 }
1057         } else {
1058                 info2->trusted_dc_name = talloc_strdup(info2, "");
1059                 if (info2->trusted_dc_name == NULL) {
1060                         return WERR_NOT_ENOUGH_MEMORY;
1061                 }
1062         }
1063         info2->tc_connection_status = check_result;
1064
1065         if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1066                 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1067                           "pdc_connection[%s] tc_connection[%s]\n",
1068                           __func__, domain->name, domain->alt_name,
1069                           domain->dcname,
1070                           win_errstr(info2->pdc_connection_status),
1071                           win_errstr(info2->tc_connection_status)));
1072         }
1073
1074         r->out.query->info2 = info2;
1075
1076         DEBUG(5, ("%s: succeeded.\n", __func__));
1077         return WERR_OK;
1078 }
1079
1080 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
1081                              struct winbindd_domain *domain,
1082                              struct winbind_LogonControl *r)
1083 {
1084         NTSTATUS status;
1085         struct rpc_pipe_client *netlogon_pipe = NULL;
1086         struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1087         struct netr_NETLOGON_INFO_2 *info2 = NULL;
1088         WERROR check_result = WERR_INTERNAL_ERROR;
1089
1090         info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1091         if (info2 == NULL) {
1092                 return WERR_NOT_ENOUGH_MEMORY;
1093         }
1094
1095         if (domain->internal) {
1096                 check_result = WERR_OK;
1097                 goto check_return;
1098         }
1099
1100         status = cm_connect_netlogon_secure(domain,
1101                                             &netlogon_pipe,
1102                                             &netlogon_creds_ctx);
1103         reset_cm_connection_on_error(domain, status);
1104         if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1105                 status = NT_STATUS_NO_LOGON_SERVERS;
1106         }
1107         if (!NT_STATUS_IS_OK(status)) {
1108                 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1109                           nt_errstr(status)));
1110                 check_result = ntstatus_to_werror(status);
1111                 goto check_return;
1112         }
1113         check_result = WERR_OK;
1114
1115 check_return:
1116         info2->pdc_connection_status = WERR_OK;
1117         if (domain->dcname != NULL) {
1118                 info2->flags |= NETLOGON_HAS_IP;
1119                 info2->flags |= NETLOGON_HAS_TIMESERV;
1120                 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1121                                                          domain->dcname);
1122                 if (info2->trusted_dc_name == NULL) {
1123                         return WERR_NOT_ENOUGH_MEMORY;
1124                 }
1125         } else {
1126                 info2->trusted_dc_name = talloc_strdup(info2, "");
1127                 if (info2->trusted_dc_name == NULL) {
1128                         return WERR_NOT_ENOUGH_MEMORY;
1129                 }
1130         }
1131         info2->tc_connection_status = check_result;
1132
1133         if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1134                 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1135                           "pdc_connection[%s] tc_connection[%s]\n",
1136                           __func__, domain->name, domain->alt_name,
1137                           domain->dcname,
1138                           win_errstr(info2->pdc_connection_status),
1139                           win_errstr(info2->tc_connection_status)));
1140         }
1141
1142         r->out.query->info2 = info2;
1143
1144         DEBUG(5, ("%s: succeeded.\n", __func__));
1145         return WERR_OK;
1146 }
1147
1148 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1149                              struct winbindd_domain *domain,
1150                              struct winbind_LogonControl *r)
1151 {
1152         TALLOC_CTX *frame = talloc_stackframe();
1153         NTSTATUS status;
1154         NTSTATUS result;
1155         struct lsa_String trusted_domain_name = {};
1156         struct lsa_StringLarge trusted_domain_name_l = {};
1157         struct rpc_pipe_client *local_lsa_pipe = NULL;
1158         struct policy_handle local_lsa_policy = {};
1159         struct dcerpc_binding_handle *local_lsa = NULL;
1160         struct rpc_pipe_client *netlogon_pipe = NULL;
1161         struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1162         struct cli_credentials *creds = NULL;
1163         struct samr_Password *cur_nt_hash = NULL;
1164         uint32_t trust_attributes = 0;
1165         struct samr_Password new_owf_password = {};
1166         int cmp_new = -1;
1167         struct samr_Password old_owf_password = {};
1168         int cmp_old = -1;
1169         const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1170         bool fetch_fti = false;
1171         struct lsa_ForestTrustInformation *new_fti = NULL;
1172         struct netr_TrustInfo *trust_info = NULL;
1173         struct netr_NETLOGON_INFO_2 *info2 = NULL;
1174         struct dcerpc_binding_handle *b = NULL;
1175         WERROR check_result = WERR_INTERNAL_ERROR;
1176         WERROR verify_result = WERR_INTERNAL_ERROR;
1177         bool retry = false;
1178
1179         trusted_domain_name.string = domain->name;
1180         trusted_domain_name_l.string = domain->name;
1181
1182         info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1183         if (info2 == NULL) {
1184                 TALLOC_FREE(frame);
1185                 return WERR_NOT_ENOUGH_MEMORY;
1186         }
1187
1188         if (domain->internal) {
1189                 check_result = WERR_OK;
1190                 goto check_return;
1191         }
1192
1193         status = pdb_get_trust_credentials(domain->name,
1194                                            domain->alt_name,
1195                                            frame,
1196                                            &creds);
1197         if (NT_STATUS_IS_OK(status)) {
1198                 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1199                 TALLOC_FREE(creds);
1200         }
1201
1202         if (!domain->primary) {
1203                 union lsa_TrustedDomainInfo *tdi = NULL;
1204
1205                 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1206                                                 &local_lsa_policy);
1207                 if (!NT_STATUS_IS_OK(status)) {
1208                         DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1209                                  __location__, __func__, nt_errstr(status)));
1210                         TALLOC_FREE(frame);
1211                         return WERR_INTERNAL_ERROR;
1212                 }
1213                 local_lsa = local_lsa_pipe->binding_handle;
1214
1215                 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1216                                                         &local_lsa_policy,
1217                                                         &trusted_domain_name,
1218                                                         LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1219                                                         &tdi, &result);
1220                 if (!NT_STATUS_IS_OK(status)) {
1221                         DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1222                                  __location__, __func__, domain->name, nt_errstr(status)));
1223                         TALLOC_FREE(frame);
1224                         return WERR_INTERNAL_ERROR;
1225                 }
1226                 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1227                         DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1228                                  __location__, __func__, domain->name));
1229                         TALLOC_FREE(frame);
1230                         return WERR_NO_SUCH_DOMAIN;
1231                 }
1232                 if (!NT_STATUS_IS_OK(result)) {
1233                         DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1234                                  __location__, __func__, domain->name, nt_errstr(result)));
1235                         TALLOC_FREE(frame);
1236                         return WERR_INTERNAL_ERROR;
1237                 }
1238                 if (tdi == NULL) {
1239                         DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1240                                  "returned no trusted domain information\n",
1241                                  __location__, __func__));
1242                         TALLOC_FREE(frame);
1243                         return WERR_INTERNAL_ERROR;
1244                 }
1245
1246                 local_tdo = &tdi->info_ex;
1247                 trust_attributes = local_tdo->trust_attributes;
1248         }
1249
1250         if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1251                 struct lsa_ForestTrustInformation *old_fti = NULL;
1252
1253                 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1254                                                         &local_lsa_policy,
1255                                                         &trusted_domain_name,
1256                                                         LSA_FOREST_TRUST_DOMAIN_INFO,
1257                                                         &old_fti, &result);
1258                 if (!NT_STATUS_IS_OK(status)) {
1259                         DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1260                                  __location__, __func__, domain->name, nt_errstr(status)));
1261                         TALLOC_FREE(frame);
1262                         return WERR_INTERNAL_ERROR;
1263                 }
1264                 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1265                         DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1266                                   __func__, domain->name));
1267                         old_fti = NULL;
1268                         fetch_fti = true;
1269                         result = NT_STATUS_OK;
1270                 }
1271                 if (!NT_STATUS_IS_OK(result)) {
1272                         DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1273                                  __location__, __func__, domain->name, nt_errstr(result)));
1274                         TALLOC_FREE(frame);
1275                         return WERR_INTERNAL_ERROR;
1276                 }
1277
1278                 TALLOC_FREE(old_fti);
1279         }
1280
1281 reconnect:
1282         status = cm_connect_netlogon_secure(domain,
1283                                             &netlogon_pipe,
1284                                             &netlogon_creds_ctx);
1285         reset_cm_connection_on_error(domain, status);
1286         if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1287                 status = NT_STATUS_NO_LOGON_SERVERS;
1288         }
1289         if (!NT_STATUS_IS_OK(status)) {
1290                 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1291                           nt_errstr(status)));
1292                 check_result = ntstatus_to_werror(status);
1293                 goto check_return;
1294         }
1295         check_result = WERR_OK;
1296         b = netlogon_pipe->binding_handle;
1297
1298         if (cur_nt_hash == NULL) {
1299                 verify_result = WERR_NO_TRUST_LSA_SECRET;
1300                 goto verify_return;
1301         }
1302
1303         if (fetch_fti) {
1304                 status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1305                                                                       b, frame,
1306                                                                       &new_fti);
1307                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1308                         status = NT_STATUS_NOT_SUPPORTED;
1309                 }
1310                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1311                         new_fti = NULL;
1312                         status = NT_STATUS_OK;
1313                 }
1314                 if (!NT_STATUS_IS_OK(status)) {
1315                         if (!retry && dcerpc_binding_handle_is_connected(b)) {
1316                                 invalidate_cm_connection(domain);
1317                                 retry = true;
1318                                 goto reconnect;
1319                         }
1320                         DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1321                                   "failed: %s\n",
1322                                   domain->name, nt_errstr(status)));
1323                         check_result = ntstatus_to_werror(status);
1324                         goto check_return;
1325                 }
1326         }
1327
1328         if (new_fti != NULL) {
1329                 struct lsa_ForestTrustInformation old_fti = {};
1330                 struct lsa_ForestTrustInformation *merged_fti = NULL;
1331                 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1332
1333                 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1334                                                       &old_fti, new_fti,
1335                                                       &merged_fti);
1336                 if (!NT_STATUS_IS_OK(status)) {
1337                         DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1338                                  __location__, __func__,
1339                                  domain->name, nt_errstr(status)));
1340                         TALLOC_FREE(frame);
1341                         return ntstatus_to_werror(status);
1342                 }
1343
1344                 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1345                                                 &local_lsa_policy,
1346                                                 &trusted_domain_name_l,
1347                                                 LSA_FOREST_TRUST_DOMAIN_INFO,
1348                                                 merged_fti,
1349                                                 0, /* check_only=0 => store it! */
1350                                                 &collision_info,
1351                                                 &result);
1352                 if (!NT_STATUS_IS_OK(status)) {
1353                         DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1354                                  __location__, __func__, domain->name, nt_errstr(status)));
1355                         TALLOC_FREE(frame);
1356                         return WERR_INTERNAL_ERROR;
1357                 }
1358                 if (!NT_STATUS_IS_OK(result)) {
1359                         DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1360                                  __location__, __func__, domain->name, nt_errstr(result)));
1361                         TALLOC_FREE(frame);
1362                         return ntstatus_to_werror(result);
1363                 }
1364         }
1365
1366         status = netlogon_creds_cli_ServerGetTrustInfo(netlogon_creds_ctx,
1367                                                        b, frame,
1368                                                        &new_owf_password,
1369                                                        &old_owf_password,
1370                                                        &trust_info);
1371         if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1372                 status = NT_STATUS_NOT_SUPPORTED;
1373         }
1374         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1375                 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1376                         nt_errstr(status)));
1377                 verify_result = WERR_OK;
1378                 goto verify_return;
1379         }
1380         if (!NT_STATUS_IS_OK(status)) {
1381                 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1382                         invalidate_cm_connection(domain);
1383                         retry = true;
1384                         goto reconnect;
1385                 }
1386                 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1387                         nt_errstr(status)));
1388
1389                 if (!dcerpc_binding_handle_is_connected(b)) {
1390                         check_result = ntstatus_to_werror(status);
1391                         goto check_return;
1392                 } else {
1393                         verify_result = ntstatus_to_werror(status);
1394                         goto verify_return;
1395                 }
1396         }
1397
1398         if (trust_info != NULL && trust_info->count >= 1) {
1399                 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1400
1401                 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1402                         verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1403                         goto verify_return;
1404                 }
1405         }
1406
1407         cmp_new = memcmp(new_owf_password.hash,
1408                          cur_nt_hash->hash,
1409                          sizeof(cur_nt_hash->hash));
1410         cmp_old = memcmp(old_owf_password.hash,
1411                          cur_nt_hash->hash,
1412                          sizeof(cur_nt_hash->hash));
1413         if (cmp_new != 0 && cmp_old != 0) {
1414                 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1415                          "any password known to dcname[%s]\n",
1416                          __func__, domain->name, domain->alt_name,
1417                          domain->dcname));
1418                 verify_result = WERR_WRONG_PASSWORD;
1419                 goto verify_return;
1420         }
1421
1422         if (cmp_new != 0) {
1423                 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1424                          "against the old password known to dcname[%s]\n",
1425                          __func__, domain->name, domain->alt_name,
1426                          domain->dcname));
1427         }
1428
1429         verify_result = WERR_OK;
1430         goto verify_return;
1431
1432 check_return:
1433         verify_result = check_result;
1434 verify_return:
1435         info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1436         info2->pdc_connection_status = verify_result;
1437         if (domain->dcname != NULL) {
1438                 info2->flags |= NETLOGON_HAS_IP;
1439                 info2->flags |= NETLOGON_HAS_TIMESERV;
1440                 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1441                                                          domain->dcname);
1442                 if (info2->trusted_dc_name == NULL) {
1443                         TALLOC_FREE(frame);
1444                         return WERR_NOT_ENOUGH_MEMORY;
1445                 }
1446         } else {
1447                 info2->trusted_dc_name = talloc_strdup(info2, "");
1448                 if (info2->trusted_dc_name == NULL) {
1449                         TALLOC_FREE(frame);
1450                         return WERR_NOT_ENOUGH_MEMORY;
1451                 }
1452         }
1453         info2->tc_connection_status = check_result;
1454
1455         if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1456                 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1457                           "pdc_connection[%s] tc_connection[%s]\n",
1458                           __func__, domain->name, domain->alt_name,
1459                           domain->dcname,
1460                           win_errstr(info2->pdc_connection_status),
1461                           win_errstr(info2->tc_connection_status)));
1462         }
1463
1464         r->out.query->info2 = info2;
1465
1466         DEBUG(5, ("%s: succeeded.\n", __func__));
1467         TALLOC_FREE(frame);
1468         return WERR_OK;
1469 }
1470
1471 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1472                              struct winbindd_domain *domain,
1473                              struct winbind_LogonControl *r)
1474 {
1475         struct messaging_context *msg_ctx = server_messaging_context();
1476         NTSTATUS status;
1477         struct rpc_pipe_client *netlogon_pipe = NULL;
1478         struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1479         struct cli_credentials *creds = NULL;
1480         struct samr_Password *cur_nt_hash = NULL;
1481         struct netr_NETLOGON_INFO_1 *info1 = NULL;
1482         struct dcerpc_binding_handle *b;
1483         WERROR change_result = WERR_OK;
1484         bool retry = false;
1485
1486         info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1487         if (info1 == NULL) {
1488                 return WERR_NOT_ENOUGH_MEMORY;
1489         }
1490
1491         if (domain->internal) {
1492                 return WERR_NOT_SUPPORTED;
1493         }
1494
1495         status = pdb_get_trust_credentials(domain->name,
1496                                            domain->alt_name,
1497                                            p->mem_ctx,
1498                                            &creds);
1499         if (NT_STATUS_IS_OK(status)) {
1500                 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1501                 TALLOC_FREE(creds);
1502         }
1503
1504 reconnect:
1505         status = cm_connect_netlogon_secure(domain,
1506                                             &netlogon_pipe,
1507                                             &netlogon_creds_ctx);
1508         reset_cm_connection_on_error(domain, status);
1509         if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1510                 status = NT_STATUS_NO_LOGON_SERVERS;
1511         }
1512         if (!NT_STATUS_IS_OK(status)) {
1513                 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1514                           __func__, domain->name, domain->alt_name,
1515                           nt_errstr(status)));
1516                 /*
1517                  * Here we return a top level error!
1518                  * This is different than TC_QUERY or TC_VERIFY.
1519                  */
1520                 return ntstatus_to_werror(status);
1521         }
1522         b = netlogon_pipe->binding_handle;
1523
1524         if (cur_nt_hash == NULL) {
1525                 change_result = WERR_NO_TRUST_LSA_SECRET;
1526                 goto change_return;
1527         }
1528         TALLOC_FREE(cur_nt_hash);
1529
1530         status = trust_pw_change(netlogon_creds_ctx,
1531                                  msg_ctx, b, domain->name,
1532                                  domain->dcname,
1533                                  true); /* force */
1534         if (!NT_STATUS_IS_OK(status)) {
1535                 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1536                         invalidate_cm_connection(domain);
1537                         retry = true;
1538                         goto reconnect;
1539                 }
1540
1541                 DEBUG(1, ("trust_pw_change(%s): %s\n",
1542                           domain->name, nt_errstr(status)));
1543
1544                 change_result = ntstatus_to_werror(status);
1545                 goto change_return;
1546         }
1547
1548         change_result = WERR_OK;
1549
1550 change_return:
1551         info1->pdc_connection_status = change_result;
1552
1553         if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1554                 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1555                           "pdc_connection[%s]\n",
1556                           __func__, domain->name, domain->alt_name,
1557                           domain->dcname,
1558                           win_errstr(info1->pdc_connection_status)));
1559         }
1560
1561         r->out.query->info1 = info1;
1562
1563         DEBUG(5, ("%s: succeeded.\n", __func__));
1564         return WERR_OK;
1565 }
1566
1567 WERROR _winbind_LogonControl(struct pipes_struct *p,
1568                              struct winbind_LogonControl *r)
1569 {
1570         struct winbindd_domain *domain;
1571
1572         domain = wb_child_domain();
1573         if (domain == NULL) {
1574                 return WERR_NO_SUCH_DOMAIN;
1575         }
1576
1577         switch (r->in.function_code) {
1578         case NETLOGON_CONTROL_REDISCOVER:
1579                 if (r->in.level != 2) {
1580                         return WERR_INVALID_PARAMETER;
1581                 }
1582                 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1583         case NETLOGON_CONTROL_TC_QUERY:
1584                 if (r->in.level != 2) {
1585                         return WERR_INVALID_PARAMETER;
1586                 }
1587                 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1588         case NETLOGON_CONTROL_TC_VERIFY:
1589                 if (r->in.level != 2) {
1590                         return WERR_INVALID_PARAMETER;
1591                 }
1592                 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1593         case NETLOGON_CONTROL_CHANGE_PASSWORD:
1594                 if (r->in.level != 1) {
1595                         return WERR_INVALID_PARAMETER;
1596                 }
1597                 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1598         default:
1599                 break;
1600         }
1601
1602         DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1603                   __func__, r->in.function_code));
1604         return WERR_NOT_SUPPORTED;
1605 }
1606
1607 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1608                              struct winbind_GetForestTrustInformation *r)
1609 {
1610         TALLOC_CTX *frame = talloc_stackframe();
1611         NTSTATUS status, result;
1612         struct winbindd_domain *domain;
1613         struct rpc_pipe_client *netlogon_pipe = NULL;
1614         struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1615         struct dcerpc_binding_handle *b;
1616         bool retry = false;
1617         struct lsa_String trusted_domain_name = {};
1618         struct lsa_StringLarge trusted_domain_name_l = {};
1619         union lsa_TrustedDomainInfo *tdi = NULL;
1620         const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1621         struct lsa_ForestTrustInformation _old_fti = {};
1622         struct lsa_ForestTrustInformation *old_fti = NULL;
1623         struct lsa_ForestTrustInformation *new_fti = NULL;
1624         struct lsa_ForestTrustInformation *merged_fti = NULL;
1625         struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1626         bool update_fti = false;
1627         struct rpc_pipe_client *local_lsa_pipe;
1628         struct policy_handle local_lsa_policy;
1629         struct dcerpc_binding_handle *local_lsa = NULL;
1630
1631         domain = wb_child_domain();
1632         if (domain == NULL) {
1633                 TALLOC_FREE(frame);
1634                 return WERR_NO_SUCH_DOMAIN;
1635         }
1636
1637         /*
1638          * checking for domain->internal and domain->primary
1639          * makes sure we only do some work when running as DC.
1640          */
1641
1642         if (domain->internal) {
1643                 TALLOC_FREE(frame);
1644                 return WERR_NO_SUCH_DOMAIN;
1645         }
1646
1647         if (domain->primary) {
1648                 TALLOC_FREE(frame);
1649                 return WERR_NO_SUCH_DOMAIN;
1650         }
1651
1652         trusted_domain_name.string = domain->name;
1653         trusted_domain_name_l.string = domain->name;
1654
1655         status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1656                                         &local_lsa_policy);
1657         if (!NT_STATUS_IS_OK(status)) {
1658                 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1659                          __location__, __func__, nt_errstr(status)));
1660                 TALLOC_FREE(frame);
1661                 return WERR_INTERNAL_ERROR;
1662         }
1663         local_lsa = local_lsa_pipe->binding_handle;
1664
1665         status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1666                                                 &local_lsa_policy,
1667                                                 &trusted_domain_name,
1668                                                 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1669                                                 &tdi, &result);
1670         if (!NT_STATUS_IS_OK(status)) {
1671                 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1672                          __location__, __func__, domain->name, nt_errstr(status)));
1673                 TALLOC_FREE(frame);
1674                 return WERR_INTERNAL_ERROR;
1675         }
1676         if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1677                 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1678                          __location__, __func__, domain->name));
1679                 TALLOC_FREE(frame);
1680                 return WERR_NO_SUCH_DOMAIN;
1681         }
1682         if (!NT_STATUS_IS_OK(result)) {
1683                 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1684                          __location__, __func__, domain->name, nt_errstr(result)));
1685                 TALLOC_FREE(frame);
1686                 return WERR_INTERNAL_ERROR;
1687         }
1688         if (tdi == NULL) {
1689                 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1690                          "returned no trusted domain information\n",
1691                          __location__, __func__));
1692                 TALLOC_FREE(frame);
1693                 return WERR_INTERNAL_ERROR;
1694         }
1695
1696         tdo = &tdi->info_ex;
1697
1698         if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1699                 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1700                          __func__, tdo->netbios_name.string,
1701                          tdo->domain_name.string,
1702                          (unsigned)tdo->trust_attributes));
1703                 TALLOC_FREE(frame);
1704                 return WERR_NO_SUCH_DOMAIN;
1705         }
1706
1707         if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1708                 TALLOC_FREE(frame);
1709                 return WERR_INVALID_FLAGS;
1710         }
1711
1712 reconnect:
1713         status = cm_connect_netlogon_secure(domain,
1714                                             &netlogon_pipe,
1715                                             &netlogon_creds_ctx);
1716         reset_cm_connection_on_error(domain, status);
1717         if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1718                 status = NT_STATUS_NO_LOGON_SERVERS;
1719         }
1720         if (!NT_STATUS_IS_OK(status)) {
1721                 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1722                           nt_errstr(status)));
1723                 TALLOC_FREE(frame);
1724                 return ntstatus_to_werror(status);
1725         }
1726         b = netlogon_pipe->binding_handle;
1727
1728         status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1729                                                               b, p->mem_ctx,
1730                                                               &new_fti);
1731         if (!NT_STATUS_IS_OK(status)) {
1732                 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1733                         invalidate_cm_connection(domain);
1734                         retry = true;
1735                         goto reconnect;
1736                 }
1737                 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1738                           domain->name, nt_errstr(status)));
1739                 TALLOC_FREE(frame);
1740                 return ntstatus_to_werror(status);
1741         }
1742
1743         *r->out.forest_trust_info = new_fti;
1744
1745         if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1746                 update_fti = true;
1747         }
1748
1749         status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1750                                                 &local_lsa_policy,
1751                                                 &trusted_domain_name,
1752                                                 LSA_FOREST_TRUST_DOMAIN_INFO,
1753                                                 &old_fti, &result);
1754         if (!NT_STATUS_IS_OK(status)) {
1755                 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1756                          __location__, __func__, domain->name, nt_errstr(status)));
1757                 TALLOC_FREE(frame);
1758                 return WERR_INTERNAL_ERROR;
1759         }
1760         if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1761                 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1762                           __func__, domain->name));
1763                 update_fti = true;
1764                 old_fti = &_old_fti;
1765                 result = NT_STATUS_OK;
1766         }
1767         if (!NT_STATUS_IS_OK(result)) {
1768                 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1769                          __location__, __func__, domain->name, nt_errstr(result)));
1770                 TALLOC_FREE(frame);
1771                 return WERR_INTERNAL_ERROR;
1772         }
1773
1774         if (old_fti == NULL) {
1775                 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1776                          "returned success without returning forest trust information\n",
1777                          __location__, __func__));
1778                 TALLOC_FREE(frame);
1779                 return WERR_INTERNAL_ERROR;
1780         }
1781
1782         if (!update_fti) {
1783                 goto done;
1784         }
1785
1786         status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1787                                               &merged_fti);
1788         if (!NT_STATUS_IS_OK(status)) {
1789                 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1790                          __location__, __func__, domain->name, nt_errstr(status)));
1791                 TALLOC_FREE(frame);
1792                 return ntstatus_to_werror(status);
1793         }
1794
1795         status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1796                                                 &local_lsa_policy,
1797                                                 &trusted_domain_name_l,
1798                                                 LSA_FOREST_TRUST_DOMAIN_INFO,
1799                                                 merged_fti,
1800                                                 0, /* check_only=0 => store it! */
1801                                                 &collision_info,
1802                                                 &result);
1803         if (!NT_STATUS_IS_OK(status)) {
1804                 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1805                          __location__, __func__, domain->name, nt_errstr(status)));
1806                 TALLOC_FREE(frame);
1807                 return WERR_INTERNAL_ERROR;
1808         }
1809         if (!NT_STATUS_IS_OK(result)) {
1810                 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1811                          __location__, __func__, domain->name, nt_errstr(result)));
1812                 TALLOC_FREE(frame);
1813                 return ntstatus_to_werror(result);
1814         }
1815
1816 done:
1817         DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
1818         TALLOC_FREE(frame);
1819         return WERR_OK;
1820 }
1821
1822 NTSTATUS _winbind_SendToSam(struct pipes_struct *p, struct winbind_SendToSam *r)
1823 {
1824         struct winbindd_domain *domain;
1825         NTSTATUS status;
1826         struct rpc_pipe_client *netlogon_pipe;
1827         struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1828
1829         DEBUG(5, ("_winbind_SendToSam received\n"));
1830         domain = wb_child_domain();
1831         if (domain == NULL) {
1832                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1833         }
1834
1835         status = cm_connect_netlogon_secure(domain,
1836                                             &netlogon_pipe,
1837                                             &netlogon_creds_ctx);
1838         if (!NT_STATUS_IS_OK(status)) {
1839                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1840                 return status;
1841         }
1842
1843         status = netlogon_creds_cli_SendToSam(netlogon_creds_ctx,
1844                                               netlogon_pipe->binding_handle,
1845                                               &r->in.message);
1846
1847         return status;
1848 }