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 domain_is_forest_root(const struct winbindd_domain *domain)
295 const uint32_t fr_flags =
296 (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
298 return ((domain->domain_flags & fr_flags) == fr_flags);
301 /********************************************************************
302 rescan our domains looking for new trusted domains
303 ********************************************************************/
305 struct trustdom_state {
306 struct winbindd_domain *domain;
307 struct winbindd_request request;
310 static void trustdom_list_done(struct tevent_req *req);
311 static void rescan_forest_root_trusts( void );
312 static void rescan_forest_trusts( void );
314 static void add_trusted_domains( struct winbindd_domain *domain )
316 struct trustdom_state *state;
317 struct tevent_req *req;
319 state = talloc_zero(NULL, struct trustdom_state);
321 DEBUG(0, ("talloc failed\n"));
324 state->domain = domain;
326 state->request.length = sizeof(state->request);
327 state->request.cmd = WINBINDD_LIST_TRUSTDOM;
329 req = wb_domain_request_send(state, server_event_context(),
330 domain, &state->request);
332 DEBUG(1, ("wb_domain_request_send failed\n"));
336 tevent_req_set_callback(req, trustdom_list_done, state);
339 static void trustdom_list_done(struct tevent_req *req)
341 struct trustdom_state *state = tevent_req_callback_data(
342 req, struct trustdom_state);
343 struct winbindd_response *response;
347 bool within_forest = false;
351 * Only when we enumerate our primary domain
352 * or our forest root domain, we should keep
353 * the NETR_TRUST_FLAG_IN_FOREST flag, in
354 * all other cases we need to clear it as the domain
355 * is not part of our forest.
357 if (state->domain->primary) {
358 within_forest = true;
359 } else if (domain_is_forest_root(state->domain)) {
360 within_forest = true;
363 res = wb_domain_request_recv(req, state, &response, &err);
364 if ((res == -1) || (response->result != WINBINDD_OK)) {
365 DBG_WARNING("Could not receive trusts for domain %s\n",
366 state->domain->name);
371 if (response->length < sizeof(struct winbindd_response)) {
372 DBG_ERR("ill-formed trustdom response - short length\n");
377 extra_len = response->length - sizeof(struct winbindd_response);
379 p = (char *)response->extra_data.data;
381 while ((p - (char *)response->extra_data.data) < extra_len) {
382 struct winbindd_domain *domain = NULL;
383 char *name, *q, *sidstr, *alt_name;
386 uint32_t trust_attribs;
387 uint32_t trust_flags;
389 DBG_DEBUG("parsing response line '%s'\n", p);
393 alt_name = strchr(p, '\\');
394 if (alt_name == NULL) {
395 DBG_ERR("Got invalid trustdom response\n");
402 sidstr = strchr(alt_name, '\\');
403 if (sidstr == NULL) {
404 DBG_ERR("Got invalid trustdom response\n");
411 /* use the real alt_name if we have one, else pass in NULL */
412 if (strequal(alt_name, "(null)")) {
416 q = strtok(sidstr, "\\");
418 DBG_ERR("Got invalid trustdom response\n");
422 if (!string_to_sid(&sid, sidstr)) {
423 DEBUG(0, ("Got invalid trustdom response\n"));
427 q = strtok(NULL, "\\");
429 DBG_ERR("Got invalid trustdom response\n");
433 trust_flags = (uint32_t)strtoul(q, NULL, 10);
435 q = strtok(NULL, "\\");
437 DBG_ERR("Got invalid trustdom response\n");
441 trust_type = (uint32_t)strtoul(q, NULL, 10);
443 q = strtok(NULL, "\n");
445 DBG_ERR("Got invalid trustdom response\n");
449 trust_attribs = (uint32_t)strtoul(q, NULL, 10);
451 if (!within_forest) {
452 trust_flags &= ~NETR_TRUST_FLAG_IN_FOREST;
455 if (!state->domain->primary) {
456 trust_flags &= ~NETR_TRUST_FLAG_PRIMARY;
460 * We always call add_trusted_domain() cause on an existing
461 * domain structure, it will update the SID if necessary.
462 * This is important because we need the SID for sibling
465 status = add_trusted_domain(name,
473 if (!NT_STATUS_IS_OK(status) &&
474 !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
476 DBG_NOTICE("add_trusted_domain returned %s\n",
481 p = q + strlen(q) + 1;
485 Cases to consider when scanning trusts:
486 (a) we are calling from a child domain (primary && !forest_root)
487 (b) we are calling from the root of the forest (primary && forest_root)
488 (c) we are calling from a trusted forest domain (!primary
492 if (state->domain->primary) {
493 /* If this is our primary domain and we are not in the
494 forest root, we have to scan the root trusts first */
496 if (!domain_is_forest_root(state->domain))
497 rescan_forest_root_trusts();
499 rescan_forest_trusts();
501 } else if (domain_is_forest_root(state->domain)) {
502 /* Once we have done root forest trust search, we can
503 go on to search the trusted forests */
505 rescan_forest_trusts();
513 /********************************************************************
514 Scan the trusts of our forest root
515 ********************************************************************/
517 static void rescan_forest_root_trusts( void )
519 struct winbindd_tdc_domain *dom_list = NULL;
520 size_t num_trusts = 0;
524 /* The only transitive trusts supported by Windows 2003 AD are
525 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
526 first two are handled in forest and listed by
527 DsEnumerateDomainTrusts(). Forest trusts are not so we
528 have to do that ourselves. */
530 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
533 for ( i=0; i<num_trusts; i++ ) {
534 struct winbindd_domain *d = NULL;
536 /* Find the forest root. Don't necessarily trust
537 the domain_list() as our primary domain may not
538 have been initialized. */
540 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
544 /* Here's the forest root */
546 d = find_domain_from_name_noinit( dom_list[i].domain_name );
548 status = add_trusted_domain(dom_list[i].domain_name,
549 dom_list[i].dns_name,
551 dom_list[i].trust_type,
552 dom_list[i].trust_flags,
553 dom_list[i].trust_attribs,
557 if (!NT_STATUS_IS_OK(status) &&
558 NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
560 DBG_ERR("add_trusted_domain returned %s\n",
569 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
570 "for domain tree root %s (%s)\n",
571 d->name, d->alt_name ));
573 d->domain_flags = dom_list[i].trust_flags;
574 d->domain_type = dom_list[i].trust_type;
575 d->domain_trust_attribs = dom_list[i].trust_attribs;
577 add_trusted_domains( d );
582 TALLOC_FREE( dom_list );
587 /********************************************************************
588 scan the transitive forest trusts (not our own)
589 ********************************************************************/
592 static void rescan_forest_trusts( void )
594 struct winbindd_domain *d = NULL;
595 struct winbindd_tdc_domain *dom_list = NULL;
596 size_t num_trusts = 0;
600 /* The only transitive trusts supported by Windows 2003 AD are
601 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
602 first two are handled in forest and listed by
603 DsEnumerateDomainTrusts(). Forest trusts are not so we
604 have to do that ourselves. */
606 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
609 for ( i=0; i<num_trusts; i++ ) {
610 uint32_t flags = dom_list[i].trust_flags;
611 uint32_t type = dom_list[i].trust_type;
612 uint32_t attribs = dom_list[i].trust_attribs;
614 d = find_domain_from_name_noinit( dom_list[i].domain_name );
616 /* ignore our primary and internal domains */
618 if ( d && (d->internal || d->primary ) )
621 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
622 (type == LSA_TRUST_TYPE_UPLEVEL) &&
623 (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
625 /* add the trusted domain if we don't know
629 status = add_trusted_domain(
630 dom_list[i].domain_name,
631 dom_list[i].dns_name,
638 if (!NT_STATUS_IS_OK(status) &&
639 NT_STATUS_EQUAL(status,
640 NT_STATUS_NO_SUCH_DOMAIN))
642 DBG_ERR("add_trusted_domain: %s\n",
652 DEBUG(10,("Following trust path for domain %s (%s)\n",
653 d->name, d->alt_name ));
654 add_trusted_domains( d );
658 TALLOC_FREE( dom_list );
663 /*********************************************************************
664 The process of updating the trusted domain list is a three step
667 (b) ask the root domain in our forest
668 (c) ask the a DC in any Win2003 trusted forests
669 *********************************************************************/
671 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
672 struct timeval now, void *private_data)
676 /* I use to clear the cache here and start over but that
677 caused problems in child processes that needed the
678 trust dom list early on. Removing it means we
679 could have some trusted domains listed that have been
680 removed from our primary domain's DC until a full
681 restart. This should be ok since I think this is what
682 Windows does as well. */
684 /* this will only add new domains we didn't already know about
685 in the domain_list()*/
687 add_trusted_domains( find_our_domain() );
689 te = tevent_add_timer(
690 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
691 rescan_trusted_domains, NULL);
693 * If te == NULL, there's not much we can do here. Don't fail, the
694 * only thing we miss is new trusted domains.
700 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
701 struct winbindd_cli_state *state)
703 /* Ensure null termination */
704 state->request->domain_name
705 [sizeof(state->request->domain_name)-1]='\0';
706 state->request->data.init_conn.dcname
707 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
709 if (strlen(state->request->data.init_conn.dcname) > 0) {
710 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
713 init_dc_connection(domain, false);
715 if (!domain->initialized) {
716 /* If we return error here we can't do any cached authentication,
717 but we may be in disconnected mode and can't initialize correctly.
718 Do what the previous code did and just return without initialization,
719 once we go online we'll re-initialize.
721 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
722 "online = %d\n", domain->name, (int)domain->online ));
725 fstrcpy(state->response->data.domain_info.name, domain->name);
726 fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
727 sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
729 state->response->data.domain_info.native_mode
730 = domain->native_mode;
731 state->response->data.domain_info.active_directory
732 = domain->active_directory;
733 state->response->data.domain_info.primary
739 static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
742 struct server_id server_id,
745 TALLOC_CTX *frame = talloc_stackframe();
746 enum netr_SchannelType secure_channel_type = SEC_CHAN_DOMAIN;
747 struct lsa_TrustDomainInfoInfoEx info;
748 enum ndr_err_code ndr_err;
749 struct winbindd_domain *d = NULL;
750 uint32_t trust_flags = 0;
753 DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
760 ndr_err = ndr_pull_struct_blob_all(data, frame, &info,
761 (ndr_pull_flags_fn_t)ndr_pull_lsa_TrustDomainInfoInfoEx);
762 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
767 d = find_domain_from_name_noinit(info.netbios_name.string);
773 if (info.trust_type == LSA_TRUST_TYPE_UPLEVEL) {
774 secure_channel_type = SEC_CHAN_DNS_DOMAIN;
776 if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
777 trust_flags |= NETR_TRUST_FLAG_INBOUND;
779 if (info.trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
780 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
782 if (info.trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
783 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
786 status = add_trusted_domain(info.netbios_name.string,
787 info.domain_name.string,
791 info.trust_attributes,
794 if (!NT_STATUS_IS_OK(status) &&
795 !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
797 DBG_NOTICE("add_trusted_domain returned %s\n",
806 * We did not get the secret when we queried secrets.tdb, so read it
807 * from secrets.tdb and re-sync the databases
809 static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
812 struct cli_credentials *creds;
813 NTSTATUS can_migrate = pdb_get_trust_credentials(domain->name,
814 NULL, domain, &creds);
815 if (!NT_STATUS_IS_OK(can_migrate)) {
816 DEBUG(0, ("Failed to fetch our own, local AD domain join "
817 "password for winbindd's internal use, both from "
818 "secrets.tdb and secrets.ldb: %s\n",
819 nt_errstr(can_migrate)));
824 * NOTE: It is very unlikely we end up here if there is an
825 * oldpass, because a new password is created at
826 * classicupgrade, so this is not a concern.
828 ok = secrets_store_machine_pw_sync(cli_credentials_get_password(creds),
830 cli_credentials_get_domain(creds),
831 cli_credentials_get_realm(creds),
832 cli_credentials_get_salt_principal(creds),
833 0, /* Supported enc types, unused */
835 cli_credentials_get_password_last_changed_time(creds),
836 cli_credentials_get_secure_channel_type(creds),
837 false /* do_delete: Do not delete */);
840 DEBUG(0, ("Failed to write our our own, "
841 "local AD domain join password for "
842 "winbindd's internal use into secrets.tdb\n"));
848 /* Look up global info for the winbind daemon */
849 bool init_domain_list(void)
851 int role = lp_server_role();
852 struct pdb_domain_info *pdb_domain_info = NULL;
853 struct winbindd_domain *domain = NULL;
856 /* Free existing list */
861 status = add_trusted_domain("BUILTIN",
864 LSA_TRUST_TYPE_DOWNLEVEL,
866 0, /* trust_attribs */
869 if (!NT_STATUS_IS_OK(status)) {
870 DBG_ERR("add_trusted_domain BUILTIN returned %s\n",
878 * In case the passdb backend is passdb_dsdb the domain SID comes from
879 * dsdb, not from secrets.tdb. As we use the domain SID in various
880 * places, we must ensure the domain SID is migrated from dsdb to
881 * secrets.tdb before get_global_sam_sid() is called the first time.
883 * The migration is done as part of the passdb_dsdb initialisation,
884 * calling pdb_get_domain_info() triggers it.
886 pdb_domain_info = pdb_get_domain_info(talloc_tos());
888 if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
889 uint32_t trust_flags;
891 enum netr_SchannelType sec_chan_type;
892 const char *account_name;
893 struct samr_Password current_nt_hash;
896 if (pdb_domain_info == NULL) {
897 DEBUG(0, ("Failed to fetch our own, local AD "
898 "domain info from sam.ldb\n"));
902 trust_flags = NETR_TRUST_FLAG_PRIMARY;
903 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
904 trust_flags |= NETR_TRUST_FLAG_NATIVE;
905 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
907 is_root = strequal(pdb_domain_info->dns_domain,
908 pdb_domain_info->dns_forest);
910 trust_flags |= NETR_TRUST_FLAG_TREEROOT;
913 status = add_trusted_domain(pdb_domain_info->name,
914 pdb_domain_info->dns_domain,
915 &pdb_domain_info->sid,
916 LSA_TRUST_TYPE_UPLEVEL,
918 LSA_TRUST_ATTRIBUTE_WITHIN_FOREST,
921 TALLOC_FREE(pdb_domain_info);
922 if (!NT_STATUS_IS_OK(status)) {
923 DBG_ERR("Failed to add our own, local AD "
924 "domain to winbindd's internal list\n");
929 * We need to call this to find out if we are an RODC
931 ok = get_trust_pw_hash(domain->name,
932 current_nt_hash.hash,
937 * If get_trust_pw_hash() fails, then try and
938 * fetch the password from the more recent of
939 * secrets.{ldb,tdb} using the
940 * pdb_get_trust_credentials()
942 ok = migrate_secrets_tdb_to_ldb(domain);
945 DEBUG(0, ("Failed to migrate our own, "
946 "local AD domain join password for "
947 "winbindd's internal use into "
951 ok = get_trust_pw_hash(domain->name,
952 current_nt_hash.hash,
956 DEBUG(0, ("Failed to find our our own, just "
957 "written local AD domain join "
958 "password for winbindd's internal "
959 "use in secrets.tdb\n"));
964 domain->secure_channel_type = sec_chan_type;
965 if (sec_chan_type == SEC_CHAN_RODC) {
970 uint32_t trust_flags;
971 enum netr_SchannelType secure_channel_type;
973 trust_flags = NETR_TRUST_FLAG_OUTBOUND;
974 if (role != ROLE_DOMAIN_MEMBER) {
975 trust_flags |= NETR_TRUST_FLAG_PRIMARY;
978 if (role > ROLE_DOMAIN_MEMBER) {
979 secure_channel_type = SEC_CHAN_BDC;
981 secure_channel_type = SEC_CHAN_LOCAL;
984 status = add_trusted_domain(get_global_sam_name(),
986 get_global_sam_sid(),
987 LSA_TRUST_TYPE_DOWNLEVEL,
989 0, /* trust_attribs */
992 if (!NT_STATUS_IS_OK(status)) {
993 DBG_ERR("Failed to add local SAM to "
994 "domain to winbindd's internal list\n");
998 /* Add ourselves as the first entry. */
1000 if ( role == ROLE_DOMAIN_MEMBER ) {
1001 struct dom_sid our_sid;
1002 uint32_t trust_type;
1004 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
1005 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
1009 if (lp_realm() != NULL) {
1010 trust_type = LSA_TRUST_TYPE_UPLEVEL;
1012 trust_type = LSA_TRUST_TYPE_DOWNLEVEL;
1015 status = add_trusted_domain(lp_workgroup(),
1019 NETR_TRUST_FLAG_PRIMARY|
1020 NETR_TRUST_FLAG_OUTBOUND,
1021 0, /* trust_attribs */
1024 if (!NT_STATUS_IS_OK(status)) {
1025 DBG_ERR("Failed to add local SAM to "
1026 "domain to winbindd's internal list\n");
1029 /* Even in the parent winbindd we'll need to
1030 talk to the DC, so try and see if we can
1031 contact it. Theoretically this isn't neccessary
1032 as the init_dc_connection() in init_child_recv()
1033 will do this, but we can start detecting the DC
1035 set_domain_online_request(domain);
1039 if (IS_DC && (pdb_capabilities() & PDB_CAP_TRUSTED_DOMAINS_EX)) {
1040 uint32_t num_domains = 0;
1041 struct pdb_trusted_domain **domains = NULL;
1044 status = pdb_enum_trusted_domains(talloc_tos(), &num_domains, &domains);
1045 if (!NT_STATUS_IS_OK(status)) {
1046 DBG_ERR("pdb_enum_trusted_domains() failed - %s\n",
1051 for (i = 0; i < num_domains; i++) {
1052 enum netr_SchannelType sec_chan_type = SEC_CHAN_DOMAIN;
1053 uint32_t trust_flags = 0;
1055 if (domains[i]->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
1056 sec_chan_type = SEC_CHAN_DNS_DOMAIN;
1059 if (!(domains[i]->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND)) {
1060 sec_chan_type = SEC_CHAN_NULL;
1063 if (domains[i]->trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
1064 trust_flags |= NETR_TRUST_FLAG_INBOUND;
1066 if (domains[i]->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
1067 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
1069 if (domains[i]->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
1070 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
1073 status = add_trusted_domain(domains[i]->netbios_name,
1074 domains[i]->domain_name,
1075 &domains[i]->security_identifier,
1076 domains[i]->trust_type,
1078 domains[i]->trust_attributes,
1081 if (!NT_STATUS_IS_OK(status)) {
1082 DBG_NOTICE("add_trusted_domain returned %s\n",
1087 if (domains[i]->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
1088 domain->active_directory = true;
1090 domain->domain_type = domains[i]->trust_type;
1091 domain->domain_trust_attribs = domains[i]->trust_attributes;
1093 if (sec_chan_type != SEC_CHAN_NULL) {
1094 /* Even in the parent winbindd we'll need to
1095 talk to the DC, so try and see if we can
1096 contact it. Theoretically this isn't neccessary
1097 as the init_dc_connection() in init_child_recv()
1098 will do this, but we can start detecting the DC
1100 set_domain_online_request(domain);
1104 for (i = 0; i < num_domains; i++) {
1105 struct ForestTrustInfo fti;
1107 enum ndr_err_code ndr_err;
1109 if (domains[i]->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
1113 if (!(domains[i]->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1117 if (domains[i]->trust_forest_trust_info.length == 0) {
1121 ndr_err = ndr_pull_struct_blob_all(
1122 &domains[i]->trust_forest_trust_info,
1124 (ndr_pull_flags_fn_t)ndr_pull_ForestTrustInfo);
1125 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1126 DBG_ERR("ndr_pull_ForestTrustInfo(%s) - %s\n",
1127 domains[i]->netbios_name,
1128 ndr_map_error2string(ndr_err));
1132 for (fi = 0; fi < fti.count; fi++) {
1133 struct ForestTrustInfoRecord *rec =
1134 &fti.records[fi].record;
1135 struct ForestTrustDataDomainInfo *drec = NULL;
1137 if (rec->type != FOREST_TRUST_DOMAIN_INFO) {
1140 drec = &rec->data.info;
1142 if (rec->flags & LSA_NB_DISABLED_MASK) {
1146 if (rec->flags & LSA_SID_DISABLED_MASK) {
1152 * also try to find a matching
1153 * LSA_TLN_DISABLED_MASK ???
1156 domain = find_domain_from_name_noinit(drec->netbios_name.string);
1157 if (domain != NULL) {
1161 status = add_trusted_domain(drec->netbios_name.string,
1162 drec->dns_name.string,
1164 LSA_TRUST_TYPE_UPLEVEL,
1165 NETR_TRUST_FLAG_OUTBOUND,
1169 if (!NT_STATUS_IS_OK(status)) {
1170 DBG_NOTICE("add_trusted_domain returned %s\n",
1177 uint32_t num_domains = 0;
1178 struct trustdom_info **domains = NULL;
1181 status = pdb_enum_trusteddoms(talloc_tos(), &num_domains, &domains);
1182 if (!NT_STATUS_IS_OK(status)) {
1183 DBG_ERR("pdb_enum_trusteddoms() failed - %s\n",
1188 for (i = 0; i < num_domains; i++) {
1189 status = add_trusted_domain(domains[i]->name,
1192 LSA_TRUST_TYPE_DOWNLEVEL,
1193 NETR_TRUST_FLAG_OUTBOUND,
1197 if (!NT_STATUS_IS_OK(status)) {
1198 DBG_NOTICE("add_trusted_domain returned %s\n",
1203 /* Even in the parent winbindd we'll need to
1204 talk to the DC, so try and see if we can
1205 contact it. Theoretically this isn't neccessary
1206 as the init_dc_connection() in init_child_recv()
1207 will do this, but we can start detecting the DC
1209 set_domain_online_request(domain);
1213 status = imessaging_register(winbind_imessaging_context(), NULL,
1214 MSG_WINBIND_NEW_TRUSTED_DOMAIN,
1215 wb_imsg_new_trusted_domain);
1216 if (!NT_STATUS_IS_OK(status)) {
1217 DEBUG(0, ("imessaging_register(MSG_WINBIND_NEW_TRUSTED_DOMAIN) - %s\n",
1218 nt_errstr(status)));
1226 * Given a domain name, return the struct winbindd domain info for it
1228 * @note Do *not* pass lp_workgroup() to this function. domain_list
1229 * may modify it's value, and free that pointer. Instead, our local
1230 * domain may be found by calling find_our_domain().
1234 * @return The domain structure for the named domain, if it is working.
1237 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
1239 struct winbindd_domain *domain;
1241 /* Search through list */
1243 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1244 if (strequal(domain_name, domain->name)) {
1247 if (domain->alt_name == NULL) {
1250 if (strequal(domain_name, domain->alt_name)) {
1261 * Given a domain name, return the struct winbindd domain if it's a direct
1264 * @return The domain structure for the named domain, if it is a direct outgoing trust
1266 struct winbindd_domain *find_trust_from_name_noinit(const char *domain_name)
1268 struct winbindd_domain *domain = NULL;
1270 domain = find_domain_from_name_noinit(domain_name);
1271 if (domain == NULL) {
1275 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1282 struct winbindd_domain *find_domain_from_name(const char *domain_name)
1284 struct winbindd_domain *domain;
1286 domain = find_domain_from_name_noinit(domain_name);
1291 if (!domain->initialized)
1292 init_dc_connection(domain, false);
1297 /* Given a domain sid, return the struct winbindd domain info for it */
1299 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
1301 struct winbindd_domain *domain;
1303 /* Search through list */
1305 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1306 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
1316 * Given a domain sid, return the struct winbindd domain if it's a direct
1319 * @return The domain structure for the specified domain, if it is a direct outgoing trust
1321 struct winbindd_domain *find_trust_from_sid_noinit(const struct dom_sid *sid)
1323 struct winbindd_domain *domain = NULL;
1325 domain = find_domain_from_sid_noinit(sid);
1326 if (domain == NULL) {
1330 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1337 /* Given a domain sid, return the struct winbindd domain info for it */
1339 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
1341 struct winbindd_domain *domain;
1343 domain = find_domain_from_sid_noinit(sid);
1348 if (!domain->initialized)
1349 init_dc_connection(domain, false);
1354 struct winbindd_domain *find_our_domain(void)
1356 struct winbindd_domain *domain;
1358 /* Search through list */
1360 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1361 if (domain->primary)
1365 smb_panic("Could not find our domain");
1369 /* Find the appropriate domain to lookup a name or SID */
1371 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
1373 DBG_DEBUG("SID [%s]\n", sid_string_dbg(sid));
1376 * SIDs in the S-1-22-{1,2} domain and well-known SIDs should be handled
1380 if ( sid_check_is_in_unix_groups(sid) ||
1381 sid_check_is_unix_groups(sid) ||
1382 sid_check_is_in_unix_users(sid) ||
1383 sid_check_is_unix_users(sid) ||
1384 sid_check_is_wellknown_domain(sid, NULL) ||
1385 sid_check_is_in_wellknown_domain(sid) )
1387 return find_domain_from_sid(get_global_sam_sid());
1390 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
1391 * one to contact the external DC's. On member servers the internal
1392 * domains are different: These are part of the local SAM. */
1394 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
1395 DEBUG(10, ("calling find_domain_from_sid\n"));
1396 return find_domain_from_sid(sid);
1399 /* On a member server a query for SID or name can always go to our
1402 DEBUG(10, ("calling find_our_domain\n"));
1403 return find_our_domain();
1406 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1408 if ( strequal(domain_name, unix_users_domain_name() ) ||
1409 strequal(domain_name, unix_groups_domain_name() ) )
1412 * The "Unix User" and "Unix Group" domain our handled by
1415 return find_domain_from_name_noinit( get_global_sam_name() );
1418 if (IS_DC || strequal(domain_name, "BUILTIN") ||
1419 strequal(domain_name, get_global_sam_name()))
1420 return find_domain_from_name_noinit(domain_name);
1423 return find_our_domain();
1426 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1428 static bool assume_domain(const char *domain)
1430 /* never assume the domain on a standalone server */
1432 if ( lp_server_role() == ROLE_STANDALONE )
1435 /* domain member servers may possibly assume for the domain name */
1437 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1438 if ( !strequal(lp_workgroup(), domain) )
1441 if ( lp_winbind_use_default_domain() )
1445 /* only left with a domain controller */
1447 if ( strequal(get_global_sam_name(), domain) ) {
1454 /* Parse a string of the form DOMAIN\user into a domain and a user */
1456 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1458 char *p = strchr(domuser,*lp_winbind_separator());
1461 fstrcpy(user, domuser);
1462 p = strchr(domuser, '@');
1464 if ( assume_domain(lp_workgroup()) && p == NULL) {
1465 fstrcpy(domain, lp_workgroup());
1466 } else if (p != NULL) {
1467 fstrcpy(domain, p + 1);
1468 user[PTR_DIFF(p, domuser)] = 0;
1474 fstrcpy(domain, domuser);
1475 domain[PTR_DIFF(p, domuser)] = 0;
1478 return strupper_m(domain);
1481 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1482 char **domain, char **user)
1484 fstring fstr_domain, fstr_user;
1485 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1488 *domain = talloc_strdup(mem_ctx, fstr_domain);
1489 *user = talloc_strdup(mem_ctx, fstr_user);
1490 return ((*domain != NULL) && (*user != NULL));
1493 /* Ensure an incoming username from NSS is fully qualified. Replace the
1494 incoming fstring with DOMAIN <separator> user. Returns the same
1495 values as parse_domain_user() but also replaces the incoming username.
1496 Used to ensure all names are fully qualified within winbindd.
1497 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1498 The protocol definitions of auth_crap, chng_pswd_auth_crap
1499 really should be changed to use this instead of doing things
1502 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1504 if (!parse_domain_user(username_inout, domain, user)) {
1507 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1508 domain, *lp_winbind_separator(),
1514 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1515 'winbind separator' options.
1517 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1520 If we are a PDC or BDC, and this is for our domain, do likewise.
1522 On an AD DC we always fill DOMAIN\\USERNAME.
1524 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1526 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1530 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1534 fstrcpy(tmp_user, user);
1535 (void)strlower_m(tmp_user);
1537 if (can_assume && assume_domain(domain)) {
1538 strlcpy(name, tmp_user, sizeof(fstring));
1540 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1541 domain, *lp_winbind_separator(),
1547 * talloc version of fill_domain_username()
1548 * return NULL on talloc failure.
1550 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1555 char *tmp_user, *name;
1557 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1561 tmp_user = talloc_strdup(mem_ctx, user);
1562 if (!strlower_m(tmp_user)) {
1563 TALLOC_FREE(tmp_user);
1567 if (can_assume && assume_domain(domain)) {
1570 name = talloc_asprintf(mem_ctx, "%s%c%s",
1572 *lp_winbind_separator(),
1574 TALLOC_FREE(tmp_user);
1581 * Client list accessor functions
1584 static struct winbindd_cli_state *_client_list;
1585 static int _num_clients;
1587 /* Return list of all connected clients */
1589 struct winbindd_cli_state *winbindd_client_list(void)
1591 return _client_list;
1594 /* Return list-tail of all connected clients */
1596 struct winbindd_cli_state *winbindd_client_list_tail(void)
1598 return DLIST_TAIL(_client_list);
1601 /* Return previous (read:newer) client in list */
1603 struct winbindd_cli_state *
1604 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1606 return DLIST_PREV(cli);
1609 /* Add a connection to the list */
1611 void winbindd_add_client(struct winbindd_cli_state *cli)
1613 cli->last_access = time(NULL);
1614 DLIST_ADD(_client_list, cli);
1618 /* Remove a client from the list */
1620 void winbindd_remove_client(struct winbindd_cli_state *cli)
1622 DLIST_REMOVE(_client_list, cli);
1626 /* Move a client to head or list */
1628 void winbindd_promote_client(struct winbindd_cli_state *cli)
1630 cli->last_access = time(NULL);
1631 DLIST_PROMOTE(_client_list, cli);
1634 /* Return number of open clients */
1636 int winbindd_num_clients(void)
1638 return _num_clients;
1641 NTSTATUS lookup_usergroups_cached(TALLOC_CTX *mem_ctx,
1642 const struct dom_sid *user_sid,
1643 uint32_t *p_num_groups, struct dom_sid **user_sids)
1645 struct netr_SamInfo3 *info3 = NULL;
1646 NTSTATUS status = NT_STATUS_NO_MEMORY;
1647 uint32_t num_groups = 0;
1649 DEBUG(3,(": lookup_usergroups_cached\n"));
1654 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1656 if (info3 == NULL) {
1657 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1661 * Before bug #7843 the "Domain Local" groups were added with a
1662 * lookupuseraliases call, but this isn't done anymore for our domain
1663 * so we need to resolve resource groups here.
1665 * When to use Resource Groups:
1666 * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1668 status = sid_array_from_info3(mem_ctx, info3,
1673 if (!NT_STATUS_IS_OK(status)) {
1679 *p_num_groups = num_groups;
1680 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1682 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1687 /*********************************************************************
1688 We use this to remove spaces from user and group names
1689 ********************************************************************/
1691 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1692 const char *domain_name,
1696 struct winbindd_domain *domain = NULL;
1699 if (!name || !normalized) {
1700 return NT_STATUS_INVALID_PARAMETER;
1703 if (!lp_winbind_normalize_names()) {
1704 return NT_STATUS_PROCEDURE_NOT_FOUND;
1707 domain = find_domain_from_name_noinit(domain_name);
1708 if (domain == NULL) {
1709 DBG_ERR("Failed to find domain '%s'\n", domain_name);
1710 return NT_STATUS_NO_SUCH_DOMAIN;
1713 /* Alias support and whitespace replacement are mutually
1716 nt_status = resolve_username_to_alias(mem_ctx, domain,
1718 if (NT_STATUS_IS_OK(nt_status)) {
1719 /* special return code to let the caller know we
1720 mapped to an alias */
1721 return NT_STATUS_FILE_RENAMED;
1724 /* check for an unreachable domain */
1726 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1727 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1729 set_domain_offline(domain);
1733 /* deal with whitespace */
1735 *normalized = talloc_strdup(mem_ctx, name);
1736 if (!(*normalized)) {
1737 return NT_STATUS_NO_MEMORY;
1740 all_string_sub( *normalized, " ", "_", 0 );
1742 return NT_STATUS_OK;
1745 /*********************************************************************
1746 We use this to do the inverse of normalize_name_map()
1747 ********************************************************************/
1749 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1754 struct winbindd_domain *domain = find_our_domain();
1756 if (!name || !normalized) {
1757 return NT_STATUS_INVALID_PARAMETER;
1760 if (!lp_winbind_normalize_names()) {
1761 return NT_STATUS_PROCEDURE_NOT_FOUND;
1764 /* Alias support and whitespace replacement are mutally
1767 /* When mapping from an alias to a username, we don't know the
1768 domain. But we only need a domain structure to cache
1769 a successful lookup , so just our own domain structure for
1772 nt_status = resolve_alias_to_username(mem_ctx, domain,
1774 if (NT_STATUS_IS_OK(nt_status)) {
1775 /* Special return code to let the caller know we mapped
1777 return NT_STATUS_FILE_RENAMED;
1780 /* check for an unreachable domain */
1782 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1783 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1785 set_domain_offline(domain);
1789 /* deal with whitespace */
1791 *normalized = talloc_strdup(mem_ctx, name);
1792 if (!(*normalized)) {
1793 return NT_STATUS_NO_MEMORY;
1796 all_string_sub(*normalized, "_", " ", 0);
1798 return NT_STATUS_OK;
1801 /*********************************************************************
1802 ********************************************************************/
1804 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1806 struct winbindd_tdc_domain *tdc = NULL;
1807 TALLOC_CTX *frame = talloc_stackframe();
1810 /* We can contact the domain if it is our primary domain */
1812 if (domain->primary) {
1817 /* Trust the TDC cache and not the winbindd_domain flags */
1819 if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1820 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1826 /* Can always contact a domain that is in out forest */
1828 if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1834 * On a _member_ server, we cannot contact the domain if it
1835 * is running AD and we have no inbound trust.
1839 domain->active_directory &&
1840 ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1842 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1843 "and we have no inbound trust.\n", domain->name));
1847 /* Assume everything else is ok (probably not true but what
1853 talloc_destroy(frame);
1858 /*********************************************************************
1859 ********************************************************************/
1861 bool winbindd_internal_child(struct winbindd_child *child)
1863 if ((child == idmap_child()) || (child == locator_child())) {
1870 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1872 /*********************************************************************
1873 ********************************************************************/
1875 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1878 char addr[INET6_ADDRSTRLEN];
1879 const char *kdc = NULL;
1882 if (!domain || !domain->alt_name || !*domain->alt_name) {
1886 if (domain->initialized && !domain->active_directory) {
1887 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1892 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1895 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1897 kdc = domain->dcname;
1900 if (!kdc || !*kdc) {
1901 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1906 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1907 domain->alt_name) == -1) {
1911 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1914 setenv(var, kdc, 1);
1918 /*********************************************************************
1919 ********************************************************************/
1921 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1923 struct winbindd_domain *our_dom = find_our_domain();
1925 winbindd_set_locator_kdc_env(domain);
1927 if (domain != our_dom) {
1928 winbindd_set_locator_kdc_env(our_dom);
1932 /*********************************************************************
1933 ********************************************************************/
1935 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1939 if (!domain || !domain->alt_name || !*domain->alt_name) {
1943 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1944 domain->alt_name) == -1) {
1953 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1958 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1963 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1965 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1967 resp->data.auth.nt_status = NT_STATUS_V(result);
1968 fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1970 /* we might have given a more useful error above */
1971 if (*resp->data.auth.error_string == '\0')
1972 fstrcpy(resp->data.auth.error_string,
1973 get_friendly_nt_error_msg(result));
1974 resp->data.auth.pam_error = nt_status_to_pam(result);
1977 bool is_domain_offline(const struct winbindd_domain *domain)
1979 if (get_global_winbindd_state_offline()) {
1982 return !domain->online;
1985 bool is_domain_online(const struct winbindd_domain *domain)
1987 return !is_domain_offline(domain);
1991 * Parse an char array into a list of sids.
1993 * The input sidstr should consist of 0-terminated strings
1994 * representing sids, separated by newline characters '\n'.
1995 * The list is terminated by an empty string, i.e.
1996 * character '\0' directly following a character '\n'
1997 * (or '\0' right at the start of sidstr).
1999 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
2000 struct dom_sid **sids, uint32_t *num_sids)
2008 while (p[0] != '\0') {
2010 const char *q = NULL;
2012 if (!dom_sid_parse_endp(p, &sid, &q)) {
2013 DEBUG(1, ("Could not parse sid %s\n", p));
2017 DEBUG(1, ("Got invalid sidstr: %s\n", p));
2020 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
2030 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
2031 struct unixid **pxids, uint32_t *pnum_xids)
2034 struct unixid *xids = NULL;
2035 uint32_t num_xids = 0;
2042 while (p[0] != '\0') {
2045 unsigned long long id;
2050 xid = (struct unixid) { .type = ID_TYPE_UID };
2053 xid = (struct unixid) { .type = ID_TYPE_GID };
2061 id = strtoull(p, &endp, 10);
2062 if ((id == ULLONG_MAX) && (errno == ERANGE)) {
2065 if (*endp != '\n') {
2071 if ((unsigned long long)xid.id != id) {
2075 tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
2081 xids[num_xids] = xid;
2086 *pnum_xids = num_xids;