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