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