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 **_d)
132 struct winbindd_domain *domain = NULL;
133 const char **ignored_domains = NULL;
134 const char **dom = NULL;
135 int role = lp_server_role();
137 if (is_null_sid(sid)) {
138 DBG_ERR("Got null SID for domain [%s]\n", domain_name);
139 return NT_STATUS_INVALID_PARAMETER;
142 ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
143 for (dom=ignored_domains; dom && *dom; dom++) {
144 if (gen_fnmatch(*dom, domain_name) == 0) {
145 DEBUG(2,("Ignoring domain '%s'\n", domain_name));
146 return NT_STATUS_NO_SUCH_DOMAIN;
151 * We can't call domain_list() as this function is called from
152 * init_domain_list() and we'll get stuck in a loop.
154 for (domain = _domain_list; domain; domain = domain->next) {
155 if (strequal(domain_name, domain->name)) {
160 if (domain != NULL) {
161 struct winbindd_domain *check_domain = NULL;
163 for (check_domain = _domain_list;
164 check_domain != NULL;
165 check_domain = check_domain->next)
167 if (check_domain == domain) {
171 if (dom_sid_equal(&check_domain->sid, sid)) {
176 if (check_domain != NULL) {
177 DBG_ERR("SID [%s] already used by domain [%s], "
179 sid_string_dbg(sid), check_domain->name,
181 return NT_STATUS_INVALID_PARAMETER;
185 if ((domain != NULL) && (dns_name != NULL)) {
186 struct winbindd_domain *check_domain = NULL;
188 for (check_domain = _domain_list;
189 check_domain != NULL;
190 check_domain = check_domain->next)
192 if (check_domain == domain) {
196 if (strequal(check_domain->alt_name, dns_name)) {
201 if (check_domain != NULL) {
202 DBG_ERR("DNS name [%s] used by domain [%s], "
204 dns_name, check_domain->name,
206 return NT_STATUS_INVALID_PARAMETER;
210 if (domain != NULL) {
215 /* Create new domain entry */
216 domain = talloc_zero(NULL, struct winbindd_domain);
217 if (domain == NULL) {
218 return NT_STATUS_NO_MEMORY;
221 domain->children = talloc_zero_array(domain,
222 struct winbindd_child,
223 lp_winbind_max_domain_connections());
224 if (domain->children == NULL) {
226 return NT_STATUS_NO_MEMORY;
229 domain->name = talloc_strdup(domain, domain_name);
230 if (domain->name == NULL) {
232 return NT_STATUS_NO_MEMORY;
235 if (dns_name != NULL) {
236 domain->alt_name = talloc_strdup(domain, dns_name);
237 if (domain->alt_name == NULL) {
239 return NT_STATUS_NO_MEMORY;
243 domain->backend = NULL;
244 domain->internal = is_internal_domain(sid);
245 domain->secure_channel_type = secure_channel_type;
246 domain->sequence_number = DOM_SEQUENCE_NONE;
247 domain->last_seq_check = 0;
248 domain->initialized = false;
249 domain->online = is_internal_domain(sid);
250 domain->check_online_timeout = 0;
251 domain->dc_probe_pid = (pid_t)-1;
252 domain->domain_flags = trust_flags;
253 domain->domain_type = trust_type;
254 domain->domain_trust_attribs = trust_attribs;
255 domain->secure_channel_type = secure_channel_type;
256 sid_copy(&domain->sid, sid);
258 /* Is this our primary domain ? */
259 if (role == ROLE_DOMAIN_MEMBER) {
260 domain->primary = strequal(domain_name, lp_workgroup());
262 domain->primary = strequal(domain_name, get_global_sam_name());
265 if (domain->primary) {
266 if (role == ROLE_ACTIVE_DIRECTORY_DC) {
267 domain->active_directory = true;
269 if (lp_security() == SEC_ADS) {
270 domain->active_directory = true;
272 } else if (!domain->internal) {
273 if (domain->domain_type == LSA_TRUST_TYPE_UPLEVEL) {
274 domain->active_directory = true;
278 /* Link to domain list */
279 DLIST_ADD_END(_domain_list, domain);
281 wcache_tdc_add_domain( domain );
283 setup_domain_child(domain);
285 DBG_NOTICE("Added domain [%s] [%s] [%s]\n",
286 domain->name, domain->alt_name,
287 sid_string_dbg(&domain->sid));
293 bool set_routing_domain(struct winbindd_domain *domain,
294 const struct winbindd_domain *routing_domain)
296 if (domain->routing_domain == NULL) {
297 domain->routing_domain = routing_domain;
300 if (domain->routing_domain != routing_domain) {
306 bool add_trusted_domain_from_auth(uint16_t validation_level,
307 struct info3_text *info3,
308 struct info6_text *info6)
310 struct winbindd_domain *domain = NULL;
311 struct dom_sid domain_sid;
312 const char *dns_domainname = NULL;
317 * We got a successfull auth from a domain that might not yet be in our
318 * domain list. If we're a member we trust our DC who authenticated the
319 * user from that domain and add the domain to our list on-the-fly. If
320 * we're a DC we rely on configured trusts and don't add on-the-fly.
327 ok = dom_sid_parse(info3->dom_sid, &domain_sid);
329 DBG_NOTICE("dom_sid_parse [%s] failed\n", info3->dom_sid);
333 if (validation_level == 6) {
334 dns_domainname = &info6->dns_domainname[0];
337 status = add_trusted_domain(info3->logon_dom,
341 NETR_TRUST_FLAG_OUTBOUND,
345 if (!NT_STATUS_IS_OK(status) &&
346 !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
348 DBG_DEBUG("Adding domain [%s] with sid [%s] failed\n",
349 info3->logon_dom, info3->dom_sid);
353 ok = set_routing_domain(domain, find_default_route_domain());
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;
420 * Only when we enumerate our primary domain
421 * or our forest root domain, we should keep
422 * the NETR_TRUST_FLAG_IN_FOREST flag, in
423 * all other cases we need to clear it as the domain
424 * is not part of our forest.
426 if (state->domain->primary) {
427 within_forest = true;
428 } else if (domain_is_forest_root(state->domain)) {
429 within_forest = true;
432 res = wb_domain_request_recv(req, state, &response, &err);
433 if ((res == -1) || (response->result != WINBINDD_OK)) {
434 DBG_WARNING("Could not receive trusts for domain %s\n",
435 state->domain->name);
440 if (response->length < sizeof(struct winbindd_response)) {
441 DBG_ERR("ill-formed trustdom response - short length\n");
446 extra_len = response->length - sizeof(struct winbindd_response);
448 p = (char *)response->extra_data.data;
450 while ((p - (char *)response->extra_data.data) < extra_len) {
451 struct winbindd_domain *domain = NULL;
452 char *name, *q, *sidstr, *alt_name;
455 uint32_t trust_attribs;
456 uint32_t trust_flags;
458 DBG_DEBUG("parsing response line '%s'\n", p);
462 alt_name = strchr(p, '\\');
463 if (alt_name == NULL) {
464 DBG_ERR("Got invalid trustdom response\n");
471 sidstr = strchr(alt_name, '\\');
472 if (sidstr == NULL) {
473 DBG_ERR("Got invalid trustdom response\n");
480 /* use the real alt_name if we have one, else pass in NULL */
481 if (strequal(alt_name, "(null)")) {
485 q = strtok(sidstr, "\\");
487 DBG_ERR("Got invalid trustdom response\n");
491 if (!string_to_sid(&sid, sidstr)) {
492 DEBUG(0, ("Got invalid trustdom response\n"));
496 q = strtok(NULL, "\\");
498 DBG_ERR("Got invalid trustdom response\n");
502 trust_flags = (uint32_t)strtoul(q, NULL, 10);
504 q = strtok(NULL, "\\");
506 DBG_ERR("Got invalid trustdom response\n");
510 trust_type = (uint32_t)strtoul(q, NULL, 10);
512 q = strtok(NULL, "\n");
514 DBG_ERR("Got invalid trustdom response\n");
518 trust_attribs = (uint32_t)strtoul(q, NULL, 10);
520 if (!within_forest) {
521 trust_flags &= ~NETR_TRUST_FLAG_IN_FOREST;
524 if (!state->domain->primary) {
525 trust_flags &= ~NETR_TRUST_FLAG_PRIMARY;
529 * We always call add_trusted_domain() cause on an existing
530 * domain structure, it will update the SID if necessary.
531 * This is important because we need the SID for sibling
534 status = add_trusted_domain(name,
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 ok = set_routing_domain(domain, find_default_route_domain());
552 DBG_ERR("set_routing_domain failed\n");
556 p = q + strlen(q) + 1;
560 Cases to consider when scanning trusts:
561 (a) we are calling from a child domain (primary && !forest_root)
562 (b) we are calling from the root of the forest (primary && forest_root)
563 (c) we are calling from a trusted forest domain (!primary
567 if (state->domain->primary) {
568 /* If this is our primary domain and we are not in the
569 forest root, we have to scan the root trusts first */
571 if (!domain_is_forest_root(state->domain))
572 rescan_forest_root_trusts();
574 rescan_forest_trusts();
576 } else if (domain_is_forest_root(state->domain)) {
577 /* Once we have done root forest trust search, we can
578 go on to search the trusted forests */
580 rescan_forest_trusts();
588 /********************************************************************
589 Scan the trusts of our forest root
590 ********************************************************************/
592 static void rescan_forest_root_trusts( void )
594 struct winbindd_tdc_domain *dom_list = NULL;
595 size_t num_trusts = 0;
600 /* The only transitive trusts supported by Windows 2003 AD are
601 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
602 first two are handled in forest and listed by
603 DsEnumerateDomainTrusts(). Forest trusts are not so we
604 have to do that ourselves. */
606 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
609 for ( i=0; i<num_trusts; i++ ) {
610 struct winbindd_domain *d = NULL;
612 /* Find the forest root. Don't necessarily trust
613 the domain_list() as our primary domain may not
614 have been initialized. */
616 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
620 /* Here's the forest root */
622 d = find_domain_from_name_noinit( dom_list[i].domain_name );
624 status = add_trusted_domain(dom_list[i].domain_name,
625 dom_list[i].dns_name,
627 dom_list[i].trust_type,
628 dom_list[i].trust_flags,
629 dom_list[i].trust_attribs,
633 if (!NT_STATUS_IS_OK(status) &&
634 NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
636 DBG_ERR("add_trusted_domain returned %s\n",
640 ok = set_routing_domain(d, find_default_route_domain());
642 DBG_ERR("set_routing_domain failed\n");
650 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
651 "for domain tree root %s (%s)\n",
652 d->name, d->alt_name ));
654 d->domain_flags = dom_list[i].trust_flags;
655 d->domain_type = dom_list[i].trust_type;
656 d->domain_trust_attribs = dom_list[i].trust_attribs;
658 add_trusted_domains( d );
663 TALLOC_FREE( dom_list );
668 /********************************************************************
669 scan the transitive forest trusts (not our own)
670 ********************************************************************/
673 static void rescan_forest_trusts( void )
675 struct winbindd_domain *d = NULL;
676 struct winbindd_tdc_domain *dom_list = NULL;
677 size_t num_trusts = 0;
682 /* The only transitive trusts supported by Windows 2003 AD are
683 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
684 first two are handled in forest and listed by
685 DsEnumerateDomainTrusts(). Forest trusts are not so we
686 have to do that ourselves. */
688 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
691 for ( i=0; i<num_trusts; i++ ) {
692 uint32_t flags = dom_list[i].trust_flags;
693 uint32_t type = dom_list[i].trust_type;
694 uint32_t attribs = dom_list[i].trust_attribs;
696 d = find_domain_from_name_noinit( dom_list[i].domain_name );
698 /* ignore our primary and internal domains */
700 if ( d && (d->internal || d->primary ) )
703 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
704 (type == LSA_TRUST_TYPE_UPLEVEL) &&
705 (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
707 /* add the trusted domain if we don't know
711 status = add_trusted_domain(
712 dom_list[i].domain_name,
713 dom_list[i].dns_name,
720 if (!NT_STATUS_IS_OK(status) &&
721 NT_STATUS_EQUAL(status,
722 NT_STATUS_NO_SUCH_DOMAIN))
724 DBG_ERR("add_trusted_domain: %s\n",
728 ok = set_routing_domain(
729 d, find_default_route_domain());
731 DBG_ERR("set_routing_domain failed\n");
740 DEBUG(10,("Following trust path for domain %s (%s)\n",
741 d->name, d->alt_name ));
742 add_trusted_domains( d );
746 TALLOC_FREE( dom_list );
751 /*********************************************************************
752 The process of updating the trusted domain list is a three step
755 (b) ask the root domain in our forest
756 (c) ask the a DC in any Win2003 trusted forests
757 *********************************************************************/
759 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
760 struct timeval now, void *private_data)
764 /* I use to clear the cache here and start over but that
765 caused problems in child processes that needed the
766 trust dom list early on. Removing it means we
767 could have some trusted domains listed that have been
768 removed from our primary domain's DC until a full
769 restart. This should be ok since I think this is what
770 Windows does as well. */
772 /* this will only add new domains we didn't already know about
773 in the domain_list()*/
775 add_trusted_domains( find_our_domain() );
777 te = tevent_add_timer(
778 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
779 rescan_trusted_domains, NULL);
781 * If te == NULL, there's not much we can do here. Don't fail, the
782 * only thing we miss is new trusted domains.
788 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
789 struct winbindd_cli_state *state)
791 /* Ensure null termination */
792 state->request->domain_name
793 [sizeof(state->request->domain_name)-1]='\0';
794 state->request->data.init_conn.dcname
795 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
797 if (strlen(state->request->data.init_conn.dcname) > 0) {
798 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
801 init_dc_connection(domain, false);
803 if (!domain->initialized) {
804 /* If we return error here we can't do any cached authentication,
805 but we may be in disconnected mode and can't initialize correctly.
806 Do what the previous code did and just return without initialization,
807 once we go online we'll re-initialize.
809 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
810 "online = %d\n", domain->name, (int)domain->online ));
813 fstrcpy(state->response->data.domain_info.name, domain->name);
814 fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
815 sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
817 state->response->data.domain_info.native_mode
818 = domain->native_mode;
819 state->response->data.domain_info.active_directory
820 = domain->active_directory;
821 state->response->data.domain_info.primary
827 static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
830 struct server_id server_id,
833 TALLOC_CTX *frame = talloc_stackframe();
834 enum netr_SchannelType secure_channel_type = SEC_CHAN_DOMAIN;
835 struct lsa_TrustDomainInfoInfoEx info;
836 enum ndr_err_code ndr_err;
837 struct winbindd_domain *d = NULL;
838 uint32_t trust_flags = 0;
842 DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
849 ndr_err = ndr_pull_struct_blob_all(data, frame, &info,
850 (ndr_pull_flags_fn_t)ndr_pull_lsa_TrustDomainInfoInfoEx);
851 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
856 d = find_domain_from_name_noinit(info.netbios_name.string);
862 if (info.trust_type == LSA_TRUST_TYPE_UPLEVEL) {
863 secure_channel_type = SEC_CHAN_DNS_DOMAIN;
865 if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
866 trust_flags |= NETR_TRUST_FLAG_INBOUND;
868 if (info.trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
869 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
871 if (info.trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
872 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
875 status = add_trusted_domain(info.netbios_name.string,
876 info.domain_name.string,
880 info.trust_attributes,
883 if (!NT_STATUS_IS_OK(status) &&
884 !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
886 DBG_NOTICE("add_trusted_domain returned %s\n",
891 ok = set_routing_domain(d, find_default_route_domain());
900 * We did not get the secret when we queried secrets.tdb, so read it
901 * from secrets.tdb and re-sync the databases
903 static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
906 struct cli_credentials *creds;
907 NTSTATUS can_migrate = pdb_get_trust_credentials(domain->name,
908 NULL, domain, &creds);
909 if (!NT_STATUS_IS_OK(can_migrate)) {
910 DEBUG(0, ("Failed to fetch our own, local AD domain join "
911 "password for winbindd's internal use, both from "
912 "secrets.tdb and secrets.ldb: %s\n",
913 nt_errstr(can_migrate)));
918 * NOTE: It is very unlikely we end up here if there is an
919 * oldpass, because a new password is created at
920 * classicupgrade, so this is not a concern.
922 ok = secrets_store_machine_pw_sync(cli_credentials_get_password(creds),
924 cli_credentials_get_domain(creds),
925 cli_credentials_get_realm(creds),
926 cli_credentials_get_salt_principal(creds),
927 0, /* Supported enc types, unused */
929 cli_credentials_get_password_last_changed_time(creds),
930 cli_credentials_get_secure_channel_type(creds),
931 false /* do_delete: Do not delete */);
934 DEBUG(0, ("Failed to write our our own, "
935 "local AD domain join password for "
936 "winbindd's internal use into secrets.tdb\n"));
942 /* Look up global info for the winbind daemon */
943 bool init_domain_list(void)
945 int role = lp_server_role();
946 struct pdb_domain_info *pdb_domain_info = NULL;
947 struct winbindd_domain *domain = NULL;
950 /* Free existing list */
955 status = add_trusted_domain("BUILTIN",
958 LSA_TRUST_TYPE_DOWNLEVEL,
960 0, /* trust_attribs */
963 if (!NT_STATUS_IS_OK(status)) {
964 DBG_ERR("add_trusted_domain BUILTIN returned %s\n",
972 * In case the passdb backend is passdb_dsdb the domain SID comes from
973 * dsdb, not from secrets.tdb. As we use the domain SID in various
974 * places, we must ensure the domain SID is migrated from dsdb to
975 * secrets.tdb before get_global_sam_sid() is called the first time.
977 * The migration is done as part of the passdb_dsdb initialisation,
978 * calling pdb_get_domain_info() triggers it.
980 pdb_domain_info = pdb_get_domain_info(talloc_tos());
982 if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
983 uint32_t trust_flags;
985 enum netr_SchannelType sec_chan_type;
986 const char *account_name;
987 struct samr_Password current_nt_hash;
990 if (pdb_domain_info == NULL) {
991 DEBUG(0, ("Failed to fetch our own, local AD "
992 "domain info from sam.ldb\n"));
996 trust_flags = NETR_TRUST_FLAG_PRIMARY;
997 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
998 trust_flags |= NETR_TRUST_FLAG_NATIVE;
999 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
1001 is_root = strequal(pdb_domain_info->dns_domain,
1002 pdb_domain_info->dns_forest);
1004 trust_flags |= NETR_TRUST_FLAG_TREEROOT;
1007 status = add_trusted_domain(pdb_domain_info->name,
1008 pdb_domain_info->dns_domain,
1009 &pdb_domain_info->sid,
1010 LSA_TRUST_TYPE_UPLEVEL,
1012 LSA_TRUST_ATTRIBUTE_WITHIN_FOREST,
1015 TALLOC_FREE(pdb_domain_info);
1016 if (!NT_STATUS_IS_OK(status)) {
1017 DBG_ERR("Failed to add our own, local AD "
1018 "domain to winbindd's internal list\n");
1023 * We need to call this to find out if we are an RODC
1025 ok = get_trust_pw_hash(domain->name,
1026 current_nt_hash.hash,
1031 * If get_trust_pw_hash() fails, then try and
1032 * fetch the password from the more recent of
1033 * secrets.{ldb,tdb} using the
1034 * pdb_get_trust_credentials()
1036 ok = migrate_secrets_tdb_to_ldb(domain);
1039 DEBUG(0, ("Failed to migrate our own, "
1040 "local AD domain join password for "
1041 "winbindd's internal use into "
1045 ok = get_trust_pw_hash(domain->name,
1046 current_nt_hash.hash,
1050 DEBUG(0, ("Failed to find our our own, just "
1051 "written local AD domain join "
1052 "password for winbindd's internal "
1053 "use in secrets.tdb\n"));
1058 domain->secure_channel_type = sec_chan_type;
1059 if (sec_chan_type == SEC_CHAN_RODC) {
1060 domain->rodc = true;
1064 uint32_t trust_flags;
1065 enum netr_SchannelType secure_channel_type;
1067 trust_flags = NETR_TRUST_FLAG_OUTBOUND;
1068 if (role != ROLE_DOMAIN_MEMBER) {
1069 trust_flags |= NETR_TRUST_FLAG_PRIMARY;
1072 if (role > ROLE_DOMAIN_MEMBER) {
1073 secure_channel_type = SEC_CHAN_BDC;
1075 secure_channel_type = SEC_CHAN_LOCAL;
1078 status = add_trusted_domain(get_global_sam_name(),
1080 get_global_sam_sid(),
1081 LSA_TRUST_TYPE_DOWNLEVEL,
1083 0, /* trust_attribs */
1084 secure_channel_type,
1086 if (!NT_STATUS_IS_OK(status)) {
1087 DBG_ERR("Failed to add local SAM to "
1088 "domain to winbindd's internal list\n");
1092 /* Add ourselves as the first entry. */
1094 if ( role == ROLE_DOMAIN_MEMBER ) {
1095 struct dom_sid our_sid;
1096 uint32_t trust_type;
1098 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
1099 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
1103 if (lp_realm() != NULL) {
1104 trust_type = LSA_TRUST_TYPE_UPLEVEL;
1106 trust_type = LSA_TRUST_TYPE_DOWNLEVEL;
1109 status = add_trusted_domain(lp_workgroup(),
1113 NETR_TRUST_FLAG_PRIMARY|
1114 NETR_TRUST_FLAG_OUTBOUND,
1115 0, /* trust_attribs */
1118 if (!NT_STATUS_IS_OK(status)) {
1119 DBG_ERR("Failed to add local SAM to "
1120 "domain to winbindd's internal list\n");
1123 /* Even in the parent winbindd we'll need to
1124 talk to the DC, so try and see if we can
1125 contact it. Theoretically this isn't neccessary
1126 as the init_dc_connection() in init_child_recv()
1127 will do this, but we can start detecting the DC
1129 set_domain_online_request(domain);
1133 if (IS_DC && (pdb_capabilities() & PDB_CAP_TRUSTED_DOMAINS_EX)) {
1134 uint32_t num_domains = 0;
1135 struct pdb_trusted_domain **domains = NULL;
1138 status = pdb_enum_trusted_domains(talloc_tos(), &num_domains, &domains);
1139 if (!NT_STATUS_IS_OK(status)) {
1140 DBG_ERR("pdb_enum_trusted_domains() failed - %s\n",
1145 for (i = 0; i < num_domains; i++) {
1146 enum netr_SchannelType sec_chan_type = SEC_CHAN_DOMAIN;
1147 uint32_t trust_flags = 0;
1149 if (domains[i]->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
1150 sec_chan_type = SEC_CHAN_DNS_DOMAIN;
1153 if (!(domains[i]->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND)) {
1154 sec_chan_type = SEC_CHAN_NULL;
1157 if (domains[i]->trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
1158 trust_flags |= NETR_TRUST_FLAG_INBOUND;
1160 if (domains[i]->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
1161 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
1163 if (domains[i]->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
1164 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
1167 status = add_trusted_domain(domains[i]->netbios_name,
1168 domains[i]->domain_name,
1169 &domains[i]->security_identifier,
1170 domains[i]->trust_type,
1172 domains[i]->trust_attributes,
1175 if (!NT_STATUS_IS_OK(status)) {
1176 DBG_NOTICE("add_trusted_domain returned %s\n",
1181 if (domains[i]->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
1182 domain->active_directory = true;
1184 domain->domain_type = domains[i]->trust_type;
1185 domain->domain_trust_attribs = domains[i]->trust_attributes;
1187 if (sec_chan_type != SEC_CHAN_NULL) {
1188 /* Even in the parent winbindd we'll need to
1189 talk to the DC, so try and see if we can
1190 contact it. Theoretically this isn't neccessary
1191 as the init_dc_connection() in init_child_recv()
1192 will do this, but we can start detecting the DC
1194 set_domain_online_request(domain);
1198 for (i = 0; i < num_domains; i++) {
1199 struct ForestTrustInfo fti;
1201 enum ndr_err_code ndr_err;
1202 struct winbindd_domain *routing_domain = NULL;
1205 if (domains[i]->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
1209 if (!(domains[i]->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1213 if (domains[i]->trust_forest_trust_info.length == 0) {
1217 routing_domain = find_domain_from_name_noinit(
1218 domains[i]->netbios_name);
1219 if (routing_domain == NULL) {
1220 DBG_ERR("Can't find winbindd domain [%s]\n",
1221 domains[i]->netbios_name);
1225 ndr_err = ndr_pull_struct_blob_all(
1226 &domains[i]->trust_forest_trust_info,
1228 (ndr_pull_flags_fn_t)ndr_pull_ForestTrustInfo);
1229 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1230 DBG_ERR("ndr_pull_ForestTrustInfo(%s) - %s\n",
1231 domains[i]->netbios_name,
1232 ndr_map_error2string(ndr_err));
1236 for (fi = 0; fi < fti.count; fi++) {
1237 struct ForestTrustInfoRecord *rec =
1238 &fti.records[fi].record;
1239 struct ForestTrustDataDomainInfo *drec = NULL;
1241 if (rec->type != FOREST_TRUST_DOMAIN_INFO) {
1244 drec = &rec->data.info;
1246 if (rec->flags & LSA_NB_DISABLED_MASK) {
1250 if (rec->flags & LSA_SID_DISABLED_MASK) {
1256 * also try to find a matching
1257 * LSA_TLN_DISABLED_MASK ???
1260 domain = find_domain_from_name_noinit(drec->netbios_name.string);
1261 if (domain != NULL) {
1265 status = add_trusted_domain(drec->netbios_name.string,
1266 drec->dns_name.string,
1268 LSA_TRUST_TYPE_UPLEVEL,
1269 NETR_TRUST_FLAG_OUTBOUND,
1273 if (!NT_STATUS_IS_OK(status)) {
1274 DBG_NOTICE("add_trusted_domain returned %s\n",
1278 if (domain == NULL) {
1281 ok = set_routing_domain(domain, routing_domain);
1283 DBG_ERR("set_routing_domain on [%s] to "
1286 routing_domain->name);
1292 uint32_t num_domains = 0;
1293 struct trustdom_info **domains = NULL;
1296 status = pdb_enum_trusteddoms(talloc_tos(), &num_domains, &domains);
1297 if (!NT_STATUS_IS_OK(status)) {
1298 DBG_ERR("pdb_enum_trusteddoms() failed - %s\n",
1303 for (i = 0; i < num_domains; i++) {
1304 status = add_trusted_domain(domains[i]->name,
1307 LSA_TRUST_TYPE_DOWNLEVEL,
1308 NETR_TRUST_FLAG_OUTBOUND,
1312 if (!NT_STATUS_IS_OK(status)) {
1313 DBG_NOTICE("add_trusted_domain returned %s\n",
1318 /* Even in the parent winbindd we'll need to
1319 talk to the DC, so try and see if we can
1320 contact it. Theoretically this isn't neccessary
1321 as the init_dc_connection() in init_child_recv()
1322 will do this, but we can start detecting the DC
1324 set_domain_online_request(domain);
1328 status = imessaging_register(winbind_imessaging_context(), NULL,
1329 MSG_WINBIND_NEW_TRUSTED_DOMAIN,
1330 wb_imsg_new_trusted_domain);
1331 if (!NT_STATUS_IS_OK(status)) {
1332 DEBUG(0, ("imessaging_register(MSG_WINBIND_NEW_TRUSTED_DOMAIN) - %s\n",
1333 nt_errstr(status)));
1341 * Given a domain name, return the struct winbindd domain info for it
1343 * @note Do *not* pass lp_workgroup() to this function. domain_list
1344 * may modify it's value, and free that pointer. Instead, our local
1345 * domain may be found by calling find_our_domain().
1349 * @return The domain structure for the named domain, if it is working.
1352 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
1354 struct winbindd_domain *domain;
1356 /* Search through list */
1358 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1359 if (strequal(domain_name, domain->name)) {
1362 if (domain->alt_name == NULL) {
1365 if (strequal(domain_name, domain->alt_name)) {
1376 * Given a domain name, return the struct winbindd domain if it's a direct
1379 * @return The domain structure for the named domain, if it is a direct outgoing trust
1381 struct winbindd_domain *find_trust_from_name_noinit(const char *domain_name)
1383 struct winbindd_domain *domain = NULL;
1385 domain = find_domain_from_name_noinit(domain_name);
1386 if (domain == NULL) {
1390 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1397 struct winbindd_domain *find_domain_from_name(const char *domain_name)
1399 struct winbindd_domain *domain;
1401 domain = find_domain_from_name_noinit(domain_name);
1406 if (!domain->initialized)
1407 init_dc_connection(domain, false);
1412 /* Given a domain sid, return the struct winbindd domain info for it */
1414 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
1416 struct winbindd_domain *domain;
1418 /* Search through list */
1420 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1421 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
1431 * Given a domain sid, return the struct winbindd domain if it's a direct
1434 * @return The domain structure for the specified domain, if it is a direct outgoing trust
1436 struct winbindd_domain *find_trust_from_sid_noinit(const struct dom_sid *sid)
1438 struct winbindd_domain *domain = NULL;
1440 domain = find_domain_from_sid_noinit(sid);
1441 if (domain == NULL) {
1445 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1452 /* Given a domain sid, return the struct winbindd domain info for it */
1454 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
1456 struct winbindd_domain *domain;
1458 domain = find_domain_from_sid_noinit(sid);
1463 if (!domain->initialized)
1464 init_dc_connection(domain, false);
1469 struct winbindd_domain *find_our_domain(void)
1471 struct winbindd_domain *domain;
1473 /* Search through list */
1475 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1476 if (domain->primary)
1480 smb_panic("Could not find our domain");
1484 struct winbindd_domain *find_default_route_domain(void)
1487 return find_our_domain();
1489 DBG_ERR("Routing logic not yet implemented on a DC");
1493 /* Find the appropriate domain to lookup a name or SID */
1495 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
1497 DBG_DEBUG("SID [%s]\n", sid_string_dbg(sid));
1500 * SIDs in the S-1-22-{1,2} domain and well-known SIDs should be handled
1504 if ( sid_check_is_in_unix_groups(sid) ||
1505 sid_check_is_unix_groups(sid) ||
1506 sid_check_is_in_unix_users(sid) ||
1507 sid_check_is_unix_users(sid) ||
1508 sid_check_is_wellknown_domain(sid, NULL) ||
1509 sid_check_is_in_wellknown_domain(sid) )
1511 return find_domain_from_sid(get_global_sam_sid());
1514 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
1515 * one to contact the external DC's. On member servers the internal
1516 * domains are different: These are part of the local SAM. */
1518 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
1519 DEBUG(10, ("calling find_domain_from_sid\n"));
1520 return find_domain_from_sid(sid);
1523 /* On a member server a query for SID or name can always go to our
1526 DEBUG(10, ("calling find_our_domain\n"));
1527 return find_our_domain();
1530 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1532 if ( strequal(domain_name, unix_users_domain_name() ) ||
1533 strequal(domain_name, unix_groups_domain_name() ) )
1536 * The "Unix User" and "Unix Group" domain our handled by
1539 return find_domain_from_name_noinit( get_global_sam_name() );
1542 if (IS_DC || strequal(domain_name, "BUILTIN") ||
1543 strequal(domain_name, get_global_sam_name()))
1544 return find_domain_from_name_noinit(domain_name);
1547 return find_our_domain();
1550 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1552 static bool assume_domain(const char *domain)
1554 /* never assume the domain on a standalone server */
1556 if ( lp_server_role() == ROLE_STANDALONE )
1559 /* domain member servers may possibly assume for the domain name */
1561 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1562 if ( !strequal(lp_workgroup(), domain) )
1565 if ( lp_winbind_use_default_domain() )
1569 /* only left with a domain controller */
1571 if ( strequal(get_global_sam_name(), domain) ) {
1578 /* Parse a string of the form DOMAIN\user into a domain and a user */
1580 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1582 char *p = strchr(domuser,*lp_winbind_separator());
1585 fstrcpy(user, domuser);
1586 p = strchr(domuser, '@');
1588 if ( assume_domain(lp_workgroup()) && p == NULL) {
1589 fstrcpy(domain, lp_workgroup());
1590 } else if (p != NULL) {
1591 fstrcpy(domain, p + 1);
1592 user[PTR_DIFF(p, domuser)] = 0;
1598 fstrcpy(domain, domuser);
1599 domain[PTR_DIFF(p, domuser)] = 0;
1602 return strupper_m(domain);
1605 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1606 char **domain, char **user)
1608 fstring fstr_domain, fstr_user;
1609 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1612 *domain = talloc_strdup(mem_ctx, fstr_domain);
1613 *user = talloc_strdup(mem_ctx, fstr_user);
1614 return ((*domain != NULL) && (*user != NULL));
1617 /* Ensure an incoming username from NSS is fully qualified. Replace the
1618 incoming fstring with DOMAIN <separator> user. Returns the same
1619 values as parse_domain_user() but also replaces the incoming username.
1620 Used to ensure all names are fully qualified within winbindd.
1621 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1622 The protocol definitions of auth_crap, chng_pswd_auth_crap
1623 really should be changed to use this instead of doing things
1626 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1628 if (!parse_domain_user(username_inout, domain, user)) {
1631 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1632 domain, *lp_winbind_separator(),
1638 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1639 'winbind separator' options.
1641 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1644 If we are a PDC or BDC, and this is for our domain, do likewise.
1646 On an AD DC we always fill DOMAIN\\USERNAME.
1648 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1650 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1654 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1658 fstrcpy(tmp_user, user);
1659 (void)strlower_m(tmp_user);
1661 if (can_assume && assume_domain(domain)) {
1662 strlcpy(name, tmp_user, sizeof(fstring));
1664 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1665 domain, *lp_winbind_separator(),
1671 * talloc version of fill_domain_username()
1672 * return NULL on talloc failure.
1674 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1679 char *tmp_user, *name;
1681 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1685 tmp_user = talloc_strdup(mem_ctx, user);
1686 if (!strlower_m(tmp_user)) {
1687 TALLOC_FREE(tmp_user);
1691 if (can_assume && assume_domain(domain)) {
1694 name = talloc_asprintf(mem_ctx, "%s%c%s",
1696 *lp_winbind_separator(),
1698 TALLOC_FREE(tmp_user);
1705 * Client list accessor functions
1708 static struct winbindd_cli_state *_client_list;
1709 static int _num_clients;
1711 /* Return list of all connected clients */
1713 struct winbindd_cli_state *winbindd_client_list(void)
1715 return _client_list;
1718 /* Return list-tail of all connected clients */
1720 struct winbindd_cli_state *winbindd_client_list_tail(void)
1722 return DLIST_TAIL(_client_list);
1725 /* Return previous (read:newer) client in list */
1727 struct winbindd_cli_state *
1728 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1730 return DLIST_PREV(cli);
1733 /* Add a connection to the list */
1735 void winbindd_add_client(struct winbindd_cli_state *cli)
1737 cli->last_access = time(NULL);
1738 DLIST_ADD(_client_list, cli);
1742 /* Remove a client from the list */
1744 void winbindd_remove_client(struct winbindd_cli_state *cli)
1746 DLIST_REMOVE(_client_list, cli);
1750 /* Move a client to head or list */
1752 void winbindd_promote_client(struct winbindd_cli_state *cli)
1754 cli->last_access = time(NULL);
1755 DLIST_PROMOTE(_client_list, cli);
1758 /* Return number of open clients */
1760 int winbindd_num_clients(void)
1762 return _num_clients;
1765 NTSTATUS lookup_usergroups_cached(TALLOC_CTX *mem_ctx,
1766 const struct dom_sid *user_sid,
1767 uint32_t *p_num_groups, struct dom_sid **user_sids)
1769 struct netr_SamInfo3 *info3 = NULL;
1770 NTSTATUS status = NT_STATUS_NO_MEMORY;
1771 uint32_t num_groups = 0;
1773 DEBUG(3,(": lookup_usergroups_cached\n"));
1778 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1780 if (info3 == NULL) {
1781 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1785 * Before bug #7843 the "Domain Local" groups were added with a
1786 * lookupuseraliases call, but this isn't done anymore for our domain
1787 * so we need to resolve resource groups here.
1789 * When to use Resource Groups:
1790 * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1792 status = sid_array_from_info3(mem_ctx, info3,
1797 if (!NT_STATUS_IS_OK(status)) {
1803 *p_num_groups = num_groups;
1804 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1806 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1811 /*********************************************************************
1812 We use this to remove spaces from user and group names
1813 ********************************************************************/
1815 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1816 const char *domain_name,
1820 struct winbindd_domain *domain = NULL;
1823 if (!name || !normalized) {
1824 return NT_STATUS_INVALID_PARAMETER;
1827 if (!lp_winbind_normalize_names()) {
1828 return NT_STATUS_PROCEDURE_NOT_FOUND;
1831 domain = find_domain_from_name_noinit(domain_name);
1832 if (domain == NULL) {
1833 DBG_ERR("Failed to find domain '%s'\n", domain_name);
1834 return NT_STATUS_NO_SUCH_DOMAIN;
1837 /* Alias support and whitespace replacement are mutually
1840 nt_status = resolve_username_to_alias(mem_ctx, domain,
1842 if (NT_STATUS_IS_OK(nt_status)) {
1843 /* special return code to let the caller know we
1844 mapped to an alias */
1845 return NT_STATUS_FILE_RENAMED;
1848 /* check for an unreachable domain */
1850 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1851 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1853 set_domain_offline(domain);
1857 /* deal with whitespace */
1859 *normalized = talloc_strdup(mem_ctx, name);
1860 if (!(*normalized)) {
1861 return NT_STATUS_NO_MEMORY;
1864 all_string_sub( *normalized, " ", "_", 0 );
1866 return NT_STATUS_OK;
1869 /*********************************************************************
1870 We use this to do the inverse of normalize_name_map()
1871 ********************************************************************/
1873 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1878 struct winbindd_domain *domain = find_our_domain();
1880 if (!name || !normalized) {
1881 return NT_STATUS_INVALID_PARAMETER;
1884 if (!lp_winbind_normalize_names()) {
1885 return NT_STATUS_PROCEDURE_NOT_FOUND;
1888 /* Alias support and whitespace replacement are mutally
1891 /* When mapping from an alias to a username, we don't know the
1892 domain. But we only need a domain structure to cache
1893 a successful lookup , so just our own domain structure for
1896 nt_status = resolve_alias_to_username(mem_ctx, domain,
1898 if (NT_STATUS_IS_OK(nt_status)) {
1899 /* Special return code to let the caller know we mapped
1901 return NT_STATUS_FILE_RENAMED;
1904 /* check for an unreachable domain */
1906 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1907 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1909 set_domain_offline(domain);
1913 /* deal with whitespace */
1915 *normalized = talloc_strdup(mem_ctx, name);
1916 if (!(*normalized)) {
1917 return NT_STATUS_NO_MEMORY;
1920 all_string_sub(*normalized, "_", " ", 0);
1922 return NT_STATUS_OK;
1925 /*********************************************************************
1926 ********************************************************************/
1928 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1930 struct winbindd_tdc_domain *tdc = NULL;
1931 TALLOC_CTX *frame = talloc_stackframe();
1934 /* We can contact the domain if it is our primary domain */
1936 if (domain->primary) {
1941 /* Trust the TDC cache and not the winbindd_domain flags */
1943 if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1944 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1950 /* Can always contact a domain that is in out forest */
1952 if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1958 * On a _member_ server, we cannot contact the domain if it
1959 * is running AD and we have no inbound trust.
1963 domain->active_directory &&
1964 ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1966 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1967 "and we have no inbound trust.\n", domain->name));
1971 /* Assume everything else is ok (probably not true but what
1977 talloc_destroy(frame);
1982 /*********************************************************************
1983 ********************************************************************/
1985 bool winbindd_internal_child(struct winbindd_child *child)
1987 if ((child == idmap_child()) || (child == locator_child())) {
1994 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1996 /*********************************************************************
1997 ********************************************************************/
1999 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
2002 char addr[INET6_ADDRSTRLEN];
2003 const char *kdc = NULL;
2006 if (!domain || !domain->alt_name || !*domain->alt_name) {
2010 if (domain->initialized && !domain->active_directory) {
2011 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
2016 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
2019 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
2021 kdc = domain->dcname;
2024 if (!kdc || !*kdc) {
2025 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
2030 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
2031 domain->alt_name) == -1) {
2035 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
2038 setenv(var, kdc, 1);
2042 /*********************************************************************
2043 ********************************************************************/
2045 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
2047 struct winbindd_domain *our_dom = find_our_domain();
2049 winbindd_set_locator_kdc_env(domain);
2051 if (domain != our_dom) {
2052 winbindd_set_locator_kdc_env(our_dom);
2056 /*********************************************************************
2057 ********************************************************************/
2059 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
2063 if (!domain || !domain->alt_name || !*domain->alt_name) {
2067 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
2068 domain->alt_name) == -1) {
2077 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
2082 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
2087 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
2089 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
2091 resp->data.auth.nt_status = NT_STATUS_V(result);
2092 fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
2094 /* we might have given a more useful error above */
2095 if (*resp->data.auth.error_string == '\0')
2096 fstrcpy(resp->data.auth.error_string,
2097 get_friendly_nt_error_msg(result));
2098 resp->data.auth.pam_error = nt_status_to_pam(result);
2101 bool is_domain_offline(const struct winbindd_domain *domain)
2103 if (get_global_winbindd_state_offline()) {
2106 return !domain->online;
2109 bool is_domain_online(const struct winbindd_domain *domain)
2111 return !is_domain_offline(domain);
2115 * Parse an char array into a list of sids.
2117 * The input sidstr should consist of 0-terminated strings
2118 * representing sids, separated by newline characters '\n'.
2119 * The list is terminated by an empty string, i.e.
2120 * character '\0' directly following a character '\n'
2121 * (or '\0' right at the start of sidstr).
2123 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
2124 struct dom_sid **sids, uint32_t *num_sids)
2132 while (p[0] != '\0') {
2134 const char *q = NULL;
2136 if (!dom_sid_parse_endp(p, &sid, &q)) {
2137 DEBUG(1, ("Could not parse sid %s\n", p));
2141 DEBUG(1, ("Got invalid sidstr: %s\n", p));
2144 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
2154 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
2155 struct unixid **pxids, uint32_t *pnum_xids)
2158 struct unixid *xids = NULL;
2159 uint32_t num_xids = 0;
2166 while (p[0] != '\0') {
2169 unsigned long long id;
2174 xid = (struct unixid) { .type = ID_TYPE_UID };
2177 xid = (struct unixid) { .type = ID_TYPE_GID };
2185 id = strtoull(p, &endp, 10);
2186 if ((id == ULLONG_MAX) && (errno == ERANGE)) {
2189 if (*endp != '\n') {
2195 if ((unsigned long long)xid.id != id) {
2199 tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
2205 xids[num_xids] = xid;
2210 *pnum_xids = num_xids;