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