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;
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,
541 if (!NT_STATUS_IS_OK(status) &&
542 !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
544 DBG_NOTICE("add_trusted_domain returned %s\n",
549 p = q + strlen(q) + 1;
553 Cases to consider when scanning trusts:
554 (a) we are calling from a child domain (primary && !forest_root)
555 (b) we are calling from the root of the forest (primary && forest_root)
556 (c) we are calling from a trusted forest domain (!primary
560 if (state->domain->primary) {
561 /* If this is our primary domain and we are not in the
562 forest root, we have to scan the root trusts first */
564 if (!domain_is_forest_root(state->domain))
565 rescan_forest_root_trusts();
567 rescan_forest_trusts();
569 } else if (domain_is_forest_root(state->domain)) {
570 /* Once we have done root forest trust search, we can
571 go on to search the trusted forests */
573 rescan_forest_trusts();
581 /********************************************************************
582 Scan the trusts of our forest root
583 ********************************************************************/
585 static void rescan_forest_root_trusts( void )
587 struct winbindd_tdc_domain *dom_list = NULL;
588 size_t num_trusts = 0;
592 /* The only transitive trusts supported by Windows 2003 AD are
593 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
594 first two are handled in forest and listed by
595 DsEnumerateDomainTrusts(). Forest trusts are not so we
596 have to do that ourselves. */
598 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
601 for ( i=0; i<num_trusts; i++ ) {
602 struct winbindd_domain *d = NULL;
604 /* Find the forest root. Don't necessarily trust
605 the domain_list() as our primary domain may not
606 have been initialized. */
608 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
612 /* Here's the forest root */
614 d = find_domain_from_name_noinit( dom_list[i].domain_name );
616 status = add_trusted_domain(dom_list[i].domain_name,
617 dom_list[i].dns_name,
619 dom_list[i].trust_type,
620 dom_list[i].trust_flags,
621 dom_list[i].trust_attribs,
625 if (!NT_STATUS_IS_OK(status) &&
626 NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
628 DBG_ERR("add_trusted_domain returned %s\n",
637 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
638 "for domain tree root %s (%s)\n",
639 d->name, d->alt_name ));
641 d->domain_flags = dom_list[i].trust_flags;
642 d->domain_type = dom_list[i].trust_type;
643 d->domain_trust_attribs = dom_list[i].trust_attribs;
645 add_trusted_domains( d );
650 TALLOC_FREE( dom_list );
655 /********************************************************************
656 scan the transitive forest trusts (not our own)
657 ********************************************************************/
660 static void rescan_forest_trusts( void )
662 struct winbindd_domain *d = NULL;
663 struct winbindd_tdc_domain *dom_list = NULL;
664 size_t num_trusts = 0;
668 /* The only transitive trusts supported by Windows 2003 AD are
669 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
670 first two are handled in forest and listed by
671 DsEnumerateDomainTrusts(). Forest trusts are not so we
672 have to do that ourselves. */
674 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
677 for ( i=0; i<num_trusts; i++ ) {
678 uint32_t flags = dom_list[i].trust_flags;
679 uint32_t type = dom_list[i].trust_type;
680 uint32_t attribs = dom_list[i].trust_attribs;
682 d = find_domain_from_name_noinit( dom_list[i].domain_name );
684 /* ignore our primary and internal domains */
686 if ( d && (d->internal || d->primary ) )
689 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
690 (type == LSA_TRUST_TYPE_UPLEVEL) &&
691 (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
693 /* add the trusted domain if we don't know
697 status = add_trusted_domain(
698 dom_list[i].domain_name,
699 dom_list[i].dns_name,
706 if (!NT_STATUS_IS_OK(status) &&
707 NT_STATUS_EQUAL(status,
708 NT_STATUS_NO_SUCH_DOMAIN))
710 DBG_ERR("add_trusted_domain: %s\n",
720 DEBUG(10,("Following trust path for domain %s (%s)\n",
721 d->name, d->alt_name ));
722 add_trusted_domains( d );
726 TALLOC_FREE( dom_list );
731 /*********************************************************************
732 The process of updating the trusted domain list is a three step
735 (b) ask the root domain in our forest
736 (c) ask the a DC in any Win2003 trusted forests
737 *********************************************************************/
739 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
740 struct timeval now, void *private_data)
744 /* I use to clear the cache here and start over but that
745 caused problems in child processes that needed the
746 trust dom list early on. Removing it means we
747 could have some trusted domains listed that have been
748 removed from our primary domain's DC until a full
749 restart. This should be ok since I think this is what
750 Windows does as well. */
752 /* this will only add new domains we didn't already know about
753 in the domain_list()*/
755 add_trusted_domains( find_our_domain() );
757 te = tevent_add_timer(
758 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
759 rescan_trusted_domains, NULL);
761 * If te == NULL, there's not much we can do here. Don't fail, the
762 * only thing we miss is new trusted domains.
768 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
769 struct winbindd_cli_state *state)
771 /* Ensure null termination */
772 state->request->domain_name
773 [sizeof(state->request->domain_name)-1]='\0';
774 state->request->data.init_conn.dcname
775 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
777 if (strlen(state->request->data.init_conn.dcname) > 0) {
778 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
781 init_dc_connection(domain, false);
783 if (!domain->initialized) {
784 /* If we return error here we can't do any cached authentication,
785 but we may be in disconnected mode and can't initialize correctly.
786 Do what the previous code did and just return without initialization,
787 once we go online we'll re-initialize.
789 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
790 "online = %d\n", domain->name, (int)domain->online ));
793 fstrcpy(state->response->data.domain_info.name, domain->name);
794 fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
795 sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
797 state->response->data.domain_info.native_mode
798 = domain->native_mode;
799 state->response->data.domain_info.active_directory
800 = domain->active_directory;
801 state->response->data.domain_info.primary
807 static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
810 struct server_id server_id,
813 TALLOC_CTX *frame = talloc_stackframe();
814 enum netr_SchannelType secure_channel_type = SEC_CHAN_DOMAIN;
815 struct lsa_TrustDomainInfoInfoEx info;
816 enum ndr_err_code ndr_err;
817 struct winbindd_domain *d = NULL;
818 uint32_t trust_flags = 0;
821 DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
828 ndr_err = ndr_pull_struct_blob_all(data, frame, &info,
829 (ndr_pull_flags_fn_t)ndr_pull_lsa_TrustDomainInfoInfoEx);
830 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
835 d = find_domain_from_name_noinit(info.netbios_name.string);
841 if (info.trust_type == LSA_TRUST_TYPE_UPLEVEL) {
842 secure_channel_type = SEC_CHAN_DNS_DOMAIN;
844 if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
845 trust_flags |= NETR_TRUST_FLAG_INBOUND;
847 if (info.trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
848 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
850 if (info.trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
851 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
854 status = add_trusted_domain(info.netbios_name.string,
855 info.domain_name.string,
859 info.trust_attributes,
862 if (!NT_STATUS_IS_OK(status) &&
863 !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
865 DBG_NOTICE("add_trusted_domain returned %s\n",
874 * We did not get the secret when we queried secrets.tdb, so read it
875 * from secrets.tdb and re-sync the databases
877 static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
880 struct cli_credentials *creds;
881 NTSTATUS can_migrate = pdb_get_trust_credentials(domain->name,
882 NULL, domain, &creds);
883 if (!NT_STATUS_IS_OK(can_migrate)) {
884 DEBUG(0, ("Failed to fetch our own, local AD domain join "
885 "password for winbindd's internal use, both from "
886 "secrets.tdb and secrets.ldb: %s\n",
887 nt_errstr(can_migrate)));
892 * NOTE: It is very unlikely we end up here if there is an
893 * oldpass, because a new password is created at
894 * classicupgrade, so this is not a concern.
896 ok = secrets_store_machine_pw_sync(cli_credentials_get_password(creds),
898 cli_credentials_get_domain(creds),
899 cli_credentials_get_realm(creds),
900 cli_credentials_get_salt_principal(creds),
901 0, /* Supported enc types, unused */
903 cli_credentials_get_password_last_changed_time(creds),
904 cli_credentials_get_secure_channel_type(creds),
905 false /* do_delete: Do not delete */);
908 DEBUG(0, ("Failed to write our our own, "
909 "local AD domain join password for "
910 "winbindd's internal use into secrets.tdb\n"));
916 /* Look up global info for the winbind daemon */
917 bool init_domain_list(void)
919 int role = lp_server_role();
920 struct pdb_domain_info *pdb_domain_info = NULL;
921 struct winbindd_domain *domain = NULL;
924 /* Free existing list */
929 status = add_trusted_domain("BUILTIN",
932 LSA_TRUST_TYPE_DOWNLEVEL,
934 0, /* trust_attribs */
937 if (!NT_STATUS_IS_OK(status)) {
938 DBG_ERR("add_trusted_domain BUILTIN returned %s\n",
946 * In case the passdb backend is passdb_dsdb the domain SID comes from
947 * dsdb, not from secrets.tdb. As we use the domain SID in various
948 * places, we must ensure the domain SID is migrated from dsdb to
949 * secrets.tdb before get_global_sam_sid() is called the first time.
951 * The migration is done as part of the passdb_dsdb initialisation,
952 * calling pdb_get_domain_info() triggers it.
954 pdb_domain_info = pdb_get_domain_info(talloc_tos());
956 if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
957 uint32_t trust_flags;
959 enum netr_SchannelType sec_chan_type;
960 const char *account_name;
961 struct samr_Password current_nt_hash;
964 if (pdb_domain_info == NULL) {
965 DEBUG(0, ("Failed to fetch our own, local AD "
966 "domain info from sam.ldb\n"));
970 trust_flags = NETR_TRUST_FLAG_PRIMARY;
971 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
972 trust_flags |= NETR_TRUST_FLAG_NATIVE;
973 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
975 is_root = strequal(pdb_domain_info->dns_domain,
976 pdb_domain_info->dns_forest);
978 trust_flags |= NETR_TRUST_FLAG_TREEROOT;
981 status = add_trusted_domain(pdb_domain_info->name,
982 pdb_domain_info->dns_domain,
983 &pdb_domain_info->sid,
984 LSA_TRUST_TYPE_UPLEVEL,
986 LSA_TRUST_ATTRIBUTE_WITHIN_FOREST,
989 TALLOC_FREE(pdb_domain_info);
990 if (!NT_STATUS_IS_OK(status)) {
991 DBG_ERR("Failed to add our own, local AD "
992 "domain to winbindd's internal list\n");
997 * We need to call this to find out if we are an RODC
999 ok = get_trust_pw_hash(domain->name,
1000 current_nt_hash.hash,
1005 * If get_trust_pw_hash() fails, then try and
1006 * fetch the password from the more recent of
1007 * secrets.{ldb,tdb} using the
1008 * pdb_get_trust_credentials()
1010 ok = migrate_secrets_tdb_to_ldb(domain);
1013 DEBUG(0, ("Failed to migrate our own, "
1014 "local AD domain join password for "
1015 "winbindd's internal use into "
1019 ok = get_trust_pw_hash(domain->name,
1020 current_nt_hash.hash,
1024 DEBUG(0, ("Failed to find our our own, just "
1025 "written local AD domain join "
1026 "password for winbindd's internal "
1027 "use in secrets.tdb\n"));
1032 domain->secure_channel_type = sec_chan_type;
1033 if (sec_chan_type == SEC_CHAN_RODC) {
1034 domain->rodc = true;
1038 uint32_t trust_flags;
1039 enum netr_SchannelType secure_channel_type;
1041 trust_flags = NETR_TRUST_FLAG_OUTBOUND;
1042 if (role != ROLE_DOMAIN_MEMBER) {
1043 trust_flags |= NETR_TRUST_FLAG_PRIMARY;
1046 if (role > ROLE_DOMAIN_MEMBER) {
1047 secure_channel_type = SEC_CHAN_BDC;
1049 secure_channel_type = SEC_CHAN_LOCAL;
1052 status = add_trusted_domain(get_global_sam_name(),
1054 get_global_sam_sid(),
1055 LSA_TRUST_TYPE_DOWNLEVEL,
1057 0, /* trust_attribs */
1058 secure_channel_type,
1060 if (!NT_STATUS_IS_OK(status)) {
1061 DBG_ERR("Failed to add local SAM to "
1062 "domain to winbindd's internal list\n");
1066 /* Add ourselves as the first entry. */
1068 if ( role == ROLE_DOMAIN_MEMBER ) {
1069 struct dom_sid our_sid;
1070 uint32_t trust_type;
1072 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
1073 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
1077 if (lp_realm() != NULL) {
1078 trust_type = LSA_TRUST_TYPE_UPLEVEL;
1080 trust_type = LSA_TRUST_TYPE_DOWNLEVEL;
1083 status = add_trusted_domain(lp_workgroup(),
1087 NETR_TRUST_FLAG_PRIMARY|
1088 NETR_TRUST_FLAG_OUTBOUND,
1089 0, /* trust_attribs */
1092 if (!NT_STATUS_IS_OK(status)) {
1093 DBG_ERR("Failed to add local SAM to "
1094 "domain to winbindd's internal list\n");
1097 /* Even in the parent winbindd we'll need to
1098 talk to the DC, so try and see if we can
1099 contact it. Theoretically this isn't neccessary
1100 as the init_dc_connection() in init_child_recv()
1101 will do this, but we can start detecting the DC
1103 set_domain_online_request(domain);
1107 if (IS_DC && (pdb_capabilities() & PDB_CAP_TRUSTED_DOMAINS_EX)) {
1108 uint32_t num_domains = 0;
1109 struct pdb_trusted_domain **domains = NULL;
1112 status = pdb_enum_trusted_domains(talloc_tos(), &num_domains, &domains);
1113 if (!NT_STATUS_IS_OK(status)) {
1114 DBG_ERR("pdb_enum_trusted_domains() failed - %s\n",
1119 for (i = 0; i < num_domains; i++) {
1120 enum netr_SchannelType sec_chan_type = SEC_CHAN_DOMAIN;
1121 uint32_t trust_flags = 0;
1123 if (domains[i]->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
1124 sec_chan_type = SEC_CHAN_DNS_DOMAIN;
1127 if (!(domains[i]->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND)) {
1128 sec_chan_type = SEC_CHAN_NULL;
1131 if (domains[i]->trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
1132 trust_flags |= NETR_TRUST_FLAG_INBOUND;
1134 if (domains[i]->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
1135 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
1137 if (domains[i]->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
1138 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
1141 status = add_trusted_domain(domains[i]->netbios_name,
1142 domains[i]->domain_name,
1143 &domains[i]->security_identifier,
1144 domains[i]->trust_type,
1146 domains[i]->trust_attributes,
1149 if (!NT_STATUS_IS_OK(status)) {
1150 DBG_NOTICE("add_trusted_domain returned %s\n",
1155 if (domains[i]->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
1156 domain->active_directory = true;
1158 domain->domain_type = domains[i]->trust_type;
1159 domain->domain_trust_attribs = domains[i]->trust_attributes;
1161 if (sec_chan_type != SEC_CHAN_NULL) {
1162 /* Even in the parent winbindd we'll need to
1163 talk to the DC, so try and see if we can
1164 contact it. Theoretically this isn't neccessary
1165 as the init_dc_connection() in init_child_recv()
1166 will do this, but we can start detecting the DC
1168 set_domain_online_request(domain);
1172 for (i = 0; i < num_domains; i++) {
1173 struct ForestTrustInfo fti;
1175 enum ndr_err_code ndr_err;
1176 struct winbindd_domain *routing_domain = NULL;
1179 if (domains[i]->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
1183 if (!(domains[i]->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1187 if (domains[i]->trust_forest_trust_info.length == 0) {
1191 routing_domain = find_domain_from_name_noinit(
1192 domains[i]->netbios_name);
1193 if (routing_domain == NULL) {
1194 DBG_ERR("Can't find winbindd domain [%s]\n",
1195 domains[i]->netbios_name);
1199 ndr_err = ndr_pull_struct_blob_all(
1200 &domains[i]->trust_forest_trust_info,
1202 (ndr_pull_flags_fn_t)ndr_pull_ForestTrustInfo);
1203 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1204 DBG_ERR("ndr_pull_ForestTrustInfo(%s) - %s\n",
1205 domains[i]->netbios_name,
1206 ndr_map_error2string(ndr_err));
1210 for (fi = 0; fi < fti.count; fi++) {
1211 struct ForestTrustInfoRecord *rec =
1212 &fti.records[fi].record;
1213 struct ForestTrustDataDomainInfo *drec = NULL;
1215 if (rec->type != FOREST_TRUST_DOMAIN_INFO) {
1218 drec = &rec->data.info;
1220 if (rec->flags & LSA_NB_DISABLED_MASK) {
1224 if (rec->flags & LSA_SID_DISABLED_MASK) {
1230 * also try to find a matching
1231 * LSA_TLN_DISABLED_MASK ???
1234 domain = find_domain_from_name_noinit(drec->netbios_name.string);
1235 if (domain != NULL) {
1239 status = add_trusted_domain(drec->netbios_name.string,
1240 drec->dns_name.string,
1242 LSA_TRUST_TYPE_UPLEVEL,
1243 NETR_TRUST_FLAG_OUTBOUND,
1247 if (!NT_STATUS_IS_OK(status)) {
1248 DBG_NOTICE("add_trusted_domain returned %s\n",
1252 if (domain == NULL) {
1255 ok = set_routing_domain(domain, routing_domain);
1257 DBG_ERR("set_routing_domain on [%s] to "
1260 routing_domain->name);
1266 uint32_t num_domains = 0;
1267 struct trustdom_info **domains = NULL;
1270 status = pdb_enum_trusteddoms(talloc_tos(), &num_domains, &domains);
1271 if (!NT_STATUS_IS_OK(status)) {
1272 DBG_ERR("pdb_enum_trusteddoms() failed - %s\n",
1277 for (i = 0; i < num_domains; i++) {
1278 status = add_trusted_domain(domains[i]->name,
1281 LSA_TRUST_TYPE_DOWNLEVEL,
1282 NETR_TRUST_FLAG_OUTBOUND,
1286 if (!NT_STATUS_IS_OK(status)) {
1287 DBG_NOTICE("add_trusted_domain returned %s\n",
1292 /* Even in the parent winbindd we'll need to
1293 talk to the DC, so try and see if we can
1294 contact it. Theoretically this isn't neccessary
1295 as the init_dc_connection() in init_child_recv()
1296 will do this, but we can start detecting the DC
1298 set_domain_online_request(domain);
1302 status = imessaging_register(winbind_imessaging_context(), NULL,
1303 MSG_WINBIND_NEW_TRUSTED_DOMAIN,
1304 wb_imsg_new_trusted_domain);
1305 if (!NT_STATUS_IS_OK(status)) {
1306 DEBUG(0, ("imessaging_register(MSG_WINBIND_NEW_TRUSTED_DOMAIN) - %s\n",
1307 nt_errstr(status)));
1315 * Given a domain name, return the struct winbindd domain info for it
1317 * @note Do *not* pass lp_workgroup() to this function. domain_list
1318 * may modify it's value, and free that pointer. Instead, our local
1319 * domain may be found by calling find_our_domain().
1323 * @return The domain structure for the named domain, if it is working.
1326 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
1328 struct winbindd_domain *domain;
1330 /* Search through list */
1332 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1333 if (strequal(domain_name, domain->name)) {
1336 if (domain->alt_name == NULL) {
1339 if (strequal(domain_name, domain->alt_name)) {
1350 * Given a domain name, return the struct winbindd domain if it's a direct
1353 * @return The domain structure for the named domain, if it is a direct outgoing trust
1355 struct winbindd_domain *find_trust_from_name_noinit(const char *domain_name)
1357 struct winbindd_domain *domain = NULL;
1359 domain = find_domain_from_name_noinit(domain_name);
1360 if (domain == NULL) {
1364 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1371 struct winbindd_domain *find_domain_from_name(const char *domain_name)
1373 struct winbindd_domain *domain;
1375 domain = find_domain_from_name_noinit(domain_name);
1380 if (!domain->initialized)
1381 init_dc_connection(domain, false);
1386 /* Given a domain sid, return the struct winbindd domain info for it */
1388 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
1390 struct winbindd_domain *domain;
1392 /* Search through list */
1394 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1395 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
1405 * Given a domain sid, return the struct winbindd domain if it's a direct
1408 * @return The domain structure for the specified domain, if it is a direct outgoing trust
1410 struct winbindd_domain *find_trust_from_sid_noinit(const struct dom_sid *sid)
1412 struct winbindd_domain *domain = NULL;
1414 domain = find_domain_from_sid_noinit(sid);
1415 if (domain == NULL) {
1419 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1426 /* Given a domain sid, return the struct winbindd domain info for it */
1428 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
1430 struct winbindd_domain *domain;
1432 domain = find_domain_from_sid_noinit(sid);
1437 if (!domain->initialized)
1438 init_dc_connection(domain, false);
1443 struct winbindd_domain *find_our_domain(void)
1445 struct winbindd_domain *domain;
1447 /* Search through list */
1449 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1450 if (domain->primary)
1454 smb_panic("Could not find our domain");
1458 struct winbindd_domain *find_default_route_domain(void)
1461 return find_our_domain();
1463 DBG_ERR("Routing logic not yet implemented on a DC");
1467 /* Find the appropriate domain to lookup a name or SID */
1469 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
1471 DBG_DEBUG("SID [%s]\n", sid_string_dbg(sid));
1474 * SIDs in the S-1-22-{1,2} domain and well-known SIDs should be handled
1478 if ( sid_check_is_in_unix_groups(sid) ||
1479 sid_check_is_unix_groups(sid) ||
1480 sid_check_is_in_unix_users(sid) ||
1481 sid_check_is_unix_users(sid) ||
1482 sid_check_is_wellknown_domain(sid, NULL) ||
1483 sid_check_is_in_wellknown_domain(sid) )
1485 return find_domain_from_sid(get_global_sam_sid());
1488 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
1489 * one to contact the external DC's. On member servers the internal
1490 * domains are different: These are part of the local SAM. */
1492 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
1493 DEBUG(10, ("calling find_domain_from_sid\n"));
1494 return find_domain_from_sid(sid);
1497 /* On a member server a query for SID or name can always go to our
1500 DEBUG(10, ("calling find_our_domain\n"));
1501 return find_our_domain();
1504 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1506 if ( strequal(domain_name, unix_users_domain_name() ) ||
1507 strequal(domain_name, unix_groups_domain_name() ) )
1510 * The "Unix User" and "Unix Group" domain our handled by
1513 return find_domain_from_name_noinit( get_global_sam_name() );
1516 if (IS_DC || strequal(domain_name, "BUILTIN") ||
1517 strequal(domain_name, get_global_sam_name()))
1518 return find_domain_from_name_noinit(domain_name);
1521 return find_our_domain();
1524 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1526 static bool assume_domain(const char *domain)
1528 /* never assume the domain on a standalone server */
1530 if ( lp_server_role() == ROLE_STANDALONE )
1533 /* domain member servers may possibly assume for the domain name */
1535 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1536 if ( !strequal(lp_workgroup(), domain) )
1539 if ( lp_winbind_use_default_domain() )
1543 /* only left with a domain controller */
1545 if ( strequal(get_global_sam_name(), domain) ) {
1552 /* Parse a string of the form DOMAIN\user into a domain and a user */
1554 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1556 char *p = strchr(domuser,*lp_winbind_separator());
1559 fstrcpy(user, domuser);
1560 p = strchr(domuser, '@');
1562 if ( assume_domain(lp_workgroup()) && p == NULL) {
1563 fstrcpy(domain, lp_workgroup());
1564 } else if (p != NULL) {
1565 fstrcpy(domain, p + 1);
1566 user[PTR_DIFF(p, domuser)] = 0;
1572 fstrcpy(domain, domuser);
1573 domain[PTR_DIFF(p, domuser)] = 0;
1576 return strupper_m(domain);
1579 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1580 char **domain, char **user)
1582 fstring fstr_domain, fstr_user;
1583 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1586 *domain = talloc_strdup(mem_ctx, fstr_domain);
1587 *user = talloc_strdup(mem_ctx, fstr_user);
1588 return ((*domain != NULL) && (*user != NULL));
1591 /* Ensure an incoming username from NSS is fully qualified. Replace the
1592 incoming fstring with DOMAIN <separator> user. Returns the same
1593 values as parse_domain_user() but also replaces the incoming username.
1594 Used to ensure all names are fully qualified within winbindd.
1595 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1596 The protocol definitions of auth_crap, chng_pswd_auth_crap
1597 really should be changed to use this instead of doing things
1600 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1602 if (!parse_domain_user(username_inout, domain, user)) {
1605 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1606 domain, *lp_winbind_separator(),
1612 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1613 'winbind separator' options.
1615 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1618 If we are a PDC or BDC, and this is for our domain, do likewise.
1620 On an AD DC we always fill DOMAIN\\USERNAME.
1622 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1624 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1628 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1632 fstrcpy(tmp_user, user);
1633 (void)strlower_m(tmp_user);
1635 if (can_assume && assume_domain(domain)) {
1636 strlcpy(name, tmp_user, sizeof(fstring));
1638 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1639 domain, *lp_winbind_separator(),
1645 * talloc version of fill_domain_username()
1646 * return NULL on talloc failure.
1648 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1653 char *tmp_user, *name;
1655 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1659 tmp_user = talloc_strdup(mem_ctx, user);
1660 if (!strlower_m(tmp_user)) {
1661 TALLOC_FREE(tmp_user);
1665 if (can_assume && assume_domain(domain)) {
1668 name = talloc_asprintf(mem_ctx, "%s%c%s",
1670 *lp_winbind_separator(),
1672 TALLOC_FREE(tmp_user);
1679 * Client list accessor functions
1682 static struct winbindd_cli_state *_client_list;
1683 static int _num_clients;
1685 /* Return list of all connected clients */
1687 struct winbindd_cli_state *winbindd_client_list(void)
1689 return _client_list;
1692 /* Return list-tail of all connected clients */
1694 struct winbindd_cli_state *winbindd_client_list_tail(void)
1696 return DLIST_TAIL(_client_list);
1699 /* Return previous (read:newer) client in list */
1701 struct winbindd_cli_state *
1702 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1704 return DLIST_PREV(cli);
1707 /* Add a connection to the list */
1709 void winbindd_add_client(struct winbindd_cli_state *cli)
1711 cli->last_access = time(NULL);
1712 DLIST_ADD(_client_list, cli);
1716 /* Remove a client from the list */
1718 void winbindd_remove_client(struct winbindd_cli_state *cli)
1720 DLIST_REMOVE(_client_list, cli);
1724 /* Move a client to head or list */
1726 void winbindd_promote_client(struct winbindd_cli_state *cli)
1728 cli->last_access = time(NULL);
1729 DLIST_PROMOTE(_client_list, cli);
1732 /* Return number of open clients */
1734 int winbindd_num_clients(void)
1736 return _num_clients;
1739 NTSTATUS lookup_usergroups_cached(TALLOC_CTX *mem_ctx,
1740 const struct dom_sid *user_sid,
1741 uint32_t *p_num_groups, struct dom_sid **user_sids)
1743 struct netr_SamInfo3 *info3 = NULL;
1744 NTSTATUS status = NT_STATUS_NO_MEMORY;
1745 uint32_t num_groups = 0;
1747 DEBUG(3,(": lookup_usergroups_cached\n"));
1752 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1754 if (info3 == NULL) {
1755 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1759 * Before bug #7843 the "Domain Local" groups were added with a
1760 * lookupuseraliases call, but this isn't done anymore for our domain
1761 * so we need to resolve resource groups here.
1763 * When to use Resource Groups:
1764 * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1766 status = sid_array_from_info3(mem_ctx, info3,
1771 if (!NT_STATUS_IS_OK(status)) {
1777 *p_num_groups = num_groups;
1778 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1780 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1785 /*********************************************************************
1786 We use this to remove spaces from user and group names
1787 ********************************************************************/
1789 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1790 const char *domain_name,
1794 struct winbindd_domain *domain = NULL;
1797 if (!name || !normalized) {
1798 return NT_STATUS_INVALID_PARAMETER;
1801 if (!lp_winbind_normalize_names()) {
1802 return NT_STATUS_PROCEDURE_NOT_FOUND;
1805 domain = find_domain_from_name_noinit(domain_name);
1806 if (domain == NULL) {
1807 DBG_ERR("Failed to find domain '%s'\n", domain_name);
1808 return NT_STATUS_NO_SUCH_DOMAIN;
1811 /* Alias support and whitespace replacement are mutually
1814 nt_status = resolve_username_to_alias(mem_ctx, domain,
1816 if (NT_STATUS_IS_OK(nt_status)) {
1817 /* special return code to let the caller know we
1818 mapped to an alias */
1819 return NT_STATUS_FILE_RENAMED;
1822 /* check for an unreachable domain */
1824 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1825 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1827 set_domain_offline(domain);
1831 /* deal with whitespace */
1833 *normalized = talloc_strdup(mem_ctx, name);
1834 if (!(*normalized)) {
1835 return NT_STATUS_NO_MEMORY;
1838 all_string_sub( *normalized, " ", "_", 0 );
1840 return NT_STATUS_OK;
1843 /*********************************************************************
1844 We use this to do the inverse of normalize_name_map()
1845 ********************************************************************/
1847 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1852 struct winbindd_domain *domain = find_our_domain();
1854 if (!name || !normalized) {
1855 return NT_STATUS_INVALID_PARAMETER;
1858 if (!lp_winbind_normalize_names()) {
1859 return NT_STATUS_PROCEDURE_NOT_FOUND;
1862 /* Alias support and whitespace replacement are mutally
1865 /* When mapping from an alias to a username, we don't know the
1866 domain. But we only need a domain structure to cache
1867 a successful lookup , so just our own domain structure for
1870 nt_status = resolve_alias_to_username(mem_ctx, domain,
1872 if (NT_STATUS_IS_OK(nt_status)) {
1873 /* Special return code to let the caller know we mapped
1875 return NT_STATUS_FILE_RENAMED;
1878 /* check for an unreachable domain */
1880 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1881 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1883 set_domain_offline(domain);
1887 /* deal with whitespace */
1889 *normalized = talloc_strdup(mem_ctx, name);
1890 if (!(*normalized)) {
1891 return NT_STATUS_NO_MEMORY;
1894 all_string_sub(*normalized, "_", " ", 0);
1896 return NT_STATUS_OK;
1899 /*********************************************************************
1900 ********************************************************************/
1902 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1904 struct winbindd_tdc_domain *tdc = NULL;
1905 TALLOC_CTX *frame = talloc_stackframe();
1908 /* We can contact the domain if it is our primary domain */
1910 if (domain->primary) {
1915 /* Trust the TDC cache and not the winbindd_domain flags */
1917 if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1918 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1924 /* Can always contact a domain that is in out forest */
1926 if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1932 * On a _member_ server, we cannot contact the domain if it
1933 * is running AD and we have no inbound trust.
1937 domain->active_directory &&
1938 ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1940 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1941 "and we have no inbound trust.\n", domain->name));
1945 /* Assume everything else is ok (probably not true but what
1951 talloc_destroy(frame);
1956 /*********************************************************************
1957 ********************************************************************/
1959 bool winbindd_internal_child(struct winbindd_child *child)
1961 if ((child == idmap_child()) || (child == locator_child())) {
1968 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1970 /*********************************************************************
1971 ********************************************************************/
1973 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1976 char addr[INET6_ADDRSTRLEN];
1977 const char *kdc = NULL;
1980 if (!domain || !domain->alt_name || !*domain->alt_name) {
1984 if (domain->initialized && !domain->active_directory) {
1985 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1990 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1993 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1995 kdc = domain->dcname;
1998 if (!kdc || !*kdc) {
1999 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
2004 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
2005 domain->alt_name) == -1) {
2009 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
2012 setenv(var, kdc, 1);
2016 /*********************************************************************
2017 ********************************************************************/
2019 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
2021 struct winbindd_domain *our_dom = find_our_domain();
2023 winbindd_set_locator_kdc_env(domain);
2025 if (domain != our_dom) {
2026 winbindd_set_locator_kdc_env(our_dom);
2030 /*********************************************************************
2031 ********************************************************************/
2033 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
2037 if (!domain || !domain->alt_name || !*domain->alt_name) {
2041 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
2042 domain->alt_name) == -1) {
2051 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
2056 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
2061 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
2063 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
2065 resp->data.auth.nt_status = NT_STATUS_V(result);
2066 fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
2068 /* we might have given a more useful error above */
2069 if (*resp->data.auth.error_string == '\0')
2070 fstrcpy(resp->data.auth.error_string,
2071 get_friendly_nt_error_msg(result));
2072 resp->data.auth.pam_error = nt_status_to_pam(result);
2075 bool is_domain_offline(const struct winbindd_domain *domain)
2077 if (get_global_winbindd_state_offline()) {
2080 return !domain->online;
2083 bool is_domain_online(const struct winbindd_domain *domain)
2085 return !is_domain_offline(domain);
2089 * Parse an char array into a list of sids.
2091 * The input sidstr should consist of 0-terminated strings
2092 * representing sids, separated by newline characters '\n'.
2093 * The list is terminated by an empty string, i.e.
2094 * character '\0' directly following a character '\n'
2095 * (or '\0' right at the start of sidstr).
2097 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
2098 struct dom_sid **sids, uint32_t *num_sids)
2106 while (p[0] != '\0') {
2108 const char *q = NULL;
2110 if (!dom_sid_parse_endp(p, &sid, &q)) {
2111 DEBUG(1, ("Could not parse sid %s\n", p));
2115 DEBUG(1, ("Got invalid sidstr: %s\n", p));
2118 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
2128 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
2129 struct unixid **pxids, uint32_t *pnum_xids)
2132 struct unixid *xids = NULL;
2133 uint32_t num_xids = 0;
2140 while (p[0] != '\0') {
2143 unsigned long long id;
2148 xid = (struct unixid) { .type = ID_TYPE_UID };
2151 xid = (struct unixid) { .type = ID_TYPE_GID };
2159 id = strtoull(p, &endp, 10);
2160 if ((id == ULLONG_MAX) && (errno == ERANGE)) {
2163 if (*endp != '\n') {
2169 if ((unsigned long long)xid.id != id) {
2173 tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
2179 xids[num_xids] = xid;
2184 *pnum_xids = num_xids;