r23779: Change from v2 or later to v3 or later.
[tprouty/samba.git] / source3 / nsswitch / 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, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "winbindd.h"
26
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_WINBIND
29
30 /* Check the machine account password is valid */
31
32 void winbindd_check_machine_acct(struct winbindd_cli_state *state)
33 {
34         DEBUG(3, ("[%5lu]: check machine account\n",
35                   (unsigned long)state->pid));
36
37         sendto_domain(state, find_our_domain());
38 }
39
40 enum winbindd_result winbindd_dual_check_machine_acct(struct winbindd_domain *domain,
41                                                       struct winbindd_cli_state *state)
42 {
43         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
44         int num_retries = 0;
45         struct winbindd_domain *contact_domain;
46
47         DEBUG(3, ("[%5lu]: check machine account\n", (unsigned long)state->pid));
48
49         /* Get trust account password */
50
51  again:
52
53         contact_domain = find_our_domain();
54         
55         /* This call does a cli_nt_setup_creds() which implicitly checks
56            the trust account password. */
57
58         invalidate_cm_connection(&contact_domain->conn);
59
60         {
61                 struct rpc_pipe_client *netlogon_pipe;
62                 result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
63         }
64
65         if (!NT_STATUS_IS_OK(result)) {
66                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
67                 goto done;
68         }
69
70         /* There is a race condition between fetching the trust account
71            password and the periodic machine password change.  So it's 
72            possible that the trust account password has been changed on us.  
73            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
74
75 #define MAX_RETRIES 8
76
77         if ((num_retries < MAX_RETRIES) && 
78             NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) {
79                 num_retries++;
80                 goto again;
81         }
82
83         /* Pass back result code - zero for success, other values for
84            specific failures. */
85
86         DEBUG(3, ("secret is %s\n", NT_STATUS_IS_OK(result) ?  
87                   "good" : "bad"));
88
89  done:
90         state->response.data.auth.nt_status = NT_STATUS_V(result);
91         fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
92         fstrcpy(state->response.data.auth.error_string, nt_errstr(result));
93         state->response.data.auth.pam_error = nt_status_to_pam(result);
94
95         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Checking the trust account password returned %s\n", 
96                                                 state->response.data.auth.nt_status_string));
97
98         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
99 }
100
101 void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
102 {
103         struct winbindd_domain *d = NULL;
104         int extra_data_len = 0;
105         char *extra_data = NULL;
106         
107         DEBUG(3, ("[%5lu]: list trusted domains\n",
108                   (unsigned long)state->pid));
109
110         for ( d=domain_list(); d; d=d->next ) {
111                 if ( !extra_data ) {
112                         extra_data = talloc_asprintf(state->mem_ctx, "%s\\%s\\%s",
113                                                      d->name,
114                                                      d->alt_name ? d->alt_name : d->name,
115                                                      sid_string_static(&d->sid));
116                 } else {
117                         extra_data = talloc_asprintf(state->mem_ctx, "%s\n%s\\%s\\%s",
118                                                      extra_data,
119                                                      d->name,
120                                                      d->alt_name ? d->alt_name : d->name,
121                                                      sid_string_static(&d->sid));
122                 }
123         }
124         
125         extra_data_len = 0;
126         if (extra_data != NULL) {
127                 extra_data_len = strlen(extra_data);
128         }
129
130         if (extra_data_len > 0) {
131                 state->response.extra_data.data = SMB_STRDUP(extra_data);
132                 state->response.length += extra_data_len+1;
133         }
134
135         TALLOC_FREE( extra_data );      
136
137         request_ok(state);      
138 }
139
140 enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
141                                                         struct winbindd_cli_state *state)
142 {
143         uint32 i, num_domains;
144         char **names, **alt_names;
145         DOM_SID *sids;
146         int extra_data_len = 0;
147         char *extra_data;
148         NTSTATUS result;
149         BOOL have_own_domain = False;
150
151         DEBUG(3, ("[%5lu]: list trusted domains\n",
152                   (unsigned long)state->pid));
153
154         result = domain->methods->trusted_domains(domain, state->mem_ctx,
155                                                   &num_domains, &names,
156                                                   &alt_names, &sids);
157
158         if (!NT_STATUS_IS_OK(result)) {
159                 DEBUG(3, ("winbindd_dual_list_trusted_domains: trusted_domains returned %s\n",
160                         nt_errstr(result) ));
161                 return WINBINDD_ERROR;
162         }
163
164         extra_data = talloc_strdup(state->mem_ctx, "");
165
166         if (num_domains > 0)
167                 extra_data = talloc_asprintf(state->mem_ctx, "%s\\%s\\%s",
168                                              names[0],
169                                              alt_names[0] ? alt_names[0] : names[0],
170                                              sid_string_static(&sids[0]));
171
172         for (i=1; i<num_domains; i++)
173                 extra_data = talloc_asprintf(state->mem_ctx, "%s\n%s\\%s\\%s",
174                                              extra_data,
175                                              names[i],
176                                              alt_names[i] ? alt_names[i] : names[i],
177                                              sid_string_static(&sids[i]));
178         /* add our primary domain */
179         
180         for (i=0; i<num_domains; i++) {
181                 if (strequal(names[i], domain->name)) {
182                         have_own_domain = True;
183                         break;
184                 }
185         }
186
187         if (state->request.data.list_all_domains && !have_own_domain) {
188                 extra_data = talloc_asprintf(state->mem_ctx, "%s\n%s\\%s\\%s",
189                                              extra_data,
190                                              domain->name,
191                                              domain->alt_name ? domain->alt_name : domain->name,
192                                              sid_string_static(&domain->sid));
193         }
194
195         /* This is a bit excessive, but the extra data sooner or later will be
196            talloc'ed */
197
198         extra_data_len = 0;
199         if (extra_data != NULL) {
200                 extra_data_len = strlen(extra_data);
201         }
202
203         if (extra_data_len > 0) {
204                 state->response.extra_data.data = SMB_STRDUP(extra_data);
205                 state->response.length += extra_data_len+1;
206         }
207
208         return WINBINDD_OK;
209 }
210
211 void winbindd_getdcname(struct winbindd_cli_state *state)
212 {
213         state->request.domain_name
214                 [sizeof(state->request.domain_name)-1] = '\0';
215
216         DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
217                   state->request.domain_name));
218
219         sendto_domain(state, find_our_domain());
220 }
221
222 enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
223                                              struct winbindd_cli_state *state)
224 {
225         fstring dcname_slash;
226         char *p;
227         struct rpc_pipe_client *netlogon_pipe;
228         NTSTATUS result;
229         WERROR werr;
230         unsigned int orig_timeout;
231
232         state->request.domain_name
233                 [sizeof(state->request.domain_name)-1] = '\0';
234
235         DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
236                   state->request.domain_name));
237
238         result = cm_connect_netlogon(domain, &netlogon_pipe);
239
240         if (!NT_STATUS_IS_OK(result)) {
241                 DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
242                 return WINBINDD_ERROR;
243         }
244
245         /* This call can take a long time - allow the server to time out.
246            35 seconds should do it. */
247
248         orig_timeout = cli_set_timeout(netlogon_pipe->cli, 35000);
249
250         werr = rpccli_netlogon_getanydcname(netlogon_pipe, state->mem_ctx, domain->dcname,
251                                             state->request.domain_name,
252                                             dcname_slash);
253         /* And restore our original timeout. */
254         cli_set_timeout(netlogon_pipe->cli, orig_timeout);
255
256         if (!W_ERROR_IS_OK(werr)) {
257                 DEBUG(5, ("Error requesting DCname: %s\n", 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 struct sequence_state {
274         TALLOC_CTX *mem_ctx;
275         struct winbindd_cli_state *cli_state;
276         struct winbindd_domain *domain;
277         struct winbindd_request *request;
278         struct winbindd_response *response;
279         char *extra_data;
280 };
281
282 static void sequence_recv(void *private_data, BOOL success);
283
284 void winbindd_show_sequence(struct winbindd_cli_state *state)
285 {
286         struct sequence_state *seq;
287
288         /* Ensure null termination */
289         state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
290
291         if (strlen(state->request.domain_name) > 0) {
292                 struct winbindd_domain *domain;
293                 domain = find_domain_from_name_noinit(
294                         state->request.domain_name);
295                 if (domain == NULL) {
296                         request_error(state);
297                         return;
298                 }
299                 sendto_domain(state, domain);
300                 return;
301         }
302
303         /* Ask all domains in sequence, collect the results in sequence_recv */
304
305         seq = TALLOC_P(state->mem_ctx, struct sequence_state);
306         if (seq == NULL) {
307                 DEBUG(0, ("talloc failed\n"));
308                 request_error(state);
309                 return;
310         }
311
312         seq->mem_ctx = state->mem_ctx;
313         seq->cli_state = state;
314         seq->domain = domain_list();
315         if (seq->domain == NULL) {
316                 DEBUG(0, ("domain list empty\n"));
317                 request_error(state);
318                 return;
319         }
320         seq->request = TALLOC_ZERO_P(state->mem_ctx,
321                                      struct winbindd_request);
322         seq->response = TALLOC_ZERO_P(state->mem_ctx,
323                                       struct winbindd_response);
324         seq->extra_data = talloc_strdup(state->mem_ctx, "");
325
326         if ((seq->request == NULL) || (seq->response == NULL) ||
327             (seq->extra_data == NULL)) {
328                 DEBUG(0, ("talloc failed\n"));
329                 request_error(state);
330                 return;
331         }
332
333         seq->request->length = sizeof(*seq->request);
334         seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
335         fstrcpy(seq->request->domain_name, seq->domain->name);
336
337         async_domain_request(state->mem_ctx, seq->domain,
338                              seq->request, seq->response,
339                              sequence_recv, seq);
340 }
341
342 static void sequence_recv(void *private_data, BOOL success)
343 {
344         struct sequence_state *state =
345                 (struct sequence_state *)private_data;
346         uint32 seq = DOM_SEQUENCE_NONE;
347
348         if ((success) && (state->response->result == WINBINDD_OK))
349                 seq = state->response->data.domain_info.sequence_number;
350
351         if (seq == DOM_SEQUENCE_NONE) {
352                 state->extra_data = talloc_asprintf(state->mem_ctx,
353                                                     "%s%s : DISCONNECTED\n",
354                                                     state->extra_data,
355                                                     state->domain->name);
356         } else {
357                 state->extra_data = talloc_asprintf(state->mem_ctx,
358                                                     "%s%s : %d\n",
359                                                     state->extra_data,
360                                                     state->domain->name, seq);
361         }
362
363         state->domain->sequence_number = seq;
364
365         state->domain = state->domain->next;
366
367         if (state->domain == NULL) {
368                 struct winbindd_cli_state *cli_state = state->cli_state;
369                 cli_state->response.length =
370                         sizeof(cli_state->response) +
371                         strlen(state->extra_data) + 1;
372                 cli_state->response.extra_data.data =
373                         SMB_STRDUP(state->extra_data);
374                 request_ok(cli_state);
375                 return;
376         }
377
378         /* Ask the next domain */
379         fstrcpy(state->request->domain_name, state->domain->name);
380         async_domain_request(state->mem_ctx, state->domain,
381                              state->request, state->response,
382                              sequence_recv, state);
383 }
384
385 /* This is the child-only version of --sequence. It only allows for a single
386  * domain (ie "our" one) to be displayed. */
387
388 enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
389                                                  struct winbindd_cli_state *state)
390 {
391         DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
392
393         /* Ensure null termination */
394         state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
395
396         domain->methods->sequence_number(domain, &domain->sequence_number);
397
398         state->response.data.domain_info.sequence_number =
399                 domain->sequence_number;
400
401         return WINBINDD_OK;
402 }
403
404 struct domain_info_state {
405         struct winbindd_domain *domain;
406         struct winbindd_cli_state *cli_state;
407 };
408
409 static void domain_info_init_recv(void *private_data, BOOL success);
410
411 void winbindd_domain_info(struct winbindd_cli_state *state)
412 {
413         struct winbindd_domain *domain;
414
415         DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
416                   state->request.domain_name));
417
418         domain = find_domain_from_name_noinit(state->request.domain_name);
419
420         if (domain == NULL) {
421                 DEBUG(3, ("Did not find domain [%s]\n",
422                           state->request.domain_name));
423                 request_error(state);
424                 return;
425         }
426
427         if (!domain->initialized) {
428                 struct domain_info_state *istate;
429
430                 istate = TALLOC_P(state->mem_ctx, struct domain_info_state);
431                 if (istate == NULL) {
432                         DEBUG(0, ("talloc failed\n"));
433                         request_error(state);
434                         return;
435                 }
436
437                 istate->cli_state = state;
438                 istate->domain = domain;
439
440                 init_child_connection(domain, domain_info_init_recv, istate);
441                                       
442                 return;
443         }
444
445         fstrcpy(state->response.data.domain_info.name,
446                 domain->name);
447         fstrcpy(state->response.data.domain_info.alt_name,
448                 domain->alt_name);
449         fstrcpy(state->response.data.domain_info.sid,
450                 sid_string_static(&domain->sid));
451         
452         state->response.data.domain_info.native_mode =
453                 domain->native_mode;
454         state->response.data.domain_info.active_directory =
455                 domain->active_directory;
456         state->response.data.domain_info.primary =
457                 domain->primary;
458         state->response.data.domain_info.sequence_number =
459                 domain->sequence_number;
460
461         request_ok(state);
462 }
463
464 static void domain_info_init_recv(void *private_data, BOOL success)
465 {
466         struct domain_info_state *istate =
467                 (struct domain_info_state *)private_data;
468         struct winbindd_cli_state *state = istate->cli_state;
469         struct winbindd_domain *domain = istate->domain;
470
471         DEBUG(10, ("Got back from child init: %d\n", success));
472
473         if ((!success) || (!domain->initialized)) {
474                 DEBUG(5, ("Could not init child for domain %s\n",
475                           domain->name));
476                 request_error(state);
477                 return;
478         }
479
480         fstrcpy(state->response.data.domain_info.name,
481                 domain->name);
482         fstrcpy(state->response.data.domain_info.alt_name,
483                 domain->alt_name);
484         fstrcpy(state->response.data.domain_info.sid,
485                 sid_string_static(&domain->sid));
486         
487         state->response.data.domain_info.native_mode =
488                 domain->native_mode;
489         state->response.data.domain_info.active_directory =
490                 domain->active_directory;
491         state->response.data.domain_info.primary =
492                 domain->primary;
493         state->response.data.domain_info.sequence_number =
494                 domain->sequence_number;
495
496         request_ok(state);
497 }
498
499 void winbindd_ping(struct winbindd_cli_state *state)
500 {
501         DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid));
502         request_ok(state);
503 }
504
505 /* List various tidbits of information */
506
507 void winbindd_info(struct winbindd_cli_state *state)
508 {
509
510         DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
511
512         state->response.data.info.winbind_separator = *lp_winbind_separator();
513         fstrcpy(state->response.data.info.samba_version, SAMBA_VERSION_STRING);
514         request_ok(state);
515 }
516
517 /* Tell the client the current interface version */
518
519 void winbindd_interface_version(struct winbindd_cli_state *state)
520 {
521         DEBUG(3, ("[%5lu]: request interface version\n",
522                   (unsigned long)state->pid));
523         
524         state->response.data.interface_version = WINBIND_INTERFACE_VERSION;
525         request_ok(state);
526 }
527
528 /* What domain are we a member of? */
529
530 void winbindd_domain_name(struct winbindd_cli_state *state)
531 {
532         DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
533         
534         fstrcpy(state->response.data.domain_name, lp_workgroup());
535         request_ok(state);
536 }
537
538 /* What's my name again? */
539
540 void winbindd_netbios_name(struct winbindd_cli_state *state)
541 {
542         DEBUG(3, ("[%5lu]: request netbios name\n",
543                   (unsigned long)state->pid));
544         
545         fstrcpy(state->response.data.netbios_name, global_myname());
546         request_ok(state);
547 }
548
549 /* Where can I find the privilaged pipe? */
550
551 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
552 {
553
554         DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
555                   (unsigned long)state->pid));
556         
557         state->response.extra_data.data = SMB_STRDUP(get_winbind_priv_pipe_dir());
558         if (!state->response.extra_data.data) {
559                 DEBUG(0, ("malloc failed\n"));
560                 request_error(state);
561                 return;
562         }
563
564         /* must add one to length to copy the 0 for string termination */
565         state->response.length +=
566                 strlen((char *)state->response.extra_data.data) + 1;
567
568         request_ok(state);
569 }