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