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