s3:winbind: Convert WINBINDD_LIST_GROUPS to the new API
[Samba/aatanasov.git] / source3 / winbindd / winbindd_misc.c
blobb9673909664372e4b044ef9310c479192efc480e
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 3 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, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "winbindd.h"
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_WINBIND
29 /* Check the machine account password is valid */
31 void winbindd_check_machine_acct(struct winbindd_cli_state *state)
33 DEBUG(3, ("[%5lu]: check machine account\n",
34 (unsigned long)state->pid));
36 sendto_domain(state, find_our_domain());
39 enum winbindd_result winbindd_dual_check_machine_acct(struct winbindd_domain *domain,
40 struct winbindd_cli_state *state)
42 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
43 int num_retries = 0;
44 struct winbindd_domain *contact_domain;
46 DEBUG(3, ("[%5lu]: check machine account\n", (unsigned long)state->pid));
48 /* Get trust account password */
50 again:
52 contact_domain = find_our_domain();
54 /* This call does a cli_nt_setup_creds() which implicitly checks
55 the trust account password. */
57 invalidate_cm_connection(&contact_domain->conn);
60 struct rpc_pipe_client *netlogon_pipe;
61 result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
64 if (!NT_STATUS_IS_OK(result)) {
65 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
66 goto done;
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. */
74 #define MAX_RETRIES 8
76 if ((num_retries < MAX_RETRIES) &&
77 NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) {
78 num_retries++;
79 goto again;
82 /* Pass back result code - zero for success, other values for
83 specific failures. */
85 DEBUG(3, ("secret is %s\n", NT_STATUS_IS_OK(result) ?
86 "good" : "bad"));
88 done:
89 set_auth_errors(state->response, result);
91 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Checking the trust account password returned %s\n",
92 state->response->data.auth.nt_status_string));
94 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
97 /* Constants and helper functions for determining domain trust types */
99 enum trust_type {
100 EXTERNAL = 0,
101 FOREST,
102 IN_FOREST,
103 NONE,
106 const char *trust_type_strings[] = {"External",
107 "Forest",
108 "In Forest",
109 "None"};
111 static enum trust_type get_trust_type(struct winbindd_tdc_domain *domain)
113 if (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN)
114 return EXTERNAL;
115 else if (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)
116 return FOREST;
117 else if (((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) == NETR_TRUST_FLAG_IN_FOREST) &&
118 ((domain->trust_flags & NETR_TRUST_FLAG_PRIMARY) == 0x0))
119 return IN_FOREST;
120 return NONE;
123 static const char *get_trust_type_string(struct winbindd_tdc_domain *domain)
125 return trust_type_strings[get_trust_type(domain)];
128 static bool trust_is_inbound(struct winbindd_tdc_domain *domain)
130 return (domain->trust_flags == 0x0) ||
131 ((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) ==
132 NETR_TRUST_FLAG_IN_FOREST) ||
133 ((domain->trust_flags & NETR_TRUST_FLAG_INBOUND) ==
134 NETR_TRUST_FLAG_INBOUND);
137 static bool trust_is_outbound(struct winbindd_tdc_domain *domain)
139 return (domain->trust_flags == 0x0) ||
140 ((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) ==
141 NETR_TRUST_FLAG_IN_FOREST) ||
142 ((domain->trust_flags & NETR_TRUST_FLAG_OUTBOUND) ==
143 NETR_TRUST_FLAG_OUTBOUND);
146 static bool trust_is_transitive(struct winbindd_tdc_domain *domain)
148 if ((domain->trust_attribs == NETR_TRUST_ATTRIBUTE_NON_TRANSITIVE) ||
149 (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) ||
150 (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL))
151 return False;
152 return True;
155 void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
157 struct winbindd_tdc_domain *dom_list = NULL;
158 struct winbindd_tdc_domain *d = NULL;
159 size_t num_domains = 0;
160 int extra_data_len = 0;
161 char *extra_data = NULL;
162 int i = 0;
164 DEBUG(3, ("[%5lu]: list trusted domains\n",
165 (unsigned long)state->pid));
167 if( !wcache_tdc_fetch_list( &dom_list, &num_domains )) {
168 request_error(state);
169 goto done;
172 for ( i = 0; i < num_domains; i++ ) {
173 struct winbindd_domain *domain;
174 bool is_online = true;
176 d = &dom_list[i];
177 domain = find_domain_from_name_noinit(d->domain_name);
178 if (domain) {
179 is_online = domain->online;
182 if ( !extra_data ) {
183 extra_data = talloc_asprintf(state->mem_ctx,
184 "%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s",
185 d->domain_name,
186 d->dns_name ? d->dns_name : d->domain_name,
187 sid_string_talloc(state->mem_ctx, &d->sid),
188 get_trust_type_string(d),
189 trust_is_transitive(d) ? "Yes" : "No",
190 trust_is_inbound(d) ? "Yes" : "No",
191 trust_is_outbound(d) ? "Yes" : "No",
192 is_online ? "Online" : "Offline" );
193 } else {
194 extra_data = talloc_asprintf(state->mem_ctx,
195 "%s\n%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s",
196 extra_data,
197 d->domain_name,
198 d->dns_name ? d->dns_name : d->domain_name,
199 sid_string_talloc(state->mem_ctx, &d->sid),
200 get_trust_type_string(d),
201 trust_is_transitive(d) ? "Yes" : "No",
202 trust_is_inbound(d) ? "Yes" : "No",
203 trust_is_outbound(d) ? "Yes" : "No",
204 is_online ? "Online" : "Offline" );
208 extra_data_len = 0;
209 if (extra_data != NULL) {
210 extra_data_len = strlen(extra_data);
213 if (extra_data_len > 0) {
214 state->response->extra_data.data = extra_data;
215 state->response->length += extra_data_len+1;
218 request_ok(state);
219 done:
220 TALLOC_FREE( dom_list );
223 enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
224 struct winbindd_cli_state *state)
226 uint32 i, num_domains;
227 char **names, **alt_names;
228 DOM_SID *sids;
229 int extra_data_len = 0;
230 char *extra_data;
231 NTSTATUS result;
232 bool have_own_domain = False;
234 DEBUG(3, ("[%5lu]: list trusted domains\n",
235 (unsigned long)state->pid));
237 result = domain->methods->trusted_domains(domain, state->mem_ctx,
238 &num_domains, &names,
239 &alt_names, &sids);
241 if (!NT_STATUS_IS_OK(result)) {
242 DEBUG(3, ("winbindd_dual_list_trusted_domains: trusted_domains returned %s\n",
243 nt_errstr(result) ));
244 return WINBINDD_ERROR;
247 extra_data = talloc_strdup(state->mem_ctx, "");
249 if (num_domains > 0)
250 extra_data = talloc_asprintf(
251 state->mem_ctx, "%s\\%s\\%s",
252 names[0], alt_names[0] ? alt_names[0] : names[0],
253 sid_string_talloc(state->mem_ctx, &sids[0]));
255 for (i=1; i<num_domains; i++)
256 extra_data = talloc_asprintf(
257 state->mem_ctx, "%s\n%s\\%s\\%s",
258 extra_data, names[i],
259 alt_names[i] ? alt_names[i] : names[i],
260 sid_string_talloc(state->mem_ctx, &sids[i]));
262 /* add our primary domain */
264 for (i=0; i<num_domains; i++) {
265 if (strequal(names[i], domain->name)) {
266 have_own_domain = True;
267 break;
271 if (state->request->data.list_all_domains && !have_own_domain) {
272 extra_data = talloc_asprintf(
273 state->mem_ctx, "%s\n%s\\%s\\%s",
274 extra_data, domain->name,
275 domain->alt_name ? domain->alt_name : domain->name,
276 sid_string_talloc(state->mem_ctx, &domain->sid));
279 /* This is a bit excessive, but the extra data sooner or later will be
280 talloc'ed */
282 extra_data_len = 0;
283 if (extra_data != NULL) {
284 extra_data_len = strlen(extra_data);
287 if (extra_data_len > 0) {
288 state->response->extra_data.data = extra_data;
289 state->response->length += extra_data_len+1;
292 return WINBINDD_OK;
295 enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
296 struct winbindd_cli_state *state)
298 const char *dcname_slash = NULL;
299 const char *p;
300 struct rpc_pipe_client *netlogon_pipe;
301 NTSTATUS result;
302 WERROR werr;
303 unsigned int orig_timeout;
304 struct winbindd_domain *req_domain;
306 state->request->domain_name
307 [sizeof(state->request->domain_name)-1] = '\0';
309 DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
310 state->request->domain_name));
312 result = cm_connect_netlogon(domain, &netlogon_pipe);
314 if (!NT_STATUS_IS_OK(result)) {
315 DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
316 return WINBINDD_ERROR;
319 /* This call can take a long time - allow the server to time out.
320 35 seconds should do it. */
322 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
324 req_domain = find_domain_from_name_noinit(state->request->domain_name);
325 if (req_domain == domain) {
326 result = rpccli_netr_GetDcName(netlogon_pipe,
327 state->mem_ctx,
328 domain->dcname,
329 state->request->domain_name,
330 &dcname_slash,
331 &werr);
332 } else {
333 result = rpccli_netr_GetAnyDCName(netlogon_pipe,
334 state->mem_ctx,
335 domain->dcname,
336 state->request->domain_name,
337 &dcname_slash,
338 &werr);
340 /* And restore our original timeout. */
341 rpccli_set_timeout(netlogon_pipe, orig_timeout);
343 if (!NT_STATUS_IS_OK(result)) {
344 DEBUG(5,("Error requesting DCname for domain %s: %s\n",
345 state->request->domain_name, nt_errstr(result)));
346 return WINBINDD_ERROR;
349 if (!W_ERROR_IS_OK(werr)) {
350 DEBUG(5, ("Error requesting DCname for domain %s: %s\n",
351 state->request->domain_name, win_errstr(werr)));
352 return WINBINDD_ERROR;
355 p = dcname_slash;
356 if (*p == '\\') {
357 p+=1;
359 if (*p == '\\') {
360 p+=1;
363 fstrcpy(state->response->data.dc_name, p);
364 return WINBINDD_OK;
367 /* This is the child-only version of --sequence. It only allows for a single
368 * domain (ie "our" one) to be displayed. */
370 enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
371 struct winbindd_cli_state *state)
373 DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
375 /* Ensure null termination */
376 state->request->domain_name[sizeof(state->request->domain_name)-1]='\0';
378 domain->methods->sequence_number(domain, &domain->sequence_number);
380 state->response->data.sequence_number =
381 domain->sequence_number;
383 return WINBINDD_OK;
386 struct domain_info_state {
387 struct winbindd_domain *domain;
388 struct winbindd_cli_state *cli;
389 struct winbindd_request ping_request;
392 static void domain_info_done(struct tevent_req *req);
394 void winbindd_domain_info(struct winbindd_cli_state *cli)
396 struct domain_info_state *state;
397 struct winbindd_domain *domain;
398 struct tevent_req *req;
400 DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)cli->pid,
401 cli->request->domain_name));
403 domain = find_domain_from_name_noinit(cli->request->domain_name);
405 if (domain == NULL) {
406 DEBUG(3, ("Did not find domain [%s]\n",
407 cli->request->domain_name));
408 request_error(cli);
409 return;
412 if (domain->initialized) {
413 fstrcpy(cli->response->data.domain_info.name,
414 domain->name);
415 fstrcpy(cli->response->data.domain_info.alt_name,
416 domain->alt_name);
417 sid_to_fstring(cli->response->data.domain_info.sid,
418 &domain->sid);
419 cli->response->data.domain_info.native_mode =
420 domain->native_mode;
421 cli->response->data.domain_info.active_directory =
422 domain->active_directory;
423 cli->response->data.domain_info.primary =
424 domain->primary;
425 request_ok(cli);
426 return;
429 state = talloc_zero(cli->mem_ctx, struct domain_info_state);
430 if (state == NULL) {
431 DEBUG(0, ("talloc failed\n"));
432 request_error(cli);
433 return;
436 state->cli = cli;
437 state->domain = domain;
438 state->ping_request.cmd = WINBINDD_PING;
441 * Send a ping down. This implicitly initializes the domain.
444 req = wb_domain_request_send(state, winbind_event_context(),
445 domain, &state->ping_request);
446 if (req == NULL) {
447 DEBUG(3, ("wb_domain_request_send failed\n"));
448 request_error(cli);
450 tevent_req_set_callback(req, domain_info_done, state);
453 static void domain_info_done(struct tevent_req *req)
455 struct domain_info_state *state = tevent_req_callback_data(
456 req, struct domain_info_state);
457 struct winbindd_response *response;
458 int ret, err;
460 ret = wb_domain_request_recv(req, req, &response, &err);
461 TALLOC_FREE(req);
462 if (ret == -1) {
463 DEBUG(10, ("wb_domain_request failed: %s\n", strerror(errno)));
464 request_error(state->cli);
465 return;
467 if (!state->domain->initialized) {
468 DEBUG(5, ("wb_domain_request did not initialize domain %s\n",
469 state->domain->name));
470 request_error(state->cli);
471 return;
474 fstrcpy(state->cli->response->data.domain_info.name,
475 state->domain->name);
476 fstrcpy(state->cli->response->data.domain_info.alt_name,
477 state->domain->alt_name);
478 sid_to_fstring(state->cli->response->data.domain_info.sid,
479 &state->domain->sid);
481 state->cli->response->data.domain_info.native_mode =
482 state->domain->native_mode;
483 state->cli->response->data.domain_info.active_directory =
484 state->domain->active_directory;
485 state->cli->response->data.domain_info.primary =
486 state->domain->primary;
488 request_ok(state->cli);
491 /* List various tidbits of information */
493 void winbindd_info(struct winbindd_cli_state *state)
496 DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
498 state->response->data.info.winbind_separator = *lp_winbind_separator();
499 fstrcpy(state->response->data.info.samba_version, samba_version_string());
500 request_ok(state);
503 /* Tell the client the current interface version */
505 void winbindd_interface_version(struct winbindd_cli_state *state)
507 DEBUG(3, ("[%5lu]: request interface version\n",
508 (unsigned long)state->pid));
510 state->response->data.interface_version = WINBIND_INTERFACE_VERSION;
511 request_ok(state);
514 /* What domain are we a member of? */
516 void winbindd_domain_name(struct winbindd_cli_state *state)
518 DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
520 fstrcpy(state->response->data.domain_name, lp_workgroup());
521 request_ok(state);
524 /* What's my name again? */
526 void winbindd_netbios_name(struct winbindd_cli_state *state)
528 DEBUG(3, ("[%5lu]: request netbios name\n",
529 (unsigned long)state->pid));
531 fstrcpy(state->response->data.netbios_name, global_myname());
532 request_ok(state);
535 /* Where can I find the privilaged pipe? */
537 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
539 char *priv_dir;
540 DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
541 (unsigned long)state->pid));
543 priv_dir = get_winbind_priv_pipe_dir();
544 state->response->extra_data.data = talloc_move(state->mem_ctx,
545 &priv_dir);
547 /* must add one to length to copy the 0 for string termination */
548 state->response->length +=
549 strlen((char *)state->response->extra_data.data) + 1;
551 request_ok(state);