r12912: patch from Tony Mountifield <tony@softins.co.uk> for BUG 3327 (fix bad access...
[Samba/gbeck.git] / source3 / nsswitch / winbindd_misc.c
blob1fbf4b33df2dc83096f97b281e1090ef0f78440a
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind daemon - miscellaneous other functions
6 Copyright (C) Tim Potter 2000
7 Copyright (C) Andrew Bartlett 2002
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.
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.
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.
24 #include "includes.h"
25 #include "winbindd.h"
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_WINBIND
30 /* Check the machine account password is valid */
32 void winbindd_check_machine_acct(struct winbindd_cli_state *state)
34 DEBUG(3, ("[%5lu]: check machine account\n",
35 (unsigned long)state->pid));
37 sendto_domain(state, find_our_domain());
40 enum winbindd_result winbindd_dual_check_machine_acct(struct winbindd_domain *domain,
41 struct winbindd_cli_state *state)
43 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
44 int num_retries = 0;
45 struct winbindd_domain *contact_domain;
47 DEBUG(3, ("[%5lu]: check machine account\n", (unsigned long)state->pid));
49 /* Get trust account password */
51 again:
53 contact_domain = find_our_domain();
55 /* This call does a cli_nt_setup_creds() which implicitly checks
56 the trust account password. */
58 invalidate_cm_connection(&contact_domain->conn);
61 struct rpc_pipe_client *netlogon_pipe;
62 result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
65 if (!NT_STATUS_IS_OK(result)) {
66 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
67 goto done;
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. */
75 #define MAX_RETRIES 8
77 if ((num_retries < MAX_RETRIES) &&
78 NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) {
79 num_retries++;
80 goto again;
83 /* Pass back result code - zero for success, other values for
84 specific failures. */
86 DEBUG(3, ("secret is %s\n", NT_STATUS_IS_OK(result) ?
87 "good" : "bad"));
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);
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));
98 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
101 void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
103 DEBUG(3, ("[%5lu]: list trusted domains\n",
104 (unsigned long)state->pid));
106 sendto_domain(state, find_our_domain());
109 enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
110 struct winbindd_cli_state *state)
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;
119 DEBUG(3, ("[%5lu]: list trusted domains\n",
120 (unsigned long)state->pid));
122 result = domain->methods->trusted_domains(domain, state->mem_ctx,
123 &num_domains, &names,
124 &alt_names, &sids);
126 extra_data = talloc_strdup(state->mem_ctx, "");
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]));
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]));
141 /* This is a bit excessive, but the extra data sooner or later will be
142 talloc'ed */
144 extra_data_len = strlen(extra_data);
146 if (extra_data_len > 0) {
147 state->response.extra_data = SMB_STRDUP(extra_data);
148 state->response.length += extra_data_len+1;
151 return WINBINDD_OK;
154 void winbindd_getdcname(struct winbindd_cli_state *state)
156 state->request.domain_name
157 [sizeof(state->request.domain_name)-1] = '\0';
159 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
160 state->request.domain_name));
162 sendto_domain(state, find_our_domain());
165 enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
166 struct winbindd_cli_state *state)
168 fstring dcname_slash;
169 char *p;
170 struct rpc_pipe_client *netlogon_pipe;
171 NTSTATUS result;
173 state->request.domain_name
174 [sizeof(state->request.domain_name)-1] = '\0';
176 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
177 state->request.domain_name));
179 result = cm_connect_netlogon(domain, &netlogon_pipe);
181 if (!NT_STATUS_IS_OK(result)) {
182 DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
183 return WINBINDD_ERROR;
186 result = rpccli_netlogon_getdcname(netlogon_pipe, state->mem_ctx, domain->dcname,
187 state->request.domain_name,
188 dcname_slash);
190 if (!NT_STATUS_IS_OK(result)) {
191 DEBUG(5, ("Error requesting DCname: %s\n", nt_errstr(result)));
192 return WINBINDD_ERROR;
195 p = dcname_slash;
196 if (*p == '\\') {
197 p+=1;
199 if (*p == '\\') {
200 p+=1;
203 fstrcpy(state->response.data.dc_name, p);
204 return WINBINDD_OK;
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;
216 static void sequence_recv(void *private_data, BOOL success);
218 void winbindd_show_sequence(struct winbindd_cli_state *state)
220 struct sequence_state *seq;
222 /* Ensure null termination */
223 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
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;
233 sendto_domain(state, domain);
234 return;
237 /* Ask all domains in sequence, collect the results in sequence_recv */
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;
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;
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, "");
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;
267 seq->request->length = sizeof(*seq->request);
268 seq->request->cmd = WINBINDD_SHOW_SEQUENCE;
269 fstrcpy(seq->request->domain_name, seq->domain->name);
271 async_domain_request(state->mem_ctx, seq->domain,
272 seq->request, seq->response,
273 sequence_recv, seq);
276 static void sequence_recv(void *private_data, BOOL success)
278 struct sequence_state *state = private_data;
279 uint32 seq = DOM_SEQUENCE_NONE;
281 if ((success) && (state->response->result == WINBINDD_OK))
282 seq = state->response->data.domain_info.sequence_number;
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);
296 state->domain->sequence_number = seq;
298 state->domain = state->domain->next;
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;
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);
318 /* This is the child-only version of --sequence. It only allows for a single
319 * domain (ie "our" one) to be displayed. */
321 enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
322 struct winbindd_cli_state *state)
324 DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
326 /* Ensure null termination */
327 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
329 domain->methods->sequence_number(domain, &domain->sequence_number);
331 state->response.data.domain_info.sequence_number =
332 domain->sequence_number;
334 return WINBINDD_OK;
337 struct domain_info_state {
338 struct winbindd_domain *domain;
339 struct winbindd_cli_state *cli_state;
342 static void domain_info_init_recv(void *private_data, BOOL success);
344 void winbindd_domain_info(struct winbindd_cli_state *state)
346 struct winbindd_domain *domain;
348 DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)state->pid,
349 state->request.domain_name));
351 domain = find_domain_from_name_noinit(state->request.domain_name);
353 if (domain == NULL) {
354 DEBUG(3, ("Did not find domain [%s]\n",
355 state->request.domain_name));
356 request_error(state);
357 return;
360 if (!domain->initialized) {
361 struct domain_info_state *istate;
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;
370 istate->cli_state = state;
371 istate->domain = domain;
373 init_child_connection(domain, domain_info_init_recv, istate);
375 return;
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));
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;
394 request_ok(state);
397 static void domain_info_init_recv(void *private_data, BOOL success)
399 struct domain_info_state *istate = private_data;
400 struct winbindd_cli_state *state = istate->cli_state;
401 struct winbindd_domain *domain = istate->domain;
403 DEBUG(10, ("Got back from child init: %d\n", success));
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;
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));
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;
428 request_ok(state);
431 void winbindd_ping(struct winbindd_cli_state *state)
433 DEBUG(3, ("[%5lu]: ping\n", (unsigned long)state->pid));
434 request_ok(state);
437 /* List various tidbits of information */
439 void winbindd_info(struct winbindd_cli_state *state)
442 DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
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);
449 /* Tell the client the current interface version */
451 void winbindd_interface_version(struct winbindd_cli_state *state)
453 DEBUG(3, ("[%5lu]: request interface version\n",
454 (unsigned long)state->pid));
456 state->response.data.interface_version = WINBIND_INTERFACE_VERSION;
457 request_ok(state);
460 /* What domain are we a member of? */
462 void winbindd_domain_name(struct winbindd_cli_state *state)
464 DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
466 fstrcpy(state->response.data.domain_name, lp_workgroup());
467 request_ok(state);
470 /* What's my name again? */
472 void winbindd_netbios_name(struct winbindd_cli_state *state)
474 DEBUG(3, ("[%5lu]: request netbios name\n",
475 (unsigned long)state->pid));
477 fstrcpy(state->response.data.netbios_name, global_myname());
478 request_ok(state);
481 /* Where can I find the privilaged pipe? */
483 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
486 DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
487 (unsigned long)state->pid));
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;
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;
500 request_ok(state);