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 struct winbindd_domain *find_default_route_domain(void)
1372 return find_our_domain();
1374 DBG_ERR("Routing logic not yet implemented on a DC");
1378 /* Find the appropriate domain to lookup a name or SID */
1380 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
1382 DBG_DEBUG("SID [%s]\n", sid_string_dbg(sid));
1385 * SIDs in the S-1-22-{1,2} domain and well-known SIDs should be handled
1389 if ( sid_check_is_in_unix_groups(sid) ||
1390 sid_check_is_unix_groups(sid) ||
1391 sid_check_is_in_unix_users(sid) ||
1392 sid_check_is_unix_users(sid) ||
1393 sid_check_is_wellknown_domain(sid, NULL) ||
1394 sid_check_is_in_wellknown_domain(sid) )
1396 return find_domain_from_sid(get_global_sam_sid());
1399 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
1400 * one to contact the external DC's. On member servers the internal
1401 * domains are different: These are part of the local SAM. */
1403 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
1404 DEBUG(10, ("calling find_domain_from_sid\n"));
1405 return find_domain_from_sid(sid);
1408 /* On a member server a query for SID or name can always go to our
1411 DEBUG(10, ("calling find_our_domain\n"));
1412 return find_our_domain();
1415 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1417 if ( strequal(domain_name, unix_users_domain_name() ) ||
1418 strequal(domain_name, unix_groups_domain_name() ) )
1421 * The "Unix User" and "Unix Group" domain our handled by
1424 return find_domain_from_name_noinit( get_global_sam_name() );
1427 if (IS_DC || strequal(domain_name, "BUILTIN") ||
1428 strequal(domain_name, get_global_sam_name()))
1429 return find_domain_from_name_noinit(domain_name);
1432 return find_our_domain();
1435 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1437 static bool assume_domain(const char *domain)
1439 /* never assume the domain on a standalone server */
1441 if ( lp_server_role() == ROLE_STANDALONE )
1444 /* domain member servers may possibly assume for the domain name */
1446 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1447 if ( !strequal(lp_workgroup(), domain) )
1450 if ( lp_winbind_use_default_domain() )
1454 /* only left with a domain controller */
1456 if ( strequal(get_global_sam_name(), domain) ) {
1463 /* Parse a string of the form DOMAIN\user into a domain and a user */
1465 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1467 char *p = strchr(domuser,*lp_winbind_separator());
1470 fstrcpy(user, domuser);
1471 p = strchr(domuser, '@');
1473 if ( assume_domain(lp_workgroup()) && p == NULL) {
1474 fstrcpy(domain, lp_workgroup());
1475 } else if (p != NULL) {
1476 fstrcpy(domain, p + 1);
1477 user[PTR_DIFF(p, domuser)] = 0;
1483 fstrcpy(domain, domuser);
1484 domain[PTR_DIFF(p, domuser)] = 0;
1487 return strupper_m(domain);
1490 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1491 char **domain, char **user)
1493 fstring fstr_domain, fstr_user;
1494 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1497 *domain = talloc_strdup(mem_ctx, fstr_domain);
1498 *user = talloc_strdup(mem_ctx, fstr_user);
1499 return ((*domain != NULL) && (*user != NULL));
1502 /* Ensure an incoming username from NSS is fully qualified. Replace the
1503 incoming fstring with DOMAIN <separator> user. Returns the same
1504 values as parse_domain_user() but also replaces the incoming username.
1505 Used to ensure all names are fully qualified within winbindd.
1506 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1507 The protocol definitions of auth_crap, chng_pswd_auth_crap
1508 really should be changed to use this instead of doing things
1511 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1513 if (!parse_domain_user(username_inout, domain, user)) {
1516 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1517 domain, *lp_winbind_separator(),
1523 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1524 'winbind separator' options.
1526 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1529 If we are a PDC or BDC, and this is for our domain, do likewise.
1531 On an AD DC we always fill DOMAIN\\USERNAME.
1533 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1535 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1539 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1543 fstrcpy(tmp_user, user);
1544 (void)strlower_m(tmp_user);
1546 if (can_assume && assume_domain(domain)) {
1547 strlcpy(name, tmp_user, sizeof(fstring));
1549 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1550 domain, *lp_winbind_separator(),
1556 * talloc version of fill_domain_username()
1557 * return NULL on talloc failure.
1559 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1564 char *tmp_user, *name;
1566 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1570 tmp_user = talloc_strdup(mem_ctx, user);
1571 if (!strlower_m(tmp_user)) {
1572 TALLOC_FREE(tmp_user);
1576 if (can_assume && assume_domain(domain)) {
1579 name = talloc_asprintf(mem_ctx, "%s%c%s",
1581 *lp_winbind_separator(),
1583 TALLOC_FREE(tmp_user);
1590 * Client list accessor functions
1593 static struct winbindd_cli_state *_client_list;
1594 static int _num_clients;
1596 /* Return list of all connected clients */
1598 struct winbindd_cli_state *winbindd_client_list(void)
1600 return _client_list;
1603 /* Return list-tail of all connected clients */
1605 struct winbindd_cli_state *winbindd_client_list_tail(void)
1607 return DLIST_TAIL(_client_list);
1610 /* Return previous (read:newer) client in list */
1612 struct winbindd_cli_state *
1613 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1615 return DLIST_PREV(cli);
1618 /* Add a connection to the list */
1620 void winbindd_add_client(struct winbindd_cli_state *cli)
1622 cli->last_access = time(NULL);
1623 DLIST_ADD(_client_list, cli);
1627 /* Remove a client from the list */
1629 void winbindd_remove_client(struct winbindd_cli_state *cli)
1631 DLIST_REMOVE(_client_list, cli);
1635 /* Move a client to head or list */
1637 void winbindd_promote_client(struct winbindd_cli_state *cli)
1639 cli->last_access = time(NULL);
1640 DLIST_PROMOTE(_client_list, cli);
1643 /* Return number of open clients */
1645 int winbindd_num_clients(void)
1647 return _num_clients;
1650 NTSTATUS lookup_usergroups_cached(TALLOC_CTX *mem_ctx,
1651 const struct dom_sid *user_sid,
1652 uint32_t *p_num_groups, struct dom_sid **user_sids)
1654 struct netr_SamInfo3 *info3 = NULL;
1655 NTSTATUS status = NT_STATUS_NO_MEMORY;
1656 uint32_t num_groups = 0;
1658 DEBUG(3,(": lookup_usergroups_cached\n"));
1663 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1665 if (info3 == NULL) {
1666 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1670 * Before bug #7843 the "Domain Local" groups were added with a
1671 * lookupuseraliases call, but this isn't done anymore for our domain
1672 * so we need to resolve resource groups here.
1674 * When to use Resource Groups:
1675 * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1677 status = sid_array_from_info3(mem_ctx, info3,
1682 if (!NT_STATUS_IS_OK(status)) {
1688 *p_num_groups = num_groups;
1689 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1691 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1696 /*********************************************************************
1697 We use this to remove spaces from user and group names
1698 ********************************************************************/
1700 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1701 const char *domain_name,
1705 struct winbindd_domain *domain = NULL;
1708 if (!name || !normalized) {
1709 return NT_STATUS_INVALID_PARAMETER;
1712 if (!lp_winbind_normalize_names()) {
1713 return NT_STATUS_PROCEDURE_NOT_FOUND;
1716 domain = find_domain_from_name_noinit(domain_name);
1717 if (domain == NULL) {
1718 DBG_ERR("Failed to find domain '%s'\n", domain_name);
1719 return NT_STATUS_NO_SUCH_DOMAIN;
1722 /* Alias support and whitespace replacement are mutually
1725 nt_status = resolve_username_to_alias(mem_ctx, domain,
1727 if (NT_STATUS_IS_OK(nt_status)) {
1728 /* special return code to let the caller know we
1729 mapped to an alias */
1730 return NT_STATUS_FILE_RENAMED;
1733 /* check for an unreachable domain */
1735 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1736 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1738 set_domain_offline(domain);
1742 /* deal with whitespace */
1744 *normalized = talloc_strdup(mem_ctx, name);
1745 if (!(*normalized)) {
1746 return NT_STATUS_NO_MEMORY;
1749 all_string_sub( *normalized, " ", "_", 0 );
1751 return NT_STATUS_OK;
1754 /*********************************************************************
1755 We use this to do the inverse of normalize_name_map()
1756 ********************************************************************/
1758 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1763 struct winbindd_domain *domain = find_our_domain();
1765 if (!name || !normalized) {
1766 return NT_STATUS_INVALID_PARAMETER;
1769 if (!lp_winbind_normalize_names()) {
1770 return NT_STATUS_PROCEDURE_NOT_FOUND;
1773 /* Alias support and whitespace replacement are mutally
1776 /* When mapping from an alias to a username, we don't know the
1777 domain. But we only need a domain structure to cache
1778 a successful lookup , so just our own domain structure for
1781 nt_status = resolve_alias_to_username(mem_ctx, domain,
1783 if (NT_STATUS_IS_OK(nt_status)) {
1784 /* Special return code to let the caller know we mapped
1786 return NT_STATUS_FILE_RENAMED;
1789 /* check for an unreachable domain */
1791 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1792 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1794 set_domain_offline(domain);
1798 /* deal with whitespace */
1800 *normalized = talloc_strdup(mem_ctx, name);
1801 if (!(*normalized)) {
1802 return NT_STATUS_NO_MEMORY;
1805 all_string_sub(*normalized, "_", " ", 0);
1807 return NT_STATUS_OK;
1810 /*********************************************************************
1811 ********************************************************************/
1813 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1815 struct winbindd_tdc_domain *tdc = NULL;
1816 TALLOC_CTX *frame = talloc_stackframe();
1819 /* We can contact the domain if it is our primary domain */
1821 if (domain->primary) {
1826 /* Trust the TDC cache and not the winbindd_domain flags */
1828 if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1829 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1835 /* Can always contact a domain that is in out forest */
1837 if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1843 * On a _member_ server, we cannot contact the domain if it
1844 * is running AD and we have no inbound trust.
1848 domain->active_directory &&
1849 ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1851 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1852 "and we have no inbound trust.\n", domain->name));
1856 /* Assume everything else is ok (probably not true but what
1862 talloc_destroy(frame);
1867 /*********************************************************************
1868 ********************************************************************/
1870 bool winbindd_internal_child(struct winbindd_child *child)
1872 if ((child == idmap_child()) || (child == locator_child())) {
1879 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1881 /*********************************************************************
1882 ********************************************************************/
1884 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1887 char addr[INET6_ADDRSTRLEN];
1888 const char *kdc = NULL;
1891 if (!domain || !domain->alt_name || !*domain->alt_name) {
1895 if (domain->initialized && !domain->active_directory) {
1896 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1901 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1904 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1906 kdc = domain->dcname;
1909 if (!kdc || !*kdc) {
1910 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1915 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1916 domain->alt_name) == -1) {
1920 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1923 setenv(var, kdc, 1);
1927 /*********************************************************************
1928 ********************************************************************/
1930 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1932 struct winbindd_domain *our_dom = find_our_domain();
1934 winbindd_set_locator_kdc_env(domain);
1936 if (domain != our_dom) {
1937 winbindd_set_locator_kdc_env(our_dom);
1941 /*********************************************************************
1942 ********************************************************************/
1944 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1948 if (!domain || !domain->alt_name || !*domain->alt_name) {
1952 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1953 domain->alt_name) == -1) {
1962 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1967 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1972 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1974 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1976 resp->data.auth.nt_status = NT_STATUS_V(result);
1977 fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1979 /* we might have given a more useful error above */
1980 if (*resp->data.auth.error_string == '\0')
1981 fstrcpy(resp->data.auth.error_string,
1982 get_friendly_nt_error_msg(result));
1983 resp->data.auth.pam_error = nt_status_to_pam(result);
1986 bool is_domain_offline(const struct winbindd_domain *domain)
1988 if (get_global_winbindd_state_offline()) {
1991 return !domain->online;
1994 bool is_domain_online(const struct winbindd_domain *domain)
1996 return !is_domain_offline(domain);
2000 * Parse an char array into a list of sids.
2002 * The input sidstr should consist of 0-terminated strings
2003 * representing sids, separated by newline characters '\n'.
2004 * The list is terminated by an empty string, i.e.
2005 * character '\0' directly following a character '\n'
2006 * (or '\0' right at the start of sidstr).
2008 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
2009 struct dom_sid **sids, uint32_t *num_sids)
2017 while (p[0] != '\0') {
2019 const char *q = NULL;
2021 if (!dom_sid_parse_endp(p, &sid, &q)) {
2022 DEBUG(1, ("Could not parse sid %s\n", p));
2026 DEBUG(1, ("Got invalid sidstr: %s\n", p));
2029 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
2039 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
2040 struct unixid **pxids, uint32_t *pnum_xids)
2043 struct unixid *xids = NULL;
2044 uint32_t num_xids = 0;
2051 while (p[0] != '\0') {
2054 unsigned long long id;
2059 xid = (struct unixid) { .type = ID_TYPE_UID };
2062 xid = (struct unixid) { .type = ID_TYPE_GID };
2070 id = strtoull(p, &endp, 10);
2071 if ((id == ULLONG_MAX) && (errno == ERANGE)) {
2074 if (*endp != '\n') {
2080 if ((unsigned long long)xid.id != id) {
2084 tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
2090 xids[num_xids] = xid;
2095 *pnum_xids = num_xids;