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