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