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.
47 /* The list of trusted domains. Note that the list can be deleted and
48 recreated using the init_domain_list() function so pointers to
49 individual winbindd_domain structures cannot be made. Keep a copy of
50 the domain name instead. */
52 static struct winbindd_domain *_domain_list = NULL;
54 struct winbindd_domain *domain_list(void)
58 if ((!_domain_list) && (!init_domain_list())) {
59 smb_panic("Init_domain_list failed");
65 /* Free all entries in the trusted domain list */
67 static void free_domain_list(void)
69 struct winbindd_domain *domain = _domain_list;
72 struct winbindd_domain *next = domain->next;
74 DLIST_REMOVE(_domain_list, domain);
81 * Iterator for winbindd's domain list.
82 * To be used (e.g.) in tevent based loops.
84 struct winbindd_domain *wb_next_domain(struct winbindd_domain *domain)
87 domain = domain_list();
89 domain = domain->next;
92 if ((domain != NULL) &&
93 (lp_server_role() != ROLE_ACTIVE_DIRECTORY_DC) &&
94 sid_check_is_our_sam(&domain->sid))
96 domain = domain->next;
102 static bool is_internal_domain(const struct dom_sid *sid)
107 return (sid_check_is_our_sam(sid) || sid_check_is_builtin(sid));
110 static bool is_in_internal_domain(const struct dom_sid *sid)
115 return (sid_check_is_in_our_sam(sid) || sid_check_is_in_builtin(sid));
119 /* Add a trusted domain to our list of domains.
120 If the domain already exists in the list,
121 return it and don't re-initialize. */
123 static NTSTATUS add_trusted_domain(const char *domain_name,
124 const char *dns_name,
125 const struct dom_sid *sid,
127 uint32_t trust_flags,
128 uint32_t trust_attribs,
129 enum netr_SchannelType secure_channel_type,
130 struct winbindd_domain *routing_domain,
131 struct winbindd_domain **_d)
133 struct winbindd_domain *domain = NULL;
134 const char **ignored_domains = NULL;
135 const char **dom = NULL;
136 int role = lp_server_role();
138 if (is_null_sid(sid)) {
139 DBG_ERR("Got null SID for domain [%s]\n", domain_name);
140 return NT_STATUS_INVALID_PARAMETER;
143 ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
144 for (dom=ignored_domains; dom && *dom; dom++) {
145 if (gen_fnmatch(*dom, domain_name) == 0) {
146 DEBUG(2,("Ignoring domain '%s'\n", domain_name));
147 return NT_STATUS_NO_SUCH_DOMAIN;
152 * We can't call domain_list() as this function is called from
153 * init_domain_list() and we'll get stuck in a loop.
155 for (domain = _domain_list; domain; domain = domain->next) {
156 if (strequal(domain_name, domain->name)) {
161 if (domain != NULL) {
162 struct winbindd_domain *check_domain = NULL;
164 for (check_domain = _domain_list;
165 check_domain != NULL;
166 check_domain = check_domain->next)
168 if (check_domain == domain) {
172 if (dom_sid_equal(&check_domain->sid, sid)) {
177 if (check_domain != NULL) {
178 DBG_ERR("SID [%s] already used by domain [%s], "
180 sid_string_dbg(sid), check_domain->name,
182 return NT_STATUS_INVALID_PARAMETER;
186 if ((domain != NULL) && (dns_name != NULL)) {
187 struct winbindd_domain *check_domain = NULL;
189 for (check_domain = _domain_list;
190 check_domain != NULL;
191 check_domain = check_domain->next)
193 if (check_domain == domain) {
197 if (strequal(check_domain->alt_name, dns_name)) {
202 if (check_domain != NULL) {
203 DBG_ERR("DNS name [%s] used by domain [%s], "
205 dns_name, check_domain->name,
207 return NT_STATUS_INVALID_PARAMETER;
211 if (domain != NULL) {
216 /* Create new domain entry */
217 domain = talloc_zero(NULL, struct winbindd_domain);
218 if (domain == NULL) {
219 return NT_STATUS_NO_MEMORY;
222 domain->children = talloc_zero_array(domain,
223 struct winbindd_child,
224 lp_winbind_max_domain_connections());
225 if (domain->children == NULL) {
227 return NT_STATUS_NO_MEMORY;
230 domain->name = talloc_strdup(domain, domain_name);
231 if (domain->name == NULL) {
233 return NT_STATUS_NO_MEMORY;
236 if (dns_name != NULL) {
237 domain->alt_name = talloc_strdup(domain, dns_name);
238 if (domain->alt_name == NULL) {
240 return NT_STATUS_NO_MEMORY;
244 domain->backend = NULL;
245 domain->internal = is_internal_domain(sid);
246 domain->secure_channel_type = secure_channel_type;
247 domain->sequence_number = DOM_SEQUENCE_NONE;
248 domain->last_seq_check = 0;
249 domain->initialized = false;
250 domain->online = is_internal_domain(sid);
251 domain->check_online_timeout = 0;
252 domain->dc_probe_pid = (pid_t)-1;
253 domain->domain_flags = trust_flags;
254 domain->domain_type = trust_type;
255 domain->domain_trust_attribs = trust_attribs;
256 domain->secure_channel_type = secure_channel_type;
257 domain->routing_domain = routing_domain;
258 sid_copy(&domain->sid, sid);
260 /* Is this our primary domain ? */
261 if (role == ROLE_DOMAIN_MEMBER) {
262 domain->primary = strequal(domain_name, lp_workgroup());
264 domain->primary = strequal(domain_name, get_global_sam_name());
267 if (domain->primary) {
268 if (role == ROLE_ACTIVE_DIRECTORY_DC) {
269 domain->active_directory = true;
271 if (lp_security() == SEC_ADS) {
272 domain->active_directory = true;
274 } else if (!domain->internal) {
275 if (domain->domain_type == LSA_TRUST_TYPE_UPLEVEL) {
276 domain->active_directory = true;
280 domain->can_do_ncacn_ip_tcp = domain->active_directory;
282 /* Link to domain list */
283 DLIST_ADD_END(_domain_list, domain);
285 wcache_tdc_add_domain( domain );
287 setup_domain_child(domain);
289 DBG_NOTICE("Added domain [%s] [%s] [%s]\n",
290 domain->name, domain->alt_name,
291 sid_string_dbg(&domain->sid));
297 bool set_routing_domain(struct winbindd_domain *domain,
298 struct winbindd_domain *routing_domain)
300 if (domain->routing_domain == NULL) {
301 domain->routing_domain = routing_domain;
304 if (domain->routing_domain != routing_domain) {
310 bool add_trusted_domain_from_auth(uint16_t validation_level,
311 struct info3_text *info3,
312 struct info6_text *info6)
314 struct winbindd_domain *domain = NULL;
315 struct dom_sid domain_sid;
316 const char *dns_domainname = NULL;
321 * We got a successfull auth from a domain that might not yet be in our
322 * domain list. If we're a member we trust our DC who authenticated the
323 * user from that domain and add the domain to our list on-the-fly. If
324 * we're a DC we rely on configured trusts and don't add on-the-fly.
331 ok = dom_sid_parse(info3->dom_sid, &domain_sid);
333 DBG_NOTICE("dom_sid_parse [%s] failed\n", info3->dom_sid);
337 if (validation_level == 6) {
338 dns_domainname = &info6->dns_domainname[0];
341 status = add_trusted_domain(info3->logon_dom,
345 NETR_TRUST_FLAG_OUTBOUND,
348 find_default_route_domain(),
350 if (!NT_STATUS_IS_OK(status) &&
351 !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
353 DBG_DEBUG("Adding domain [%s] with sid [%s] failed\n",
354 info3->logon_dom, info3->dom_sid);
361 bool domain_is_forest_root(const struct winbindd_domain *domain)
363 const uint32_t fr_flags =
364 (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
366 return ((domain->domain_flags & fr_flags) == fr_flags);
369 /********************************************************************
370 rescan our domains looking for new trusted domains
371 ********************************************************************/
373 struct trustdom_state {
374 struct winbindd_domain *domain;
375 struct winbindd_request request;
378 static void trustdom_list_done(struct tevent_req *req);
379 static void rescan_forest_root_trusts( void );
380 static void rescan_forest_trusts( void );
382 static void add_trusted_domains( struct winbindd_domain *domain )
384 struct trustdom_state *state;
385 struct tevent_req *req;
387 state = talloc_zero(NULL, struct trustdom_state);
389 DEBUG(0, ("talloc failed\n"));
392 state->domain = domain;
394 state->request.length = sizeof(state->request);
395 state->request.cmd = WINBINDD_LIST_TRUSTDOM;
397 req = wb_domain_request_send(state, server_event_context(),
398 domain, &state->request);
400 DEBUG(1, ("wb_domain_request_send failed\n"));
404 tevent_req_set_callback(req, trustdom_list_done, state);
407 static void trustdom_list_done(struct tevent_req *req)
409 struct trustdom_state *state = tevent_req_callback_data(
410 req, struct trustdom_state);
411 struct winbindd_response *response;
415 bool within_forest = false;
419 * Only when we enumerate our primary domain
420 * or our forest root domain, we should keep
421 * the NETR_TRUST_FLAG_IN_FOREST flag, in
422 * all other cases we need to clear it as the domain
423 * is not part of our forest.
425 if (state->domain->primary) {
426 within_forest = true;
427 } else if (domain_is_forest_root(state->domain)) {
428 within_forest = true;
431 res = wb_domain_request_recv(req, state, &response, &err);
432 if ((res == -1) || (response->result != WINBINDD_OK)) {
433 DBG_WARNING("Could not receive trusts for domain %s\n",
434 state->domain->name);
439 if (response->length < sizeof(struct winbindd_response)) {
440 DBG_ERR("ill-formed trustdom response - short length\n");
445 extra_len = response->length - sizeof(struct winbindd_response);
447 p = (char *)response->extra_data.data;
449 while ((p - (char *)response->extra_data.data) < extra_len) {
450 struct winbindd_domain *domain = NULL;
451 char *name, *q, *sidstr, *alt_name;
454 uint32_t trust_attribs;
455 uint32_t trust_flags;
457 DBG_DEBUG("parsing response line '%s'\n", p);
461 alt_name = strchr(p, '\\');
462 if (alt_name == NULL) {
463 DBG_ERR("Got invalid trustdom response\n");
470 sidstr = strchr(alt_name, '\\');
471 if (sidstr == NULL) {
472 DBG_ERR("Got invalid trustdom response\n");
479 /* use the real alt_name if we have one, else pass in NULL */
480 if (strequal(alt_name, "(null)")) {
484 q = strtok(sidstr, "\\");
486 DBG_ERR("Got invalid trustdom response\n");
490 if (!string_to_sid(&sid, sidstr)) {
491 DEBUG(0, ("Got invalid trustdom response\n"));
495 q = strtok(NULL, "\\");
497 DBG_ERR("Got invalid trustdom response\n");
501 trust_flags = (uint32_t)strtoul(q, NULL, 10);
503 q = strtok(NULL, "\\");
505 DBG_ERR("Got invalid trustdom response\n");
509 trust_type = (uint32_t)strtoul(q, NULL, 10);
511 q = strtok(NULL, "\n");
513 DBG_ERR("Got invalid trustdom response\n");
517 trust_attribs = (uint32_t)strtoul(q, NULL, 10);
519 if (!within_forest) {
520 trust_flags &= ~NETR_TRUST_FLAG_IN_FOREST;
523 if (!state->domain->primary) {
524 trust_flags &= ~NETR_TRUST_FLAG_PRIMARY;
528 * We always call add_trusted_domain() cause on an existing
529 * domain structure, it will update the SID if necessary.
530 * This is important because we need the SID for sibling
533 status = add_trusted_domain(name,
540 find_default_route_domain(),
542 if (!NT_STATUS_IS_OK(status) &&
543 !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
545 DBG_NOTICE("add_trusted_domain returned %s\n",
550 p = q + strlen(q) + 1;
554 Cases to consider when scanning trusts:
555 (a) we are calling from a child domain (primary && !forest_root)
556 (b) we are calling from the root of the forest (primary && forest_root)
557 (c) we are calling from a trusted forest domain (!primary
561 if (state->domain->primary) {
562 /* If this is our primary domain and we are not in the
563 forest root, we have to scan the root trusts first */
565 if (!domain_is_forest_root(state->domain))
566 rescan_forest_root_trusts();
568 rescan_forest_trusts();
570 } else if (domain_is_forest_root(state->domain)) {
571 /* Once we have done root forest trust search, we can
572 go on to search the trusted forests */
574 rescan_forest_trusts();
582 /********************************************************************
583 Scan the trusts of our forest root
584 ********************************************************************/
586 static void rescan_forest_root_trusts( void )
588 struct winbindd_tdc_domain *dom_list = NULL;
589 size_t num_trusts = 0;
593 /* The only transitive trusts supported by Windows 2003 AD are
594 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
595 first two are handled in forest and listed by
596 DsEnumerateDomainTrusts(). Forest trusts are not so we
597 have to do that ourselves. */
599 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
602 for ( i=0; i<num_trusts; i++ ) {
603 struct winbindd_domain *d = NULL;
605 /* Find the forest root. Don't necessarily trust
606 the domain_list() as our primary domain may not
607 have been initialized. */
609 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
613 /* Here's the forest root */
615 d = find_domain_from_name_noinit( dom_list[i].domain_name );
617 status = add_trusted_domain(dom_list[i].domain_name,
618 dom_list[i].dns_name,
620 dom_list[i].trust_type,
621 dom_list[i].trust_flags,
622 dom_list[i].trust_attribs,
624 find_default_route_domain(),
627 if (!NT_STATUS_IS_OK(status) &&
628 NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
630 DBG_ERR("add_trusted_domain returned %s\n",
639 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
640 "for domain tree root %s (%s)\n",
641 d->name, d->alt_name ));
643 d->domain_flags = dom_list[i].trust_flags;
644 d->domain_type = dom_list[i].trust_type;
645 d->domain_trust_attribs = dom_list[i].trust_attribs;
647 add_trusted_domains( d );
652 TALLOC_FREE( dom_list );
657 /********************************************************************
658 scan the transitive forest trusts (not our own)
659 ********************************************************************/
662 static void rescan_forest_trusts( void )
664 struct winbindd_domain *d = NULL;
665 struct winbindd_tdc_domain *dom_list = NULL;
666 size_t num_trusts = 0;
670 /* The only transitive trusts supported by Windows 2003 AD are
671 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
672 first two are handled in forest and listed by
673 DsEnumerateDomainTrusts(). Forest trusts are not so we
674 have to do that ourselves. */
676 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
679 for ( i=0; i<num_trusts; i++ ) {
680 uint32_t flags = dom_list[i].trust_flags;
681 uint32_t type = dom_list[i].trust_type;
682 uint32_t attribs = dom_list[i].trust_attribs;
684 d = find_domain_from_name_noinit( dom_list[i].domain_name );
686 /* ignore our primary and internal domains */
688 if ( d && (d->internal || d->primary ) )
691 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
692 (type == LSA_TRUST_TYPE_UPLEVEL) &&
693 (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
695 /* add the trusted domain if we don't know
699 status = add_trusted_domain(
700 dom_list[i].domain_name,
701 dom_list[i].dns_name,
707 find_default_route_domain(),
709 if (!NT_STATUS_IS_OK(status) &&
710 NT_STATUS_EQUAL(status,
711 NT_STATUS_NO_SUCH_DOMAIN))
713 DBG_ERR("add_trusted_domain: %s\n",
723 DEBUG(10,("Following trust path for domain %s (%s)\n",
724 d->name, d->alt_name ));
725 add_trusted_domains( d );
729 TALLOC_FREE( dom_list );
734 /*********************************************************************
735 The process of updating the trusted domain list is a three step
738 (b) ask the root domain in our forest
739 (c) ask the a DC in any Win2003 trusted forests
740 *********************************************************************/
742 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
743 struct timeval now, void *private_data)
747 /* I use to clear the cache here and start over but that
748 caused problems in child processes that needed the
749 trust dom list early on. Removing it means we
750 could have some trusted domains listed that have been
751 removed from our primary domain's DC until a full
752 restart. This should be ok since I think this is what
753 Windows does as well. */
755 /* this will only add new domains we didn't already know about
756 in the domain_list()*/
758 add_trusted_domains( find_our_domain() );
760 te = tevent_add_timer(
761 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
762 rescan_trusted_domains, NULL);
764 * If te == NULL, there's not much we can do here. Don't fail, the
765 * only thing we miss is new trusted domains.
771 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
772 struct winbindd_cli_state *state)
774 /* Ensure null termination */
775 state->request->domain_name
776 [sizeof(state->request->domain_name)-1]='\0';
777 state->request->data.init_conn.dcname
778 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
780 if (strlen(state->request->data.init_conn.dcname) > 0) {
781 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
784 init_dc_connection(domain, false);
786 if (!domain->initialized) {
787 /* If we return error here we can't do any cached authentication,
788 but we may be in disconnected mode and can't initialize correctly.
789 Do what the previous code did and just return without initialization,
790 once we go online we'll re-initialize.
792 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
793 "online = %d\n", domain->name, (int)domain->online ));
796 fstrcpy(state->response->data.domain_info.name, domain->name);
797 fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
798 sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
800 state->response->data.domain_info.native_mode
801 = domain->native_mode;
802 state->response->data.domain_info.active_directory
803 = domain->active_directory;
804 state->response->data.domain_info.primary
810 static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
813 struct server_id server_id,
816 TALLOC_CTX *frame = talloc_stackframe();
817 enum netr_SchannelType secure_channel_type = SEC_CHAN_DOMAIN;
818 struct lsa_TrustDomainInfoInfoEx info;
819 enum ndr_err_code ndr_err;
820 struct winbindd_domain *d = NULL;
821 uint32_t trust_flags = 0;
824 DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
831 ndr_err = ndr_pull_struct_blob_all(data, frame, &info,
832 (ndr_pull_flags_fn_t)ndr_pull_lsa_TrustDomainInfoInfoEx);
833 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
838 d = find_domain_from_name_noinit(info.netbios_name.string);
844 if (info.trust_type == LSA_TRUST_TYPE_UPLEVEL) {
845 secure_channel_type = SEC_CHAN_DNS_DOMAIN;
847 if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
848 trust_flags |= NETR_TRUST_FLAG_INBOUND;
850 if (info.trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
851 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
853 if (info.trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
854 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
857 status = add_trusted_domain(info.netbios_name.string,
858 info.domain_name.string,
862 info.trust_attributes,
864 find_default_route_domain(),
866 if (!NT_STATUS_IS_OK(status) &&
867 !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
869 DBG_NOTICE("add_trusted_domain returned %s\n",
879 * We did not get the secret when we queried secrets.tdb, so read it
880 * from secrets.tdb and re-sync the databases
882 static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
885 struct cli_credentials *creds;
886 NTSTATUS can_migrate = pdb_get_trust_credentials(domain->name,
887 NULL, domain, &creds);
888 if (!NT_STATUS_IS_OK(can_migrate)) {
889 DEBUG(0, ("Failed to fetch our own, local AD domain join "
890 "password for winbindd's internal use, both from "
891 "secrets.tdb and secrets.ldb: %s\n",
892 nt_errstr(can_migrate)));
897 * NOTE: It is very unlikely we end up here if there is an
898 * oldpass, because a new password is created at
899 * classicupgrade, so this is not a concern.
901 ok = secrets_store_machine_pw_sync(cli_credentials_get_password(creds),
903 cli_credentials_get_domain(creds),
904 cli_credentials_get_realm(creds),
905 cli_credentials_get_salt_principal(creds),
906 0, /* Supported enc types, unused */
908 cli_credentials_get_password_last_changed_time(creds),
909 cli_credentials_get_secure_channel_type(creds),
910 false /* do_delete: Do not delete */);
913 DEBUG(0, ("Failed to write our our own, "
914 "local AD domain join password for "
915 "winbindd's internal use into secrets.tdb\n"));
921 static bool add_trusted_domains_dc(void)
923 struct winbindd_domain *domain = NULL;
924 struct pdb_trusted_domain **domains = NULL;
925 uint32_t num_domains = 0;
929 if (!(pdb_capabilities() & PDB_CAP_TRUSTED_DOMAINS_EX)) {
930 struct trustdom_info **ti = NULL;
932 status = pdb_enum_trusteddoms(talloc_tos(), &num_domains, &ti);
933 if (!NT_STATUS_IS_OK(status)) {
934 DBG_ERR("pdb_enum_trusteddoms() failed - %s\n",
939 for (i = 0; i < num_domains; i++) {
940 status = add_trusted_domain(ti[i]->name,
943 LSA_TRUST_TYPE_DOWNLEVEL,
944 NETR_TRUST_FLAG_OUTBOUND,
949 if (!NT_STATUS_IS_OK(status)) {
950 DBG_NOTICE("add_trusted_domain returned %s\n",
955 /* Even in the parent winbindd we'll need to
956 talk to the DC, so try and see if we can
957 contact it. Theoretically this isn't neccessary
958 as the init_dc_connection() in init_child_recv()
959 will do this, but we can start detecting the DC
961 set_domain_online_request(domain);
967 status = pdb_enum_trusted_domains(talloc_tos(), &num_domains, &domains);
968 if (!NT_STATUS_IS_OK(status)) {
969 DBG_ERR("pdb_enum_trusted_domains() failed - %s\n",
974 for (i = 0; i < num_domains; i++) {
975 enum netr_SchannelType sec_chan_type = SEC_CHAN_DOMAIN;
976 uint32_t trust_flags = 0;
978 if (domains[i]->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
979 sec_chan_type = SEC_CHAN_DNS_DOMAIN;
982 if (!(domains[i]->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND)) {
983 sec_chan_type = SEC_CHAN_NULL;
986 if (domains[i]->trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
987 trust_flags |= NETR_TRUST_FLAG_INBOUND;
989 if (domains[i]->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
990 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
992 if (domains[i]->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
993 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
996 status = add_trusted_domain(domains[i]->netbios_name,
997 domains[i]->domain_name,
998 &domains[i]->security_identifier,
999 domains[i]->trust_type,
1001 domains[i]->trust_attributes,
1005 if (!NT_STATUS_IS_OK(status)) {
1006 DBG_NOTICE("add_trusted_domain returned %s\n",
1011 if (domains[i]->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
1012 domain->active_directory = true;
1014 domain->domain_type = domains[i]->trust_type;
1015 domain->domain_trust_attribs = domains[i]->trust_attributes;
1017 if (sec_chan_type != SEC_CHAN_NULL) {
1018 /* Even in the parent winbindd we'll need to
1019 talk to the DC, so try and see if we can
1020 contact it. Theoretically this isn't neccessary
1021 as the init_dc_connection() in init_child_recv()
1022 will do this, but we can start detecting the DC
1024 set_domain_online_request(domain);
1028 for (i = 0; i < num_domains; i++) {
1029 struct ForestTrustInfo fti;
1031 enum ndr_err_code ndr_err;
1032 struct winbindd_domain *routing_domain = NULL;
1034 if (domains[i]->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
1038 if (!(domains[i]->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1042 if (domains[i]->trust_forest_trust_info.length == 0) {
1046 routing_domain = find_domain_from_name_noinit(
1047 domains[i]->netbios_name);
1048 if (routing_domain == NULL) {
1049 DBG_ERR("Can't find winbindd domain [%s]\n",
1050 domains[i]->netbios_name);
1054 ndr_err = ndr_pull_struct_blob_all(
1055 &domains[i]->trust_forest_trust_info,
1057 (ndr_pull_flags_fn_t)ndr_pull_ForestTrustInfo);
1058 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1059 DBG_ERR("ndr_pull_ForestTrustInfo(%s) - %s\n",
1060 domains[i]->netbios_name,
1061 ndr_map_error2string(ndr_err));
1065 for (fi = 0; fi < fti.count; fi++) {
1066 struct ForestTrustInfoRecord *rec =
1067 &fti.records[fi].record;
1068 struct ForestTrustDataDomainInfo *drec = NULL;
1070 if (rec->type != FOREST_TRUST_DOMAIN_INFO) {
1073 drec = &rec->data.info;
1075 if (rec->flags & LSA_NB_DISABLED_MASK) {
1079 if (rec->flags & LSA_SID_DISABLED_MASK) {
1085 * also try to find a matching
1086 * LSA_TLN_DISABLED_MASK ???
1089 domain = find_domain_from_name_noinit(drec->netbios_name.string);
1090 if (domain != NULL) {
1094 status = add_trusted_domain(drec->netbios_name.string,
1095 drec->dns_name.string,
1097 LSA_TRUST_TYPE_UPLEVEL,
1098 NETR_TRUST_FLAG_OUTBOUND,
1103 if (!NT_STATUS_IS_OK(status)) {
1104 DBG_NOTICE("add_trusted_domain returned %s\n",
1108 if (domain == NULL) {
1118 /* Look up global info for the winbind daemon */
1119 bool init_domain_list(void)
1121 int role = lp_server_role();
1122 struct pdb_domain_info *pdb_domain_info = NULL;
1123 struct winbindd_domain *domain = NULL;
1127 /* Free existing list */
1130 /* BUILTIN domain */
1132 status = add_trusted_domain("BUILTIN",
1134 &global_sid_Builtin,
1135 LSA_TRUST_TYPE_DOWNLEVEL,
1136 0, /* trust_flags */
1137 0, /* trust_attribs */
1141 if (!NT_STATUS_IS_OK(status)) {
1142 DBG_ERR("add_trusted_domain BUILTIN returned %s\n",
1150 * In case the passdb backend is passdb_dsdb the domain SID comes from
1151 * dsdb, not from secrets.tdb. As we use the domain SID in various
1152 * places, we must ensure the domain SID is migrated from dsdb to
1153 * secrets.tdb before get_global_sam_sid() is called the first time.
1155 * The migration is done as part of the passdb_dsdb initialisation,
1156 * calling pdb_get_domain_info() triggers it.
1158 pdb_domain_info = pdb_get_domain_info(talloc_tos());
1160 if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
1161 uint32_t trust_flags;
1163 enum netr_SchannelType sec_chan_type;
1164 const char *account_name;
1165 struct samr_Password current_nt_hash;
1167 if (pdb_domain_info == NULL) {
1168 DEBUG(0, ("Failed to fetch our own, local AD "
1169 "domain info from sam.ldb\n"));
1173 trust_flags = NETR_TRUST_FLAG_PRIMARY;
1174 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
1175 trust_flags |= NETR_TRUST_FLAG_NATIVE;
1176 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
1178 is_root = strequal(pdb_domain_info->dns_domain,
1179 pdb_domain_info->dns_forest);
1181 trust_flags |= NETR_TRUST_FLAG_TREEROOT;
1184 status = add_trusted_domain(pdb_domain_info->name,
1185 pdb_domain_info->dns_domain,
1186 &pdb_domain_info->sid,
1187 LSA_TRUST_TYPE_UPLEVEL,
1189 LSA_TRUST_ATTRIBUTE_WITHIN_FOREST,
1193 TALLOC_FREE(pdb_domain_info);
1194 if (!NT_STATUS_IS_OK(status)) {
1195 DBG_ERR("Failed to add our own, local AD "
1196 "domain to winbindd's internal list\n");
1201 * We need to call this to find out if we are an RODC
1203 ok = get_trust_pw_hash(domain->name,
1204 current_nt_hash.hash,
1209 * If get_trust_pw_hash() fails, then try and
1210 * fetch the password from the more recent of
1211 * secrets.{ldb,tdb} using the
1212 * pdb_get_trust_credentials()
1214 ok = migrate_secrets_tdb_to_ldb(domain);
1217 DEBUG(0, ("Failed to migrate our own, "
1218 "local AD domain join password for "
1219 "winbindd's internal use into "
1223 ok = get_trust_pw_hash(domain->name,
1224 current_nt_hash.hash,
1228 DEBUG(0, ("Failed to find our our own, just "
1229 "written local AD domain join "
1230 "password for winbindd's internal "
1231 "use in secrets.tdb\n"));
1236 domain->secure_channel_type = sec_chan_type;
1237 if (sec_chan_type == SEC_CHAN_RODC) {
1238 domain->rodc = true;
1242 uint32_t trust_flags;
1243 enum netr_SchannelType secure_channel_type;
1245 trust_flags = NETR_TRUST_FLAG_OUTBOUND;
1246 if (role != ROLE_DOMAIN_MEMBER) {
1247 trust_flags |= NETR_TRUST_FLAG_PRIMARY;
1250 if (role > ROLE_DOMAIN_MEMBER) {
1251 secure_channel_type = SEC_CHAN_BDC;
1253 secure_channel_type = SEC_CHAN_LOCAL;
1256 status = add_trusted_domain(get_global_sam_name(),
1258 get_global_sam_sid(),
1259 LSA_TRUST_TYPE_DOWNLEVEL,
1261 0, /* trust_attribs */
1262 secure_channel_type,
1265 if (!NT_STATUS_IS_OK(status)) {
1266 DBG_ERR("Failed to add local SAM to "
1267 "domain to winbindd's internal list\n");
1273 ok = add_trusted_domains_dc();
1275 DBG_ERR("init_domain_list_dc failed\n");
1280 if ( role == ROLE_DOMAIN_MEMBER ) {
1281 struct dom_sid our_sid;
1282 uint32_t trust_type;
1284 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
1285 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
1289 if (lp_realm() != NULL) {
1290 trust_type = LSA_TRUST_TYPE_UPLEVEL;
1292 trust_type = LSA_TRUST_TYPE_DOWNLEVEL;
1295 status = add_trusted_domain(lp_workgroup(),
1299 NETR_TRUST_FLAG_PRIMARY|
1300 NETR_TRUST_FLAG_OUTBOUND,
1301 0, /* trust_attribs */
1305 if (!NT_STATUS_IS_OK(status)) {
1306 DBG_ERR("Failed to add local SAM to "
1307 "domain to winbindd's internal list\n");
1310 /* Even in the parent winbindd we'll need to
1311 talk to the DC, so try and see if we can
1312 contact it. Theoretically this isn't neccessary
1313 as the init_dc_connection() in init_child_recv()
1314 will do this, but we can start detecting the DC
1316 set_domain_online_request(domain);
1320 status = imessaging_register(winbind_imessaging_context(), NULL,
1321 MSG_WINBIND_NEW_TRUSTED_DOMAIN,
1322 wb_imsg_new_trusted_domain);
1323 if (!NT_STATUS_IS_OK(status)) {
1324 DBG_ERR("imessaging_register failed %s\n", nt_errstr(status));
1332 * Given a domain name, return the struct winbindd domain info for it
1334 * @note Do *not* pass lp_workgroup() to this function. domain_list
1335 * may modify it's value, and free that pointer. Instead, our local
1336 * domain may be found by calling find_our_domain().
1340 * @return The domain structure for the named domain, if it is working.
1343 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
1345 struct winbindd_domain *domain;
1347 /* Search through list */
1349 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1350 if (strequal(domain_name, domain->name)) {
1353 if (domain->alt_name == NULL) {
1356 if (strequal(domain_name, domain->alt_name)) {
1367 * Given a domain name, return the struct winbindd domain if it's a direct
1370 * @return The domain structure for the named domain, if it is a direct outgoing trust
1372 struct winbindd_domain *find_trust_from_name_noinit(const char *domain_name)
1374 struct winbindd_domain *domain = NULL;
1376 domain = find_domain_from_name_noinit(domain_name);
1377 if (domain == NULL) {
1381 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1388 struct winbindd_domain *find_domain_from_name(const char *domain_name)
1390 struct winbindd_domain *domain;
1392 domain = find_domain_from_name_noinit(domain_name);
1397 if (!domain->initialized)
1398 init_dc_connection(domain, false);
1403 /* Given a domain sid, return the struct winbindd domain info for it */
1405 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
1407 struct winbindd_domain *domain;
1409 /* Search through list */
1411 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1412 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
1422 * Given a domain sid, return the struct winbindd domain if it's a direct
1425 * @return The domain structure for the specified domain, if it is a direct outgoing trust
1427 struct winbindd_domain *find_trust_from_sid_noinit(const struct dom_sid *sid)
1429 struct winbindd_domain *domain = NULL;
1431 domain = find_domain_from_sid_noinit(sid);
1432 if (domain == NULL) {
1436 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1443 /* Given a domain sid, return the struct winbindd domain info for it */
1445 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
1447 struct winbindd_domain *domain;
1449 domain = find_domain_from_sid_noinit(sid);
1454 if (!domain->initialized)
1455 init_dc_connection(domain, false);
1460 struct winbindd_domain *find_our_domain(void)
1462 struct winbindd_domain *domain;
1464 /* Search through list */
1466 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1467 if (domain->primary)
1471 smb_panic("Could not find our domain");
1475 struct winbindd_domain *find_default_route_domain(void)
1478 return find_our_domain();
1480 DBG_ERR("Routing logic not yet implemented on a DC");
1484 /* Find the appropriate domain to lookup a name or SID */
1486 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
1488 DBG_DEBUG("SID [%s]\n", sid_string_dbg(sid));
1491 * SIDs in the S-1-22-{1,2} domain and well-known SIDs should be handled
1495 if ( sid_check_is_in_unix_groups(sid) ||
1496 sid_check_is_unix_groups(sid) ||
1497 sid_check_is_in_unix_users(sid) ||
1498 sid_check_is_unix_users(sid) ||
1499 sid_check_is_wellknown_domain(sid, NULL) ||
1500 sid_check_is_in_wellknown_domain(sid) )
1502 return find_domain_from_sid(get_global_sam_sid());
1506 * On member servers the internal domains are different: These are part
1510 if (is_internal_domain(sid) || is_in_internal_domain(sid)) {
1511 DEBUG(10, ("calling find_domain_from_sid\n"));
1512 return find_domain_from_sid(sid);
1516 struct winbindd_domain *domain = NULL;
1518 domain = find_domain_from_sid_noinit(sid);
1519 if (domain == NULL) {
1523 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1527 return domain->routing_domain;
1530 /* On a member server a query for SID or name can always go to our
1533 DEBUG(10, ("calling find_our_domain\n"));
1534 return find_our_domain();
1537 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1539 if ( strequal(domain_name, unix_users_domain_name() ) ||
1540 strequal(domain_name, unix_groups_domain_name() ) )
1543 * The "Unix User" and "Unix Group" domain our handled by
1546 return find_domain_from_name_noinit( get_global_sam_name() );
1549 if (strequal(domain_name, "BUILTIN") ||
1550 strequal(domain_name, get_global_sam_name()))
1551 return find_domain_from_name_noinit(domain_name);
1554 struct winbindd_domain *domain = NULL;
1556 domain = find_domain_from_name_noinit(domain_name);
1557 if (domain == NULL) {
1561 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1565 return domain->routing_domain;
1568 return find_our_domain();
1571 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1573 static bool assume_domain(const char *domain)
1575 /* never assume the domain on a standalone server */
1577 if ( lp_server_role() == ROLE_STANDALONE )
1580 /* domain member servers may possibly assume for the domain name */
1582 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1583 if ( !strequal(lp_workgroup(), domain) )
1586 if ( lp_winbind_use_default_domain() )
1590 /* only left with a domain controller */
1592 if ( strequal(get_global_sam_name(), domain) ) {
1599 /* Parse a string of the form DOMAIN\user into a domain and a user */
1601 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1603 char *p = strchr(domuser,*lp_winbind_separator());
1606 fstrcpy(user, domuser);
1607 p = strchr(domuser, '@');
1609 if ( assume_domain(lp_workgroup()) && p == NULL) {
1610 fstrcpy(domain, lp_workgroup());
1611 } else if (p != NULL) {
1612 fstrcpy(domain, p + 1);
1613 user[PTR_DIFF(p, domuser)] = 0;
1619 fstrcpy(domain, domuser);
1620 domain[PTR_DIFF(p, domuser)] = 0;
1623 return strupper_m(domain);
1626 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1627 char **domain, char **user)
1629 fstring fstr_domain, fstr_user;
1630 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1633 *domain = talloc_strdup(mem_ctx, fstr_domain);
1634 *user = talloc_strdup(mem_ctx, fstr_user);
1635 return ((*domain != NULL) && (*user != NULL));
1638 /* Ensure an incoming username from NSS is fully qualified. Replace the
1639 incoming fstring with DOMAIN <separator> user. Returns the same
1640 values as parse_domain_user() but also replaces the incoming username.
1641 Used to ensure all names are fully qualified within winbindd.
1642 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1643 The protocol definitions of auth_crap, chng_pswd_auth_crap
1644 really should be changed to use this instead of doing things
1647 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1649 if (!parse_domain_user(username_inout, domain, user)) {
1652 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1653 domain, *lp_winbind_separator(),
1659 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1660 'winbind separator' options.
1662 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1665 If we are a PDC or BDC, and this is for our domain, do likewise.
1667 On an AD DC we always fill DOMAIN\\USERNAME.
1669 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1671 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1675 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1679 fstrcpy(tmp_user, user);
1680 (void)strlower_m(tmp_user);
1682 if (can_assume && assume_domain(domain)) {
1683 strlcpy(name, tmp_user, sizeof(fstring));
1685 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1686 domain, *lp_winbind_separator(),
1692 * talloc version of fill_domain_username()
1693 * return NULL on talloc failure.
1695 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1700 char *tmp_user, *name;
1702 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1706 tmp_user = talloc_strdup(mem_ctx, user);
1707 if (!strlower_m(tmp_user)) {
1708 TALLOC_FREE(tmp_user);
1712 if (can_assume && assume_domain(domain)) {
1715 name = talloc_asprintf(mem_ctx, "%s%c%s",
1717 *lp_winbind_separator(),
1719 TALLOC_FREE(tmp_user);
1726 * Client list accessor functions
1729 static struct winbindd_cli_state *_client_list;
1730 static int _num_clients;
1732 /* Return list of all connected clients */
1734 struct winbindd_cli_state *winbindd_client_list(void)
1736 return _client_list;
1739 /* Return list-tail of all connected clients */
1741 struct winbindd_cli_state *winbindd_client_list_tail(void)
1743 return DLIST_TAIL(_client_list);
1746 /* Return previous (read:newer) client in list */
1748 struct winbindd_cli_state *
1749 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1751 return DLIST_PREV(cli);
1754 /* Add a connection to the list */
1756 void winbindd_add_client(struct winbindd_cli_state *cli)
1758 cli->last_access = time(NULL);
1759 DLIST_ADD(_client_list, cli);
1763 /* Remove a client from the list */
1765 void winbindd_remove_client(struct winbindd_cli_state *cli)
1767 DLIST_REMOVE(_client_list, cli);
1771 /* Move a client to head or list */
1773 void winbindd_promote_client(struct winbindd_cli_state *cli)
1775 cli->last_access = time(NULL);
1776 DLIST_PROMOTE(_client_list, cli);
1779 /* Return number of open clients */
1781 int winbindd_num_clients(void)
1783 return _num_clients;
1786 NTSTATUS lookup_usergroups_cached(TALLOC_CTX *mem_ctx,
1787 const struct dom_sid *user_sid,
1788 uint32_t *p_num_groups, struct dom_sid **user_sids)
1790 struct netr_SamInfo3 *info3 = NULL;
1791 NTSTATUS status = NT_STATUS_NO_MEMORY;
1792 uint32_t num_groups = 0;
1794 DEBUG(3,(": lookup_usergroups_cached\n"));
1799 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1801 if (info3 == NULL) {
1802 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1806 * Before bug #7843 the "Domain Local" groups were added with a
1807 * lookupuseraliases call, but this isn't done anymore for our domain
1808 * so we need to resolve resource groups here.
1810 * When to use Resource Groups:
1811 * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1813 status = sid_array_from_info3(mem_ctx, info3,
1818 if (!NT_STATUS_IS_OK(status)) {
1824 *p_num_groups = num_groups;
1825 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1827 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1832 /*********************************************************************
1833 We use this to remove spaces from user and group names
1834 ********************************************************************/
1836 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1837 const char *domain_name,
1841 struct winbindd_domain *domain = NULL;
1844 if (!name || !normalized) {
1845 return NT_STATUS_INVALID_PARAMETER;
1848 if (!lp_winbind_normalize_names()) {
1849 return NT_STATUS_PROCEDURE_NOT_FOUND;
1852 domain = find_domain_from_name_noinit(domain_name);
1853 if (domain == NULL) {
1854 DBG_ERR("Failed to find domain '%s'\n", domain_name);
1855 return NT_STATUS_NO_SUCH_DOMAIN;
1858 /* Alias support and whitespace replacement are mutually
1861 nt_status = resolve_username_to_alias(mem_ctx, domain,
1863 if (NT_STATUS_IS_OK(nt_status)) {
1864 /* special return code to let the caller know we
1865 mapped to an alias */
1866 return NT_STATUS_FILE_RENAMED;
1869 /* check for an unreachable domain */
1871 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1872 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1874 set_domain_offline(domain);
1878 /* deal with whitespace */
1880 *normalized = talloc_strdup(mem_ctx, name);
1881 if (!(*normalized)) {
1882 return NT_STATUS_NO_MEMORY;
1885 all_string_sub( *normalized, " ", "_", 0 );
1887 return NT_STATUS_OK;
1890 /*********************************************************************
1891 We use this to do the inverse of normalize_name_map()
1892 ********************************************************************/
1894 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1899 struct winbindd_domain *domain = find_our_domain();
1901 if (!name || !normalized) {
1902 return NT_STATUS_INVALID_PARAMETER;
1905 if (!lp_winbind_normalize_names()) {
1906 return NT_STATUS_PROCEDURE_NOT_FOUND;
1909 /* Alias support and whitespace replacement are mutally
1912 /* When mapping from an alias to a username, we don't know the
1913 domain. But we only need a domain structure to cache
1914 a successful lookup , so just our own domain structure for
1917 nt_status = resolve_alias_to_username(mem_ctx, domain,
1919 if (NT_STATUS_IS_OK(nt_status)) {
1920 /* Special return code to let the caller know we mapped
1922 return NT_STATUS_FILE_RENAMED;
1925 /* check for an unreachable domain */
1927 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1928 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1930 set_domain_offline(domain);
1934 /* deal with whitespace */
1936 *normalized = talloc_strdup(mem_ctx, name);
1937 if (!(*normalized)) {
1938 return NT_STATUS_NO_MEMORY;
1941 all_string_sub(*normalized, "_", " ", 0);
1943 return NT_STATUS_OK;
1946 /*********************************************************************
1947 ********************************************************************/
1949 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1951 struct winbindd_tdc_domain *tdc = NULL;
1952 TALLOC_CTX *frame = talloc_stackframe();
1955 /* We can contact the domain if it is our primary domain */
1957 if (domain->primary) {
1962 /* Trust the TDC cache and not the winbindd_domain flags */
1964 if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1965 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1971 /* Can always contact a domain that is in out forest */
1973 if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1979 * On a _member_ server, we cannot contact the domain if it
1980 * is running AD and we have no inbound trust.
1984 domain->active_directory &&
1985 ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1987 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1988 "and we have no inbound trust.\n", domain->name));
1992 /* Assume everything else is ok (probably not true but what
1998 talloc_destroy(frame);
2003 /*********************************************************************
2004 ********************************************************************/
2006 bool winbindd_internal_child(struct winbindd_child *child)
2008 if ((child == idmap_child()) || (child == locator_child())) {
2015 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
2017 /*********************************************************************
2018 ********************************************************************/
2020 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
2023 char addr[INET6_ADDRSTRLEN];
2024 const char *kdc = NULL;
2027 if (!domain || !domain->alt_name || !*domain->alt_name) {
2031 if (domain->initialized && !domain->active_directory) {
2032 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
2037 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
2040 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
2042 kdc = domain->dcname;
2045 if (!kdc || !*kdc) {
2046 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
2051 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
2052 domain->alt_name) == -1) {
2056 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
2059 setenv(var, kdc, 1);
2063 /*********************************************************************
2064 ********************************************************************/
2066 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
2068 struct winbindd_domain *our_dom = find_our_domain();
2070 winbindd_set_locator_kdc_env(domain);
2072 if (domain != our_dom) {
2073 winbindd_set_locator_kdc_env(our_dom);
2077 /*********************************************************************
2078 ********************************************************************/
2080 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
2084 if (!domain || !domain->alt_name || !*domain->alt_name) {
2088 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
2089 domain->alt_name) == -1) {
2098 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
2103 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
2108 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
2110 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
2112 resp->data.auth.nt_status = NT_STATUS_V(result);
2113 fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
2115 /* we might have given a more useful error above */
2116 if (*resp->data.auth.error_string == '\0')
2117 fstrcpy(resp->data.auth.error_string,
2118 get_friendly_nt_error_msg(result));
2119 resp->data.auth.pam_error = nt_status_to_pam(result);
2122 bool is_domain_offline(const struct winbindd_domain *domain)
2124 if (get_global_winbindd_state_offline()) {
2127 return !domain->online;
2130 bool is_domain_online(const struct winbindd_domain *domain)
2132 return !is_domain_offline(domain);
2136 * Parse an char array into a list of sids.
2138 * The input sidstr should consist of 0-terminated strings
2139 * representing sids, separated by newline characters '\n'.
2140 * The list is terminated by an empty string, i.e.
2141 * character '\0' directly following a character '\n'
2142 * (or '\0' right at the start of sidstr).
2144 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
2145 struct dom_sid **sids, uint32_t *num_sids)
2153 while (p[0] != '\0') {
2155 const char *q = NULL;
2157 if (!dom_sid_parse_endp(p, &sid, &q)) {
2158 DEBUG(1, ("Could not parse sid %s\n", p));
2162 DEBUG(1, ("Got invalid sidstr: %s\n", p));
2165 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
2175 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
2176 struct unixid **pxids, uint32_t *pnum_xids)
2179 struct unixid *xids = NULL;
2180 uint32_t num_xids = 0;
2187 while (p[0] != '\0') {
2190 unsigned long long id;
2195 xid = (struct unixid) { .type = ID_TYPE_UID };
2198 xid = (struct unixid) { .type = ID_TYPE_GID };
2206 id = strtoull(p, &endp, 10);
2207 if ((id == ULLONG_MAX) && (errno == ERANGE)) {
2210 if (*endp != '\n') {
2216 if ((unsigned long long)xid.id != id) {
2220 tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
2226 xids[num_xids] = xid;
2231 *pnum_xids = num_xids;