r23784: use the GPLv3 boilerplate as recommended by the FSF and the license text
[tprouty/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 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: %s\n", dos_errstr(werr)));
257                 return WINBINDD_ERROR;
258         }
259
260         p = dcname_slash;
261         if (*p == '\\') {
262                 p+=1;
263         }
264         if (*p == '\\') {
265                 p+=1;
266         }
267
268         fstrcpy(state->response.data.dc_name, p);
269         return WINBINDD_OK;
270 }
271
272 struct sequence_state {
273         TALLOC_CTX *mem_ctx;
274         struct winbindd_cli_state *cli_state;
275         struct winbindd_domain *domain;
276         struct winbindd_request *request;
277         struct winbindd_response *response;
278         char *extra_data;
279 };
280
281 static void sequence_recv(void *private_data, BOOL success);
282
283 void winbindd_show_sequence(struct winbindd_cli_state *state)
284 {
285         struct sequence_state *seq;
286
287         /* Ensure null termination */
288         state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
289
290         if (strlen(state->request.domain_name) > 0) {
291                 struct winbindd_domain *domain;
292                 domain = find_domain_from_name_noinit(
293                         state->request.domain_name);
294                 if (domain == NULL) {
295                         request_error(state);
296                         return;
297                 }
298                 sendto_domain(state, domain);
299                 return;
300         }
301
302         /* Ask all domains in sequence, collect the results in sequence_recv */
303
304         seq = TALLOC_P(state->mem_ctx, struct sequence_state);
305         if (seq == NULL) {
306                 DEBUG(0, ("talloc failed\n"));
307                 request_error(state);
308                 return;
309         }
310
311         seq->mem_ctx = state->mem_ctx;
312         seq->cli_state = state;
313         seq->domain = domain_list();
314         if (seq->domain == NULL) {
315                 DEBUG(0, ("domain list empty\n"));
316                 request_error(state);
317                 return;
318         }
319         seq->request = TALLOC_ZERO_P(state->mem_ctx,
320                                      struct winbindd_request);
321         seq->response = TALLOC_ZERO_P(state->mem_ctx,
322                                       struct winbindd_response);
323         seq->extra_data = talloc_strdup(state->mem_ctx, "");
324
325         if ((seq->request == NULL) || (seq->response == NULL) ||
326             (seq->extra_data == NULL)) {
327                 DEBUG(0, ("talloc failed\n"));
328                 request_error(state);
329                 return;
330         }
331
332         seq->request->length = sizeof(*seq->request);
333         seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
334         fstrcpy(seq->request->domain_name, seq->domain->name);
335
336         async_domain_request(state->mem_ctx, seq->domain,
337                              seq->request, seq->response,
338                              sequence_recv, seq);
339 }
340
341 static void sequence_recv(void *private_data, BOOL success)
342 {
343         struct sequence_state *state =
344                 (struct sequence_state *)private_data;
345         uint32 seq = DOM_SEQUENCE_NONE;
346
347         if ((success) && (state->response->result == WINBINDD_OK))
348                 seq = state->response->data.domain_info.sequence_number;
349
350         if (seq == DOM_SEQUENCE_NONE) {
351                 state->extra_data = talloc_asprintf(state->mem_ctx,
352                                                     "%s%s : DISCONNECTED\n",
353                                                     state->extra_data,
354                                                     state->domain->name);
355         } else {
356                 state->extra_data = talloc_asprintf(state->mem_ctx,
357                                                     "%s%s : %d\n",
358                                                     state->extra_data,
359                                                     state->domain->name, seq);
360         }
361
362         state->domain->sequence_number = seq;
363
364         state->domain = state->domain->next;
365
366         if (state->domain == NULL) {
367                 struct winbindd_cli_state *cli_state = state->cli_state;
368                 cli_state->response.length =
369                         sizeof(cli_state->response) +
370                         strlen(state->extra_data) + 1;
371                 cli_state->response.extra_data.data =
372                         SMB_STRDUP(state->extra_data);
373                 request_ok(cli_state);
374                 return;
375         }
376
377         /* Ask the next domain */
378         fstrcpy(state->request->domain_name, state->domain->name);
379         async_domain_request(state->mem_ctx, state->domain,
380                              state->request, state->response,
381                              sequence_recv, state);
382 }
383
384 /* This is the child-only version of --sequence. It only allows for a single
385  * domain (ie "our" one) to be displayed. */
386
387 enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
388                                                  struct winbindd_cli_state *state)
389 {
390         DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
391
392         /* Ensure null termination */
393         state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
394
395         domain->methods->sequence_number(domain, &domain->sequence_number);
396
397         state->response.data.domain_info.sequence_number =
398                 domain->sequence_number;
399
400         return WINBINDD_OK;
401 }
402
403 struct domain_info_state {
404         struct winbindd_domain *domain;
405         struct winbindd_cli_state *cli_state;
406 };
407
408 static void domain_info_init_recv(void *private_data, BOOL success);
409
410 void winbindd_domain_info(struct winbindd_cli_state *state)
411 {
412         struct winbindd_domain *domain;
413
414         DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
415                   state->request.domain_name));
416
417         domain = find_domain_from_name_noinit(state->request.domain_name);
418
419         if (domain == NULL) {
420                 DEBUG(3, ("Did not find domain [%s]\n",
421                           state->request.domain_name));
422                 request_error(state);
423                 return;
424         }
425
426         if (!domain->initialized) {
427                 struct domain_info_state *istate;
428
429                 istate = TALLOC_P(state->mem_ctx, struct domain_info_state);
430                 if (istate == NULL) {
431                         DEBUG(0, ("talloc failed\n"));
432                         request_error(state);
433                         return;
434                 }
435
436                 istate->cli_state = state;
437                 istate->domain = domain;
438
439                 init_child_connection(domain, domain_info_init_recv, istate);
440                                       
441                 return;
442         }
443
444         fstrcpy(state->response.data.domain_info.name,
445                 domain->name);
446         fstrcpy(state->response.data.domain_info.alt_name,
447                 domain->alt_name);
448         fstrcpy(state->response.data.domain_info.sid,
449                 sid_string_static(&domain->sid));
450         
451         state->response.data.domain_info.native_mode =
452                 domain->native_mode;
453         state->response.data.domain_info.active_directory =
454                 domain->active_directory;
455         state->response.data.domain_info.primary =
456                 domain->primary;
457         state->response.data.domain_info.sequence_number =
458                 domain->sequence_number;
459
460         request_ok(state);
461 }
462
463 static void domain_info_init_recv(void *private_data, BOOL success)
464 {
465         struct domain_info_state *istate =
466                 (struct domain_info_state *)private_data;
467         struct winbindd_cli_state *state = istate->cli_state;
468         struct winbindd_domain *domain = istate->domain;
469
470         DEBUG(10, ("Got back from child init: %d\n", success));
471
472         if ((!success) || (!domain->initialized)) {
473                 DEBUG(5, ("Could not init child for domain %s\n",
474                           domain->name));
475                 request_error(state);
476                 return;
477         }
478
479         fstrcpy(state->response.data.domain_info.name,
480                 domain->name);
481         fstrcpy(state->response.data.domain_info.alt_name,
482                 domain->alt_name);
483         fstrcpy(state->response.data.domain_info.sid,
484                 sid_string_static(&domain->sid));
485         
486         state->response.data.domain_info.native_mode =
487                 domain->native_mode;
488         state->response.data.domain_info.active_directory =
489                 domain->active_directory;
490         state->response.data.domain_info.primary =
491                 domain->primary;
492         state->response.data.domain_info.sequence_number =
493                 domain->sequence_number;
494
495         request_ok(state);
496 }
497
498 void winbindd_ping(struct winbindd_cli_state *state)
499 {
500         DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid));
501         request_ok(state);
502 }
503
504 /* List various tidbits of information */
505
506 void winbindd_info(struct winbindd_cli_state *state)
507 {
508
509         DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
510
511         state->response.data.info.winbind_separator = *lp_winbind_separator();
512         fstrcpy(state->response.data.info.samba_version, SAMBA_VERSION_STRING);
513         request_ok(state);
514 }
515
516 /* Tell the client the current interface version */
517
518 void winbindd_interface_version(struct winbindd_cli_state *state)
519 {
520         DEBUG(3, ("[%5lu]: request interface version\n",
521                   (unsigned long)state->pid));
522         
523         state->response.data.interface_version = WINBIND_INTERFACE_VERSION;
524         request_ok(state);
525 }
526
527 /* What domain are we a member of? */
528
529 void winbindd_domain_name(struct winbindd_cli_state *state)
530 {
531         DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
532         
533         fstrcpy(state->response.data.domain_name, lp_workgroup());
534         request_ok(state);
535 }
536
537 /* What's my name again? */
538
539 void winbindd_netbios_name(struct winbindd_cli_state *state)
540 {
541         DEBUG(3, ("[%5lu]: request netbios name\n",
542                   (unsigned long)state->pid));
543         
544         fstrcpy(state->response.data.netbios_name, global_myname());
545         request_ok(state);
546 }
547
548 /* Where can I find the privilaged pipe? */
549
550 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
551 {
552
553         DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
554                   (unsigned long)state->pid));
555         
556         state->response.extra_data.data = SMB_STRDUP(get_winbind_priv_pipe_dir());
557         if (!state->response.extra_data.data) {
558                 DEBUG(0, ("malloc failed\n"));
559                 request_error(state);
560                 return;
561         }
562
563         /* must add one to length to copy the 0 for string termination */
564         state->response.length +=
565                 strlen((char *)state->response.extra_data.data) + 1;
566
567         request_ok(state);
568 }