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