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