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