2 Unix SMB/CIFS implementation.
4 Winbind daemon for ntdom nss module
6 Copyright (C) Tim Potter 2000-2001
7 Copyright (C) 2001 by Martin Pool <mbp@samba.org>
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/>.
25 #include "lib/util_unixsids.h"
27 #include "../libcli/security/security.h"
28 #include "../libcli/auth/pam_errors.h"
29 #include "passdb/machine_sid.h"
31 #include "source4/lib/messaging/messaging.h"
32 #include "librpc/gen_ndr/ndr_lsa.h"
33 #include "librpc/gen_ndr/ndr_drsblobs.h"
34 #include "auth/credentials/credentials.h"
35 #include "libsmb/samlogon_cache.h"
38 #define DBGC_CLASS DBGC_WINBIND
41 * @file winbindd_util.c
43 * Winbind daemon for NT domain authentication nss module.
46 static bool add_trusted_domains_dc(void);
48 /* The list of trusted domains. Note that the list can be deleted and
49 recreated using the init_domain_list() function so pointers to
50 individual winbindd_domain structures cannot be made. Keep a copy of
51 the domain name instead. */
53 static struct winbindd_domain *_domain_list = NULL;
55 struct winbindd_domain *domain_list(void)
59 if ((!_domain_list) && (!init_domain_list())) {
60 smb_panic("Init_domain_list failed");
66 /* Free all entries in the trusted domain list */
68 static void free_domain_list(void)
70 struct winbindd_domain *domain = _domain_list;
73 struct winbindd_domain *next = domain->next;
75 DLIST_REMOVE(_domain_list, domain);
82 * Iterator for winbindd's domain list.
83 * To be used (e.g.) in tevent based loops.
85 struct winbindd_domain *wb_next_domain(struct winbindd_domain *domain)
88 domain = domain_list();
90 domain = domain->next;
93 if ((domain != NULL) &&
94 (lp_server_role() != ROLE_ACTIVE_DIRECTORY_DC) &&
95 sid_check_is_our_sam(&domain->sid))
97 domain = domain->next;
103 static bool is_internal_domain(const struct dom_sid *sid)
108 return (sid_check_is_our_sam(sid) || sid_check_is_builtin(sid));
111 static bool is_in_internal_domain(const struct dom_sid *sid)
116 return (sid_check_is_in_our_sam(sid) || sid_check_is_in_builtin(sid));
120 /* Add a trusted domain to our list of domains.
121 If the domain already exists in the list,
122 return it and don't re-initialize. */
124 static NTSTATUS add_trusted_domain(const char *domain_name,
125 const char *dns_name,
126 const struct dom_sid *sid,
128 uint32_t trust_flags,
129 uint32_t trust_attribs,
130 enum netr_SchannelType secure_channel_type,
131 struct winbindd_domain *routing_domain,
132 struct winbindd_domain **_d)
134 struct winbindd_domain *domain = NULL;
135 const char **ignored_domains = NULL;
136 const char **dom = NULL;
137 int role = lp_server_role();
139 if (is_null_sid(sid)) {
140 DBG_ERR("Got null SID for domain [%s]\n", domain_name);
141 return NT_STATUS_INVALID_PARAMETER;
144 ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
145 for (dom=ignored_domains; dom && *dom; dom++) {
146 if (gen_fnmatch(*dom, domain_name) == 0) {
147 DEBUG(2,("Ignoring domain '%s'\n", domain_name));
148 return NT_STATUS_NO_SUCH_DOMAIN;
153 * We can't call domain_list() as this function is called from
154 * init_domain_list() and we'll get stuck in a loop.
156 for (domain = _domain_list; domain; domain = domain->next) {
157 if (strequal(domain_name, domain->name)) {
162 if (domain != NULL) {
163 struct winbindd_domain *check_domain = NULL;
165 for (check_domain = _domain_list;
166 check_domain != NULL;
167 check_domain = check_domain->next)
169 if (check_domain == domain) {
173 if (dom_sid_equal(&check_domain->sid, sid)) {
178 if (check_domain != NULL) {
179 DBG_ERR("SID [%s] already used by domain [%s], "
181 sid_string_dbg(sid), check_domain->name,
183 return NT_STATUS_INVALID_PARAMETER;
187 if ((domain != NULL) && (dns_name != NULL)) {
188 struct winbindd_domain *check_domain = NULL;
190 for (check_domain = _domain_list;
191 check_domain != NULL;
192 check_domain = check_domain->next)
194 if (check_domain == domain) {
198 if (strequal(check_domain->alt_name, dns_name)) {
203 if (check_domain != NULL) {
204 DBG_ERR("DNS name [%s] used by domain [%s], "
206 dns_name, check_domain->name,
208 return NT_STATUS_INVALID_PARAMETER;
212 if (domain != NULL) {
217 /* Create new domain entry */
218 domain = talloc_zero(NULL, struct winbindd_domain);
219 if (domain == NULL) {
220 return NT_STATUS_NO_MEMORY;
223 domain->children = talloc_zero_array(domain,
224 struct winbindd_child,
225 lp_winbind_max_domain_connections());
226 if (domain->children == NULL) {
228 return NT_STATUS_NO_MEMORY;
231 domain->queue = tevent_queue_create(domain, "winbind_domain");
232 if (domain->queue == NULL) {
234 return NT_STATUS_NO_MEMORY;
237 domain->binding_handle = wbint_binding_handle(domain, domain, NULL);
238 if (domain->binding_handle == NULL) {
240 return NT_STATUS_NO_MEMORY;
243 domain->name = talloc_strdup(domain, domain_name);
244 if (domain->name == NULL) {
246 return NT_STATUS_NO_MEMORY;
249 if (dns_name != NULL) {
250 domain->alt_name = talloc_strdup(domain, dns_name);
251 if (domain->alt_name == NULL) {
253 return NT_STATUS_NO_MEMORY;
257 domain->backend = NULL;
258 domain->internal = is_internal_domain(sid);
259 domain->secure_channel_type = secure_channel_type;
260 domain->sequence_number = DOM_SEQUENCE_NONE;
261 domain->last_seq_check = 0;
262 domain->initialized = false;
263 domain->online = is_internal_domain(sid);
264 domain->check_online_timeout = 0;
265 domain->dc_probe_pid = (pid_t)-1;
266 domain->domain_flags = trust_flags;
267 domain->domain_type = trust_type;
268 domain->domain_trust_attribs = trust_attribs;
269 domain->secure_channel_type = secure_channel_type;
270 domain->routing_domain = routing_domain;
271 sid_copy(&domain->sid, sid);
273 /* Is this our primary domain ? */
274 if (role == ROLE_DOMAIN_MEMBER) {
275 domain->primary = strequal(domain_name, lp_workgroup());
277 domain->primary = strequal(domain_name, get_global_sam_name());
280 if (domain->primary) {
281 if (role == ROLE_ACTIVE_DIRECTORY_DC) {
282 domain->active_directory = true;
284 if (lp_security() == SEC_ADS) {
285 domain->active_directory = true;
287 } else if (!domain->internal) {
288 if (domain->domain_type == LSA_TRUST_TYPE_UPLEVEL) {
289 domain->active_directory = true;
293 domain->can_do_ncacn_ip_tcp = domain->active_directory;
295 /* Link to domain list */
296 DLIST_ADD_END(_domain_list, domain);
298 wcache_tdc_add_domain( domain );
300 setup_domain_child(domain);
302 DBG_NOTICE("Added domain [%s] [%s] [%s]\n",
303 domain->name, domain->alt_name,
304 sid_string_dbg(&domain->sid));
310 bool set_routing_domain(struct winbindd_domain *domain,
311 struct winbindd_domain *routing_domain)
313 if (domain->routing_domain == NULL) {
314 domain->routing_domain = routing_domain;
317 if (domain->routing_domain != routing_domain) {
323 bool add_trusted_domain_from_auth(uint16_t validation_level,
324 struct info3_text *info3,
325 struct info6_text *info6)
327 struct winbindd_domain *domain = NULL;
328 struct dom_sid domain_sid;
329 const char *dns_domainname = NULL;
334 * We got a successfull auth from a domain that might not yet be in our
335 * domain list. If we're a member we trust our DC who authenticated the
336 * user from that domain and add the domain to our list on-the-fly. If
337 * we're a DC we rely on configured trusts and don't add on-the-fly.
344 ok = dom_sid_parse(info3->dom_sid, &domain_sid);
346 DBG_NOTICE("dom_sid_parse [%s] failed\n", info3->dom_sid);
350 if (validation_level == 6) {
351 if (!strequal(info6->dns_domainname, "")) {
352 dns_domainname = info6->dns_domainname;
356 status = add_trusted_domain(info3->logon_dom,
360 NETR_TRUST_FLAG_OUTBOUND,
363 find_default_route_domain(),
365 if (!NT_STATUS_IS_OK(status) &&
366 !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
368 DBG_DEBUG("Adding domain [%s] with sid [%s] failed\n",
369 info3->logon_dom, info3->dom_sid);
376 bool domain_is_forest_root(const struct winbindd_domain *domain)
378 const uint32_t fr_flags =
379 (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
381 return ((domain->domain_flags & fr_flags) == fr_flags);
384 /********************************************************************
385 rescan our domains looking for new trusted domains
386 ********************************************************************/
388 struct trustdom_state {
389 struct winbindd_domain *domain;
390 struct winbindd_request request;
393 static void trustdom_list_done(struct tevent_req *req);
394 static void rescan_forest_root_trusts( void );
395 static void rescan_forest_trusts( void );
397 static void add_trusted_domains( struct winbindd_domain *domain )
399 struct trustdom_state *state;
400 struct tevent_req *req;
402 state = talloc_zero(NULL, struct trustdom_state);
404 DEBUG(0, ("talloc failed\n"));
407 state->domain = domain;
409 state->request.length = sizeof(state->request);
410 state->request.cmd = WINBINDD_LIST_TRUSTDOM;
412 req = wb_domain_request_send(state, server_event_context(),
413 domain, &state->request);
415 DEBUG(1, ("wb_domain_request_send failed\n"));
419 tevent_req_set_callback(req, trustdom_list_done, state);
422 static void trustdom_list_done(struct tevent_req *req)
424 struct trustdom_state *state = tevent_req_callback_data(
425 req, struct trustdom_state);
426 struct winbindd_response *response;
430 bool within_forest = false;
434 * Only when we enumerate our primary domain
435 * or our forest root domain, we should keep
436 * the NETR_TRUST_FLAG_IN_FOREST flag, in
437 * all other cases we need to clear it as the domain
438 * is not part of our forest.
440 if (state->domain->primary) {
441 within_forest = true;
442 } else if (domain_is_forest_root(state->domain)) {
443 within_forest = true;
446 res = wb_domain_request_recv(req, state, &response, &err);
447 if ((res == -1) || (response->result != WINBINDD_OK)) {
448 DBG_WARNING("Could not receive trusts for domain %s\n",
449 state->domain->name);
454 if (response->length < sizeof(struct winbindd_response)) {
455 DBG_ERR("ill-formed trustdom response - short length\n");
460 extra_len = response->length - sizeof(struct winbindd_response);
462 p = (char *)response->extra_data.data;
464 while ((p - (char *)response->extra_data.data) < extra_len) {
465 struct winbindd_domain *domain = NULL;
466 char *name, *q, *sidstr, *alt_name;
469 uint32_t trust_attribs;
470 uint32_t trust_flags;
472 DBG_DEBUG("parsing response line '%s'\n", p);
476 alt_name = strchr(p, '\\');
477 if (alt_name == NULL) {
478 DBG_ERR("Got invalid trustdom response\n");
485 sidstr = strchr(alt_name, '\\');
486 if (sidstr == NULL) {
487 DBG_ERR("Got invalid trustdom response\n");
494 /* use the real alt_name if we have one, else pass in NULL */
495 if (strequal(alt_name, "(null)")) {
499 q = strtok(sidstr, "\\");
501 DBG_ERR("Got invalid trustdom response\n");
505 if (!string_to_sid(&sid, sidstr)) {
506 DEBUG(0, ("Got invalid trustdom response\n"));
510 q = strtok(NULL, "\\");
512 DBG_ERR("Got invalid trustdom response\n");
516 trust_flags = (uint32_t)strtoul(q, NULL, 10);
518 q = strtok(NULL, "\\");
520 DBG_ERR("Got invalid trustdom response\n");
524 trust_type = (uint32_t)strtoul(q, NULL, 10);
526 q = strtok(NULL, "\n");
528 DBG_ERR("Got invalid trustdom response\n");
532 trust_attribs = (uint32_t)strtoul(q, NULL, 10);
534 if (!within_forest) {
535 trust_flags &= ~NETR_TRUST_FLAG_IN_FOREST;
538 if (!state->domain->primary) {
539 trust_flags &= ~NETR_TRUST_FLAG_PRIMARY;
543 * We always call add_trusted_domain() cause on an existing
544 * domain structure, it will update the SID if necessary.
545 * This is important because we need the SID for sibling
548 status = add_trusted_domain(name,
555 find_default_route_domain(),
557 if (!NT_STATUS_IS_OK(status) &&
558 !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
560 DBG_NOTICE("add_trusted_domain returned %s\n",
565 p = q + strlen(q) + 1;
569 Cases to consider when scanning trusts:
570 (a) we are calling from a child domain (primary && !forest_root)
571 (b) we are calling from the root of the forest (primary && forest_root)
572 (c) we are calling from a trusted forest domain (!primary
576 if (state->domain->primary) {
577 /* If this is our primary domain and we are not in the
578 forest root, we have to scan the root trusts first */
580 if (!domain_is_forest_root(state->domain))
581 rescan_forest_root_trusts();
583 rescan_forest_trusts();
585 } else if (domain_is_forest_root(state->domain)) {
586 /* Once we have done root forest trust search, we can
587 go on to search the trusted forests */
589 rescan_forest_trusts();
597 /********************************************************************
598 Scan the trusts of our forest root
599 ********************************************************************/
601 static void rescan_forest_root_trusts( void )
603 struct winbindd_tdc_domain *dom_list = NULL;
604 size_t num_trusts = 0;
608 /* The only transitive trusts supported by Windows 2003 AD are
609 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
610 first two are handled in forest and listed by
611 DsEnumerateDomainTrusts(). Forest trusts are not so we
612 have to do that ourselves. */
614 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
617 for ( i=0; i<num_trusts; i++ ) {
618 struct winbindd_domain *d = NULL;
620 /* Find the forest root. Don't necessarily trust
621 the domain_list() as our primary domain may not
622 have been initialized. */
624 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
628 /* Here's the forest root */
630 d = find_domain_from_name_noinit( dom_list[i].domain_name );
632 status = add_trusted_domain(dom_list[i].domain_name,
633 dom_list[i].dns_name,
635 dom_list[i].trust_type,
636 dom_list[i].trust_flags,
637 dom_list[i].trust_attribs,
639 find_default_route_domain(),
642 if (!NT_STATUS_IS_OK(status) &&
643 NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
645 DBG_ERR("add_trusted_domain returned %s\n",
654 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
655 "for domain tree root %s (%s)\n",
656 d->name, d->alt_name ));
658 d->domain_flags = dom_list[i].trust_flags;
659 d->domain_type = dom_list[i].trust_type;
660 d->domain_trust_attribs = dom_list[i].trust_attribs;
662 add_trusted_domains( d );
667 TALLOC_FREE( dom_list );
672 /********************************************************************
673 scan the transitive forest trusts (not our own)
674 ********************************************************************/
677 static void rescan_forest_trusts( void )
679 struct winbindd_domain *d = NULL;
680 struct winbindd_tdc_domain *dom_list = NULL;
681 size_t num_trusts = 0;
685 /* The only transitive trusts supported by Windows 2003 AD are
686 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
687 first two are handled in forest and listed by
688 DsEnumerateDomainTrusts(). Forest trusts are not so we
689 have to do that ourselves. */
691 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
694 for ( i=0; i<num_trusts; i++ ) {
695 uint32_t flags = dom_list[i].trust_flags;
696 uint32_t type = dom_list[i].trust_type;
697 uint32_t attribs = dom_list[i].trust_attribs;
699 d = find_domain_from_name_noinit( dom_list[i].domain_name );
701 /* ignore our primary and internal domains */
703 if ( d && (d->internal || d->primary ) )
706 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
707 (type == LSA_TRUST_TYPE_UPLEVEL) &&
708 (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
710 /* add the trusted domain if we don't know
714 status = add_trusted_domain(
715 dom_list[i].domain_name,
716 dom_list[i].dns_name,
722 find_default_route_domain(),
724 if (!NT_STATUS_IS_OK(status) &&
725 NT_STATUS_EQUAL(status,
726 NT_STATUS_NO_SUCH_DOMAIN))
728 DBG_ERR("add_trusted_domain: %s\n",
738 DEBUG(10,("Following trust path for domain %s (%s)\n",
739 d->name, d->alt_name ));
740 add_trusted_domains( d );
744 TALLOC_FREE( dom_list );
749 /*********************************************************************
750 The process of updating the trusted domain list is a three step
753 (b) ask the root domain in our forest
754 (c) ask the a DC in any Win2003 trusted forests
755 *********************************************************************/
757 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
758 struct timeval now, void *private_data)
762 /* I use to clear the cache here and start over but that
763 caused problems in child processes that needed the
764 trust dom list early on. Removing it means we
765 could have some trusted domains listed that have been
766 removed from our primary domain's DC until a full
767 restart. This should be ok since I think this is what
768 Windows does as well. */
770 /* this will only add new domains we didn't already know about
771 in the domain_list()*/
773 add_trusted_domains( find_our_domain() );
775 te = tevent_add_timer(
776 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
777 rescan_trusted_domains, NULL);
779 * If te == NULL, there's not much we can do here. Don't fail, the
780 * only thing we miss is new trusted domains.
786 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
787 struct winbindd_cli_state *state)
789 /* Ensure null termination */
790 state->request->domain_name
791 [sizeof(state->request->domain_name)-1]='\0';
792 state->request->data.init_conn.dcname
793 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
795 if (strlen(state->request->data.init_conn.dcname) > 0) {
796 TALLOC_FREE(domain->dcname);
797 domain->dcname = talloc_strdup(domain,
798 state->request->data.init_conn.dcname);
799 if (domain->dcname == NULL) {
800 return WINBINDD_ERROR;
804 init_dc_connection(domain, false);
806 if (!domain->initialized) {
807 /* If we return error here we can't do any cached authentication,
808 but we may be in disconnected mode and can't initialize correctly.
809 Do what the previous code did and just return without initialization,
810 once we go online we'll re-initialize.
812 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
813 "online = %d\n", domain->name, (int)domain->online ));
816 fstrcpy(state->response->data.domain_info.name, domain->name);
817 fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
818 sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
820 state->response->data.domain_info.native_mode
821 = domain->native_mode;
822 state->response->data.domain_info.active_directory
823 = domain->active_directory;
824 state->response->data.domain_info.primary
830 static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
833 struct server_id server_id,
838 DBG_NOTICE("Rescanning trusted domains\n");
840 ok = add_trusted_domains_dc();
842 DBG_ERR("Failed to reload trusted domains\n");
847 * We did not get the secret when we queried secrets.tdb, so read it
848 * from secrets.tdb and re-sync the databases
850 static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
853 struct cli_credentials *creds;
854 NTSTATUS can_migrate = pdb_get_trust_credentials(domain->name,
855 NULL, domain, &creds);
856 if (!NT_STATUS_IS_OK(can_migrate)) {
857 DEBUG(0, ("Failed to fetch our own, local AD domain join "
858 "password for winbindd's internal use, both from "
859 "secrets.tdb and secrets.ldb: %s\n",
860 nt_errstr(can_migrate)));
865 * NOTE: It is very unlikely we end up here if there is an
866 * oldpass, because a new password is created at
867 * classicupgrade, so this is not a concern.
869 ok = secrets_store_machine_pw_sync(cli_credentials_get_password(creds),
871 cli_credentials_get_domain(creds),
872 cli_credentials_get_realm(creds),
873 cli_credentials_get_salt_principal(creds),
874 0, /* Supported enc types, unused */
876 cli_credentials_get_password_last_changed_time(creds),
877 cli_credentials_get_secure_channel_type(creds),
878 false /* do_delete: Do not delete */);
881 DEBUG(0, ("Failed to write our our own, "
882 "local AD domain join password for "
883 "winbindd's internal use into secrets.tdb\n"));
889 static bool add_trusted_domains_dc(void)
891 struct winbindd_domain *domain = NULL;
892 struct pdb_trusted_domain **domains = NULL;
893 uint32_t num_domains = 0;
897 if (!(pdb_capabilities() & PDB_CAP_TRUSTED_DOMAINS_EX)) {
898 struct trustdom_info **ti = NULL;
900 status = pdb_enum_trusteddoms(talloc_tos(), &num_domains, &ti);
901 if (!NT_STATUS_IS_OK(status)) {
902 DBG_ERR("pdb_enum_trusteddoms() failed - %s\n",
907 for (i = 0; i < num_domains; i++) {
908 status = add_trusted_domain(ti[i]->name,
911 LSA_TRUST_TYPE_DOWNLEVEL,
912 NETR_TRUST_FLAG_OUTBOUND,
917 if (!NT_STATUS_IS_OK(status)) {
918 DBG_NOTICE("add_trusted_domain returned %s\n",
923 /* Even in the parent winbindd we'll need to
924 talk to the DC, so try and see if we can
925 contact it. Theoretically this isn't neccessary
926 as the init_dc_connection() in init_child_recv()
927 will do this, but we can start detecting the DC
929 set_domain_online_request(domain);
935 status = pdb_enum_trusted_domains(talloc_tos(), &num_domains, &domains);
936 if (!NT_STATUS_IS_OK(status)) {
937 DBG_ERR("pdb_enum_trusted_domains() failed - %s\n",
942 for (i = 0; i < num_domains; i++) {
943 enum netr_SchannelType sec_chan_type = SEC_CHAN_DOMAIN;
944 uint32_t trust_flags = 0;
946 if (domains[i]->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
947 sec_chan_type = SEC_CHAN_DNS_DOMAIN;
950 if (!(domains[i]->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND)) {
951 sec_chan_type = SEC_CHAN_NULL;
954 if (domains[i]->trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
955 trust_flags |= NETR_TRUST_FLAG_INBOUND;
957 if (domains[i]->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
958 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
960 if (domains[i]->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
961 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
964 status = add_trusted_domain(domains[i]->netbios_name,
965 domains[i]->domain_name,
966 &domains[i]->security_identifier,
967 domains[i]->trust_type,
969 domains[i]->trust_attributes,
973 if (!NT_STATUS_IS_OK(status)) {
974 DBG_NOTICE("add_trusted_domain returned %s\n",
979 if (domains[i]->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
980 domain->active_directory = true;
982 domain->domain_type = domains[i]->trust_type;
983 domain->domain_trust_attribs = domains[i]->trust_attributes;
985 if (sec_chan_type != SEC_CHAN_NULL) {
986 /* Even in the parent winbindd we'll need to
987 talk to the DC, so try and see if we can
988 contact it. Theoretically this isn't neccessary
989 as the init_dc_connection() in init_child_recv()
990 will do this, but we can start detecting the DC
992 set_domain_online_request(domain);
996 for (i = 0; i < num_domains; i++) {
997 struct ForestTrustInfo fti;
999 enum ndr_err_code ndr_err;
1000 struct winbindd_domain *routing_domain = NULL;
1002 if (domains[i]->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
1006 if (!(domains[i]->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1010 if (domains[i]->trust_forest_trust_info.length == 0) {
1014 routing_domain = find_domain_from_name_noinit(
1015 domains[i]->netbios_name);
1016 if (routing_domain == NULL) {
1017 DBG_ERR("Can't find winbindd domain [%s]\n",
1018 domains[i]->netbios_name);
1022 ndr_err = ndr_pull_struct_blob_all(
1023 &domains[i]->trust_forest_trust_info,
1025 (ndr_pull_flags_fn_t)ndr_pull_ForestTrustInfo);
1026 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1027 DBG_ERR("ndr_pull_ForestTrustInfo(%s) - %s\n",
1028 domains[i]->netbios_name,
1029 ndr_map_error2string(ndr_err));
1033 for (fi = 0; fi < fti.count; fi++) {
1034 struct ForestTrustInfoRecord *rec =
1035 &fti.records[fi].record;
1036 struct ForestTrustDataDomainInfo *drec = NULL;
1038 if (rec->type != FOREST_TRUST_DOMAIN_INFO) {
1041 drec = &rec->data.info;
1043 if (rec->flags & LSA_NB_DISABLED_MASK) {
1047 if (rec->flags & LSA_SID_DISABLED_MASK) {
1053 * also try to find a matching
1054 * LSA_TLN_DISABLED_MASK ???
1057 domain = find_domain_from_name_noinit(drec->netbios_name.string);
1058 if (domain != NULL) {
1062 status = add_trusted_domain(drec->netbios_name.string,
1063 drec->dns_name.string,
1065 LSA_TRUST_TYPE_UPLEVEL,
1066 NETR_TRUST_FLAG_OUTBOUND,
1071 if (!NT_STATUS_IS_OK(status)) {
1072 DBG_NOTICE("add_trusted_domain returned %s\n",
1076 if (domain == NULL) {
1086 /* Look up global info for the winbind daemon */
1087 bool init_domain_list(void)
1089 int role = lp_server_role();
1090 struct pdb_domain_info *pdb_domain_info = NULL;
1091 struct winbindd_domain *domain = NULL;
1095 /* Free existing list */
1098 /* BUILTIN domain */
1100 status = add_trusted_domain("BUILTIN",
1102 &global_sid_Builtin,
1103 LSA_TRUST_TYPE_DOWNLEVEL,
1104 0, /* trust_flags */
1105 0, /* trust_attribs */
1109 if (!NT_STATUS_IS_OK(status)) {
1110 DBG_ERR("add_trusted_domain BUILTIN returned %s\n",
1118 * In case the passdb backend is passdb_dsdb the domain SID comes from
1119 * dsdb, not from secrets.tdb. As we use the domain SID in various
1120 * places, we must ensure the domain SID is migrated from dsdb to
1121 * secrets.tdb before get_global_sam_sid() is called the first time.
1123 * The migration is done as part of the passdb_dsdb initialisation,
1124 * calling pdb_get_domain_info() triggers it.
1126 pdb_domain_info = pdb_get_domain_info(talloc_tos());
1128 if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
1129 uint32_t trust_flags;
1131 enum netr_SchannelType sec_chan_type;
1132 const char *account_name;
1133 struct samr_Password current_nt_hash;
1135 if (pdb_domain_info == NULL) {
1136 DEBUG(0, ("Failed to fetch our own, local AD "
1137 "domain info from sam.ldb\n"));
1141 trust_flags = NETR_TRUST_FLAG_PRIMARY;
1142 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
1143 trust_flags |= NETR_TRUST_FLAG_NATIVE;
1144 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
1146 is_root = strequal(pdb_domain_info->dns_domain,
1147 pdb_domain_info->dns_forest);
1149 trust_flags |= NETR_TRUST_FLAG_TREEROOT;
1152 status = add_trusted_domain(pdb_domain_info->name,
1153 pdb_domain_info->dns_domain,
1154 &pdb_domain_info->sid,
1155 LSA_TRUST_TYPE_UPLEVEL,
1157 LSA_TRUST_ATTRIBUTE_WITHIN_FOREST,
1161 TALLOC_FREE(pdb_domain_info);
1162 if (!NT_STATUS_IS_OK(status)) {
1163 DBG_ERR("Failed to add our own, local AD "
1164 "domain to winbindd's internal list\n");
1169 * We need to call this to find out if we are an RODC
1171 ok = get_trust_pw_hash(domain->name,
1172 current_nt_hash.hash,
1177 * If get_trust_pw_hash() fails, then try and
1178 * fetch the password from the more recent of
1179 * secrets.{ldb,tdb} using the
1180 * pdb_get_trust_credentials()
1182 ok = migrate_secrets_tdb_to_ldb(domain);
1185 DEBUG(0, ("Failed to migrate our own, "
1186 "local AD domain join password for "
1187 "winbindd's internal use into "
1191 ok = get_trust_pw_hash(domain->name,
1192 current_nt_hash.hash,
1196 DEBUG(0, ("Failed to find our our own, just "
1197 "written local AD domain join "
1198 "password for winbindd's internal "
1199 "use in secrets.tdb\n"));
1204 domain->secure_channel_type = sec_chan_type;
1205 if (sec_chan_type == SEC_CHAN_RODC) {
1206 domain->rodc = true;
1210 uint32_t trust_flags;
1211 enum netr_SchannelType secure_channel_type;
1213 trust_flags = NETR_TRUST_FLAG_OUTBOUND;
1214 if (role != ROLE_DOMAIN_MEMBER) {
1215 trust_flags |= NETR_TRUST_FLAG_PRIMARY;
1218 if (role > ROLE_DOMAIN_MEMBER) {
1219 secure_channel_type = SEC_CHAN_BDC;
1221 secure_channel_type = SEC_CHAN_LOCAL;
1224 status = add_trusted_domain(get_global_sam_name(),
1226 get_global_sam_sid(),
1227 LSA_TRUST_TYPE_DOWNLEVEL,
1229 0, /* trust_attribs */
1230 secure_channel_type,
1233 if (!NT_STATUS_IS_OK(status)) {
1234 DBG_ERR("Failed to add local SAM to "
1235 "domain to winbindd's internal list\n");
1241 ok = add_trusted_domains_dc();
1243 DBG_ERR("init_domain_list_dc failed\n");
1248 if ( role == ROLE_DOMAIN_MEMBER ) {
1249 struct dom_sid our_sid;
1250 uint32_t trust_type;
1252 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
1253 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
1257 if (lp_realm() != NULL) {
1258 trust_type = LSA_TRUST_TYPE_UPLEVEL;
1260 trust_type = LSA_TRUST_TYPE_DOWNLEVEL;
1263 status = add_trusted_domain(lp_workgroup(),
1267 NETR_TRUST_FLAG_PRIMARY|
1268 NETR_TRUST_FLAG_OUTBOUND,
1269 0, /* trust_attribs */
1273 if (!NT_STATUS_IS_OK(status)) {
1274 DBG_ERR("Failed to add local SAM to "
1275 "domain to winbindd's internal list\n");
1278 /* Even in the parent winbindd we'll need to
1279 talk to the DC, so try and see if we can
1280 contact it. Theoretically this isn't neccessary
1281 as the init_dc_connection() in init_child_recv()
1282 will do this, but we can start detecting the DC
1284 set_domain_online_request(domain);
1288 status = imessaging_register(winbind_imessaging_context(), NULL,
1289 MSG_WINBIND_RELOAD_TRUSTED_DOMAINS,
1290 wb_imsg_new_trusted_domain);
1291 if (!NT_STATUS_IS_OK(status)) {
1292 DBG_ERR("imessaging_register failed %s\n", nt_errstr(status));
1300 * Given a domain name, return the struct winbindd domain info for it
1302 * @note Do *not* pass lp_workgroup() to this function. domain_list
1303 * may modify it's value, and free that pointer. Instead, our local
1304 * domain may be found by calling find_our_domain().
1308 * @return The domain structure for the named domain, if it is working.
1311 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
1313 struct winbindd_domain *domain;
1315 /* Search through list */
1317 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1318 if (strequal(domain_name, domain->name)) {
1321 if (domain->alt_name == NULL) {
1324 if (strequal(domain_name, domain->alt_name)) {
1335 * Given a domain name, return the struct winbindd domain if it's a direct
1338 * @return The domain structure for the named domain, if it is a direct outgoing trust
1340 struct winbindd_domain *find_trust_from_name_noinit(const char *domain_name)
1342 struct winbindd_domain *domain = NULL;
1344 domain = find_domain_from_name_noinit(domain_name);
1345 if (domain == NULL) {
1349 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1356 struct winbindd_domain *find_domain_from_name(const char *domain_name)
1358 struct winbindd_domain *domain;
1360 domain = find_domain_from_name_noinit(domain_name);
1365 if (!domain->initialized)
1366 init_dc_connection(domain, false);
1371 /* Given a domain sid, return the struct winbindd domain info for it */
1373 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
1375 struct winbindd_domain *domain;
1377 /* Search through list */
1379 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1380 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
1390 * Given a domain sid, return the struct winbindd domain if it's a direct
1393 * @return The domain structure for the specified domain, if it is a direct outgoing trust
1395 struct winbindd_domain *find_trust_from_sid_noinit(const struct dom_sid *sid)
1397 struct winbindd_domain *domain = NULL;
1399 domain = find_domain_from_sid_noinit(sid);
1400 if (domain == NULL) {
1404 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1411 /* Given a domain sid, return the struct winbindd domain info for it */
1413 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
1415 struct winbindd_domain *domain;
1417 domain = find_domain_from_sid_noinit(sid);
1422 if (!domain->initialized)
1423 init_dc_connection(domain, false);
1428 struct winbindd_domain *find_our_domain(void)
1430 struct winbindd_domain *domain;
1432 /* Search through list */
1434 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1435 if (domain->primary)
1439 smb_panic("Could not find our domain");
1443 struct winbindd_domain *find_default_route_domain(void)
1446 return find_our_domain();
1448 DBG_DEBUG("Routing logic not yet implemented on a DC\n");
1452 /* Find the appropriate domain to lookup a name or SID */
1454 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
1456 DBG_DEBUG("SID [%s]\n", sid_string_dbg(sid));
1459 * SIDs in the S-1-22-{1,2} domain and well-known SIDs should be handled
1463 if ( sid_check_is_in_unix_groups(sid) ||
1464 sid_check_is_unix_groups(sid) ||
1465 sid_check_is_in_unix_users(sid) ||
1466 sid_check_is_unix_users(sid) ||
1467 sid_check_is_wellknown_domain(sid, NULL) ||
1468 sid_check_is_in_wellknown_domain(sid) )
1470 return find_domain_from_sid(get_global_sam_sid());
1474 * On member servers the internal domains are different: These are part
1478 if (is_internal_domain(sid) || is_in_internal_domain(sid)) {
1479 DEBUG(10, ("calling find_domain_from_sid\n"));
1480 return find_domain_from_sid(sid);
1484 struct winbindd_domain *domain = NULL;
1486 domain = find_domain_from_sid_noinit(sid);
1487 if (domain == NULL) {
1491 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1495 return domain->routing_domain;
1498 /* On a member server a query for SID or name can always go to our
1501 DEBUG(10, ("calling find_our_domain\n"));
1502 return find_our_domain();
1505 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1507 if ( strequal(domain_name, unix_users_domain_name() ) ||
1508 strequal(domain_name, unix_groups_domain_name() ) )
1511 * The "Unix User" and "Unix Group" domain our handled by
1514 return find_domain_from_name_noinit( get_global_sam_name() );
1517 if (strequal(domain_name, "BUILTIN") ||
1518 strequal(domain_name, get_global_sam_name()))
1519 return find_domain_from_name_noinit(domain_name);
1522 struct winbindd_domain *domain = NULL;
1524 domain = find_domain_from_name_noinit(domain_name);
1525 if (domain == NULL) {
1529 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1533 return domain->routing_domain;
1536 return find_our_domain();
1539 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1541 static bool assume_domain(const char *domain)
1543 /* never assume the domain on a standalone server */
1545 if ( lp_server_role() == ROLE_STANDALONE )
1548 /* domain member servers may possibly assume for the domain name */
1550 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1551 if ( !strequal(lp_workgroup(), domain) )
1554 if ( lp_winbind_use_default_domain() )
1558 /* only left with a domain controller */
1560 if ( strequal(get_global_sam_name(), domain) ) {
1567 /* Parse a string of the form DOMAIN\user into a domain and a user */
1569 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1571 char *p = strchr(domuser,*lp_winbind_separator());
1574 fstrcpy(user, domuser);
1575 p = strchr(domuser, '@');
1577 if ( assume_domain(lp_workgroup()) && p == NULL) {
1578 fstrcpy(domain, lp_workgroup());
1579 } else if (p != NULL) {
1580 fstrcpy(domain, p + 1);
1581 user[PTR_DIFF(p, domuser)] = 0;
1587 fstrcpy(domain, domuser);
1588 domain[PTR_DIFF(p, domuser)] = 0;
1591 return strupper_m(domain);
1594 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1595 char **domain, char **user)
1597 fstring fstr_domain, fstr_user;
1598 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1601 *domain = talloc_strdup(mem_ctx, fstr_domain);
1602 *user = talloc_strdup(mem_ctx, fstr_user);
1603 return ((*domain != NULL) && (*user != NULL));
1606 /* Ensure an incoming username from NSS is fully qualified. Replace the
1607 incoming fstring with DOMAIN <separator> user. Returns the same
1608 values as parse_domain_user() but also replaces the incoming username.
1609 Used to ensure all names are fully qualified within winbindd.
1610 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1611 The protocol definitions of auth_crap, chng_pswd_auth_crap
1612 really should be changed to use this instead of doing things
1615 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1617 if (!parse_domain_user(username_inout, domain, user)) {
1620 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1621 domain, *lp_winbind_separator(),
1627 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1628 'winbind separator' options.
1630 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1633 If we are a PDC or BDC, and this is for our domain, do likewise.
1635 On an AD DC we always fill DOMAIN\\USERNAME.
1637 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1639 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1643 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1647 fstrcpy(tmp_user, user);
1648 (void)strlower_m(tmp_user);
1650 if (can_assume && assume_domain(domain)) {
1651 strlcpy(name, tmp_user, sizeof(fstring));
1653 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1654 domain, *lp_winbind_separator(),
1660 * talloc version of fill_domain_username()
1661 * return NULL on talloc failure.
1663 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1668 char *tmp_user, *name;
1670 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1674 tmp_user = talloc_strdup(mem_ctx, user);
1675 if (!strlower_m(tmp_user)) {
1676 TALLOC_FREE(tmp_user);
1680 if (can_assume && assume_domain(domain)) {
1683 name = talloc_asprintf(mem_ctx, "%s%c%s",
1685 *lp_winbind_separator(),
1687 TALLOC_FREE(tmp_user);
1694 * Client list accessor functions
1697 static struct winbindd_cli_state *_client_list;
1698 static int _num_clients;
1700 /* Return list of all connected clients */
1702 struct winbindd_cli_state *winbindd_client_list(void)
1704 return _client_list;
1707 /* Return list-tail of all connected clients */
1709 struct winbindd_cli_state *winbindd_client_list_tail(void)
1711 return DLIST_TAIL(_client_list);
1714 /* Return previous (read:newer) client in list */
1716 struct winbindd_cli_state *
1717 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1719 return DLIST_PREV(cli);
1722 /* Add a connection to the list */
1724 void winbindd_add_client(struct winbindd_cli_state *cli)
1726 cli->last_access = time(NULL);
1727 DLIST_ADD(_client_list, cli);
1731 /* Remove a client from the list */
1733 void winbindd_remove_client(struct winbindd_cli_state *cli)
1735 DLIST_REMOVE(_client_list, cli);
1739 /* Move a client to head or list */
1741 void winbindd_promote_client(struct winbindd_cli_state *cli)
1743 cli->last_access = time(NULL);
1744 DLIST_PROMOTE(_client_list, cli);
1747 /* Return number of open clients */
1749 int winbindd_num_clients(void)
1751 return _num_clients;
1754 NTSTATUS lookup_usergroups_cached(TALLOC_CTX *mem_ctx,
1755 const struct dom_sid *user_sid,
1756 uint32_t *p_num_groups, struct dom_sid **user_sids)
1758 struct netr_SamInfo3 *info3 = NULL;
1759 NTSTATUS status = NT_STATUS_NO_MEMORY;
1760 uint32_t num_groups = 0;
1762 DEBUG(3,(": lookup_usergroups_cached\n"));
1767 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1769 if (info3 == NULL) {
1770 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1774 * Before bug #7843 the "Domain Local" groups were added with a
1775 * lookupuseraliases call, but this isn't done anymore for our domain
1776 * so we need to resolve resource groups here.
1778 * When to use Resource Groups:
1779 * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1781 status = sid_array_from_info3(mem_ctx, info3,
1786 if (!NT_STATUS_IS_OK(status)) {
1792 *p_num_groups = num_groups;
1793 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1795 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1800 /*********************************************************************
1801 We use this to remove spaces from user and group names
1802 ********************************************************************/
1804 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1805 const char *domain_name,
1809 struct winbindd_domain *domain = NULL;
1812 if (!name || !normalized) {
1813 return NT_STATUS_INVALID_PARAMETER;
1816 if (!lp_winbind_normalize_names()) {
1817 return NT_STATUS_PROCEDURE_NOT_FOUND;
1820 domain = find_domain_from_name_noinit(domain_name);
1821 if (domain == NULL) {
1822 DBG_ERR("Failed to find domain '%s'\n", domain_name);
1823 return NT_STATUS_NO_SUCH_DOMAIN;
1826 /* Alias support and whitespace replacement are mutually
1829 nt_status = resolve_username_to_alias(mem_ctx, domain,
1831 if (NT_STATUS_IS_OK(nt_status)) {
1832 /* special return code to let the caller know we
1833 mapped to an alias */
1834 return NT_STATUS_FILE_RENAMED;
1837 /* check for an unreachable domain */
1839 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1840 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1842 set_domain_offline(domain);
1846 /* deal with whitespace */
1848 *normalized = talloc_strdup(mem_ctx, name);
1849 if (!(*normalized)) {
1850 return NT_STATUS_NO_MEMORY;
1853 all_string_sub( *normalized, " ", "_", 0 );
1855 return NT_STATUS_OK;
1858 /*********************************************************************
1859 We use this to do the inverse of normalize_name_map()
1860 ********************************************************************/
1862 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1867 struct winbindd_domain *domain = find_our_domain();
1869 if (!name || !normalized) {
1870 return NT_STATUS_INVALID_PARAMETER;
1873 if (!lp_winbind_normalize_names()) {
1874 return NT_STATUS_PROCEDURE_NOT_FOUND;
1877 /* Alias support and whitespace replacement are mutally
1880 /* When mapping from an alias to a username, we don't know the
1881 domain. But we only need a domain structure to cache
1882 a successful lookup , so just our own domain structure for
1885 nt_status = resolve_alias_to_username(mem_ctx, domain,
1887 if (NT_STATUS_IS_OK(nt_status)) {
1888 /* Special return code to let the caller know we mapped
1890 return NT_STATUS_FILE_RENAMED;
1893 /* check for an unreachable domain */
1895 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1896 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1898 set_domain_offline(domain);
1902 /* deal with whitespace */
1904 *normalized = talloc_strdup(mem_ctx, name);
1905 if (!(*normalized)) {
1906 return NT_STATUS_NO_MEMORY;
1909 all_string_sub(*normalized, "_", " ", 0);
1911 return NT_STATUS_OK;
1914 /*********************************************************************
1915 ********************************************************************/
1917 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1919 struct winbindd_tdc_domain *tdc = NULL;
1920 TALLOC_CTX *frame = talloc_stackframe();
1923 /* We can contact the domain if it is our primary domain */
1925 if (domain->primary) {
1930 /* Trust the TDC cache and not the winbindd_domain flags */
1932 if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1933 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1939 /* Can always contact a domain that is in out forest */
1941 if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1947 * On a _member_ server, we cannot contact the domain if it
1948 * is running AD and we have no inbound trust.
1952 domain->active_directory &&
1953 ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1955 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1956 "and we have no inbound trust.\n", domain->name));
1960 /* Assume everything else is ok (probably not true but what
1966 talloc_destroy(frame);
1971 /*********************************************************************
1972 ********************************************************************/
1974 bool winbindd_internal_child(struct winbindd_child *child)
1976 if ((child == idmap_child()) || (child == locator_child())) {
1983 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1985 /*********************************************************************
1986 ********************************************************************/
1988 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1991 char addr[INET6_ADDRSTRLEN];
1992 const char *kdc = NULL;
1995 if (!domain || !domain->alt_name || !*domain->alt_name) {
1999 if (domain->initialized && !domain->active_directory) {
2000 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
2005 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
2008 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
2010 kdc = domain->dcname;
2013 if (!kdc || !*kdc) {
2014 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
2019 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
2020 domain->alt_name) == -1) {
2024 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
2027 setenv(var, kdc, 1);
2031 /*********************************************************************
2032 ********************************************************************/
2034 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
2036 struct winbindd_domain *our_dom = find_our_domain();
2038 winbindd_set_locator_kdc_env(domain);
2040 if (domain != our_dom) {
2041 winbindd_set_locator_kdc_env(our_dom);
2045 /*********************************************************************
2046 ********************************************************************/
2048 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
2052 if (!domain || !domain->alt_name || !*domain->alt_name) {
2056 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
2057 domain->alt_name) == -1) {
2066 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
2071 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
2076 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
2078 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
2080 resp->data.auth.nt_status = NT_STATUS_V(result);
2081 fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
2083 /* we might have given a more useful error above */
2084 if (*resp->data.auth.error_string == '\0')
2085 fstrcpy(resp->data.auth.error_string,
2086 get_friendly_nt_error_msg(result));
2087 resp->data.auth.pam_error = nt_status_to_pam(result);
2090 bool is_domain_offline(const struct winbindd_domain *domain)
2092 if (get_global_winbindd_state_offline()) {
2095 return !domain->online;
2098 bool is_domain_online(const struct winbindd_domain *domain)
2100 return !is_domain_offline(domain);
2104 * Parse an char array into a list of sids.
2106 * The input sidstr should consist of 0-terminated strings
2107 * representing sids, separated by newline characters '\n'.
2108 * The list is terminated by an empty string, i.e.
2109 * character '\0' directly following a character '\n'
2110 * (or '\0' right at the start of sidstr).
2112 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
2113 struct dom_sid **sids, uint32_t *num_sids)
2121 while (p[0] != '\0') {
2123 const char *q = NULL;
2125 if (!dom_sid_parse_endp(p, &sid, &q)) {
2126 DEBUG(1, ("Could not parse sid %s\n", p));
2130 DEBUG(1, ("Got invalid sidstr: %s\n", p));
2133 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
2143 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
2144 struct unixid **pxids, uint32_t *pnum_xids)
2147 struct unixid *xids = NULL;
2148 uint32_t num_xids = 0;
2155 while (p[0] != '\0') {
2158 unsigned long long id;
2163 xid = (struct unixid) { .type = ID_TYPE_UID };
2166 xid = (struct unixid) { .type = ID_TYPE_GID };
2174 id = strtoull(p, &endp, 10);
2175 if ((id == ULLONG_MAX) && (errno == ERANGE)) {
2178 if (*endp != '\n') {
2184 if ((unsigned long long)xid.id != id) {
2188 tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
2194 xids[num_xids] = xid;
2199 *pnum_xids = num_xids;