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