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 domain->can_do_ncacn_ip_tcp = domain->active_directory;
280 /* Link to domain list */
281 DLIST_ADD_END(_domain_list, domain);
283 wcache_tdc_add_domain( domain );
285 setup_domain_child(domain);
287 DBG_NOTICE("Added domain [%s] [%s] [%s]\n",
288 domain->name, domain->alt_name,
289 sid_string_dbg(&domain->sid));
295 bool set_routing_domain(struct winbindd_domain *domain,
296 const struct winbindd_domain *routing_domain)
298 if (domain->routing_domain == NULL) {
299 domain->routing_domain = routing_domain;
302 if (domain->routing_domain != routing_domain) {
308 bool add_trusted_domain_from_auth(uint16_t validation_level,
309 struct info3_text *info3,
310 struct info6_text *info6)
312 struct winbindd_domain *domain = NULL;
313 struct dom_sid domain_sid;
314 const char *dns_domainname = NULL;
319 * We got a successfull auth from a domain that might not yet be in our
320 * domain list. If we're a member we trust our DC who authenticated the
321 * user from that domain and add the domain to our list on-the-fly. If
322 * we're a DC we rely on configured trusts and don't add on-the-fly.
329 ok = dom_sid_parse(info3->dom_sid, &domain_sid);
331 DBG_NOTICE("dom_sid_parse [%s] failed\n", info3->dom_sid);
335 if (validation_level == 6) {
336 dns_domainname = &info6->dns_domainname[0];
339 status = add_trusted_domain(info3->logon_dom,
343 NETR_TRUST_FLAG_OUTBOUND,
347 if (!NT_STATUS_IS_OK(status) &&
348 !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
350 DBG_DEBUG("Adding domain [%s] with sid [%s] failed\n",
351 info3->logon_dom, info3->dom_sid);
355 ok = set_routing_domain(domain, find_default_route_domain());
363 bool domain_is_forest_root(const struct winbindd_domain *domain)
365 const uint32_t fr_flags =
366 (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
368 return ((domain->domain_flags & fr_flags) == fr_flags);
371 /********************************************************************
372 rescan our domains looking for new trusted domains
373 ********************************************************************/
375 struct trustdom_state {
376 struct winbindd_domain *domain;
377 struct winbindd_request request;
380 static void trustdom_list_done(struct tevent_req *req);
381 static void rescan_forest_root_trusts( void );
382 static void rescan_forest_trusts( void );
384 static void add_trusted_domains( struct winbindd_domain *domain )
386 struct trustdom_state *state;
387 struct tevent_req *req;
389 state = talloc_zero(NULL, struct trustdom_state);
391 DEBUG(0, ("talloc failed\n"));
394 state->domain = domain;
396 state->request.length = sizeof(state->request);
397 state->request.cmd = WINBINDD_LIST_TRUSTDOM;
399 req = wb_domain_request_send(state, server_event_context(),
400 domain, &state->request);
402 DEBUG(1, ("wb_domain_request_send failed\n"));
406 tevent_req_set_callback(req, trustdom_list_done, state);
409 static void trustdom_list_done(struct tevent_req *req)
411 struct trustdom_state *state = tevent_req_callback_data(
412 req, struct trustdom_state);
413 struct winbindd_response *response;
417 bool within_forest = false;
422 * Only when we enumerate our primary domain
423 * or our forest root domain, we should keep
424 * the NETR_TRUST_FLAG_IN_FOREST flag, in
425 * all other cases we need to clear it as the domain
426 * is not part of our forest.
428 if (state->domain->primary) {
429 within_forest = true;
430 } else if (domain_is_forest_root(state->domain)) {
431 within_forest = true;
434 res = wb_domain_request_recv(req, state, &response, &err);
435 if ((res == -1) || (response->result != WINBINDD_OK)) {
436 DBG_WARNING("Could not receive trusts for domain %s\n",
437 state->domain->name);
442 if (response->length < sizeof(struct winbindd_response)) {
443 DBG_ERR("ill-formed trustdom response - short length\n");
448 extra_len = response->length - sizeof(struct winbindd_response);
450 p = (char *)response->extra_data.data;
452 while ((p - (char *)response->extra_data.data) < extra_len) {
453 struct winbindd_domain *domain = NULL;
454 char *name, *q, *sidstr, *alt_name;
457 uint32_t trust_attribs;
458 uint32_t trust_flags;
460 DBG_DEBUG("parsing response line '%s'\n", p);
464 alt_name = strchr(p, '\\');
465 if (alt_name == NULL) {
466 DBG_ERR("Got invalid trustdom response\n");
473 sidstr = strchr(alt_name, '\\');
474 if (sidstr == NULL) {
475 DBG_ERR("Got invalid trustdom response\n");
482 /* use the real alt_name if we have one, else pass in NULL */
483 if (strequal(alt_name, "(null)")) {
487 q = strtok(sidstr, "\\");
489 DBG_ERR("Got invalid trustdom response\n");
493 if (!string_to_sid(&sid, sidstr)) {
494 DEBUG(0, ("Got invalid trustdom response\n"));
498 q = strtok(NULL, "\\");
500 DBG_ERR("Got invalid trustdom response\n");
504 trust_flags = (uint32_t)strtoul(q, NULL, 10);
506 q = strtok(NULL, "\\");
508 DBG_ERR("Got invalid trustdom response\n");
512 trust_type = (uint32_t)strtoul(q, NULL, 10);
514 q = strtok(NULL, "\n");
516 DBG_ERR("Got invalid trustdom response\n");
520 trust_attribs = (uint32_t)strtoul(q, NULL, 10);
522 if (!within_forest) {
523 trust_flags &= ~NETR_TRUST_FLAG_IN_FOREST;
526 if (!state->domain->primary) {
527 trust_flags &= ~NETR_TRUST_FLAG_PRIMARY;
531 * We always call add_trusted_domain() cause on an existing
532 * domain structure, it will update the SID if necessary.
533 * This is important because we need the SID for sibling
536 status = add_trusted_domain(name,
544 if (!NT_STATUS_IS_OK(status) &&
545 !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
547 DBG_NOTICE("add_trusted_domain returned %s\n",
552 ok = set_routing_domain(domain, find_default_route_domain());
554 DBG_ERR("set_routing_domain failed\n");
558 p = q + strlen(q) + 1;
562 Cases to consider when scanning trusts:
563 (a) we are calling from a child domain (primary && !forest_root)
564 (b) we are calling from the root of the forest (primary && forest_root)
565 (c) we are calling from a trusted forest domain (!primary
569 if (state->domain->primary) {
570 /* If this is our primary domain and we are not in the
571 forest root, we have to scan the root trusts first */
573 if (!domain_is_forest_root(state->domain))
574 rescan_forest_root_trusts();
576 rescan_forest_trusts();
578 } else if (domain_is_forest_root(state->domain)) {
579 /* Once we have done root forest trust search, we can
580 go on to search the trusted forests */
582 rescan_forest_trusts();
590 /********************************************************************
591 Scan the trusts of our forest root
592 ********************************************************************/
594 static void rescan_forest_root_trusts( void )
596 struct winbindd_tdc_domain *dom_list = NULL;
597 size_t num_trusts = 0;
602 /* The only transitive trusts supported by Windows 2003 AD are
603 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
604 first two are handled in forest and listed by
605 DsEnumerateDomainTrusts(). Forest trusts are not so we
606 have to do that ourselves. */
608 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
611 for ( i=0; i<num_trusts; i++ ) {
612 struct winbindd_domain *d = NULL;
614 /* Find the forest root. Don't necessarily trust
615 the domain_list() as our primary domain may not
616 have been initialized. */
618 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
622 /* Here's the forest root */
624 d = find_domain_from_name_noinit( dom_list[i].domain_name );
626 status = add_trusted_domain(dom_list[i].domain_name,
627 dom_list[i].dns_name,
629 dom_list[i].trust_type,
630 dom_list[i].trust_flags,
631 dom_list[i].trust_attribs,
635 if (!NT_STATUS_IS_OK(status) &&
636 NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
638 DBG_ERR("add_trusted_domain returned %s\n",
642 ok = set_routing_domain(d, find_default_route_domain());
644 DBG_ERR("set_routing_domain failed\n");
652 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
653 "for domain tree root %s (%s)\n",
654 d->name, d->alt_name ));
656 d->domain_flags = dom_list[i].trust_flags;
657 d->domain_type = dom_list[i].trust_type;
658 d->domain_trust_attribs = dom_list[i].trust_attribs;
660 add_trusted_domains( d );
665 TALLOC_FREE( dom_list );
670 /********************************************************************
671 scan the transitive forest trusts (not our own)
672 ********************************************************************/
675 static void rescan_forest_trusts( void )
677 struct winbindd_domain *d = NULL;
678 struct winbindd_tdc_domain *dom_list = NULL;
679 size_t num_trusts = 0;
684 /* The only transitive trusts supported by Windows 2003 AD are
685 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
686 first two are handled in forest and listed by
687 DsEnumerateDomainTrusts(). Forest trusts are not so we
688 have to do that ourselves. */
690 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
693 for ( i=0; i<num_trusts; i++ ) {
694 uint32_t flags = dom_list[i].trust_flags;
695 uint32_t type = dom_list[i].trust_type;
696 uint32_t attribs = dom_list[i].trust_attribs;
698 d = find_domain_from_name_noinit( dom_list[i].domain_name );
700 /* ignore our primary and internal domains */
702 if ( d && (d->internal || d->primary ) )
705 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
706 (type == LSA_TRUST_TYPE_UPLEVEL) &&
707 (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
709 /* add the trusted domain if we don't know
713 status = add_trusted_domain(
714 dom_list[i].domain_name,
715 dom_list[i].dns_name,
722 if (!NT_STATUS_IS_OK(status) &&
723 NT_STATUS_EQUAL(status,
724 NT_STATUS_NO_SUCH_DOMAIN))
726 DBG_ERR("add_trusted_domain: %s\n",
730 ok = set_routing_domain(
731 d, find_default_route_domain());
733 DBG_ERR("set_routing_domain failed\n");
742 DEBUG(10,("Following trust path for domain %s (%s)\n",
743 d->name, d->alt_name ));
744 add_trusted_domains( d );
748 TALLOC_FREE( dom_list );
753 /*********************************************************************
754 The process of updating the trusted domain list is a three step
757 (b) ask the root domain in our forest
758 (c) ask the a DC in any Win2003 trusted forests
759 *********************************************************************/
761 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
762 struct timeval now, void *private_data)
766 /* I use to clear the cache here and start over but that
767 caused problems in child processes that needed the
768 trust dom list early on. Removing it means we
769 could have some trusted domains listed that have been
770 removed from our primary domain's DC until a full
771 restart. This should be ok since I think this is what
772 Windows does as well. */
774 /* this will only add new domains we didn't already know about
775 in the domain_list()*/
777 add_trusted_domains( find_our_domain() );
779 te = tevent_add_timer(
780 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
781 rescan_trusted_domains, NULL);
783 * If te == NULL, there's not much we can do here. Don't fail, the
784 * only thing we miss is new trusted domains.
790 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
791 struct winbindd_cli_state *state)
793 /* Ensure null termination */
794 state->request->domain_name
795 [sizeof(state->request->domain_name)-1]='\0';
796 state->request->data.init_conn.dcname
797 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
799 if (strlen(state->request->data.init_conn.dcname) > 0) {
800 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
803 init_dc_connection(domain, false);
805 if (!domain->initialized) {
806 /* If we return error here we can't do any cached authentication,
807 but we may be in disconnected mode and can't initialize correctly.
808 Do what the previous code did and just return without initialization,
809 once we go online we'll re-initialize.
811 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
812 "online = %d\n", domain->name, (int)domain->online ));
815 fstrcpy(state->response->data.domain_info.name, domain->name);
816 fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
817 sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
819 state->response->data.domain_info.native_mode
820 = domain->native_mode;
821 state->response->data.domain_info.active_directory
822 = domain->active_directory;
823 state->response->data.domain_info.primary
829 static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
832 struct server_id server_id,
835 TALLOC_CTX *frame = talloc_stackframe();
836 enum netr_SchannelType secure_channel_type = SEC_CHAN_DOMAIN;
837 struct lsa_TrustDomainInfoInfoEx info;
838 enum ndr_err_code ndr_err;
839 struct winbindd_domain *d = NULL;
840 uint32_t trust_flags = 0;
844 DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
851 ndr_err = ndr_pull_struct_blob_all(data, frame, &info,
852 (ndr_pull_flags_fn_t)ndr_pull_lsa_TrustDomainInfoInfoEx);
853 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
858 d = find_domain_from_name_noinit(info.netbios_name.string);
864 if (info.trust_type == LSA_TRUST_TYPE_UPLEVEL) {
865 secure_channel_type = SEC_CHAN_DNS_DOMAIN;
867 if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
868 trust_flags |= NETR_TRUST_FLAG_INBOUND;
870 if (info.trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
871 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
873 if (info.trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
874 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
877 status = add_trusted_domain(info.netbios_name.string,
878 info.domain_name.string,
882 info.trust_attributes,
885 if (!NT_STATUS_IS_OK(status) &&
886 !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
888 DBG_NOTICE("add_trusted_domain returned %s\n",
893 ok = set_routing_domain(d, find_default_route_domain());
902 * We did not get the secret when we queried secrets.tdb, so read it
903 * from secrets.tdb and re-sync the databases
905 static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
908 struct cli_credentials *creds;
909 NTSTATUS can_migrate = pdb_get_trust_credentials(domain->name,
910 NULL, domain, &creds);
911 if (!NT_STATUS_IS_OK(can_migrate)) {
912 DEBUG(0, ("Failed to fetch our own, local AD domain join "
913 "password for winbindd's internal use, both from "
914 "secrets.tdb and secrets.ldb: %s\n",
915 nt_errstr(can_migrate)));
920 * NOTE: It is very unlikely we end up here if there is an
921 * oldpass, because a new password is created at
922 * classicupgrade, so this is not a concern.
924 ok = secrets_store_machine_pw_sync(cli_credentials_get_password(creds),
926 cli_credentials_get_domain(creds),
927 cli_credentials_get_realm(creds),
928 cli_credentials_get_salt_principal(creds),
929 0, /* Supported enc types, unused */
931 cli_credentials_get_password_last_changed_time(creds),
932 cli_credentials_get_secure_channel_type(creds),
933 false /* do_delete: Do not delete */);
936 DEBUG(0, ("Failed to write our our own, "
937 "local AD domain join password for "
938 "winbindd's internal use into secrets.tdb\n"));
944 /* Look up global info for the winbind daemon */
945 bool init_domain_list(void)
947 int role = lp_server_role();
948 struct pdb_domain_info *pdb_domain_info = NULL;
949 struct winbindd_domain *domain = NULL;
952 /* Free existing list */
957 status = add_trusted_domain("BUILTIN",
960 LSA_TRUST_TYPE_DOWNLEVEL,
962 0, /* trust_attribs */
965 if (!NT_STATUS_IS_OK(status)) {
966 DBG_ERR("add_trusted_domain BUILTIN returned %s\n",
974 * In case the passdb backend is passdb_dsdb the domain SID comes from
975 * dsdb, not from secrets.tdb. As we use the domain SID in various
976 * places, we must ensure the domain SID is migrated from dsdb to
977 * secrets.tdb before get_global_sam_sid() is called the first time.
979 * The migration is done as part of the passdb_dsdb initialisation,
980 * calling pdb_get_domain_info() triggers it.
982 pdb_domain_info = pdb_get_domain_info(talloc_tos());
984 if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
985 uint32_t trust_flags;
987 enum netr_SchannelType sec_chan_type;
988 const char *account_name;
989 struct samr_Password current_nt_hash;
992 if (pdb_domain_info == NULL) {
993 DEBUG(0, ("Failed to fetch our own, local AD "
994 "domain info from sam.ldb\n"));
998 trust_flags = NETR_TRUST_FLAG_PRIMARY;
999 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
1000 trust_flags |= NETR_TRUST_FLAG_NATIVE;
1001 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
1003 is_root = strequal(pdb_domain_info->dns_domain,
1004 pdb_domain_info->dns_forest);
1006 trust_flags |= NETR_TRUST_FLAG_TREEROOT;
1009 status = add_trusted_domain(pdb_domain_info->name,
1010 pdb_domain_info->dns_domain,
1011 &pdb_domain_info->sid,
1012 LSA_TRUST_TYPE_UPLEVEL,
1014 LSA_TRUST_ATTRIBUTE_WITHIN_FOREST,
1017 TALLOC_FREE(pdb_domain_info);
1018 if (!NT_STATUS_IS_OK(status)) {
1019 DBG_ERR("Failed to add our own, local AD "
1020 "domain to winbindd's internal list\n");
1025 * We need to call this to find out if we are an RODC
1027 ok = get_trust_pw_hash(domain->name,
1028 current_nt_hash.hash,
1033 * If get_trust_pw_hash() fails, then try and
1034 * fetch the password from the more recent of
1035 * secrets.{ldb,tdb} using the
1036 * pdb_get_trust_credentials()
1038 ok = migrate_secrets_tdb_to_ldb(domain);
1041 DEBUG(0, ("Failed to migrate our own, "
1042 "local AD domain join password for "
1043 "winbindd's internal use into "
1047 ok = get_trust_pw_hash(domain->name,
1048 current_nt_hash.hash,
1052 DEBUG(0, ("Failed to find our our own, just "
1053 "written local AD domain join "
1054 "password for winbindd's internal "
1055 "use in secrets.tdb\n"));
1060 domain->secure_channel_type = sec_chan_type;
1061 if (sec_chan_type == SEC_CHAN_RODC) {
1062 domain->rodc = true;
1066 uint32_t trust_flags;
1067 enum netr_SchannelType secure_channel_type;
1069 trust_flags = NETR_TRUST_FLAG_OUTBOUND;
1070 if (role != ROLE_DOMAIN_MEMBER) {
1071 trust_flags |= NETR_TRUST_FLAG_PRIMARY;
1074 if (role > ROLE_DOMAIN_MEMBER) {
1075 secure_channel_type = SEC_CHAN_BDC;
1077 secure_channel_type = SEC_CHAN_LOCAL;
1080 status = add_trusted_domain(get_global_sam_name(),
1082 get_global_sam_sid(),
1083 LSA_TRUST_TYPE_DOWNLEVEL,
1085 0, /* trust_attribs */
1086 secure_channel_type,
1088 if (!NT_STATUS_IS_OK(status)) {
1089 DBG_ERR("Failed to add local SAM to "
1090 "domain to winbindd's internal list\n");
1094 /* Add ourselves as the first entry. */
1096 if ( role == ROLE_DOMAIN_MEMBER ) {
1097 struct dom_sid our_sid;
1098 uint32_t trust_type;
1100 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
1101 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
1105 if (lp_realm() != NULL) {
1106 trust_type = LSA_TRUST_TYPE_UPLEVEL;
1108 trust_type = LSA_TRUST_TYPE_DOWNLEVEL;
1111 status = add_trusted_domain(lp_workgroup(),
1115 NETR_TRUST_FLAG_PRIMARY|
1116 NETR_TRUST_FLAG_OUTBOUND,
1117 0, /* trust_attribs */
1120 if (!NT_STATUS_IS_OK(status)) {
1121 DBG_ERR("Failed to add local SAM to "
1122 "domain to winbindd's internal list\n");
1125 /* Even in the parent winbindd we'll need to
1126 talk to the DC, so try and see if we can
1127 contact it. Theoretically this isn't neccessary
1128 as the init_dc_connection() in init_child_recv()
1129 will do this, but we can start detecting the DC
1131 set_domain_online_request(domain);
1135 if (IS_DC && (pdb_capabilities() & PDB_CAP_TRUSTED_DOMAINS_EX)) {
1136 uint32_t num_domains = 0;
1137 struct pdb_trusted_domain **domains = NULL;
1140 status = pdb_enum_trusted_domains(talloc_tos(), &num_domains, &domains);
1141 if (!NT_STATUS_IS_OK(status)) {
1142 DBG_ERR("pdb_enum_trusted_domains() failed - %s\n",
1147 for (i = 0; i < num_domains; i++) {
1148 enum netr_SchannelType sec_chan_type = SEC_CHAN_DOMAIN;
1149 uint32_t trust_flags = 0;
1151 if (domains[i]->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
1152 sec_chan_type = SEC_CHAN_DNS_DOMAIN;
1155 if (!(domains[i]->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND)) {
1156 sec_chan_type = SEC_CHAN_NULL;
1159 if (domains[i]->trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
1160 trust_flags |= NETR_TRUST_FLAG_INBOUND;
1162 if (domains[i]->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
1163 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
1165 if (domains[i]->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
1166 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
1169 status = add_trusted_domain(domains[i]->netbios_name,
1170 domains[i]->domain_name,
1171 &domains[i]->security_identifier,
1172 domains[i]->trust_type,
1174 domains[i]->trust_attributes,
1177 if (!NT_STATUS_IS_OK(status)) {
1178 DBG_NOTICE("add_trusted_domain returned %s\n",
1183 if (domains[i]->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
1184 domain->active_directory = true;
1186 domain->domain_type = domains[i]->trust_type;
1187 domain->domain_trust_attribs = domains[i]->trust_attributes;
1189 if (sec_chan_type != SEC_CHAN_NULL) {
1190 /* Even in the parent winbindd we'll need to
1191 talk to the DC, so try and see if we can
1192 contact it. Theoretically this isn't neccessary
1193 as the init_dc_connection() in init_child_recv()
1194 will do this, but we can start detecting the DC
1196 set_domain_online_request(domain);
1200 for (i = 0; i < num_domains; i++) {
1201 struct ForestTrustInfo fti;
1203 enum ndr_err_code ndr_err;
1204 struct winbindd_domain *routing_domain = NULL;
1207 if (domains[i]->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
1211 if (!(domains[i]->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1215 if (domains[i]->trust_forest_trust_info.length == 0) {
1219 routing_domain = find_domain_from_name_noinit(
1220 domains[i]->netbios_name);
1221 if (routing_domain == NULL) {
1222 DBG_ERR("Can't find winbindd domain [%s]\n",
1223 domains[i]->netbios_name);
1227 ndr_err = ndr_pull_struct_blob_all(
1228 &domains[i]->trust_forest_trust_info,
1230 (ndr_pull_flags_fn_t)ndr_pull_ForestTrustInfo);
1231 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1232 DBG_ERR("ndr_pull_ForestTrustInfo(%s) - %s\n",
1233 domains[i]->netbios_name,
1234 ndr_map_error2string(ndr_err));
1238 for (fi = 0; fi < fti.count; fi++) {
1239 struct ForestTrustInfoRecord *rec =
1240 &fti.records[fi].record;
1241 struct ForestTrustDataDomainInfo *drec = NULL;
1243 if (rec->type != FOREST_TRUST_DOMAIN_INFO) {
1246 drec = &rec->data.info;
1248 if (rec->flags & LSA_NB_DISABLED_MASK) {
1252 if (rec->flags & LSA_SID_DISABLED_MASK) {
1258 * also try to find a matching
1259 * LSA_TLN_DISABLED_MASK ???
1262 domain = find_domain_from_name_noinit(drec->netbios_name.string);
1263 if (domain != NULL) {
1267 status = add_trusted_domain(drec->netbios_name.string,
1268 drec->dns_name.string,
1270 LSA_TRUST_TYPE_UPLEVEL,
1271 NETR_TRUST_FLAG_OUTBOUND,
1275 if (!NT_STATUS_IS_OK(status)) {
1276 DBG_NOTICE("add_trusted_domain returned %s\n",
1280 if (domain == NULL) {
1283 ok = set_routing_domain(domain, routing_domain);
1285 DBG_ERR("set_routing_domain on [%s] to "
1288 routing_domain->name);
1294 uint32_t num_domains = 0;
1295 struct trustdom_info **domains = NULL;
1298 status = pdb_enum_trusteddoms(talloc_tos(), &num_domains, &domains);
1299 if (!NT_STATUS_IS_OK(status)) {
1300 DBG_ERR("pdb_enum_trusteddoms() failed - %s\n",
1305 for (i = 0; i < num_domains; i++) {
1306 status = add_trusted_domain(domains[i]->name,
1309 LSA_TRUST_TYPE_DOWNLEVEL,
1310 NETR_TRUST_FLAG_OUTBOUND,
1314 if (!NT_STATUS_IS_OK(status)) {
1315 DBG_NOTICE("add_trusted_domain returned %s\n",
1320 /* Even in the parent winbindd we'll need to
1321 talk to the DC, so try and see if we can
1322 contact it. Theoretically this isn't neccessary
1323 as the init_dc_connection() in init_child_recv()
1324 will do this, but we can start detecting the DC
1326 set_domain_online_request(domain);
1330 status = imessaging_register(winbind_imessaging_context(), NULL,
1331 MSG_WINBIND_NEW_TRUSTED_DOMAIN,
1332 wb_imsg_new_trusted_domain);
1333 if (!NT_STATUS_IS_OK(status)) {
1334 DEBUG(0, ("imessaging_register(MSG_WINBIND_NEW_TRUSTED_DOMAIN) - %s\n",
1335 nt_errstr(status)));
1343 * Given a domain name, return the struct winbindd domain info for it
1345 * @note Do *not* pass lp_workgroup() to this function. domain_list
1346 * may modify it's value, and free that pointer. Instead, our local
1347 * domain may be found by calling find_our_domain().
1351 * @return The domain structure for the named domain, if it is working.
1354 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
1356 struct winbindd_domain *domain;
1358 /* Search through list */
1360 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1361 if (strequal(domain_name, domain->name)) {
1364 if (domain->alt_name == NULL) {
1367 if (strequal(domain_name, domain->alt_name)) {
1378 * Given a domain name, return the struct winbindd domain if it's a direct
1381 * @return The domain structure for the named domain, if it is a direct outgoing trust
1383 struct winbindd_domain *find_trust_from_name_noinit(const char *domain_name)
1385 struct winbindd_domain *domain = NULL;
1387 domain = find_domain_from_name_noinit(domain_name);
1388 if (domain == NULL) {
1392 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1399 struct winbindd_domain *find_domain_from_name(const char *domain_name)
1401 struct winbindd_domain *domain;
1403 domain = find_domain_from_name_noinit(domain_name);
1408 if (!domain->initialized)
1409 init_dc_connection(domain, false);
1414 /* Given a domain sid, return the struct winbindd domain info for it */
1416 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
1418 struct winbindd_domain *domain;
1420 /* Search through list */
1422 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1423 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
1433 * Given a domain sid, return the struct winbindd domain if it's a direct
1436 * @return The domain structure for the specified domain, if it is a direct outgoing trust
1438 struct winbindd_domain *find_trust_from_sid_noinit(const struct dom_sid *sid)
1440 struct winbindd_domain *domain = NULL;
1442 domain = find_domain_from_sid_noinit(sid);
1443 if (domain == NULL) {
1447 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1454 /* Given a domain sid, return the struct winbindd domain info for it */
1456 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
1458 struct winbindd_domain *domain;
1460 domain = find_domain_from_sid_noinit(sid);
1465 if (!domain->initialized)
1466 init_dc_connection(domain, false);
1471 struct winbindd_domain *find_our_domain(void)
1473 struct winbindd_domain *domain;
1475 /* Search through list */
1477 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1478 if (domain->primary)
1482 smb_panic("Could not find our domain");
1486 struct winbindd_domain *find_default_route_domain(void)
1489 return find_our_domain();
1491 DBG_ERR("Routing logic not yet implemented on a DC");
1495 /* Find the appropriate domain to lookup a name or SID */
1497 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
1499 DBG_DEBUG("SID [%s]\n", sid_string_dbg(sid));
1502 * SIDs in the S-1-22-{1,2} domain and well-known SIDs should be handled
1506 if ( sid_check_is_in_unix_groups(sid) ||
1507 sid_check_is_unix_groups(sid) ||
1508 sid_check_is_in_unix_users(sid) ||
1509 sid_check_is_unix_users(sid) ||
1510 sid_check_is_wellknown_domain(sid, NULL) ||
1511 sid_check_is_in_wellknown_domain(sid) )
1513 return find_domain_from_sid(get_global_sam_sid());
1516 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
1517 * one to contact the external DC's. On member servers the internal
1518 * domains are different: These are part of the local SAM. */
1520 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
1521 DEBUG(10, ("calling find_domain_from_sid\n"));
1522 return find_domain_from_sid(sid);
1525 /* On a member server a query for SID or name can always go to our
1528 DEBUG(10, ("calling find_our_domain\n"));
1529 return find_our_domain();
1532 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1534 if ( strequal(domain_name, unix_users_domain_name() ) ||
1535 strequal(domain_name, unix_groups_domain_name() ) )
1538 * The "Unix User" and "Unix Group" domain our handled by
1541 return find_domain_from_name_noinit( get_global_sam_name() );
1544 if (IS_DC || strequal(domain_name, "BUILTIN") ||
1545 strequal(domain_name, get_global_sam_name()))
1546 return find_domain_from_name_noinit(domain_name);
1549 return find_our_domain();
1552 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1554 static bool assume_domain(const char *domain)
1556 /* never assume the domain on a standalone server */
1558 if ( lp_server_role() == ROLE_STANDALONE )
1561 /* domain member servers may possibly assume for the domain name */
1563 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1564 if ( !strequal(lp_workgroup(), domain) )
1567 if ( lp_winbind_use_default_domain() )
1571 /* only left with a domain controller */
1573 if ( strequal(get_global_sam_name(), domain) ) {
1580 /* Parse a string of the form DOMAIN\user into a domain and a user */
1582 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1584 char *p = strchr(domuser,*lp_winbind_separator());
1587 fstrcpy(user, domuser);
1588 p = strchr(domuser, '@');
1590 if ( assume_domain(lp_workgroup()) && p == NULL) {
1591 fstrcpy(domain, lp_workgroup());
1592 } else if (p != NULL) {
1593 fstrcpy(domain, p + 1);
1594 user[PTR_DIFF(p, domuser)] = 0;
1600 fstrcpy(domain, domuser);
1601 domain[PTR_DIFF(p, domuser)] = 0;
1604 return strupper_m(domain);
1607 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1608 char **domain, char **user)
1610 fstring fstr_domain, fstr_user;
1611 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1614 *domain = talloc_strdup(mem_ctx, fstr_domain);
1615 *user = talloc_strdup(mem_ctx, fstr_user);
1616 return ((*domain != NULL) && (*user != NULL));
1619 /* Ensure an incoming username from NSS is fully qualified. Replace the
1620 incoming fstring with DOMAIN <separator> user. Returns the same
1621 values as parse_domain_user() but also replaces the incoming username.
1622 Used to ensure all names are fully qualified within winbindd.
1623 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1624 The protocol definitions of auth_crap, chng_pswd_auth_crap
1625 really should be changed to use this instead of doing things
1628 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1630 if (!parse_domain_user(username_inout, domain, user)) {
1633 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1634 domain, *lp_winbind_separator(),
1640 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1641 'winbind separator' options.
1643 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1646 If we are a PDC or BDC, and this is for our domain, do likewise.
1648 On an AD DC we always fill DOMAIN\\USERNAME.
1650 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1652 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1656 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1660 fstrcpy(tmp_user, user);
1661 (void)strlower_m(tmp_user);
1663 if (can_assume && assume_domain(domain)) {
1664 strlcpy(name, tmp_user, sizeof(fstring));
1666 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1667 domain, *lp_winbind_separator(),
1673 * talloc version of fill_domain_username()
1674 * return NULL on talloc failure.
1676 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1681 char *tmp_user, *name;
1683 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1687 tmp_user = talloc_strdup(mem_ctx, user);
1688 if (!strlower_m(tmp_user)) {
1689 TALLOC_FREE(tmp_user);
1693 if (can_assume && assume_domain(domain)) {
1696 name = talloc_asprintf(mem_ctx, "%s%c%s",
1698 *lp_winbind_separator(),
1700 TALLOC_FREE(tmp_user);
1707 * Client list accessor functions
1710 static struct winbindd_cli_state *_client_list;
1711 static int _num_clients;
1713 /* Return list of all connected clients */
1715 struct winbindd_cli_state *winbindd_client_list(void)
1717 return _client_list;
1720 /* Return list-tail of all connected clients */
1722 struct winbindd_cli_state *winbindd_client_list_tail(void)
1724 return DLIST_TAIL(_client_list);
1727 /* Return previous (read:newer) client in list */
1729 struct winbindd_cli_state *
1730 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1732 return DLIST_PREV(cli);
1735 /* Add a connection to the list */
1737 void winbindd_add_client(struct winbindd_cli_state *cli)
1739 cli->last_access = time(NULL);
1740 DLIST_ADD(_client_list, cli);
1744 /* Remove a client from the list */
1746 void winbindd_remove_client(struct winbindd_cli_state *cli)
1748 DLIST_REMOVE(_client_list, cli);
1752 /* Move a client to head or list */
1754 void winbindd_promote_client(struct winbindd_cli_state *cli)
1756 cli->last_access = time(NULL);
1757 DLIST_PROMOTE(_client_list, cli);
1760 /* Return number of open clients */
1762 int winbindd_num_clients(void)
1764 return _num_clients;
1767 NTSTATUS lookup_usergroups_cached(TALLOC_CTX *mem_ctx,
1768 const struct dom_sid *user_sid,
1769 uint32_t *p_num_groups, struct dom_sid **user_sids)
1771 struct netr_SamInfo3 *info3 = NULL;
1772 NTSTATUS status = NT_STATUS_NO_MEMORY;
1773 uint32_t num_groups = 0;
1775 DEBUG(3,(": lookup_usergroups_cached\n"));
1780 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1782 if (info3 == NULL) {
1783 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1787 * Before bug #7843 the "Domain Local" groups were added with a
1788 * lookupuseraliases call, but this isn't done anymore for our domain
1789 * so we need to resolve resource groups here.
1791 * When to use Resource Groups:
1792 * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1794 status = sid_array_from_info3(mem_ctx, info3,
1799 if (!NT_STATUS_IS_OK(status)) {
1805 *p_num_groups = num_groups;
1806 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1808 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1813 /*********************************************************************
1814 We use this to remove spaces from user and group names
1815 ********************************************************************/
1817 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1818 const char *domain_name,
1822 struct winbindd_domain *domain = NULL;
1825 if (!name || !normalized) {
1826 return NT_STATUS_INVALID_PARAMETER;
1829 if (!lp_winbind_normalize_names()) {
1830 return NT_STATUS_PROCEDURE_NOT_FOUND;
1833 domain = find_domain_from_name_noinit(domain_name);
1834 if (domain == NULL) {
1835 DBG_ERR("Failed to find domain '%s'\n", domain_name);
1836 return NT_STATUS_NO_SUCH_DOMAIN;
1839 /* Alias support and whitespace replacement are mutually
1842 nt_status = resolve_username_to_alias(mem_ctx, domain,
1844 if (NT_STATUS_IS_OK(nt_status)) {
1845 /* special return code to let the caller know we
1846 mapped to an alias */
1847 return NT_STATUS_FILE_RENAMED;
1850 /* check for an unreachable domain */
1852 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1853 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1855 set_domain_offline(domain);
1859 /* deal with whitespace */
1861 *normalized = talloc_strdup(mem_ctx, name);
1862 if (!(*normalized)) {
1863 return NT_STATUS_NO_MEMORY;
1866 all_string_sub( *normalized, " ", "_", 0 );
1868 return NT_STATUS_OK;
1871 /*********************************************************************
1872 We use this to do the inverse of normalize_name_map()
1873 ********************************************************************/
1875 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1880 struct winbindd_domain *domain = find_our_domain();
1882 if (!name || !normalized) {
1883 return NT_STATUS_INVALID_PARAMETER;
1886 if (!lp_winbind_normalize_names()) {
1887 return NT_STATUS_PROCEDURE_NOT_FOUND;
1890 /* Alias support and whitespace replacement are mutally
1893 /* When mapping from an alias to a username, we don't know the
1894 domain. But we only need a domain structure to cache
1895 a successful lookup , so just our own domain structure for
1898 nt_status = resolve_alias_to_username(mem_ctx, domain,
1900 if (NT_STATUS_IS_OK(nt_status)) {
1901 /* Special return code to let the caller know we mapped
1903 return NT_STATUS_FILE_RENAMED;
1906 /* check for an unreachable domain */
1908 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1909 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1911 set_domain_offline(domain);
1915 /* deal with whitespace */
1917 *normalized = talloc_strdup(mem_ctx, name);
1918 if (!(*normalized)) {
1919 return NT_STATUS_NO_MEMORY;
1922 all_string_sub(*normalized, "_", " ", 0);
1924 return NT_STATUS_OK;
1927 /*********************************************************************
1928 ********************************************************************/
1930 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1932 struct winbindd_tdc_domain *tdc = NULL;
1933 TALLOC_CTX *frame = talloc_stackframe();
1936 /* We can contact the domain if it is our primary domain */
1938 if (domain->primary) {
1943 /* Trust the TDC cache and not the winbindd_domain flags */
1945 if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1946 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1952 /* Can always contact a domain that is in out forest */
1954 if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1960 * On a _member_ server, we cannot contact the domain if it
1961 * is running AD and we have no inbound trust.
1965 domain->active_directory &&
1966 ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1968 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1969 "and we have no inbound trust.\n", domain->name));
1973 /* Assume everything else is ok (probably not true but what
1979 talloc_destroy(frame);
1984 /*********************************************************************
1985 ********************************************************************/
1987 bool winbindd_internal_child(struct winbindd_child *child)
1989 if ((child == idmap_child()) || (child == locator_child())) {
1996 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1998 /*********************************************************************
1999 ********************************************************************/
2001 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
2004 char addr[INET6_ADDRSTRLEN];
2005 const char *kdc = NULL;
2008 if (!domain || !domain->alt_name || !*domain->alt_name) {
2012 if (domain->initialized && !domain->active_directory) {
2013 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
2018 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
2021 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
2023 kdc = domain->dcname;
2026 if (!kdc || !*kdc) {
2027 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
2032 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
2033 domain->alt_name) == -1) {
2037 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
2040 setenv(var, kdc, 1);
2044 /*********************************************************************
2045 ********************************************************************/
2047 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
2049 struct winbindd_domain *our_dom = find_our_domain();
2051 winbindd_set_locator_kdc_env(domain);
2053 if (domain != our_dom) {
2054 winbindd_set_locator_kdc_env(our_dom);
2058 /*********************************************************************
2059 ********************************************************************/
2061 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
2065 if (!domain || !domain->alt_name || !*domain->alt_name) {
2069 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
2070 domain->alt_name) == -1) {
2079 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
2084 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
2089 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
2091 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
2093 resp->data.auth.nt_status = NT_STATUS_V(result);
2094 fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
2096 /* we might have given a more useful error above */
2097 if (*resp->data.auth.error_string == '\0')
2098 fstrcpy(resp->data.auth.error_string,
2099 get_friendly_nt_error_msg(result));
2100 resp->data.auth.pam_error = nt_status_to_pam(result);
2103 bool is_domain_offline(const struct winbindd_domain *domain)
2105 if (get_global_winbindd_state_offline()) {
2108 return !domain->online;
2111 bool is_domain_online(const struct winbindd_domain *domain)
2113 return !is_domain_offline(domain);
2117 * Parse an char array into a list of sids.
2119 * The input sidstr should consist of 0-terminated strings
2120 * representing sids, separated by newline characters '\n'.
2121 * The list is terminated by an empty string, i.e.
2122 * character '\0' directly following a character '\n'
2123 * (or '\0' right at the start of sidstr).
2125 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
2126 struct dom_sid **sids, uint32_t *num_sids)
2134 while (p[0] != '\0') {
2136 const char *q = NULL;
2138 if (!dom_sid_parse_endp(p, &sid, &q)) {
2139 DEBUG(1, ("Could not parse sid %s\n", p));
2143 DEBUG(1, ("Got invalid sidstr: %s\n", p));
2146 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
2156 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
2157 struct unixid **pxids, uint32_t *pnum_xids)
2160 struct unixid *xids = NULL;
2161 uint32_t num_xids = 0;
2168 while (p[0] != '\0') {
2171 unsigned long long id;
2176 xid = (struct unixid) { .type = ID_TYPE_UID };
2179 xid = (struct unixid) { .type = ID_TYPE_GID };
2187 id = strtoull(p, &endp, 10);
2188 if ((id == ULLONG_MAX) && (errno == ERANGE)) {
2191 if (*endp != '\n') {
2197 if ((unsigned long long)xid.id != id) {
2201 tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
2207 xids[num_xids] = xid;
2212 *pnum_xids = num_xids;