s3: Add wbinfo --dc-info
[obnox/samba-ctdb.git] / source3 / winbindd / winbindd_misc.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Winbind daemon - miscellaneous other functions
5
6    Copyright (C) Tim Potter      2000
7    Copyright (C) Andrew Bartlett 2002
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.h"
25
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_WINBIND
28
29 /* Check the machine account password is valid */
30
31 void winbindd_check_machine_acct(struct winbindd_cli_state *state)
32 {
33         DEBUG(3, ("[%5lu]: check machine account\n",
34                   (unsigned long)state->pid));
35
36         sendto_domain(state, find_our_domain());
37 }
38
39 enum winbindd_result winbindd_dual_check_machine_acct(struct winbindd_domain *domain,
40                                                       struct winbindd_cli_state *state)
41 {
42         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
43         int num_retries = 0;
44         struct winbindd_domain *contact_domain;
45
46         DEBUG(3, ("[%5lu]: check machine account\n", (unsigned long)state->pid));
47
48         /* Get trust account password */
49
50  again:
51
52         contact_domain = find_our_domain();
53         
54         /* This call does a cli_nt_setup_creds() which implicitly checks
55            the trust account password. */
56
57         invalidate_cm_connection(&contact_domain->conn);
58
59         {
60                 struct rpc_pipe_client *netlogon_pipe;
61                 result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
62         }
63
64         if (!NT_STATUS_IS_OK(result)) {
65                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
66                 goto done;
67         }
68
69         /* There is a race condition between fetching the trust account
70            password and the periodic machine password change.  So it's 
71            possible that the trust account password has been changed on us.  
72            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
73
74 #define MAX_RETRIES 8
75
76         if ((num_retries < MAX_RETRIES) && 
77             NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) {
78                 num_retries++;
79                 goto again;
80         }
81
82         /* Pass back result code - zero for success, other values for
83            specific failures. */
84
85         DEBUG(3, ("secret is %s\n", NT_STATUS_IS_OK(result) ?  
86                   "good" : "bad"));
87
88  done:
89         set_auth_errors(&state->response, result);
90
91         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Checking the trust account password returned %s\n", 
92                                                 state->response.data.auth.nt_status_string));
93
94         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
95 }
96
97 void winbindd_ping_dc(struct winbindd_cli_state *state)
98 {
99         DEBUG(3, ("[%5lu]: ping dc\n", (unsigned long)state->pid));
100
101         sendto_domain(state, find_our_domain());
102 }
103
104 enum winbindd_result winbindd_dual_ping_dc(struct winbindd_domain *domain,
105                                            struct winbindd_cli_state *state)
106 {
107         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
108         struct winbindd_domain *contact_domain;
109         struct rpc_pipe_client *netlogon_pipe;
110         union netr_CONTROL_QUERY_INFORMATION info;
111         WERROR werr;
112         fstring logon_server;
113
114         DEBUG(3, ("[%5lu]: ping dc\n", (unsigned long)state->pid));
115
116         contact_domain = find_our_domain();
117
118         status = cm_connect_netlogon(contact_domain, &netlogon_pipe);
119         if (!NT_STATUS_IS_OK(status)) {
120                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
121                 return WINBINDD_ERROR;
122         }
123
124         fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
125
126         /*
127          * This provokes a WERR_NOT_SUPPORTED error message. This is
128          * documented in the wspp docs. I could not get a successful
129          * call to work, but the main point here is testing that the
130          * netlogon pipe works.
131          */
132         status = rpccli_netr_LogonControl(netlogon_pipe, state->mem_ctx,
133                                           logon_server, NETLOGON_CONTROL_QUERY,
134                                           2, &info, &werr);
135
136         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
137                 DEBUG(2, ("rpccli_netr_LogonControl timed out\n"));
138                 invalidate_cm_connection(&contact_domain->conn);
139                 return WINBINDD_ERROR;
140         }
141
142         if (!NT_STATUS_EQUAL(status, NT_STATUS_CTL_FILE_NOT_SUPPORTED)) {
143                 DEBUG(2, ("rpccli_netr_LogonControl returned %s, expected "
144                           "NT_STATUS_CTL_FILE_NOT_SUPPORTED\n",
145                           nt_errstr(status)));
146                 return WINBINDD_ERROR;
147         }
148
149         DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
150         return WINBINDD_OK;
151 }
152
153 /* Helpers for listing user and group names */
154
155 const char *ent_type_strings[] = {"users", 
156                                   "groups"};
157
158 static const char *get_ent_type_string(enum ent_type type)
159 {
160         return ent_type_strings[type];
161 }
162
163 struct listent_state {
164         TALLOC_CTX *mem_ctx;
165         struct winbindd_cli_state *cli_state;
166         enum ent_type type;
167         int domain_count;
168         char *extra_data;
169         uint32_t extra_data_len;
170 };
171
172 static void listent_recv(void *private_data, bool success, fstring dom_name,
173                          char *extra_data);
174
175 /* List domain users/groups without mapping to unix ids */
176 void winbindd_list_ent(struct winbindd_cli_state *state, enum ent_type type)
177 {
178         struct winbindd_domain *domain;
179         const char *which_domain;
180         struct listent_state *ent_state;
181
182         DEBUG(3, ("[%5lu]: list %s\n", (unsigned long)state->pid, 
183               get_ent_type_string(type)));
184
185         /* Ensure null termination */
186         state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';  
187         which_domain = state->request.domain_name;
188         
189         /* Initialize listent_state */
190         ent_state = TALLOC_P(state->mem_ctx, struct listent_state);
191         if (ent_state == NULL) {
192                 DEBUG(0, ("talloc failed\n"));
193                 request_error(state);
194                 return;
195         }
196
197         ent_state->mem_ctx = state->mem_ctx;
198         ent_state->cli_state = state;
199         ent_state->type = type;
200         ent_state->domain_count = 0;
201         ent_state->extra_data = NULL;
202         ent_state->extra_data_len = 0;
203
204         /* Must count the full list of expected domains before we request data
205          * from any of them.  Otherwise it's possible for a connection to the
206          * first domain to fail, call listent_recv(), and return to the
207          * client without checking any other domains. */
208         for (domain = domain_list(); domain; domain = domain->next) {
209                 /* if we have a domain name restricting the request and this
210                    one in the list doesn't match, then just bypass the remainder
211                    of the loop */
212                 if ( *which_domain && !strequal(which_domain, domain->name) )
213                         continue;
214
215                 ent_state->domain_count++;
216         }
217
218         /* Make sure we're enumerating at least one domain */
219         if (!ent_state->domain_count) {
220                 request_ok(state);
221                 return;
222         }
223
224         /* Enumerate list of trusted domains and request user/group list from
225          * each */
226         for (domain = domain_list(); domain; domain = domain->next) {
227                 if ( *which_domain && !strequal(which_domain, domain->name) )
228                         continue;
229
230                 winbindd_listent_async(state->mem_ctx, domain, 
231                                           listent_recv, ent_state, type);
232         }
233 }
234
235 static void listent_recv(void *private_data, bool success, fstring dom_name,
236                          char *extra_data)
237 {
238         /* extra_data comes to us as a '\0' terminated string of comma
239            separated users or groups */
240         struct listent_state *state = talloc_get_type_abort(
241                 private_data, struct listent_state);
242
243         /* Append users/groups from one domain onto the whole list */
244         if (extra_data) {
245                 DEBUG(5, ("listent_recv: %s returned %s.\n", 
246                       dom_name, get_ent_type_string(state->type)));
247                 if (!state->extra_data)
248                         state->extra_data = talloc_asprintf(state->mem_ctx,
249                                                             "%s", extra_data);
250                 else
251                         state->extra_data = talloc_asprintf_append(
252                                                             state->extra_data,
253                                                             ",%s", extra_data);
254                 /* Add one for the '\0' and each additional ',' */
255                 state->extra_data_len += strlen(extra_data) + 1;
256         }
257         else {
258                 DEBUG(5, ("listent_recv: %s returned no %s.\n", 
259                       dom_name, get_ent_type_string(state->type)));
260         }
261
262         if (--state->domain_count)
263                 /* Still waiting for some child domains to return */
264                 return;
265
266         /* Return list of all users/groups to the client */
267         if (state->extra_data) {
268                 state->cli_state->response.extra_data.data = 
269                         SMB_STRDUP(state->extra_data);
270                 state->cli_state->response.length += state->extra_data_len;
271         }
272
273         request_ok(state->cli_state);
274 }       
275
276 /* Constants and helper functions for determining domain trust types */
277
278 enum trust_type {
279         EXTERNAL = 0,
280         FOREST,
281         IN_FOREST,
282         NONE,
283 };
284
285 const char *trust_type_strings[] = {"External", 
286                                     "Forest", 
287                                     "In Forest",
288                                     "None"};
289
290 static enum trust_type get_trust_type(struct winbindd_tdc_domain *domain)
291 {
292         if (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN)   
293                 return EXTERNAL;
294         else if (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)
295                 return FOREST;
296         else if (((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) == NETR_TRUST_FLAG_IN_FOREST) &&
297             ((domain->trust_flags & NETR_TRUST_FLAG_PRIMARY) == 0x0))
298                 return IN_FOREST;
299         return NONE;    
300 }
301
302 static const char *get_trust_type_string(struct winbindd_tdc_domain *domain)
303 {
304         return trust_type_strings[get_trust_type(domain)];
305 }
306
307 static bool trust_is_inbound(struct winbindd_tdc_domain *domain)
308 {
309         return (domain->trust_flags == 0x0) ||
310             ((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) ==
311             NETR_TRUST_FLAG_IN_FOREST) ||                       
312             ((domain->trust_flags & NETR_TRUST_FLAG_INBOUND) ==
313             NETR_TRUST_FLAG_INBOUND);           
314 }
315
316 static bool trust_is_outbound(struct winbindd_tdc_domain *domain)
317 {
318         return (domain->trust_flags == 0x0) ||
319             ((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) ==
320             NETR_TRUST_FLAG_IN_FOREST) ||                       
321             ((domain->trust_flags & NETR_TRUST_FLAG_OUTBOUND) ==
322             NETR_TRUST_FLAG_OUTBOUND);          
323 }
324
325 static bool trust_is_transitive(struct winbindd_tdc_domain *domain)
326 {
327         if ((domain->trust_attribs == NETR_TRUST_ATTRIBUTE_NON_TRANSITIVE) ||         
328             (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) ||
329             (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL))
330                 return False;
331         return True;
332 }
333
334 void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
335 {
336         struct winbindd_tdc_domain *dom_list = NULL;
337         struct winbindd_tdc_domain *d = NULL;
338         size_t num_domains = 0;
339         int extra_data_len = 0;
340         char *extra_data = NULL;
341         int i = 0;
342         
343         DEBUG(3, ("[%5lu]: list trusted domains\n",
344                   (unsigned long)state->pid));
345
346         if( !wcache_tdc_fetch_list( &dom_list, &num_domains )) {
347                 request_error(state);   
348                 goto done;
349         }
350
351         for ( i = 0; i < num_domains; i++ ) {
352                 struct winbindd_domain *domain;
353                 bool is_online = true;          
354
355                 d = &dom_list[i];
356                 domain = find_domain_from_name_noinit(d->domain_name);
357                 if (domain) {
358                         is_online = domain->online;
359                 }
360
361                 if ( !extra_data ) {
362                         extra_data = talloc_asprintf(state->mem_ctx, 
363                                                      "%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s",
364                                                      d->domain_name,
365                                                      d->dns_name ? d->dns_name : d->domain_name,
366                                                      sid_string_talloc(state->mem_ctx, &d->sid),
367                                                      get_trust_type_string(d),
368                                                      trust_is_transitive(d) ? "Yes" : "No",
369                                                      trust_is_inbound(d) ? "Yes" : "No",
370                                                      trust_is_outbound(d) ? "Yes" : "No",
371                                                      is_online ? "Online" : "Offline" );
372                 } else {
373                         extra_data = talloc_asprintf(state->mem_ctx, 
374                                                      "%s\n%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s",
375                                                      extra_data,
376                                                      d->domain_name,
377                                                      d->dns_name ? d->dns_name : d->domain_name,
378                                                      sid_string_talloc(state->mem_ctx, &d->sid),
379                                                      get_trust_type_string(d),
380                                                      trust_is_transitive(d) ? "Yes" : "No",
381                                                      trust_is_inbound(d) ? "Yes" : "No",
382                                                      trust_is_outbound(d) ? "Yes" : "No",
383                                                      is_online ? "Online" : "Offline" );
384                 }
385         }
386         
387         extra_data_len = 0;
388         if (extra_data != NULL) {
389                 extra_data_len = strlen(extra_data);
390         }
391
392         if (extra_data_len > 0) {
393                 state->response.extra_data.data = SMB_STRDUP(extra_data);
394                 state->response.length += extra_data_len+1;
395         }
396
397         request_ok(state);      
398 done:
399         TALLOC_FREE( dom_list );
400         TALLOC_FREE( extra_data );      
401 }
402
403 enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
404                                                         struct winbindd_cli_state *state)
405 {
406         uint32 i, num_domains;
407         char **names, **alt_names;
408         DOM_SID *sids;
409         int extra_data_len = 0;
410         char *extra_data;
411         NTSTATUS result;
412         bool have_own_domain = False;
413
414         DEBUG(3, ("[%5lu]: list trusted domains\n",
415                   (unsigned long)state->pid));
416
417         result = domain->methods->trusted_domains(domain, state->mem_ctx,
418                                                   &num_domains, &names,
419                                                   &alt_names, &sids);
420
421         if (!NT_STATUS_IS_OK(result)) {
422                 DEBUG(3, ("winbindd_dual_list_trusted_domains: trusted_domains returned %s\n",
423                         nt_errstr(result) ));
424                 return WINBINDD_ERROR;
425         }
426
427         extra_data = talloc_strdup(state->mem_ctx, "");
428
429         if (num_domains > 0)
430                 extra_data = talloc_asprintf(
431                         state->mem_ctx, "%s\\%s\\%s",
432                         names[0], alt_names[0] ? alt_names[0] : names[0],
433                         sid_string_talloc(state->mem_ctx, &sids[0]));
434
435         for (i=1; i<num_domains; i++)
436                 extra_data = talloc_asprintf(
437                         state->mem_ctx, "%s\n%s\\%s\\%s",
438                         extra_data, names[i],
439                         alt_names[i] ? alt_names[i] : names[i],
440                         sid_string_talloc(state->mem_ctx, &sids[i]));
441
442         /* add our primary domain */
443         
444         for (i=0; i<num_domains; i++) {
445                 if (strequal(names[i], domain->name)) {
446                         have_own_domain = True;
447                         break;
448                 }
449         }
450
451         if (state->request.data.list_all_domains && !have_own_domain) {
452                 extra_data = talloc_asprintf(
453                         state->mem_ctx, "%s\n%s\\%s\\%s",
454                         extra_data, domain->name,
455                         domain->alt_name ? domain->alt_name : domain->name,
456                         sid_string_talloc(state->mem_ctx, &domain->sid));
457         }
458
459         /* This is a bit excessive, but the extra data sooner or later will be
460            talloc'ed */
461
462         extra_data_len = 0;
463         if (extra_data != NULL) {
464                 extra_data_len = strlen(extra_data);
465         }
466
467         if (extra_data_len > 0) {
468                 state->response.extra_data.data = SMB_STRDUP(extra_data);
469                 state->response.length += extra_data_len+1;
470         }
471
472         return WINBINDD_OK;
473 }
474
475 void winbindd_getdcname(struct winbindd_cli_state *state)
476 {
477         struct winbindd_domain *domain;
478
479         state->request.domain_name
480                 [sizeof(state->request.domain_name)-1] = '\0';
481
482         DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
483                   state->request.domain_name));
484
485         domain = find_domain_from_name_noinit(state->request.domain_name);
486         if (domain && domain->internal) {
487                 fstrcpy(state->response.data.dc_name, global_myname());
488                 request_ok(state);      
489                 return;
490         }
491
492         sendto_domain(state, find_our_domain());
493 }
494
495 enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
496                                              struct winbindd_cli_state *state)
497 {
498         const char *dcname_slash = NULL;
499         const char *p;
500         struct rpc_pipe_client *netlogon_pipe;
501         NTSTATUS result;
502         WERROR werr;
503         unsigned int orig_timeout;
504         struct winbindd_domain *req_domain;
505
506         state->request.domain_name
507                 [sizeof(state->request.domain_name)-1] = '\0';
508
509         DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
510                   state->request.domain_name));
511
512         result = cm_connect_netlogon(domain, &netlogon_pipe);
513
514         if (!NT_STATUS_IS_OK(result)) {
515                 DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
516                 return WINBINDD_ERROR;
517         }
518
519         /* This call can take a long time - allow the server to time out.
520            35 seconds should do it. */
521
522         orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
523
524         req_domain = find_domain_from_name_noinit(state->request.domain_name);
525         if (req_domain == domain) {
526                 result = rpccli_netr_GetDcName(netlogon_pipe,
527                                                state->mem_ctx,
528                                                domain->dcname,
529                                                state->request.domain_name,
530                                                &dcname_slash,
531                                                &werr);
532         } else {
533                 result = rpccli_netr_GetAnyDCName(netlogon_pipe,
534                                                   state->mem_ctx,
535                                                   domain->dcname,
536                                                   state->request.domain_name,
537                                                   &dcname_slash,
538                                                   &werr);
539         }
540         /* And restore our original timeout. */
541         rpccli_set_timeout(netlogon_pipe, orig_timeout);
542
543         if (!NT_STATUS_IS_OK(result)) {
544                 DEBUG(5,("Error requesting DCname for domain %s: %s\n",
545                         state->request.domain_name, nt_errstr(result)));
546                 return WINBINDD_ERROR;
547         }
548
549         if (!W_ERROR_IS_OK(werr)) {
550                 DEBUG(5, ("Error requesting DCname for domain %s: %s\n",
551                         state->request.domain_name, win_errstr(werr)));
552                 return WINBINDD_ERROR;
553         }
554
555         p = dcname_slash;
556         if (*p == '\\') {
557                 p+=1;
558         }
559         if (*p == '\\') {
560                 p+=1;
561         }
562
563         fstrcpy(state->response.data.dc_name, p);
564         return WINBINDD_OK;
565 }
566
567 struct sequence_state {
568         TALLOC_CTX *mem_ctx;
569         struct winbindd_cli_state *cli_state;
570         struct winbindd_domain *domain;
571         struct winbindd_request *request;
572         struct winbindd_response *response;
573         char *extra_data;
574 };
575
576 static void sequence_recv(void *private_data, bool success);
577
578 void winbindd_show_sequence(struct winbindd_cli_state *state)
579 {
580         struct sequence_state *seq;
581
582         /* Ensure null termination */
583         state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
584
585         if (strlen(state->request.domain_name) > 0) {
586                 struct winbindd_domain *domain;
587                 domain = find_domain_from_name_noinit(
588                         state->request.domain_name);
589                 if (domain == NULL) {
590                         request_error(state);
591                         return;
592                 }
593                 sendto_domain(state, domain);
594                 return;
595         }
596
597         /* Ask all domains in sequence, collect the results in sequence_recv */
598
599         seq = TALLOC_P(state->mem_ctx, struct sequence_state);
600         if (seq == NULL) {
601                 DEBUG(0, ("talloc failed\n"));
602                 request_error(state);
603                 return;
604         }
605
606         seq->mem_ctx = state->mem_ctx;
607         seq->cli_state = state;
608         seq->domain = domain_list();
609         if (seq->domain == NULL) {
610                 DEBUG(0, ("domain list empty\n"));
611                 request_error(state);
612                 return;
613         }
614         seq->request = TALLOC_ZERO_P(state->mem_ctx,
615                                      struct winbindd_request);
616         seq->response = TALLOC_ZERO_P(state->mem_ctx,
617                                       struct winbindd_response);
618         seq->extra_data = talloc_strdup(state->mem_ctx, "");
619
620         if ((seq->request == NULL) || (seq->response == NULL) ||
621             (seq->extra_data == NULL)) {
622                 DEBUG(0, ("talloc failed\n"));
623                 request_error(state);
624                 return;
625         }
626
627         seq->request->length = sizeof(*seq->request);
628         seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
629         fstrcpy(seq->request->domain_name, seq->domain->name);
630
631         async_domain_request(state->mem_ctx, seq->domain,
632                              seq->request, seq->response,
633                              sequence_recv, seq);
634 }
635
636 static void sequence_recv(void *private_data, bool success)
637 {
638         struct sequence_state *state =
639                 (struct sequence_state *)private_data;
640         uint32 seq = DOM_SEQUENCE_NONE;
641
642         if ((success) && (state->response->result == WINBINDD_OK))
643                 seq = state->response->data.sequence_number;
644
645         if (seq == DOM_SEQUENCE_NONE) {
646                 state->extra_data = talloc_asprintf(state->mem_ctx,
647                                                     "%s%s : DISCONNECTED\n",
648                                                     state->extra_data,
649                                                     state->domain->name);
650         } else {
651                 state->extra_data = talloc_asprintf(state->mem_ctx,
652                                                     "%s%s : %d\n",
653                                                     state->extra_data,
654                                                     state->domain->name, seq);
655         }
656
657         state->domain->sequence_number = seq;
658
659         state->domain = state->domain->next;
660
661         if (state->domain == NULL) {
662                 struct winbindd_cli_state *cli_state = state->cli_state;
663                 cli_state->response.length =
664                         sizeof(cli_state->response) +
665                         strlen(state->extra_data) + 1;
666                 cli_state->response.extra_data.data =
667                         SMB_STRDUP(state->extra_data);
668                 request_ok(cli_state);
669                 return;
670         }
671
672         /* Ask the next domain */
673         fstrcpy(state->request->domain_name, state->domain->name);
674         async_domain_request(state->mem_ctx, state->domain,
675                              state->request, state->response,
676                              sequence_recv, state);
677 }
678
679 /* This is the child-only version of --sequence. It only allows for a single
680  * domain (ie "our" one) to be displayed. */
681
682 enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
683                                                  struct winbindd_cli_state *state)
684 {
685         DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
686
687         /* Ensure null termination */
688         state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
689
690         domain->methods->sequence_number(domain, &domain->sequence_number);
691
692         state->response.data.sequence_number =
693                 domain->sequence_number;
694
695         return WINBINDD_OK;
696 }
697
698 struct domain_info_state {
699         struct winbindd_domain *domain;
700         struct winbindd_cli_state *cli_state;
701 };
702
703 static void domain_info_init_recv(void *private_data, bool success);
704
705 void winbindd_domain_info(struct winbindd_cli_state *state)
706 {
707         struct winbindd_domain *domain;
708
709         DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
710                   state->request.domain_name));
711
712         domain = find_domain_from_name_noinit(state->request.domain_name);
713
714         if (domain == NULL) {
715                 DEBUG(3, ("Did not find domain [%s]\n",
716                           state->request.domain_name));
717                 request_error(state);
718                 return;
719         }
720
721         if (!domain->initialized) {
722                 struct domain_info_state *istate;
723
724                 istate = TALLOC_P(state->mem_ctx, struct domain_info_state);
725                 if (istate == NULL) {
726                         DEBUG(0, ("talloc failed\n"));
727                         request_error(state);
728                         return;
729                 }
730
731                 istate->cli_state = state;
732                 istate->domain = domain;
733
734                 init_child_connection(domain, domain_info_init_recv, istate);
735                                       
736                 return;
737         }
738
739         fstrcpy(state->response.data.domain_info.name,
740                 domain->name);
741         fstrcpy(state->response.data.domain_info.alt_name,
742                 domain->alt_name);
743         sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
744         
745         state->response.data.domain_info.native_mode =
746                 domain->native_mode;
747         state->response.data.domain_info.active_directory =
748                 domain->active_directory;
749         state->response.data.domain_info.primary =
750                 domain->primary;
751
752         request_ok(state);
753 }
754
755 static void domain_info_init_recv(void *private_data, bool success)
756 {
757         struct domain_info_state *istate =
758                 (struct domain_info_state *)private_data;
759         struct winbindd_cli_state *state = istate->cli_state;
760         struct winbindd_domain *domain = istate->domain;
761
762         DEBUG(10, ("Got back from child init: %d\n", success));
763
764         if ((!success) || (!domain->initialized)) {
765                 DEBUG(5, ("Could not init child for domain %s\n",
766                           domain->name));
767                 request_error(state);
768                 return;
769         }
770
771         fstrcpy(state->response.data.domain_info.name,
772                 domain->name);
773         fstrcpy(state->response.data.domain_info.alt_name,
774                 domain->alt_name);
775         sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
776         
777         state->response.data.domain_info.native_mode =
778                 domain->native_mode;
779         state->response.data.domain_info.active_directory =
780                 domain->active_directory;
781         state->response.data.domain_info.primary =
782                 domain->primary;
783
784         request_ok(state);
785 }
786
787 void winbindd_ping(struct winbindd_cli_state *state)
788 {
789         DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid));
790         request_ok(state);
791 }
792
793 void winbindd_dc_info(struct winbindd_cli_state *cli)
794 {
795         struct winbindd_domain *domain;
796         char *dc_name, *dc_ip;
797         char *extra;
798         bool ret;
799
800         cli->request.domain_name[sizeof(cli->request.domain_name-1)] = '\0';
801
802         DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)cli->pid,
803                   cli->request.domain_name));
804
805         if (cli->request.domain_name[0] != '\0') {
806                 domain = find_domain_from_name_noinit(
807                         cli->request.domain_name);
808                 DEBUG(10, ("Could not find domain %s\n",
809                            cli->request.domain_name));
810                 if (domain == NULL) {
811                         request_error(cli);
812                         return;
813                 }
814         } else {
815                 domain = find_our_domain();
816         }
817
818         if (!fetch_current_dc_from_gencache(
819                     talloc_tos(), domain->name, &dc_name, &dc_ip)) {
820                 DEBUG(10, ("fetch_current_dc_from_gencache(%s) failed\n",
821                            domain->name));
822                 request_error(cli);
823                 return;
824         }
825
826         ret = (asprintf(&extra, "%s\n%s\n", dc_name, dc_ip) > 0);
827
828         TALLOC_FREE(dc_name);
829         TALLOC_FREE(dc_ip);
830
831         if (!ret) {
832                 request_error(cli);
833                 return;
834         }
835
836         cli->response.data.num_entries = 1;
837         cli->response.extra_data.data = extra;
838
839         /* must add one to length to copy the 0 for string termination */
840         cli->response.length +=
841                 strlen((char *)cli->response.extra_data.data) + 1;
842
843         request_ok(cli);
844 }
845
846 /* List various tidbits of information */
847
848 void winbindd_info(struct winbindd_cli_state *state)
849 {
850
851         DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
852
853         state->response.data.info.winbind_separator = *lp_winbind_separator();
854         fstrcpy(state->response.data.info.samba_version, samba_version_string());
855         request_ok(state);
856 }
857
858 /* Tell the client the current interface version */
859
860 void winbindd_interface_version(struct winbindd_cli_state *state)
861 {
862         DEBUG(3, ("[%5lu]: request interface version\n",
863                   (unsigned long)state->pid));
864         
865         state->response.data.interface_version = WINBIND_INTERFACE_VERSION;
866         request_ok(state);
867 }
868
869 /* What domain are we a member of? */
870
871 void winbindd_domain_name(struct winbindd_cli_state *state)
872 {
873         DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
874         
875         fstrcpy(state->response.data.domain_name, lp_workgroup());
876         request_ok(state);
877 }
878
879 /* What's my name again? */
880
881 void winbindd_netbios_name(struct winbindd_cli_state *state)
882 {
883         DEBUG(3, ("[%5lu]: request netbios name\n",
884                   (unsigned long)state->pid));
885         
886         fstrcpy(state->response.data.netbios_name, global_myname());
887         request_ok(state);
888 }
889
890 /* Where can I find the privilaged pipe? */
891
892 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
893 {
894
895         DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
896                   (unsigned long)state->pid));
897         
898         state->response.extra_data.data = SMB_STRDUP(get_winbind_priv_pipe_dir());
899         if (!state->response.extra_data.data) {
900                 DEBUG(0, ("malloc failed\n"));
901                 request_error(state);
902                 return;
903         }
904
905         /* must add one to length to copy the 0 for string termination */
906         state->response.length +=
907                 strlen((char *)state->response.extra_data.data) + 1;
908
909         request_ok(state);
910 }
911