c6608316d1c5a8770b13e40d36d90d4f0018bf08
[metze/samba/wip.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 /* Helpers for listing user and group names */
98
99 const char *ent_type_strings[] = {"users", 
100                                   "groups"};
101
102 static const char *get_ent_type_string(enum ent_type type)
103 {
104         return ent_type_strings[type];
105 }
106
107 struct listent_state {
108         TALLOC_CTX *mem_ctx;
109         struct winbindd_cli_state *cli_state;
110         enum ent_type type;
111         int domain_count;
112         char *extra_data;
113         uint32_t extra_data_len;
114 };
115
116 static void listent_recv(void *private_data, bool success, fstring dom_name,
117                          char *extra_data);
118
119 /* List domain users/groups without mapping to unix ids */
120 void winbindd_list_ent(struct winbindd_cli_state *state, enum ent_type type)
121 {
122         struct winbindd_domain *domain;
123         const char *which_domain;
124         struct listent_state *ent_state;
125
126         DEBUG(3, ("[%5lu]: list %s\n", (unsigned long)state->pid, 
127               get_ent_type_string(type)));
128
129         /* Ensure null termination */
130         state->request->domain_name[sizeof(state->request->domain_name)-1]='\0';
131         which_domain = state->request->domain_name;
132         
133         /* Initialize listent_state */
134         ent_state = TALLOC_P(state->mem_ctx, struct listent_state);
135         if (ent_state == NULL) {
136                 DEBUG(0, ("talloc failed\n"));
137                 request_error(state);
138                 return;
139         }
140
141         ent_state->mem_ctx = state->mem_ctx;
142         ent_state->cli_state = state;
143         ent_state->type = type;
144         ent_state->domain_count = 0;
145         ent_state->extra_data = NULL;
146         ent_state->extra_data_len = 0;
147
148         /* Must count the full list of expected domains before we request data
149          * from any of them.  Otherwise it's possible for a connection to the
150          * first domain to fail, call listent_recv(), and return to the
151          * client without checking any other domains. */
152         for (domain = domain_list(); domain; domain = domain->next) {
153                 /* if we have a domain name restricting the request and this
154                    one in the list doesn't match, then just bypass the remainder
155                    of the loop */
156                 if ( *which_domain && !strequal(which_domain, domain->name) )
157                         continue;
158
159                 ent_state->domain_count++;
160         }
161
162         /* Make sure we're enumerating at least one domain */
163         if (!ent_state->domain_count) {
164                 request_ok(state);
165                 return;
166         }
167
168         /* Enumerate list of trusted domains and request user/group list from
169          * each */
170         for (domain = domain_list(); domain; domain = domain->next) {
171                 if ( *which_domain && !strequal(which_domain, domain->name) )
172                         continue;
173
174                 winbindd_listent_async(state->mem_ctx, domain, 
175                                           listent_recv, ent_state, type);
176         }
177 }
178
179 static void listent_recv(void *private_data, bool success, fstring dom_name,
180                          char *extra_data)
181 {
182         /* extra_data comes to us as a '\0' terminated string of comma
183            separated users or groups */
184         struct listent_state *state = talloc_get_type_abort(
185                 private_data, struct listent_state);
186
187         /* Append users/groups from one domain onto the whole list */
188         if (extra_data) {
189                 DEBUG(5, ("listent_recv: %s returned %s.\n", 
190                       dom_name, get_ent_type_string(state->type)));
191                 if (!state->extra_data)
192                         state->extra_data = talloc_asprintf(state->mem_ctx,
193                                                             "%s", extra_data);
194                 else
195                         state->extra_data = talloc_asprintf_append(
196                                                             state->extra_data,
197                                                             ",%s", extra_data);
198                 /* Add one for the '\0' and each additional ',' */
199                 state->extra_data_len += strlen(extra_data) + 1;
200         }
201         else {
202                 DEBUG(5, ("listent_recv: %s returned no %s.\n", 
203                       dom_name, get_ent_type_string(state->type)));
204         }
205
206         if (--state->domain_count)
207                 /* Still waiting for some child domains to return */
208                 return;
209
210         /* Return list of all users/groups to the client */
211         if (state->extra_data) {
212                 state->cli_state->response->extra_data.data = state->extra_data;
213                 state->cli_state->response->length += state->extra_data_len;
214         }
215
216         request_ok(state->cli_state);
217 }       
218
219 /* Constants and helper functions for determining domain trust types */
220
221 enum trust_type {
222         EXTERNAL = 0,
223         FOREST,
224         IN_FOREST,
225         NONE,
226 };
227
228 const char *trust_type_strings[] = {"External", 
229                                     "Forest", 
230                                     "In Forest",
231                                     "None"};
232
233 static enum trust_type get_trust_type(struct winbindd_tdc_domain *domain)
234 {
235         if (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN)   
236                 return EXTERNAL;
237         else if (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)
238                 return FOREST;
239         else if (((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) == NETR_TRUST_FLAG_IN_FOREST) &&
240             ((domain->trust_flags & NETR_TRUST_FLAG_PRIMARY) == 0x0))
241                 return IN_FOREST;
242         return NONE;    
243 }
244
245 static const char *get_trust_type_string(struct winbindd_tdc_domain *domain)
246 {
247         return trust_type_strings[get_trust_type(domain)];
248 }
249
250 static bool trust_is_inbound(struct winbindd_tdc_domain *domain)
251 {
252         return (domain->trust_flags == 0x0) ||
253             ((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) ==
254             NETR_TRUST_FLAG_IN_FOREST) ||                       
255             ((domain->trust_flags & NETR_TRUST_FLAG_INBOUND) ==
256             NETR_TRUST_FLAG_INBOUND);           
257 }
258
259 static bool trust_is_outbound(struct winbindd_tdc_domain *domain)
260 {
261         return (domain->trust_flags == 0x0) ||
262             ((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) ==
263             NETR_TRUST_FLAG_IN_FOREST) ||                       
264             ((domain->trust_flags & NETR_TRUST_FLAG_OUTBOUND) ==
265             NETR_TRUST_FLAG_OUTBOUND);          
266 }
267
268 static bool trust_is_transitive(struct winbindd_tdc_domain *domain)
269 {
270         if ((domain->trust_attribs == NETR_TRUST_ATTRIBUTE_NON_TRANSITIVE) ||         
271             (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) ||
272             (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL))
273                 return False;
274         return True;
275 }
276
277 void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
278 {
279         struct winbindd_tdc_domain *dom_list = NULL;
280         struct winbindd_tdc_domain *d = NULL;
281         size_t num_domains = 0;
282         int extra_data_len = 0;
283         char *extra_data = NULL;
284         int i = 0;
285         
286         DEBUG(3, ("[%5lu]: list trusted domains\n",
287                   (unsigned long)state->pid));
288
289         if( !wcache_tdc_fetch_list( &dom_list, &num_domains )) {
290                 request_error(state);   
291                 goto done;
292         }
293
294         for ( i = 0; i < num_domains; i++ ) {
295                 struct winbindd_domain *domain;
296                 bool is_online = true;          
297
298                 d = &dom_list[i];
299                 domain = find_domain_from_name_noinit(d->domain_name);
300                 if (domain) {
301                         is_online = domain->online;
302                 }
303
304                 if ( !extra_data ) {
305                         extra_data = talloc_asprintf(state->mem_ctx, 
306                                                      "%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s",
307                                                      d->domain_name,
308                                                      d->dns_name ? d->dns_name : d->domain_name,
309                                                      sid_string_talloc(state->mem_ctx, &d->sid),
310                                                      get_trust_type_string(d),
311                                                      trust_is_transitive(d) ? "Yes" : "No",
312                                                      trust_is_inbound(d) ? "Yes" : "No",
313                                                      trust_is_outbound(d) ? "Yes" : "No",
314                                                      is_online ? "Online" : "Offline" );
315                 } else {
316                         extra_data = talloc_asprintf(state->mem_ctx, 
317                                                      "%s\n%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s",
318                                                      extra_data,
319                                                      d->domain_name,
320                                                      d->dns_name ? d->dns_name : d->domain_name,
321                                                      sid_string_talloc(state->mem_ctx, &d->sid),
322                                                      get_trust_type_string(d),
323                                                      trust_is_transitive(d) ? "Yes" : "No",
324                                                      trust_is_inbound(d) ? "Yes" : "No",
325                                                      trust_is_outbound(d) ? "Yes" : "No",
326                                                      is_online ? "Online" : "Offline" );
327                 }
328         }
329         
330         extra_data_len = 0;
331         if (extra_data != NULL) {
332                 extra_data_len = strlen(extra_data);
333         }
334
335         if (extra_data_len > 0) {
336                 state->response->extra_data.data = extra_data;
337                 state->response->length += extra_data_len+1;
338         }
339
340         request_ok(state);      
341 done:
342         TALLOC_FREE( dom_list );
343 }
344
345 enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
346                                                         struct winbindd_cli_state *state)
347 {
348         uint32 i, num_domains;
349         char **names, **alt_names;
350         DOM_SID *sids;
351         int extra_data_len = 0;
352         char *extra_data;
353         NTSTATUS result;
354         bool have_own_domain = False;
355
356         DEBUG(3, ("[%5lu]: list trusted domains\n",
357                   (unsigned long)state->pid));
358
359         result = domain->methods->trusted_domains(domain, state->mem_ctx,
360                                                   &num_domains, &names,
361                                                   &alt_names, &sids);
362
363         if (!NT_STATUS_IS_OK(result)) {
364                 DEBUG(3, ("winbindd_dual_list_trusted_domains: trusted_domains returned %s\n",
365                         nt_errstr(result) ));
366                 return WINBINDD_ERROR;
367         }
368
369         extra_data = talloc_strdup(state->mem_ctx, "");
370
371         if (num_domains > 0)
372                 extra_data = talloc_asprintf(
373                         state->mem_ctx, "%s\\%s\\%s",
374                         names[0], alt_names[0] ? alt_names[0] : names[0],
375                         sid_string_talloc(state->mem_ctx, &sids[0]));
376
377         for (i=1; i<num_domains; i++)
378                 extra_data = talloc_asprintf(
379                         state->mem_ctx, "%s\n%s\\%s\\%s",
380                         extra_data, names[i],
381                         alt_names[i] ? alt_names[i] : names[i],
382                         sid_string_talloc(state->mem_ctx, &sids[i]));
383
384         /* add our primary domain */
385         
386         for (i=0; i<num_domains; i++) {
387                 if (strequal(names[i], domain->name)) {
388                         have_own_domain = True;
389                         break;
390                 }
391         }
392
393         if (state->request->data.list_all_domains && !have_own_domain) {
394                 extra_data = talloc_asprintf(
395                         state->mem_ctx, "%s\n%s\\%s\\%s",
396                         extra_data, domain->name,
397                         domain->alt_name ? domain->alt_name : domain->name,
398                         sid_string_talloc(state->mem_ctx, &domain->sid));
399         }
400
401         /* This is a bit excessive, but the extra data sooner or later will be
402            talloc'ed */
403
404         extra_data_len = 0;
405         if (extra_data != NULL) {
406                 extra_data_len = strlen(extra_data);
407         }
408
409         if (extra_data_len > 0) {
410                 state->response->extra_data.data = extra_data;
411                 state->response->length += extra_data_len+1;
412         }
413
414         return WINBINDD_OK;
415 }
416
417 void winbindd_getdcname(struct winbindd_cli_state *state)
418 {
419         struct winbindd_domain *domain;
420
421         state->request->domain_name
422                 [sizeof(state->request->domain_name)-1] = '\0';
423
424         DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
425                   state->request->domain_name));
426
427         domain = find_domain_from_name_noinit(state->request->domain_name);
428         if (domain && domain->internal) {
429                 fstrcpy(state->response->data.dc_name, global_myname());
430                 request_ok(state);      
431                 return;
432         }
433
434         sendto_domain(state, find_our_domain());
435 }
436
437 enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
438                                              struct winbindd_cli_state *state)
439 {
440         const char *dcname_slash = NULL;
441         const char *p;
442         struct rpc_pipe_client *netlogon_pipe;
443         NTSTATUS result;
444         WERROR werr;
445         unsigned int orig_timeout;
446         struct winbindd_domain *req_domain;
447
448         state->request->domain_name
449                 [sizeof(state->request->domain_name)-1] = '\0';
450
451         DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
452                   state->request->domain_name));
453
454         result = cm_connect_netlogon(domain, &netlogon_pipe);
455
456         if (!NT_STATUS_IS_OK(result)) {
457                 DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
458                 return WINBINDD_ERROR;
459         }
460
461         /* This call can take a long time - allow the server to time out.
462            35 seconds should do it. */
463
464         orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
465
466         req_domain = find_domain_from_name_noinit(state->request->domain_name);
467         if (req_domain == domain) {
468                 result = rpccli_netr_GetDcName(netlogon_pipe,
469                                                state->mem_ctx,
470                                                domain->dcname,
471                                                state->request->domain_name,
472                                                &dcname_slash,
473                                                &werr);
474         } else {
475                 result = rpccli_netr_GetAnyDCName(netlogon_pipe,
476                                                   state->mem_ctx,
477                                                   domain->dcname,
478                                                   state->request->domain_name,
479                                                   &dcname_slash,
480                                                   &werr);
481         }
482         /* And restore our original timeout. */
483         rpccli_set_timeout(netlogon_pipe, orig_timeout);
484
485         if (!NT_STATUS_IS_OK(result)) {
486                 DEBUG(5,("Error requesting DCname for domain %s: %s\n",
487                         state->request->domain_name, nt_errstr(result)));
488                 return WINBINDD_ERROR;
489         }
490
491         if (!W_ERROR_IS_OK(werr)) {
492                 DEBUG(5, ("Error requesting DCname for domain %s: %s\n",
493                         state->request->domain_name, win_errstr(werr)));
494                 return WINBINDD_ERROR;
495         }
496
497         p = dcname_slash;
498         if (*p == '\\') {
499                 p+=1;
500         }
501         if (*p == '\\') {
502                 p+=1;
503         }
504
505         fstrcpy(state->response->data.dc_name, p);
506         return WINBINDD_OK;
507 }
508
509 struct sequence_state {
510         TALLOC_CTX *mem_ctx;
511         struct winbindd_cli_state *cli_state;
512         struct winbindd_domain *domain;
513         struct winbindd_request *request;
514         struct winbindd_response *response;
515         char *extra_data;
516 };
517
518 static void sequence_recv(void *private_data, bool success);
519
520 void winbindd_show_sequence(struct winbindd_cli_state *state)
521 {
522         struct sequence_state *seq;
523
524         /* Ensure null termination */
525         state->request->domain_name[sizeof(state->request->domain_name)-1]='\0';
526
527         if (strlen(state->request->domain_name) > 0) {
528                 struct winbindd_domain *domain;
529                 domain = find_domain_from_name_noinit(
530                         state->request->domain_name);
531                 if (domain == NULL) {
532                         request_error(state);
533                         return;
534                 }
535                 sendto_domain(state, domain);
536                 return;
537         }
538
539         /* Ask all domains in sequence, collect the results in sequence_recv */
540
541         seq = TALLOC_P(state->mem_ctx, struct sequence_state);
542         if (seq == NULL) {
543                 DEBUG(0, ("talloc failed\n"));
544                 request_error(state);
545                 return;
546         }
547
548         seq->mem_ctx = state->mem_ctx;
549         seq->cli_state = state;
550         seq->domain = domain_list();
551         if (seq->domain == NULL) {
552                 DEBUG(0, ("domain list empty\n"));
553                 request_error(state);
554                 return;
555         }
556         seq->request = TALLOC_ZERO_P(state->mem_ctx,
557                                      struct winbindd_request);
558         seq->response = TALLOC_ZERO_P(state->mem_ctx,
559                                       struct winbindd_response);
560         seq->extra_data = talloc_strdup(state->mem_ctx, "");
561
562         if ((seq->request == NULL) || (seq->response == NULL) ||
563             (seq->extra_data == NULL)) {
564                 DEBUG(0, ("talloc failed\n"));
565                 request_error(state);
566                 return;
567         }
568
569         seq->request->length = sizeof(*seq->request);
570         seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
571         fstrcpy(seq->request->domain_name, seq->domain->name);
572
573         async_domain_request(state->mem_ctx, seq->domain,
574                              seq->request, seq->response,
575                              sequence_recv, seq);
576 }
577
578 static void sequence_recv(void *private_data, bool success)
579 {
580         struct sequence_state *state =
581                 (struct sequence_state *)private_data;
582         uint32 seq = DOM_SEQUENCE_NONE;
583
584         if ((success) && (state->response->result == WINBINDD_OK))
585                 seq = state->response->data.sequence_number;
586
587         if (seq == DOM_SEQUENCE_NONE) {
588                 state->extra_data = talloc_asprintf(state->mem_ctx,
589                                                     "%s%s : DISCONNECTED\n",
590                                                     state->extra_data,
591                                                     state->domain->name);
592         } else {
593                 state->extra_data = talloc_asprintf(state->mem_ctx,
594                                                     "%s%s : %d\n",
595                                                     state->extra_data,
596                                                     state->domain->name, seq);
597         }
598
599         state->domain->sequence_number = seq;
600
601         state->domain = state->domain->next;
602
603         if (state->domain == NULL) {
604                 struct winbindd_cli_state *cli_state = state->cli_state;
605                 cli_state->response->length =
606                         sizeof(struct winbindd_response) +
607                         strlen(state->extra_data) + 1;
608                 cli_state->response->extra_data.data = state->extra_data;
609                 request_ok(cli_state);
610                 return;
611         }
612
613         /* Ask the next domain */
614         fstrcpy(state->request->domain_name, state->domain->name);
615         async_domain_request(state->mem_ctx, state->domain,
616                              state->request, state->response,
617                              sequence_recv, state);
618 }
619
620 /* This is the child-only version of --sequence. It only allows for a single
621  * domain (ie "our" one) to be displayed. */
622
623 enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
624                                                  struct winbindd_cli_state *state)
625 {
626         DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
627
628         /* Ensure null termination */
629         state->request->domain_name[sizeof(state->request->domain_name)-1]='\0';
630
631         domain->methods->sequence_number(domain, &domain->sequence_number);
632
633         state->response->data.sequence_number =
634                 domain->sequence_number;
635
636         return WINBINDD_OK;
637 }
638
639 struct domain_info_state {
640         struct winbindd_domain *domain;
641         struct winbindd_cli_state *cli;
642         struct winbindd_request ping_request;
643 };
644
645 static void domain_info_done(struct tevent_req *req);
646
647 void winbindd_domain_info(struct winbindd_cli_state *cli)
648 {
649         struct domain_info_state *state;
650         struct winbindd_domain *domain;
651         struct tevent_req *req;
652
653         DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)cli->pid,
654                   cli->request->domain_name));
655
656         domain = find_domain_from_name_noinit(cli->request->domain_name);
657
658         if (domain == NULL) {
659                 DEBUG(3, ("Did not find domain [%s]\n",
660                           cli->request->domain_name));
661                 request_error(cli);
662                 return;
663         }
664
665         if (domain->initialized) {
666                 fstrcpy(cli->response->data.domain_info.name,
667                         domain->name);
668                 fstrcpy(cli->response->data.domain_info.alt_name,
669                         domain->alt_name);
670                 sid_to_fstring(cli->response->data.domain_info.sid,
671                                &domain->sid);
672                 cli->response->data.domain_info.native_mode =
673                         domain->native_mode;
674                 cli->response->data.domain_info.active_directory =
675                         domain->active_directory;
676                 cli->response->data.domain_info.primary =
677                         domain->primary;
678                 request_ok(cli);
679                 return;
680         }
681
682         state = talloc_zero(cli->mem_ctx, struct domain_info_state);
683         if (state == NULL) {
684                 DEBUG(0, ("talloc failed\n"));
685                 request_error(cli);
686                 return;
687         }
688
689         state->cli = cli;
690         state->domain = domain;
691         state->ping_request.cmd = WINBINDD_PING;
692
693         /*
694          * Send a ping down. This implicitly initializes the domain.
695          */
696
697         req = wb_domain_request_send(state, winbind_event_context(),
698                                      domain, &state->ping_request);
699         if (req == NULL) {
700                 DEBUG(3, ("wb_domain_request_send failed\n"));
701                 request_error(cli);
702         }
703         tevent_req_set_callback(req, domain_info_done, state);
704 }
705
706 static void domain_info_done(struct tevent_req *req)
707 {
708         struct domain_info_state *state = tevent_req_callback_data(
709                 req, struct domain_info_state);
710         struct winbindd_response *response;
711         int ret, err;
712
713         ret = wb_domain_request_recv(req, req, &response, &err);
714         TALLOC_FREE(req);
715         if (ret == -1) {
716                 DEBUG(10, ("wb_domain_request failed: %s\n", strerror(errno)));
717                 request_error(state->cli);
718                 return;
719         }
720         if (!state->domain->initialized) {
721                 DEBUG(5, ("wb_domain_request did not initialize domain %s\n",
722                           state->domain->name));
723                 request_error(state->cli);
724                 return;
725         }
726
727         fstrcpy(state->cli->response->data.domain_info.name,
728                 state->domain->name);
729         fstrcpy(state->cli->response->data.domain_info.alt_name,
730                 state->domain->alt_name);
731         sid_to_fstring(state->cli->response->data.domain_info.sid,
732                        &state->domain->sid);
733
734         state->cli->response->data.domain_info.native_mode =
735                 state->domain->native_mode;
736         state->cli->response->data.domain_info.active_directory =
737                 state->domain->active_directory;
738         state->cli->response->data.domain_info.primary =
739                 state->domain->primary;
740
741         request_ok(state->cli);
742 }
743
744 /* List various tidbits of information */
745
746 void winbindd_info(struct winbindd_cli_state *state)
747 {
748
749         DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
750
751         state->response->data.info.winbind_separator = *lp_winbind_separator();
752         fstrcpy(state->response->data.info.samba_version, samba_version_string());
753         request_ok(state);
754 }
755
756 /* Tell the client the current interface version */
757
758 void winbindd_interface_version(struct winbindd_cli_state *state)
759 {
760         DEBUG(3, ("[%5lu]: request interface version\n",
761                   (unsigned long)state->pid));
762         
763         state->response->data.interface_version = WINBIND_INTERFACE_VERSION;
764         request_ok(state);
765 }
766
767 /* What domain are we a member of? */
768
769 void winbindd_domain_name(struct winbindd_cli_state *state)
770 {
771         DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
772         
773         fstrcpy(state->response->data.domain_name, lp_workgroup());
774         request_ok(state);
775 }
776
777 /* What's my name again? */
778
779 void winbindd_netbios_name(struct winbindd_cli_state *state)
780 {
781         DEBUG(3, ("[%5lu]: request netbios name\n",
782                   (unsigned long)state->pid));
783         
784         fstrcpy(state->response->data.netbios_name, global_myname());
785         request_ok(state);
786 }
787
788 /* Where can I find the privilaged pipe? */
789
790 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
791 {
792         char *priv_dir;
793         DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
794                   (unsigned long)state->pid));
795         
796         priv_dir = get_winbind_priv_pipe_dir();
797         state->response->extra_data.data = talloc_move(state->mem_ctx,
798                                                       &priv_dir);
799
800         /* must add one to length to copy the 0 for string termination */
801         state->response->length +=
802                 strlen((char *)state->response->extra_data.data) + 1;
803
804         request_ok(state);
805 }
806