Augmented "wbinfo -m" to list additional information about the type, direction, and...
[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         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 /* Constants and helper functions for determining domain trust types */
101
102 enum trust_type {
103         EXTERNAL = 0,
104         FOREST,
105         IN_FOREST,
106         NONE,
107 };
108
109 const char *trust_type_strings[] = {"External", 
110                                     "Forest", 
111                                     "In Forest",
112                                     "None"};
113
114 static enum trust_type get_trust_type(struct winbindd_tdc_domain *domain)
115 {
116         if (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN)   
117                 return EXTERNAL;
118         else if (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)
119                 return FOREST;
120         else if (((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) == NETR_TRUST_FLAG_IN_FOREST) &&
121             ((domain->trust_flags & NETR_TRUST_FLAG_PRIMARY) == 0x0))
122                 return IN_FOREST;
123         return NONE;    
124 }
125
126 static const char *get_trust_type_string(struct winbindd_tdc_domain *domain)
127 {
128         return trust_type_strings[get_trust_type(domain)];
129 }
130
131 static bool trust_is_inbound(struct winbindd_tdc_domain *domain)
132 {
133         return (domain->trust_flags == 0x0) ||
134             ((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) ==
135             NETR_TRUST_FLAG_IN_FOREST) ||                       
136             ((domain->trust_flags & NETR_TRUST_FLAG_INBOUND) ==
137             NETR_TRUST_FLAG_INBOUND);           
138 }
139
140 static bool trust_is_outbound(struct winbindd_tdc_domain *domain)
141 {
142         return (domain->trust_flags == 0x0) ||
143             ((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) ==
144             NETR_TRUST_FLAG_IN_FOREST) ||                       
145             ((domain->trust_flags & NETR_TRUST_FLAG_OUTBOUND) ==
146             NETR_TRUST_FLAG_OUTBOUND);          
147 }
148
149 static bool trust_is_transitive(struct winbindd_tdc_domain *domain)
150 {
151         if ((domain->trust_attribs == NETR_TRUST_ATTRIBUTE_NON_TRANSITIVE) ||         
152             (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) ||
153             (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL))
154                 return False;
155         return True;
156 }
157
158 void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
159 {
160         struct winbindd_tdc_domain *dom_list = NULL;
161         struct winbindd_tdc_domain *d = NULL;
162         size_t num_domains = 0;
163         int extra_data_len = 0;
164         char *extra_data = NULL;
165         int i = 0;
166         
167         DEBUG(3, ("[%5lu]: list trusted domains\n",
168                   (unsigned long)state->pid));
169
170         if( !wcache_tdc_fetch_list( &dom_list, &num_domains )) {
171                 request_error(state);   
172                 goto done;
173         }
174
175         for ( i = 0; i < num_domains; i++ ) {
176                 d = &dom_list[i];
177                 if ( !extra_data ) {
178                         extra_data = talloc_asprintf(state->mem_ctx, 
179                                                      "%s\\%s\\%s\\%s\\%s\\%s\\%s",
180                                                      d->domain_name,
181                                                      d->dns_name ? d->dns_name : d->domain_name,
182                                                      sid_string_talloc(state->mem_ctx, &d->sid),
183                                                      get_trust_type_string(d),
184                                                      trust_is_transitive(d) ? "Yes" : "No",
185                                                      trust_is_inbound(d) ? "Yes" : "No",
186                                                      trust_is_outbound(d) ? "Yes" : "No");
187                 } else {
188                         extra_data = talloc_asprintf(state->mem_ctx, 
189                                                      "%s\n%s\\%s\\%s\\%s\\%s\\%s\\%s",
190                                                      extra_data,
191                                                      d->domain_name,
192                                                      d->dns_name ? d->dns_name : d->domain_name,
193                                                      sid_string_talloc(state->mem_ctx, &d->sid),
194                                                      get_trust_type_string(d),
195                                                      trust_is_transitive(d) ? "Yes" : "No",
196                                                      trust_is_inbound(d) ? "Yes" : "No",
197                                                      trust_is_outbound(d) ? "Yes" : "No");
198                 }
199         }
200         
201         extra_data_len = 0;
202         if (extra_data != NULL) {
203                 extra_data_len = strlen(extra_data);
204         }
205
206         if (extra_data_len > 0) {
207                 state->response.extra_data.data = SMB_STRDUP(extra_data);
208                 state->response.length += extra_data_len+1;
209         }
210
211         request_ok(state);      
212 done:
213         TALLOC_FREE( dom_list );
214         TALLOC_FREE( extra_data );      
215 }
216
217 enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
218                                                         struct winbindd_cli_state *state)
219 {
220         uint32 i, num_domains;
221         char **names, **alt_names;
222         DOM_SID *sids;
223         int extra_data_len = 0;
224         char *extra_data;
225         NTSTATUS result;
226         bool have_own_domain = False;
227
228         DEBUG(3, ("[%5lu]: list trusted domains\n",
229                   (unsigned long)state->pid));
230
231         result = domain->methods->trusted_domains(domain, state->mem_ctx,
232                                                   &num_domains, &names,
233                                                   &alt_names, &sids);
234
235         if (!NT_STATUS_IS_OK(result)) {
236                 DEBUG(3, ("winbindd_dual_list_trusted_domains: trusted_domains returned %s\n",
237                         nt_errstr(result) ));
238                 return WINBINDD_ERROR;
239         }
240
241         extra_data = talloc_strdup(state->mem_ctx, "");
242
243         if (num_domains > 0)
244                 extra_data = talloc_asprintf(
245                         state->mem_ctx, "%s\\%s\\%s",
246                         names[0], alt_names[0] ? alt_names[0] : names[0],
247                         sid_string_talloc(state->mem_ctx, &sids[0]));
248
249         for (i=1; i<num_domains; i++)
250                 extra_data = talloc_asprintf(
251                         state->mem_ctx, "%s\n%s\\%s\\%s",
252                         extra_data, names[i],
253                         alt_names[i] ? alt_names[i] : names[i],
254                         sid_string_talloc(state->mem_ctx, &sids[i]));
255
256         /* add our primary domain */
257         
258         for (i=0; i<num_domains; i++) {
259                 if (strequal(names[i], domain->name)) {
260                         have_own_domain = True;
261                         break;
262                 }
263         }
264
265         if (state->request.data.list_all_domains && !have_own_domain) {
266                 extra_data = talloc_asprintf(
267                         state->mem_ctx, "%s\n%s\\%s\\%s",
268                         extra_data, domain->name,
269                         domain->alt_name ? domain->alt_name : domain->name,
270                         sid_string_talloc(state->mem_ctx, &domain->sid));
271         }
272
273         /* This is a bit excessive, but the extra data sooner or later will be
274            talloc'ed */
275
276         extra_data_len = 0;
277         if (extra_data != NULL) {
278                 extra_data_len = strlen(extra_data);
279         }
280
281         if (extra_data_len > 0) {
282                 state->response.extra_data.data = SMB_STRDUP(extra_data);
283                 state->response.length += extra_data_len+1;
284         }
285
286         return WINBINDD_OK;
287 }
288
289 void winbindd_getdcname(struct winbindd_cli_state *state)
290 {
291         struct winbindd_domain *domain;
292
293         state->request.domain_name
294                 [sizeof(state->request.domain_name)-1] = '\0';
295
296         DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
297                   state->request.domain_name));
298
299         domain = find_domain_from_name_noinit(state->request.domain_name);
300         if (domain && domain->internal) {
301                 fstrcpy(state->response.data.dc_name, global_myname());
302                 request_ok(state);      
303                 return;
304         }
305
306         sendto_domain(state, find_our_domain());
307 }
308
309 enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
310                                              struct winbindd_cli_state *state)
311 {
312         const char *dcname_slash = NULL;
313         const char *p;
314         struct rpc_pipe_client *netlogon_pipe;
315         NTSTATUS result;
316         WERROR werr;
317         unsigned int orig_timeout;
318         struct winbindd_domain *req_domain;
319
320         state->request.domain_name
321                 [sizeof(state->request.domain_name)-1] = '\0';
322
323         DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
324                   state->request.domain_name));
325
326         result = cm_connect_netlogon(domain, &netlogon_pipe);
327
328         if (!NT_STATUS_IS_OK(result)) {
329                 DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
330                 return WINBINDD_ERROR;
331         }
332
333         /* This call can take a long time - allow the server to time out.
334            35 seconds should do it. */
335
336         orig_timeout = cli_set_timeout(netlogon_pipe->cli, 35000);
337
338         req_domain = find_domain_from_name_noinit(state->request.domain_name);
339         if (req_domain == domain) {
340                 result = rpccli_netr_GetDcName(netlogon_pipe,
341                                                state->mem_ctx,
342                                                domain->dcname,
343                                                state->request.domain_name,
344                                                &dcname_slash,
345                                                &werr);
346         } else {
347                 result = rpccli_netr_GetAnyDCName(netlogon_pipe,
348                                                   state->mem_ctx,
349                                                   domain->dcname,
350                                                   state->request.domain_name,
351                                                   &dcname_slash,
352                                                   &werr);
353         }
354         /* And restore our original timeout. */
355         cli_set_timeout(netlogon_pipe->cli, orig_timeout);
356
357         if (!NT_STATUS_IS_OK(result)) {
358                 DEBUG(5,("Error requesting DCname for domain %s: %s\n",
359                         state->request.domain_name, nt_errstr(result)));
360                 return WINBINDD_ERROR;
361         }
362
363         if (!W_ERROR_IS_OK(werr)) {
364                 DEBUG(5, ("Error requesting DCname for domain %s: %s\n",
365                         state->request.domain_name, dos_errstr(werr)));
366                 return WINBINDD_ERROR;
367         }
368
369         p = dcname_slash;
370         if (*p == '\\') {
371                 p+=1;
372         }
373         if (*p == '\\') {
374                 p+=1;
375         }
376
377         fstrcpy(state->response.data.dc_name, p);
378         return WINBINDD_OK;
379 }
380
381 struct sequence_state {
382         TALLOC_CTX *mem_ctx;
383         struct winbindd_cli_state *cli_state;
384         struct winbindd_domain *domain;
385         struct winbindd_request *request;
386         struct winbindd_response *response;
387         char *extra_data;
388 };
389
390 static void sequence_recv(void *private_data, bool success);
391
392 void winbindd_show_sequence(struct winbindd_cli_state *state)
393 {
394         struct sequence_state *seq;
395
396         /* Ensure null termination */
397         state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
398
399         if (strlen(state->request.domain_name) > 0) {
400                 struct winbindd_domain *domain;
401                 domain = find_domain_from_name_noinit(
402                         state->request.domain_name);
403                 if (domain == NULL) {
404                         request_error(state);
405                         return;
406                 }
407                 sendto_domain(state, domain);
408                 return;
409         }
410
411         /* Ask all domains in sequence, collect the results in sequence_recv */
412
413         seq = TALLOC_P(state->mem_ctx, struct sequence_state);
414         if (seq == NULL) {
415                 DEBUG(0, ("talloc failed\n"));
416                 request_error(state);
417                 return;
418         }
419
420         seq->mem_ctx = state->mem_ctx;
421         seq->cli_state = state;
422         seq->domain = domain_list();
423         if (seq->domain == NULL) {
424                 DEBUG(0, ("domain list empty\n"));
425                 request_error(state);
426                 return;
427         }
428         seq->request = TALLOC_ZERO_P(state->mem_ctx,
429                                      struct winbindd_request);
430         seq->response = TALLOC_ZERO_P(state->mem_ctx,
431                                       struct winbindd_response);
432         seq->extra_data = talloc_strdup(state->mem_ctx, "");
433
434         if ((seq->request == NULL) || (seq->response == NULL) ||
435             (seq->extra_data == NULL)) {
436                 DEBUG(0, ("talloc failed\n"));
437                 request_error(state);
438                 return;
439         }
440
441         seq->request->length = sizeof(*seq->request);
442         seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
443         fstrcpy(seq->request->domain_name, seq->domain->name);
444
445         async_domain_request(state->mem_ctx, seq->domain,
446                              seq->request, seq->response,
447                              sequence_recv, seq);
448 }
449
450 static void sequence_recv(void *private_data, bool success)
451 {
452         struct sequence_state *state =
453                 (struct sequence_state *)private_data;
454         uint32 seq = DOM_SEQUENCE_NONE;
455
456         if ((success) && (state->response->result == WINBINDD_OK))
457                 seq = state->response->data.sequence_number;
458
459         if (seq == DOM_SEQUENCE_NONE) {
460                 state->extra_data = talloc_asprintf(state->mem_ctx,
461                                                     "%s%s : DISCONNECTED\n",
462                                                     state->extra_data,
463                                                     state->domain->name);
464         } else {
465                 state->extra_data = talloc_asprintf(state->mem_ctx,
466                                                     "%s%s : %d\n",
467                                                     state->extra_data,
468                                                     state->domain->name, seq);
469         }
470
471         state->domain->sequence_number = seq;
472
473         state->domain = state->domain->next;
474
475         if (state->domain == NULL) {
476                 struct winbindd_cli_state *cli_state = state->cli_state;
477                 cli_state->response.length =
478                         sizeof(cli_state->response) +
479                         strlen(state->extra_data) + 1;
480                 cli_state->response.extra_data.data =
481                         SMB_STRDUP(state->extra_data);
482                 request_ok(cli_state);
483                 return;
484         }
485
486         /* Ask the next domain */
487         fstrcpy(state->request->domain_name, state->domain->name);
488         async_domain_request(state->mem_ctx, state->domain,
489                              state->request, state->response,
490                              sequence_recv, state);
491 }
492
493 /* This is the child-only version of --sequence. It only allows for a single
494  * domain (ie "our" one) to be displayed. */
495
496 enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
497                                                  struct winbindd_cli_state *state)
498 {
499         DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
500
501         /* Ensure null termination */
502         state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
503
504         domain->methods->sequence_number(domain, &domain->sequence_number);
505
506         state->response.data.sequence_number =
507                 domain->sequence_number;
508
509         return WINBINDD_OK;
510 }
511
512 struct domain_info_state {
513         struct winbindd_domain *domain;
514         struct winbindd_cli_state *cli_state;
515 };
516
517 static void domain_info_init_recv(void *private_data, bool success);
518
519 void winbindd_domain_info(struct winbindd_cli_state *state)
520 {
521         struct winbindd_domain *domain;
522
523         DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
524                   state->request.domain_name));
525
526         domain = find_domain_from_name_noinit(state->request.domain_name);
527
528         if (domain == NULL) {
529                 DEBUG(3, ("Did not find domain [%s]\n",
530                           state->request.domain_name));
531                 request_error(state);
532                 return;
533         }
534
535         if (!domain->initialized) {
536                 struct domain_info_state *istate;
537
538                 istate = TALLOC_P(state->mem_ctx, struct domain_info_state);
539                 if (istate == NULL) {
540                         DEBUG(0, ("talloc failed\n"));
541                         request_error(state);
542                         return;
543                 }
544
545                 istate->cli_state = state;
546                 istate->domain = domain;
547
548                 init_child_connection(domain, domain_info_init_recv, istate);
549                                       
550                 return;
551         }
552
553         fstrcpy(state->response.data.domain_info.name,
554                 domain->name);
555         fstrcpy(state->response.data.domain_info.alt_name,
556                 domain->alt_name);
557         sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
558         
559         state->response.data.domain_info.native_mode =
560                 domain->native_mode;
561         state->response.data.domain_info.active_directory =
562                 domain->active_directory;
563         state->response.data.domain_info.primary =
564                 domain->primary;
565
566         request_ok(state);
567 }
568
569 static void domain_info_init_recv(void *private_data, bool success)
570 {
571         struct domain_info_state *istate =
572                 (struct domain_info_state *)private_data;
573         struct winbindd_cli_state *state = istate->cli_state;
574         struct winbindd_domain *domain = istate->domain;
575
576         DEBUG(10, ("Got back from child init: %d\n", success));
577
578         if ((!success) || (!domain->initialized)) {
579                 DEBUG(5, ("Could not init child for domain %s\n",
580                           domain->name));
581                 request_error(state);
582                 return;
583         }
584
585         fstrcpy(state->response.data.domain_info.name,
586                 domain->name);
587         fstrcpy(state->response.data.domain_info.alt_name,
588                 domain->alt_name);
589         sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
590         
591         state->response.data.domain_info.native_mode =
592                 domain->native_mode;
593         state->response.data.domain_info.active_directory =
594                 domain->active_directory;
595         state->response.data.domain_info.primary =
596                 domain->primary;
597
598         request_ok(state);
599 }
600
601 void winbindd_ping(struct winbindd_cli_state *state)
602 {
603         DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid));
604         request_ok(state);
605 }
606
607 /* List various tidbits of information */
608
609 void winbindd_info(struct winbindd_cli_state *state)
610 {
611
612         DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
613
614         state->response.data.info.winbind_separator = *lp_winbind_separator();
615         fstrcpy(state->response.data.info.samba_version, SAMBA_VERSION_STRING);
616         request_ok(state);
617 }
618
619 /* Tell the client the current interface version */
620
621 void winbindd_interface_version(struct winbindd_cli_state *state)
622 {
623         DEBUG(3, ("[%5lu]: request interface version\n",
624                   (unsigned long)state->pid));
625         
626         state->response.data.interface_version = WINBIND_INTERFACE_VERSION;
627         request_ok(state);
628 }
629
630 /* What domain are we a member of? */
631
632 void winbindd_domain_name(struct winbindd_cli_state *state)
633 {
634         DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
635         
636         fstrcpy(state->response.data.domain_name, lp_workgroup());
637         request_ok(state);
638 }
639
640 /* What's my name again? */
641
642 void winbindd_netbios_name(struct winbindd_cli_state *state)
643 {
644         DEBUG(3, ("[%5lu]: request netbios name\n",
645                   (unsigned long)state->pid));
646         
647         fstrcpy(state->response.data.netbios_name, global_myname());
648         request_ok(state);
649 }
650
651 /* Where can I find the privilaged pipe? */
652
653 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
654 {
655
656         DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
657                   (unsigned long)state->pid));
658         
659         state->response.extra_data.data = SMB_STRDUP(get_winbind_priv_pipe_dir());
660         if (!state->response.extra_data.data) {
661                 DEBUG(0, ("malloc failed\n"));
662                 request_error(state);
663                 return;
664         }
665
666         /* must add one to length to copy the 0 for string termination */
667         state->response.length +=
668                 strlen((char *)state->response.extra_data.data) + 1;
669
670         request_ok(state);
671 }
672