winbind: Retry LogonControl RPC in ping-dc after session expiration
[samba.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 "idmap.h"
31 #include "../libcli/security/security.h"
32 #include "../libcli/auth/netlogon_creds_cli.h"
33
34 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
35 {
36         *r->out.out_data = r->in.in_data;
37 }
38
39 static bool reset_cm_connection_on_error(struct winbindd_domain *domain,
40                                         NTSTATUS status)
41 {
42         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
43                 invalidate_cm_connection(domain);
44                 /* We invalidated the connection. */
45                 return true;
46         }
47         return false;
48 }
49
50 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
51 {
52         struct winbindd_domain *domain = wb_child_domain();
53         char *dom_name;
54         char *name;
55         enum lsa_SidType type;
56         NTSTATUS status;
57
58         if (domain == NULL) {
59                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
60         }
61
62         status = domain->methods->sid_to_name(domain, p->mem_ctx, r->in.sid,
63                                               &dom_name, &name, &type);
64         reset_cm_connection_on_error(domain, status);
65         if (!NT_STATUS_IS_OK(status)) {
66                 return status;
67         }
68
69         *r->out.domain = dom_name;
70         *r->out.name = name;
71         *r->out.type = type;
72         return NT_STATUS_OK;
73 }
74
75 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
76 {
77         struct winbindd_domain *domain = wb_child_domain();
78         struct lsa_RefDomainList *domains = r->out.domains;
79         NTSTATUS status;
80
81         if (domain == NULL) {
82                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
83         }
84
85         /*
86          * This breaks the winbindd_domain->methods abstraction: This
87          * is only called for remote domains, and both winbindd_msrpc
88          * and winbindd_ad call into lsa_lookupsids anyway. Caching is
89          * done at the wbint RPC layer.
90          */
91         status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
92                                  &domains, &r->out.names);
93
94         if (domains != NULL) {
95                 r->out.domains = domains;
96         }
97
98         reset_cm_connection_on_error(domain, status);
99         return status;
100 }
101
102 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
103 {
104         struct winbindd_domain *domain = wb_child_domain();
105         NTSTATUS status;
106
107         if (domain == NULL) {
108                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
109         }
110
111         status = domain->methods->name_to_sid(
112                 domain, p->mem_ctx, r->in.domain, r->in.name, r->in.flags,
113                 r->out.sid, r->out.type);
114         reset_cm_connection_on_error(domain, status);
115         return status;
116 }
117
118 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
119                              struct wbint_Sids2UnixIDs *r)
120 {
121         uint32_t i, j;
122         struct id_map *ids = NULL;
123         struct id_map **id_ptrs = NULL;
124         struct dom_sid *sids = NULL;
125         uint32_t *id_idx = NULL;
126         NTSTATUS status = NT_STATUS_NO_MEMORY;
127
128         for (i=0; i<r->in.domains->count; i++) {
129                 struct lsa_DomainInfo *d = &r->in.domains->domains[i];
130                 struct idmap_domain *dom;
131                 uint32_t num_ids;
132
133                 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
134                 if (dom == NULL) {
135                         DEBUG(10, ("idmap domain %s:%s not found\n",
136                                    d->name.string, sid_string_dbg(d->sid)));
137                         continue;
138                 }
139
140                 num_ids = 0;
141
142                 for (j=0; j<r->in.ids->num_ids; j++) {
143                         if (r->in.ids->ids[j].domain_index == i) {
144                                 num_ids += 1;
145                         }
146                 }
147
148                 ids = talloc_realloc(talloc_tos(), ids,
149                                            struct id_map, num_ids);
150                 if (ids == NULL) {
151                         goto nomem;
152                 }
153                 id_ptrs = talloc_realloc(talloc_tos(), id_ptrs,
154                                                struct id_map *, num_ids+1);
155                 if (id_ptrs == NULL) {
156                         goto nomem;
157                 }
158                 id_idx = talloc_realloc(talloc_tos(), id_idx,
159                                               uint32_t, num_ids);
160                 if (id_idx == NULL) {
161                         goto nomem;
162                 }
163                 sids = talloc_realloc(talloc_tos(), sids,
164                                             struct dom_sid, num_ids);
165                 if (sids == NULL) {
166                         goto nomem;
167                 }
168
169                 num_ids = 0;
170
171                 /*
172                  * Convert the input data into a list of
173                  * id_map structs suitable for handing in
174                  * to the idmap sids_to_unixids method.
175                  */
176                 for (j=0; j<r->in.ids->num_ids; j++) {
177                         struct wbint_TransID *id = &r->in.ids->ids[j];
178
179                         if (id->domain_index != i) {
180                                 continue;
181                         }
182                         id_idx[num_ids] = j;
183                         id_ptrs[num_ids] = &ids[num_ids];
184
185                         ids[num_ids].sid = &sids[num_ids];
186                         sid_compose(ids[num_ids].sid, d->sid, id->rid);
187                         ids[num_ids].xid.type = id->type;
188                         ids[num_ids].status = ID_UNKNOWN;
189                         num_ids += 1;
190                 }
191                 id_ptrs[num_ids] = NULL;
192
193                 status = dom->methods->sids_to_unixids(dom, id_ptrs);
194                 DEBUG(10, ("sids_to_unixids returned %s\n",
195                            nt_errstr(status)));
196
197                 /*
198                  * Extract the results for handing them back to the caller.
199                  */
200                 for (j=0; j<num_ids; j++) {
201                         struct wbint_TransID *id = &r->in.ids->ids[id_idx[j]];
202
203                         if (ids[j].status != ID_MAPPED) {
204                                 id->xid.id = UINT32_MAX;
205                                 id->xid.type = ID_TYPE_NOT_SPECIFIED;
206                                 continue;
207                         }
208
209                         id->xid = ids[j].xid;
210                 }
211         }
212         status = NT_STATUS_OK;
213 nomem:
214         TALLOC_FREE(ids);
215         TALLOC_FREE(id_ptrs);
216         TALLOC_FREE(id_idx);
217         TALLOC_FREE(sids);
218         return status;
219 }
220
221 NTSTATUS _wbint_Uid2Sid(struct pipes_struct *p, struct wbint_Uid2Sid *r)
222 {
223         return idmap_uid_to_sid(r->in.dom_name ? r->in.dom_name : "",
224                                 r->out.sid, r->in.uid);
225 }
226
227 NTSTATUS _wbint_Gid2Sid(struct pipes_struct *p, struct wbint_Gid2Sid *r)
228 {
229         return idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "",
230                                 r->out.sid, r->in.gid);
231 }
232
233 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
234 {
235         struct unixid xid;
236         NTSTATUS status;
237
238         status = idmap_allocate_uid(&xid);
239         if (!NT_STATUS_IS_OK(status)) {
240                 return status;
241         }
242         *r->out.uid = xid.id;
243         return NT_STATUS_OK;
244 }
245
246 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
247 {
248         struct unixid xid;
249         NTSTATUS status;
250
251         status = idmap_allocate_gid(&xid);
252         if (!NT_STATUS_IS_OK(status)) {
253                 return status;
254         }
255         *r->out.gid = xid.id;
256         return NT_STATUS_OK;
257 }
258
259 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
260 {
261         struct winbindd_domain *domain = wb_child_domain();
262         NTSTATUS status;
263
264         if (domain == NULL) {
265                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
266         }
267
268         status = domain->methods->query_user(domain, p->mem_ctx, r->in.sid,
269                                              r->out.info);
270         reset_cm_connection_on_error(domain, status);
271         return status;
272 }
273
274 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
275                                   struct wbint_LookupUserAliases *r)
276 {
277         struct winbindd_domain *domain = wb_child_domain();
278         NTSTATUS status;
279
280         if (domain == NULL) {
281                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
282         }
283
284         status = domain->methods->lookup_useraliases(
285                 domain, p->mem_ctx, r->in.sids->num_sids, r->in.sids->sids,
286                 &r->out.rids->num_rids, &r->out.rids->rids);
287         reset_cm_connection_on_error(domain, status);
288         return status;
289 }
290
291 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
292                                  struct wbint_LookupUserGroups *r)
293 {
294         struct winbindd_domain *domain = wb_child_domain();
295         NTSTATUS status;
296
297         if (domain == NULL) {
298                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
299         }
300
301         status = domain->methods->lookup_usergroups(
302                 domain, p->mem_ctx, r->in.sid,
303                 &r->out.sids->num_sids, &r->out.sids->sids);
304         reset_cm_connection_on_error(domain, status);
305         return status;
306 }
307
308 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
309                                     struct wbint_QuerySequenceNumber *r)
310 {
311         struct winbindd_domain *domain = wb_child_domain();
312         NTSTATUS status;
313
314         if (domain == NULL) {
315                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
316         }
317
318         status = domain->methods->sequence_number(domain, r->out.sequence);
319         reset_cm_connection_on_error(domain, status);
320         return status;
321 }
322
323 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
324                                    struct wbint_LookupGroupMembers *r)
325 {
326         struct winbindd_domain *domain = wb_child_domain();
327         uint32_t i, num_names;
328         struct dom_sid *sid_mem;
329         char **names;
330         uint32_t *name_types;
331         NTSTATUS status;
332
333         if (domain == NULL) {
334                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
335         }
336
337         status = domain->methods->lookup_groupmem(
338                 domain, p->mem_ctx, r->in.sid, r->in.type,
339                 &num_names, &sid_mem, &names, &name_types);
340         reset_cm_connection_on_error(domain, status);
341         if (!NT_STATUS_IS_OK(status)) {
342                 return status;
343         }
344
345         r->out.members->num_principals = num_names;
346         r->out.members->principals = talloc_array(
347                 r->out.members, struct wbint_Principal, num_names);
348         if (r->out.members->principals == NULL) {
349                 return NT_STATUS_NO_MEMORY;
350         }
351
352         for (i=0; i<num_names; i++) {
353                 struct wbint_Principal *m = &r->out.members->principals[i];
354                 sid_copy(&m->sid, &sid_mem[i]);
355                 m->name = talloc_move(r->out.members->principals, &names[i]);
356                 m->type = (enum lsa_SidType)name_types[i];
357         }
358
359         return NT_STATUS_OK;
360 }
361
362 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
363                               struct wbint_QueryUserList *r)
364 {
365         struct winbindd_domain *domain = wb_child_domain();
366         NTSTATUS status;
367
368         if (domain == NULL) {
369                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
370         }
371
372         status = domain->methods->query_user_list(
373                 domain, p->mem_ctx, &r->out.users->num_userinfos,
374                 &r->out.users->userinfos);
375         reset_cm_connection_on_error(domain, status);
376         return status;
377 }
378
379 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
380                                struct wbint_QueryGroupList *r)
381 {
382         struct winbindd_domain *domain = wb_child_domain();
383         uint32_t i, num_groups;
384         struct wb_acct_info *groups;
385         struct wbint_Principal *result;
386         NTSTATUS status;
387
388         if (domain == NULL) {
389                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
390         }
391
392         status = domain->methods->enum_dom_groups(domain, talloc_tos(),
393                                                   &num_groups, &groups);
394         reset_cm_connection_on_error(domain, status);
395         if (!NT_STATUS_IS_OK(status)) {
396                 return status;
397         }
398
399         result = talloc_array(r->out.groups, struct wbint_Principal,
400                               num_groups);
401         if (result == NULL) {
402                 return NT_STATUS_NO_MEMORY;
403         }
404
405         for (i=0; i<num_groups; i++) {
406                 sid_compose(&result[i].sid, &domain->sid, groups[i].rid);
407                 result[i].type = SID_NAME_DOM_GRP;
408                 result[i].name = talloc_strdup(result, groups[i].acct_name);
409                 if (result[i].name == NULL) {
410                         TALLOC_FREE(result);
411                         TALLOC_FREE(groups);
412                         return NT_STATUS_NO_MEMORY;
413                 }
414         }
415
416         r->out.groups->num_principals = num_groups;
417         r->out.groups->principals = result;
418
419         TALLOC_FREE(groups);
420         return NT_STATUS_OK;
421 }
422
423 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
424 {
425         struct winbindd_domain *domain = wb_child_domain();
426         struct rpc_pipe_client *netlogon_pipe;
427         struct netr_DsRGetDCNameInfo *dc_info;
428         NTSTATUS status;
429         WERROR werr;
430         unsigned int orig_timeout;
431         struct dcerpc_binding_handle *b;
432
433         if (domain == NULL) {
434                 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
435                                    r->in.domain_name, r->in.domain_guid,
436                                    r->in.site_name ? r->in.site_name : "",
437                                    r->in.flags,
438                                    r->out.dc_info);
439         }
440
441         status = cm_connect_netlogon(domain, &netlogon_pipe);
442
443         reset_cm_connection_on_error(domain, status);
444         if (!NT_STATUS_IS_OK(status)) {
445                 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
446                 return status;
447         }
448
449         b = netlogon_pipe->binding_handle;
450
451         /* This call can take a long time - allow the server to time out.
452            35 seconds should do it. */
453
454         orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
455
456         if (domain->active_directory) {
457                 status = dcerpc_netr_DsRGetDCName(b,
458                         p->mem_ctx, domain->dcname,
459                         r->in.domain_name, NULL, r->in.domain_guid,
460                         r->in.flags, r->out.dc_info, &werr);
461                 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
462                         goto done;
463                 }
464                 if (reset_cm_connection_on_error(domain, status)) {
465                         /* Re-initialize. */
466                         status = cm_connect_netlogon(domain, &netlogon_pipe);
467
468                         reset_cm_connection_on_error(domain, status);
469                         if (!NT_STATUS_IS_OK(status)) {
470                                 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
471                                 return status;
472                         }
473
474                         b = netlogon_pipe->binding_handle;
475
476                         /* This call can take a long time - allow the server to time out.
477                            35 seconds should do it. */
478
479                         orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
480                 }
481         }
482
483         /*
484          * Fallback to less capable methods
485          */
486
487         dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
488         if (dc_info == NULL) {
489                 status = NT_STATUS_NO_MEMORY;
490                 goto done;
491         }
492
493         if (r->in.flags & DS_PDC_REQUIRED) {
494                 status = dcerpc_netr_GetDcName(b,
495                         p->mem_ctx, domain->dcname,
496                         r->in.domain_name, &dc_info->dc_unc, &werr);
497         } else {
498                 status = dcerpc_netr_GetAnyDCName(b,
499                         p->mem_ctx, domain->dcname,
500                         r->in.domain_name, &dc_info->dc_unc, &werr);
501         }
502
503         reset_cm_connection_on_error(domain, status);
504         if (!NT_STATUS_IS_OK(status)) {
505                 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
506                            nt_errstr(status)));
507                 goto done;
508         }
509         if (!W_ERROR_IS_OK(werr)) {
510                 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
511                            win_errstr(werr)));
512                 status = werror_to_ntstatus(werr);
513                 goto done;
514         }
515
516         *r->out.dc_info = dc_info;
517         status = NT_STATUS_OK;
518
519 done:
520         /* And restore our original timeout. */
521         rpccli_set_timeout(netlogon_pipe, orig_timeout);
522
523         return status;
524 }
525
526 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
527 {
528         struct winbindd_domain *domain = wb_child_domain();
529         char *domain_name;
530         char **names;
531         enum lsa_SidType *types;
532         struct wbint_Principal *result;
533         NTSTATUS status;
534         int i;
535
536         if (domain == NULL) {
537                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
538         }
539
540         status = domain->methods->rids_to_names(
541                 domain, talloc_tos(), r->in.domain_sid, r->in.rids->rids,
542                 r->in.rids->num_rids, &domain_name, &names, &types);
543         reset_cm_connection_on_error(domain, status);
544         if (!NT_STATUS_IS_OK(status)) {
545                 return status;
546         }
547
548         *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
549
550         result = talloc_array(p->mem_ctx, struct wbint_Principal,
551                               r->in.rids->num_rids);
552         if (result == NULL) {
553                 return NT_STATUS_NO_MEMORY;
554         }
555
556         for (i=0; i<r->in.rids->num_rids; i++) {
557                 sid_compose(&result[i].sid, r->in.domain_sid,
558                             r->in.rids->rids[i]);
559                 result[i].type = types[i];
560                 result[i].name = talloc_move(result, &names[i]);
561         }
562         TALLOC_FREE(types);
563         TALLOC_FREE(names);
564
565         r->out.names->num_principals = r->in.rids->num_rids;
566         r->out.names->principals = result;
567         return NT_STATUS_OK;
568 }
569
570 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
571                                     struct wbint_CheckMachineAccount *r)
572 {
573         struct winbindd_domain *domain;
574         int num_retries = 0;
575         NTSTATUS status;
576
577         domain = wb_child_domain();
578         if (domain == NULL) {
579                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
580         }
581
582 again:
583         invalidate_cm_connection(domain);
584         domain->conn.netlogon_force_reauth = true;
585
586         {
587                 struct rpc_pipe_client *netlogon_pipe;
588                 status = cm_connect_netlogon(domain, &netlogon_pipe);
589         }
590
591         /* There is a race condition between fetching the trust account
592            password and the periodic machine password change.  So it's
593            possible that the trust account password has been changed on us.
594            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
595
596 #define MAX_RETRIES 3
597
598         if ((num_retries < MAX_RETRIES)
599             && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
600                 num_retries++;
601                 goto again;
602         }
603
604         if (!NT_STATUS_IS_OK(status)) {
605                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
606                 goto done;
607         }
608
609         /* Pass back result code - zero for success, other values for
610            specific failures. */
611
612         DEBUG(3,("domain %s secret is %s\n", domain->name,
613                 NT_STATUS_IS_OK(status) ? "good" : "bad"));
614
615  done:
616         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
617               ("Checking the trust account password for domain %s returned %s\n",
618                domain->name, nt_errstr(status)));
619
620         return status;
621 }
622
623 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
624                                      struct wbint_ChangeMachineAccount *r)
625 {
626         struct messaging_context *msg_ctx = winbind_messaging_context();
627         struct winbindd_domain *domain;
628         NTSTATUS status;
629         struct rpc_pipe_client *netlogon_pipe;
630
631         domain = wb_child_domain();
632         if (domain == NULL) {
633                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
634         }
635
636         status = cm_connect_netlogon(domain, &netlogon_pipe);
637         if (!NT_STATUS_IS_OK(status)) {
638                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
639                 goto done;
640         }
641
642         status = trust_pw_change(domain->conn.netlogon_creds,
643                                  msg_ctx,
644                                  netlogon_pipe->binding_handle,
645                                  domain->name,
646                                  true); /* force */
647
648         /* Pass back result code - zero for success, other values for
649            specific failures. */
650
651         DEBUG(3,("domain %s secret %s\n", domain->name,
652                 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
653
654  done:
655         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
656               ("Changing the trust account password for domain %s returned %s\n",
657                domain->name, nt_errstr(status)));
658
659         return status;
660 }
661
662 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
663 {
664         NTSTATUS status;
665         struct winbindd_domain *domain;
666         struct rpc_pipe_client *netlogon_pipe;
667         union netr_CONTROL_QUERY_INFORMATION info;
668         WERROR werr;
669         fstring logon_server;
670         struct dcerpc_binding_handle *b;
671         bool retry = false;
672
673         domain = wb_child_domain();
674         if (domain == NULL) {
675                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
676         }
677
678 reconnect:
679         status = cm_connect_netlogon(domain, &netlogon_pipe);
680         reset_cm_connection_on_error(domain, status);
681         if (!NT_STATUS_IS_OK(status)) {
682                 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
683                           nt_errstr(status)));
684                 return status;
685         }
686
687         b = netlogon_pipe->binding_handle;
688
689         fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
690         *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
691         if (*r->out.dcname == NULL) {
692                 DEBUG(2, ("Could not allocate memory\n"));
693                 return NT_STATUS_NO_MEMORY;
694         }
695
696         /*
697          * This provokes a WERR_NOT_SUPPORTED error message. This is
698          * documented in the wspp docs. I could not get a successful
699          * call to work, but the main point here is testing that the
700          * netlogon pipe works.
701          */
702         status = dcerpc_netr_LogonControl(b, p->mem_ctx,
703                                           logon_server, NETLOGON_CONTROL_QUERY,
704                                           2, &info, &werr);
705
706         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR) && !retry) {
707                 DEBUG(10, ("Session might have expired. "
708                            "Reconnect and retry once.\n"));
709                 invalidate_cm_connection(domain);
710                 retry = true;
711                 goto reconnect;
712         }
713
714         reset_cm_connection_on_error(domain, status);
715         if (!NT_STATUS_IS_OK(status)) {
716                 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
717                         nt_errstr(status)));
718                 return status;
719         }
720
721         if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
722                 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
723                           "WERR_NOT_SUPPORTED\n",
724                           win_errstr(werr)));
725                 return werror_to_ntstatus(werr);
726         }
727
728         DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
729         return NT_STATUS_OK;
730 }
731
732 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
733                                                     struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
734 {
735         struct winbindd_domain *domain;
736         NTSTATUS status;
737         struct rpc_pipe_client *netlogon_pipe;
738
739         domain = wb_child_domain();
740         if (domain == NULL) {
741                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
742         }
743
744         status = cm_connect_netlogon(domain, &netlogon_pipe);
745         if (!NT_STATUS_IS_OK(status)) {
746                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
747                 goto done;
748         }
749
750         status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(domain->conn.netlogon_creds,
751                                                                       netlogon_pipe->binding_handle,
752                                                                       r->in.site_name,
753                                                                       r->in.dns_ttl,
754                                                                       r->in.dns_names);
755
756         /* Pass back result code - zero for success, other values for
757            specific failures. */
758
759         DEBUG(3,("DNS records for domain %s %s\n", domain->name,
760                 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
761
762  done:
763         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
764               ("Update of DNS records via RW DC %s returned %s\n",
765                domain->name, nt_errstr(status)));
766
767         return status;
768 }
769
770 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
771                         struct winbind_SamLogon *r)
772 {
773         struct winbindd_domain *domain;
774         NTSTATUS status;
775         DATA_BLOB lm_response, nt_response;
776         domain = wb_child_domain();
777         if (domain == NULL) {
778                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
779         }
780
781         /* TODO: Handle interactive logons here */
782         if (r->in.validation_level != 3 ||
783             r->in.logon.network == NULL ||
784             (r->in.logon_level != NetlogonNetworkInformation
785              && r->in.logon_level != NetlogonNetworkTransitiveInformation)) {
786                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
787         }
788
789
790         lm_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->lm.data, r->in.logon.network->lm.length);
791         nt_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->nt.data, r->in.logon.network->nt.length);
792
793         status = winbind_dual_SamLogon(domain, p->mem_ctx,
794                                        r->in.logon.network->identity_info.parameter_control,
795                                        r->in.logon.network->identity_info.account_name.string,
796                                        r->in.logon.network->identity_info.domain_name.string,
797                                        r->in.logon.network->identity_info.workstation.string,
798                                        r->in.logon.network->challenge,
799                                        lm_response, nt_response, &r->out.validation.sam3);
800         return status;
801 }