2 Unix SMB/CIFS implementation.
4 Winbind daemon for ntdom nss module
6 Copyright (C) Tim Potter 2000-2001
7 Copyright (C) 2001 by Martin Pool <mbp@samba.org>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "lib/util_unixsids.h"
27 #include "../libcli/security/security.h"
28 #include "../libcli/auth/pam_errors.h"
29 #include "passdb/machine_sid.h"
31 #include "source4/lib/messaging/messaging.h"
32 #include "librpc/gen_ndr/ndr_lsa.h"
33 #include "librpc/gen_ndr/ndr_drsblobs.h"
34 #include "auth/credentials/credentials.h"
35 #include "libsmb/samlogon_cache.h"
38 #define DBGC_CLASS DBGC_WINBIND
41 * @file winbindd_util.c
43 * Winbind daemon for NT domain authentication nss module.
47 /* The list of trusted domains. Note that the list can be deleted and
48 recreated using the init_domain_list() function so pointers to
49 individual winbindd_domain structures cannot be made. Keep a copy of
50 the domain name instead. */
52 static struct winbindd_domain *_domain_list = NULL;
54 struct winbindd_domain *domain_list(void)
58 if ((!_domain_list) && (!init_domain_list())) {
59 smb_panic("Init_domain_list failed");
65 /* Free all entries in the trusted domain list */
67 static void free_domain_list(void)
69 struct winbindd_domain *domain = _domain_list;
72 struct winbindd_domain *next = domain->next;
74 DLIST_REMOVE(_domain_list, domain);
81 * Iterator for winbindd's domain list.
82 * To be used (e.g.) in tevent based loops.
84 struct winbindd_domain *wb_next_domain(struct winbindd_domain *domain)
87 domain = domain_list();
89 domain = domain->next;
92 if ((domain != NULL) &&
93 (lp_server_role() != ROLE_ACTIVE_DIRECTORY_DC) &&
94 sid_check_is_our_sam(&domain->sid))
96 domain = domain->next;
102 static bool is_internal_domain(const struct dom_sid *sid)
107 return (sid_check_is_our_sam(sid) || sid_check_is_builtin(sid));
110 static bool is_in_internal_domain(const struct dom_sid *sid)
115 return (sid_check_is_in_our_sam(sid) || sid_check_is_in_builtin(sid));
119 /* Add a trusted domain to our list of domains.
120 If the domain already exists in the list,
121 return it and don't re-initialize. */
123 static NTSTATUS add_trusted_domain(const char *domain_name,
124 const char *dns_name,
125 const struct dom_sid *sid,
127 uint32_t trust_flags,
128 uint32_t trust_attribs,
129 enum netr_SchannelType secure_channel_type,
130 struct winbindd_domain **_d)
132 struct winbindd_domain *domain = NULL;
133 const char **ignored_domains = NULL;
134 const char **dom = NULL;
135 int role = lp_server_role();
137 if (is_null_sid(sid)) {
138 DBG_ERR("Got null SID for domain [%s]\n", domain_name);
139 return NT_STATUS_INVALID_PARAMETER;
142 ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
143 for (dom=ignored_domains; dom && *dom; dom++) {
144 if (gen_fnmatch(*dom, domain_name) == 0) {
145 DEBUG(2,("Ignoring domain '%s'\n", domain_name));
146 return NT_STATUS_NO_SUCH_DOMAIN;
151 * We can't call domain_list() as this function is called from
152 * init_domain_list() and we'll get stuck in a loop.
154 for (domain = _domain_list; domain; domain = domain->next) {
155 if (strequal(domain_name, domain->name)) {
160 if (domain != NULL) {
161 struct winbindd_domain *check_domain = NULL;
163 for (check_domain = _domain_list;
164 check_domain != NULL;
165 check_domain = check_domain->next)
167 if (check_domain == domain) {
171 if (dom_sid_equal(&check_domain->sid, sid)) {
176 if (check_domain != NULL) {
177 DBG_ERR("SID [%s] already used by domain [%s], "
179 sid_string_dbg(sid), check_domain->name,
181 return NT_STATUS_INVALID_PARAMETER;
185 if ((domain != NULL) && (dns_name != NULL)) {
186 struct winbindd_domain *check_domain = NULL;
188 for (check_domain = _domain_list;
189 check_domain != NULL;
190 check_domain = check_domain->next)
192 if (check_domain == domain) {
196 if (strequal(check_domain->alt_name, dns_name)) {
201 if (check_domain != NULL) {
202 DBG_ERR("DNS name [%s] used by domain [%s], "
204 dns_name, check_domain->name,
206 return NT_STATUS_INVALID_PARAMETER;
210 if (domain != NULL) {
215 /* Create new domain entry */
216 domain = talloc_zero(NULL, struct winbindd_domain);
217 if (domain == NULL) {
218 return NT_STATUS_NO_MEMORY;
221 domain->children = talloc_zero_array(domain,
222 struct winbindd_child,
223 lp_winbind_max_domain_connections());
224 if (domain->children == NULL) {
226 return NT_STATUS_NO_MEMORY;
229 domain->name = talloc_strdup(domain, domain_name);
230 if (domain->name == NULL) {
232 return NT_STATUS_NO_MEMORY;
235 if (dns_name != NULL) {
236 domain->alt_name = talloc_strdup(domain, dns_name);
237 if (domain->alt_name == NULL) {
239 return NT_STATUS_NO_MEMORY;
243 domain->backend = NULL;
244 domain->internal = is_internal_domain(sid);
245 domain->secure_channel_type = secure_channel_type;
246 domain->sequence_number = DOM_SEQUENCE_NONE;
247 domain->last_seq_check = 0;
248 domain->initialized = false;
249 domain->online = is_internal_domain(sid);
250 domain->check_online_timeout = 0;
251 domain->dc_probe_pid = (pid_t)-1;
252 domain->domain_flags = trust_flags;
253 domain->domain_type = trust_type;
254 domain->domain_trust_attribs = trust_attribs;
255 domain->secure_channel_type = secure_channel_type;
256 sid_copy(&domain->sid, sid);
258 /* Is this our primary domain ? */
259 if (role == ROLE_DOMAIN_MEMBER) {
260 domain->primary = strequal(domain_name, lp_workgroup());
262 domain->primary = strequal(domain_name, get_global_sam_name());
265 if (domain->primary) {
266 if (role == ROLE_ACTIVE_DIRECTORY_DC) {
267 domain->active_directory = true;
269 if (lp_security() == SEC_ADS) {
270 domain->active_directory = true;
272 } else if (!domain->internal) {
273 if (domain->domain_type == LSA_TRUST_TYPE_UPLEVEL) {
274 domain->active_directory = true;
278 /* Link to domain list */
279 DLIST_ADD_END(_domain_list, domain);
281 wcache_tdc_add_domain( domain );
283 setup_domain_child(domain);
285 DBG_NOTICE("Added domain [%s] [%s] [%s]\n",
286 domain->name, domain->alt_name,
287 sid_string_dbg(&domain->sid));
293 bool set_routing_domain(struct winbindd_domain *domain,
294 const struct winbindd_domain *routing_domain)
296 if (domain->routing_domain == NULL) {
297 domain->routing_domain = routing_domain;
300 if (domain->routing_domain != routing_domain) {
306 bool domain_is_forest_root(const struct winbindd_domain *domain)
308 const uint32_t fr_flags =
309 (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
311 return ((domain->domain_flags & fr_flags) == fr_flags);
314 /********************************************************************
315 rescan our domains looking for new trusted domains
316 ********************************************************************/
318 struct trustdom_state {
319 struct winbindd_domain *domain;
320 struct winbindd_request request;
323 static void trustdom_list_done(struct tevent_req *req);
324 static void rescan_forest_root_trusts( void );
325 static void rescan_forest_trusts( void );
327 static void add_trusted_domains( struct winbindd_domain *domain )
329 struct trustdom_state *state;
330 struct tevent_req *req;
332 state = talloc_zero(NULL, struct trustdom_state);
334 DEBUG(0, ("talloc failed\n"));
337 state->domain = domain;
339 state->request.length = sizeof(state->request);
340 state->request.cmd = WINBINDD_LIST_TRUSTDOM;
342 req = wb_domain_request_send(state, server_event_context(),
343 domain, &state->request);
345 DEBUG(1, ("wb_domain_request_send failed\n"));
349 tevent_req_set_callback(req, trustdom_list_done, state);
352 static void trustdom_list_done(struct tevent_req *req)
354 struct trustdom_state *state = tevent_req_callback_data(
355 req, struct trustdom_state);
356 struct winbindd_response *response;
360 bool within_forest = false;
364 * Only when we enumerate our primary domain
365 * or our forest root domain, we should keep
366 * the NETR_TRUST_FLAG_IN_FOREST flag, in
367 * all other cases we need to clear it as the domain
368 * is not part of our forest.
370 if (state->domain->primary) {
371 within_forest = true;
372 } else if (domain_is_forest_root(state->domain)) {
373 within_forest = true;
376 res = wb_domain_request_recv(req, state, &response, &err);
377 if ((res == -1) || (response->result != WINBINDD_OK)) {
378 DBG_WARNING("Could not receive trusts for domain %s\n",
379 state->domain->name);
384 if (response->length < sizeof(struct winbindd_response)) {
385 DBG_ERR("ill-formed trustdom response - short length\n");
390 extra_len = response->length - sizeof(struct winbindd_response);
392 p = (char *)response->extra_data.data;
394 while ((p - (char *)response->extra_data.data) < extra_len) {
395 struct winbindd_domain *domain = NULL;
396 char *name, *q, *sidstr, *alt_name;
399 uint32_t trust_attribs;
400 uint32_t trust_flags;
402 DBG_DEBUG("parsing response line '%s'\n", p);
406 alt_name = strchr(p, '\\');
407 if (alt_name == NULL) {
408 DBG_ERR("Got invalid trustdom response\n");
415 sidstr = strchr(alt_name, '\\');
416 if (sidstr == NULL) {
417 DBG_ERR("Got invalid trustdom response\n");
424 /* use the real alt_name if we have one, else pass in NULL */
425 if (strequal(alt_name, "(null)")) {
429 q = strtok(sidstr, "\\");
431 DBG_ERR("Got invalid trustdom response\n");
435 if (!string_to_sid(&sid, sidstr)) {
436 DEBUG(0, ("Got invalid trustdom response\n"));
440 q = strtok(NULL, "\\");
442 DBG_ERR("Got invalid trustdom response\n");
446 trust_flags = (uint32_t)strtoul(q, NULL, 10);
448 q = strtok(NULL, "\\");
450 DBG_ERR("Got invalid trustdom response\n");
454 trust_type = (uint32_t)strtoul(q, NULL, 10);
456 q = strtok(NULL, "\n");
458 DBG_ERR("Got invalid trustdom response\n");
462 trust_attribs = (uint32_t)strtoul(q, NULL, 10);
464 if (!within_forest) {
465 trust_flags &= ~NETR_TRUST_FLAG_IN_FOREST;
468 if (!state->domain->primary) {
469 trust_flags &= ~NETR_TRUST_FLAG_PRIMARY;
473 * We always call add_trusted_domain() cause on an existing
474 * domain structure, it will update the SID if necessary.
475 * This is important because we need the SID for sibling
478 status = add_trusted_domain(name,
486 if (!NT_STATUS_IS_OK(status) &&
487 !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
489 DBG_NOTICE("add_trusted_domain returned %s\n",
494 p = q + strlen(q) + 1;
498 Cases to consider when scanning trusts:
499 (a) we are calling from a child domain (primary && !forest_root)
500 (b) we are calling from the root of the forest (primary && forest_root)
501 (c) we are calling from a trusted forest domain (!primary
505 if (state->domain->primary) {
506 /* If this is our primary domain and we are not in the
507 forest root, we have to scan the root trusts first */
509 if (!domain_is_forest_root(state->domain))
510 rescan_forest_root_trusts();
512 rescan_forest_trusts();
514 } else if (domain_is_forest_root(state->domain)) {
515 /* Once we have done root forest trust search, we can
516 go on to search the trusted forests */
518 rescan_forest_trusts();
526 /********************************************************************
527 Scan the trusts of our forest root
528 ********************************************************************/
530 static void rescan_forest_root_trusts( void )
532 struct winbindd_tdc_domain *dom_list = NULL;
533 size_t num_trusts = 0;
537 /* The only transitive trusts supported by Windows 2003 AD are
538 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
539 first two are handled in forest and listed by
540 DsEnumerateDomainTrusts(). Forest trusts are not so we
541 have to do that ourselves. */
543 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
546 for ( i=0; i<num_trusts; i++ ) {
547 struct winbindd_domain *d = NULL;
549 /* Find the forest root. Don't necessarily trust
550 the domain_list() as our primary domain may not
551 have been initialized. */
553 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
557 /* Here's the forest root */
559 d = find_domain_from_name_noinit( dom_list[i].domain_name );
561 status = add_trusted_domain(dom_list[i].domain_name,
562 dom_list[i].dns_name,
564 dom_list[i].trust_type,
565 dom_list[i].trust_flags,
566 dom_list[i].trust_attribs,
570 if (!NT_STATUS_IS_OK(status) &&
571 NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
573 DBG_ERR("add_trusted_domain returned %s\n",
582 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
583 "for domain tree root %s (%s)\n",
584 d->name, d->alt_name ));
586 d->domain_flags = dom_list[i].trust_flags;
587 d->domain_type = dom_list[i].trust_type;
588 d->domain_trust_attribs = dom_list[i].trust_attribs;
590 add_trusted_domains( d );
595 TALLOC_FREE( dom_list );
600 /********************************************************************
601 scan the transitive forest trusts (not our own)
602 ********************************************************************/
605 static void rescan_forest_trusts( void )
607 struct winbindd_domain *d = NULL;
608 struct winbindd_tdc_domain *dom_list = NULL;
609 size_t num_trusts = 0;
613 /* The only transitive trusts supported by Windows 2003 AD are
614 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
615 first two are handled in forest and listed by
616 DsEnumerateDomainTrusts(). Forest trusts are not so we
617 have to do that ourselves. */
619 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
622 for ( i=0; i<num_trusts; i++ ) {
623 uint32_t flags = dom_list[i].trust_flags;
624 uint32_t type = dom_list[i].trust_type;
625 uint32_t attribs = dom_list[i].trust_attribs;
627 d = find_domain_from_name_noinit( dom_list[i].domain_name );
629 /* ignore our primary and internal domains */
631 if ( d && (d->internal || d->primary ) )
634 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
635 (type == LSA_TRUST_TYPE_UPLEVEL) &&
636 (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
638 /* add the trusted domain if we don't know
642 status = add_trusted_domain(
643 dom_list[i].domain_name,
644 dom_list[i].dns_name,
651 if (!NT_STATUS_IS_OK(status) &&
652 NT_STATUS_EQUAL(status,
653 NT_STATUS_NO_SUCH_DOMAIN))
655 DBG_ERR("add_trusted_domain: %s\n",
665 DEBUG(10,("Following trust path for domain %s (%s)\n",
666 d->name, d->alt_name ));
667 add_trusted_domains( d );
671 TALLOC_FREE( dom_list );
676 /*********************************************************************
677 The process of updating the trusted domain list is a three step
680 (b) ask the root domain in our forest
681 (c) ask the a DC in any Win2003 trusted forests
682 *********************************************************************/
684 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
685 struct timeval now, void *private_data)
689 /* I use to clear the cache here and start over but that
690 caused problems in child processes that needed the
691 trust dom list early on. Removing it means we
692 could have some trusted domains listed that have been
693 removed from our primary domain's DC until a full
694 restart. This should be ok since I think this is what
695 Windows does as well. */
697 /* this will only add new domains we didn't already know about
698 in the domain_list()*/
700 add_trusted_domains( find_our_domain() );
702 te = tevent_add_timer(
703 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
704 rescan_trusted_domains, NULL);
706 * If te == NULL, there's not much we can do here. Don't fail, the
707 * only thing we miss is new trusted domains.
713 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
714 struct winbindd_cli_state *state)
716 /* Ensure null termination */
717 state->request->domain_name
718 [sizeof(state->request->domain_name)-1]='\0';
719 state->request->data.init_conn.dcname
720 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
722 if (strlen(state->request->data.init_conn.dcname) > 0) {
723 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
726 init_dc_connection(domain, false);
728 if (!domain->initialized) {
729 /* If we return error here we can't do any cached authentication,
730 but we may be in disconnected mode and can't initialize correctly.
731 Do what the previous code did and just return without initialization,
732 once we go online we'll re-initialize.
734 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
735 "online = %d\n", domain->name, (int)domain->online ));
738 fstrcpy(state->response->data.domain_info.name, domain->name);
739 fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
740 sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
742 state->response->data.domain_info.native_mode
743 = domain->native_mode;
744 state->response->data.domain_info.active_directory
745 = domain->active_directory;
746 state->response->data.domain_info.primary
752 static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
755 struct server_id server_id,
758 TALLOC_CTX *frame = talloc_stackframe();
759 enum netr_SchannelType secure_channel_type = SEC_CHAN_DOMAIN;
760 struct lsa_TrustDomainInfoInfoEx info;
761 enum ndr_err_code ndr_err;
762 struct winbindd_domain *d = NULL;
763 uint32_t trust_flags = 0;
766 DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
773 ndr_err = ndr_pull_struct_blob_all(data, frame, &info,
774 (ndr_pull_flags_fn_t)ndr_pull_lsa_TrustDomainInfoInfoEx);
775 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
780 d = find_domain_from_name_noinit(info.netbios_name.string);
786 if (info.trust_type == LSA_TRUST_TYPE_UPLEVEL) {
787 secure_channel_type = SEC_CHAN_DNS_DOMAIN;
789 if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
790 trust_flags |= NETR_TRUST_FLAG_INBOUND;
792 if (info.trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
793 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
795 if (info.trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
796 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
799 status = add_trusted_domain(info.netbios_name.string,
800 info.domain_name.string,
804 info.trust_attributes,
807 if (!NT_STATUS_IS_OK(status) &&
808 !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
810 DBG_NOTICE("add_trusted_domain returned %s\n",
819 * We did not get the secret when we queried secrets.tdb, so read it
820 * from secrets.tdb and re-sync the databases
822 static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
825 struct cli_credentials *creds;
826 NTSTATUS can_migrate = pdb_get_trust_credentials(domain->name,
827 NULL, domain, &creds);
828 if (!NT_STATUS_IS_OK(can_migrate)) {
829 DEBUG(0, ("Failed to fetch our own, local AD domain join "
830 "password for winbindd's internal use, both from "
831 "secrets.tdb and secrets.ldb: %s\n",
832 nt_errstr(can_migrate)));
837 * NOTE: It is very unlikely we end up here if there is an
838 * oldpass, because a new password is created at
839 * classicupgrade, so this is not a concern.
841 ok = secrets_store_machine_pw_sync(cli_credentials_get_password(creds),
843 cli_credentials_get_domain(creds),
844 cli_credentials_get_realm(creds),
845 cli_credentials_get_salt_principal(creds),
846 0, /* Supported enc types, unused */
848 cli_credentials_get_password_last_changed_time(creds),
849 cli_credentials_get_secure_channel_type(creds),
850 false /* do_delete: Do not delete */);
853 DEBUG(0, ("Failed to write our our own, "
854 "local AD domain join password for "
855 "winbindd's internal use into secrets.tdb\n"));
861 /* Look up global info for the winbind daemon */
862 bool init_domain_list(void)
864 int role = lp_server_role();
865 struct pdb_domain_info *pdb_domain_info = NULL;
866 struct winbindd_domain *domain = NULL;
869 /* Free existing list */
874 status = add_trusted_domain("BUILTIN",
877 LSA_TRUST_TYPE_DOWNLEVEL,
879 0, /* trust_attribs */
882 if (!NT_STATUS_IS_OK(status)) {
883 DBG_ERR("add_trusted_domain BUILTIN returned %s\n",
891 * In case the passdb backend is passdb_dsdb the domain SID comes from
892 * dsdb, not from secrets.tdb. As we use the domain SID in various
893 * places, we must ensure the domain SID is migrated from dsdb to
894 * secrets.tdb before get_global_sam_sid() is called the first time.
896 * The migration is done as part of the passdb_dsdb initialisation,
897 * calling pdb_get_domain_info() triggers it.
899 pdb_domain_info = pdb_get_domain_info(talloc_tos());
901 if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
902 uint32_t trust_flags;
904 enum netr_SchannelType sec_chan_type;
905 const char *account_name;
906 struct samr_Password current_nt_hash;
909 if (pdb_domain_info == NULL) {
910 DEBUG(0, ("Failed to fetch our own, local AD "
911 "domain info from sam.ldb\n"));
915 trust_flags = NETR_TRUST_FLAG_PRIMARY;
916 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
917 trust_flags |= NETR_TRUST_FLAG_NATIVE;
918 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
920 is_root = strequal(pdb_domain_info->dns_domain,
921 pdb_domain_info->dns_forest);
923 trust_flags |= NETR_TRUST_FLAG_TREEROOT;
926 status = add_trusted_domain(pdb_domain_info->name,
927 pdb_domain_info->dns_domain,
928 &pdb_domain_info->sid,
929 LSA_TRUST_TYPE_UPLEVEL,
931 LSA_TRUST_ATTRIBUTE_WITHIN_FOREST,
934 TALLOC_FREE(pdb_domain_info);
935 if (!NT_STATUS_IS_OK(status)) {
936 DBG_ERR("Failed to add our own, local AD "
937 "domain to winbindd's internal list\n");
942 * We need to call this to find out if we are an RODC
944 ok = get_trust_pw_hash(domain->name,
945 current_nt_hash.hash,
950 * If get_trust_pw_hash() fails, then try and
951 * fetch the password from the more recent of
952 * secrets.{ldb,tdb} using the
953 * pdb_get_trust_credentials()
955 ok = migrate_secrets_tdb_to_ldb(domain);
958 DEBUG(0, ("Failed to migrate our own, "
959 "local AD domain join password for "
960 "winbindd's internal use into "
964 ok = get_trust_pw_hash(domain->name,
965 current_nt_hash.hash,
969 DEBUG(0, ("Failed to find our our own, just "
970 "written local AD domain join "
971 "password for winbindd's internal "
972 "use in secrets.tdb\n"));
977 domain->secure_channel_type = sec_chan_type;
978 if (sec_chan_type == SEC_CHAN_RODC) {
983 uint32_t trust_flags;
984 enum netr_SchannelType secure_channel_type;
986 trust_flags = NETR_TRUST_FLAG_OUTBOUND;
987 if (role != ROLE_DOMAIN_MEMBER) {
988 trust_flags |= NETR_TRUST_FLAG_PRIMARY;
991 if (role > ROLE_DOMAIN_MEMBER) {
992 secure_channel_type = SEC_CHAN_BDC;
994 secure_channel_type = SEC_CHAN_LOCAL;
997 status = add_trusted_domain(get_global_sam_name(),
999 get_global_sam_sid(),
1000 LSA_TRUST_TYPE_DOWNLEVEL,
1002 0, /* trust_attribs */
1003 secure_channel_type,
1005 if (!NT_STATUS_IS_OK(status)) {
1006 DBG_ERR("Failed to add local SAM to "
1007 "domain to winbindd's internal list\n");
1011 /* Add ourselves as the first entry. */
1013 if ( role == ROLE_DOMAIN_MEMBER ) {
1014 struct dom_sid our_sid;
1015 uint32_t trust_type;
1017 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
1018 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
1022 if (lp_realm() != NULL) {
1023 trust_type = LSA_TRUST_TYPE_UPLEVEL;
1025 trust_type = LSA_TRUST_TYPE_DOWNLEVEL;
1028 status = add_trusted_domain(lp_workgroup(),
1032 NETR_TRUST_FLAG_PRIMARY|
1033 NETR_TRUST_FLAG_OUTBOUND,
1034 0, /* trust_attribs */
1037 if (!NT_STATUS_IS_OK(status)) {
1038 DBG_ERR("Failed to add local SAM to "
1039 "domain to winbindd's internal list\n");
1042 /* Even in the parent winbindd we'll need to
1043 talk to the DC, so try and see if we can
1044 contact it. Theoretically this isn't neccessary
1045 as the init_dc_connection() in init_child_recv()
1046 will do this, but we can start detecting the DC
1048 set_domain_online_request(domain);
1052 if (IS_DC && (pdb_capabilities() & PDB_CAP_TRUSTED_DOMAINS_EX)) {
1053 uint32_t num_domains = 0;
1054 struct pdb_trusted_domain **domains = NULL;
1057 status = pdb_enum_trusted_domains(talloc_tos(), &num_domains, &domains);
1058 if (!NT_STATUS_IS_OK(status)) {
1059 DBG_ERR("pdb_enum_trusted_domains() failed - %s\n",
1064 for (i = 0; i < num_domains; i++) {
1065 enum netr_SchannelType sec_chan_type = SEC_CHAN_DOMAIN;
1066 uint32_t trust_flags = 0;
1068 if (domains[i]->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
1069 sec_chan_type = SEC_CHAN_DNS_DOMAIN;
1072 if (!(domains[i]->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND)) {
1073 sec_chan_type = SEC_CHAN_NULL;
1076 if (domains[i]->trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
1077 trust_flags |= NETR_TRUST_FLAG_INBOUND;
1079 if (domains[i]->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
1080 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
1082 if (domains[i]->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
1083 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
1086 status = add_trusted_domain(domains[i]->netbios_name,
1087 domains[i]->domain_name,
1088 &domains[i]->security_identifier,
1089 domains[i]->trust_type,
1091 domains[i]->trust_attributes,
1094 if (!NT_STATUS_IS_OK(status)) {
1095 DBG_NOTICE("add_trusted_domain returned %s\n",
1100 if (domains[i]->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
1101 domain->active_directory = true;
1103 domain->domain_type = domains[i]->trust_type;
1104 domain->domain_trust_attribs = domains[i]->trust_attributes;
1106 if (sec_chan_type != SEC_CHAN_NULL) {
1107 /* Even in the parent winbindd we'll need to
1108 talk to the DC, so try and see if we can
1109 contact it. Theoretically this isn't neccessary
1110 as the init_dc_connection() in init_child_recv()
1111 will do this, but we can start detecting the DC
1113 set_domain_online_request(domain);
1117 for (i = 0; i < num_domains; i++) {
1118 struct ForestTrustInfo fti;
1120 enum ndr_err_code ndr_err;
1121 struct winbindd_domain *routing_domain = NULL;
1124 if (domains[i]->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
1128 if (!(domains[i]->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1132 if (domains[i]->trust_forest_trust_info.length == 0) {
1136 routing_domain = find_domain_from_name_noinit(
1137 domains[i]->netbios_name);
1138 if (routing_domain == NULL) {
1139 DBG_ERR("Can't find winbindd domain [%s]\n",
1140 domains[i]->netbios_name);
1144 ndr_err = ndr_pull_struct_blob_all(
1145 &domains[i]->trust_forest_trust_info,
1147 (ndr_pull_flags_fn_t)ndr_pull_ForestTrustInfo);
1148 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1149 DBG_ERR("ndr_pull_ForestTrustInfo(%s) - %s\n",
1150 domains[i]->netbios_name,
1151 ndr_map_error2string(ndr_err));
1155 for (fi = 0; fi < fti.count; fi++) {
1156 struct ForestTrustInfoRecord *rec =
1157 &fti.records[fi].record;
1158 struct ForestTrustDataDomainInfo *drec = NULL;
1160 if (rec->type != FOREST_TRUST_DOMAIN_INFO) {
1163 drec = &rec->data.info;
1165 if (rec->flags & LSA_NB_DISABLED_MASK) {
1169 if (rec->flags & LSA_SID_DISABLED_MASK) {
1175 * also try to find a matching
1176 * LSA_TLN_DISABLED_MASK ???
1179 domain = find_domain_from_name_noinit(drec->netbios_name.string);
1180 if (domain != NULL) {
1184 status = add_trusted_domain(drec->netbios_name.string,
1185 drec->dns_name.string,
1187 LSA_TRUST_TYPE_UPLEVEL,
1188 NETR_TRUST_FLAG_OUTBOUND,
1192 if (!NT_STATUS_IS_OK(status)) {
1193 DBG_NOTICE("add_trusted_domain returned %s\n",
1197 if (domain == NULL) {
1200 ok = set_routing_domain(domain, routing_domain);
1202 DBG_ERR("set_routing_domain on [%s] to "
1205 routing_domain->name);
1211 uint32_t num_domains = 0;
1212 struct trustdom_info **domains = NULL;
1215 status = pdb_enum_trusteddoms(talloc_tos(), &num_domains, &domains);
1216 if (!NT_STATUS_IS_OK(status)) {
1217 DBG_ERR("pdb_enum_trusteddoms() failed - %s\n",
1222 for (i = 0; i < num_domains; i++) {
1223 status = add_trusted_domain(domains[i]->name,
1226 LSA_TRUST_TYPE_DOWNLEVEL,
1227 NETR_TRUST_FLAG_OUTBOUND,
1231 if (!NT_STATUS_IS_OK(status)) {
1232 DBG_NOTICE("add_trusted_domain returned %s\n",
1237 /* Even in the parent winbindd we'll need to
1238 talk to the DC, so try and see if we can
1239 contact it. Theoretically this isn't neccessary
1240 as the init_dc_connection() in init_child_recv()
1241 will do this, but we can start detecting the DC
1243 set_domain_online_request(domain);
1247 status = imessaging_register(winbind_imessaging_context(), NULL,
1248 MSG_WINBIND_NEW_TRUSTED_DOMAIN,
1249 wb_imsg_new_trusted_domain);
1250 if (!NT_STATUS_IS_OK(status)) {
1251 DEBUG(0, ("imessaging_register(MSG_WINBIND_NEW_TRUSTED_DOMAIN) - %s\n",
1252 nt_errstr(status)));
1260 * Given a domain name, return the struct winbindd domain info for it
1262 * @note Do *not* pass lp_workgroup() to this function. domain_list
1263 * may modify it's value, and free that pointer. Instead, our local
1264 * domain may be found by calling find_our_domain().
1268 * @return The domain structure for the named domain, if it is working.
1271 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
1273 struct winbindd_domain *domain;
1275 /* Search through list */
1277 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1278 if (strequal(domain_name, domain->name)) {
1281 if (domain->alt_name == NULL) {
1284 if (strequal(domain_name, domain->alt_name)) {
1295 * Given a domain name, return the struct winbindd domain if it's a direct
1298 * @return The domain structure for the named domain, if it is a direct outgoing trust
1300 struct winbindd_domain *find_trust_from_name_noinit(const char *domain_name)
1302 struct winbindd_domain *domain = NULL;
1304 domain = find_domain_from_name_noinit(domain_name);
1305 if (domain == NULL) {
1309 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1316 struct winbindd_domain *find_domain_from_name(const char *domain_name)
1318 struct winbindd_domain *domain;
1320 domain = find_domain_from_name_noinit(domain_name);
1325 if (!domain->initialized)
1326 init_dc_connection(domain, false);
1331 /* Given a domain sid, return the struct winbindd domain info for it */
1333 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
1335 struct winbindd_domain *domain;
1337 /* Search through list */
1339 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1340 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
1350 * Given a domain sid, return the struct winbindd domain if it's a direct
1353 * @return The domain structure for the specified domain, if it is a direct outgoing trust
1355 struct winbindd_domain *find_trust_from_sid_noinit(const struct dom_sid *sid)
1357 struct winbindd_domain *domain = NULL;
1359 domain = find_domain_from_sid_noinit(sid);
1360 if (domain == NULL) {
1364 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1371 /* Given a domain sid, return the struct winbindd domain info for it */
1373 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
1375 struct winbindd_domain *domain;
1377 domain = find_domain_from_sid_noinit(sid);
1382 if (!domain->initialized)
1383 init_dc_connection(domain, false);
1388 struct winbindd_domain *find_our_domain(void)
1390 struct winbindd_domain *domain;
1392 /* Search through list */
1394 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1395 if (domain->primary)
1399 smb_panic("Could not find our domain");
1403 struct winbindd_domain *find_default_route_domain(void)
1406 return find_our_domain();
1408 DBG_ERR("Routing logic not yet implemented on a DC");
1412 /* Find the appropriate domain to lookup a name or SID */
1414 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
1416 DBG_DEBUG("SID [%s]\n", sid_string_dbg(sid));
1419 * SIDs in the S-1-22-{1,2} domain and well-known SIDs should be handled
1423 if ( sid_check_is_in_unix_groups(sid) ||
1424 sid_check_is_unix_groups(sid) ||
1425 sid_check_is_in_unix_users(sid) ||
1426 sid_check_is_unix_users(sid) ||
1427 sid_check_is_wellknown_domain(sid, NULL) ||
1428 sid_check_is_in_wellknown_domain(sid) )
1430 return find_domain_from_sid(get_global_sam_sid());
1433 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
1434 * one to contact the external DC's. On member servers the internal
1435 * domains are different: These are part of the local SAM. */
1437 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
1438 DEBUG(10, ("calling find_domain_from_sid\n"));
1439 return find_domain_from_sid(sid);
1442 /* On a member server a query for SID or name can always go to our
1445 DEBUG(10, ("calling find_our_domain\n"));
1446 return find_our_domain();
1449 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1451 if ( strequal(domain_name, unix_users_domain_name() ) ||
1452 strequal(domain_name, unix_groups_domain_name() ) )
1455 * The "Unix User" and "Unix Group" domain our handled by
1458 return find_domain_from_name_noinit( get_global_sam_name() );
1461 if (IS_DC || strequal(domain_name, "BUILTIN") ||
1462 strequal(domain_name, get_global_sam_name()))
1463 return find_domain_from_name_noinit(domain_name);
1466 return find_our_domain();
1469 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1471 static bool assume_domain(const char *domain)
1473 /* never assume the domain on a standalone server */
1475 if ( lp_server_role() == ROLE_STANDALONE )
1478 /* domain member servers may possibly assume for the domain name */
1480 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1481 if ( !strequal(lp_workgroup(), domain) )
1484 if ( lp_winbind_use_default_domain() )
1488 /* only left with a domain controller */
1490 if ( strequal(get_global_sam_name(), domain) ) {
1497 /* Parse a string of the form DOMAIN\user into a domain and a user */
1499 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1501 char *p = strchr(domuser,*lp_winbind_separator());
1504 fstrcpy(user, domuser);
1505 p = strchr(domuser, '@');
1507 if ( assume_domain(lp_workgroup()) && p == NULL) {
1508 fstrcpy(domain, lp_workgroup());
1509 } else if (p != NULL) {
1510 fstrcpy(domain, p + 1);
1511 user[PTR_DIFF(p, domuser)] = 0;
1517 fstrcpy(domain, domuser);
1518 domain[PTR_DIFF(p, domuser)] = 0;
1521 return strupper_m(domain);
1524 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1525 char **domain, char **user)
1527 fstring fstr_domain, fstr_user;
1528 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1531 *domain = talloc_strdup(mem_ctx, fstr_domain);
1532 *user = talloc_strdup(mem_ctx, fstr_user);
1533 return ((*domain != NULL) && (*user != NULL));
1536 /* Ensure an incoming username from NSS is fully qualified. Replace the
1537 incoming fstring with DOMAIN <separator> user. Returns the same
1538 values as parse_domain_user() but also replaces the incoming username.
1539 Used to ensure all names are fully qualified within winbindd.
1540 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1541 The protocol definitions of auth_crap, chng_pswd_auth_crap
1542 really should be changed to use this instead of doing things
1545 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1547 if (!parse_domain_user(username_inout, domain, user)) {
1550 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1551 domain, *lp_winbind_separator(),
1557 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1558 'winbind separator' options.
1560 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1563 If we are a PDC or BDC, and this is for our domain, do likewise.
1565 On an AD DC we always fill DOMAIN\\USERNAME.
1567 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1569 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1573 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1577 fstrcpy(tmp_user, user);
1578 (void)strlower_m(tmp_user);
1580 if (can_assume && assume_domain(domain)) {
1581 strlcpy(name, tmp_user, sizeof(fstring));
1583 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1584 domain, *lp_winbind_separator(),
1590 * talloc version of fill_domain_username()
1591 * return NULL on talloc failure.
1593 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1598 char *tmp_user, *name;
1600 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1604 tmp_user = talloc_strdup(mem_ctx, user);
1605 if (!strlower_m(tmp_user)) {
1606 TALLOC_FREE(tmp_user);
1610 if (can_assume && assume_domain(domain)) {
1613 name = talloc_asprintf(mem_ctx, "%s%c%s",
1615 *lp_winbind_separator(),
1617 TALLOC_FREE(tmp_user);
1624 * Client list accessor functions
1627 static struct winbindd_cli_state *_client_list;
1628 static int _num_clients;
1630 /* Return list of all connected clients */
1632 struct winbindd_cli_state *winbindd_client_list(void)
1634 return _client_list;
1637 /* Return list-tail of all connected clients */
1639 struct winbindd_cli_state *winbindd_client_list_tail(void)
1641 return DLIST_TAIL(_client_list);
1644 /* Return previous (read:newer) client in list */
1646 struct winbindd_cli_state *
1647 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1649 return DLIST_PREV(cli);
1652 /* Add a connection to the list */
1654 void winbindd_add_client(struct winbindd_cli_state *cli)
1656 cli->last_access = time(NULL);
1657 DLIST_ADD(_client_list, cli);
1661 /* Remove a client from the list */
1663 void winbindd_remove_client(struct winbindd_cli_state *cli)
1665 DLIST_REMOVE(_client_list, cli);
1669 /* Move a client to head or list */
1671 void winbindd_promote_client(struct winbindd_cli_state *cli)
1673 cli->last_access = time(NULL);
1674 DLIST_PROMOTE(_client_list, cli);
1677 /* Return number of open clients */
1679 int winbindd_num_clients(void)
1681 return _num_clients;
1684 NTSTATUS lookup_usergroups_cached(TALLOC_CTX *mem_ctx,
1685 const struct dom_sid *user_sid,
1686 uint32_t *p_num_groups, struct dom_sid **user_sids)
1688 struct netr_SamInfo3 *info3 = NULL;
1689 NTSTATUS status = NT_STATUS_NO_MEMORY;
1690 uint32_t num_groups = 0;
1692 DEBUG(3,(": lookup_usergroups_cached\n"));
1697 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1699 if (info3 == NULL) {
1700 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1704 * Before bug #7843 the "Domain Local" groups were added with a
1705 * lookupuseraliases call, but this isn't done anymore for our domain
1706 * so we need to resolve resource groups here.
1708 * When to use Resource Groups:
1709 * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1711 status = sid_array_from_info3(mem_ctx, info3,
1716 if (!NT_STATUS_IS_OK(status)) {
1722 *p_num_groups = num_groups;
1723 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1725 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1730 /*********************************************************************
1731 We use this to remove spaces from user and group names
1732 ********************************************************************/
1734 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1735 const char *domain_name,
1739 struct winbindd_domain *domain = NULL;
1742 if (!name || !normalized) {
1743 return NT_STATUS_INVALID_PARAMETER;
1746 if (!lp_winbind_normalize_names()) {
1747 return NT_STATUS_PROCEDURE_NOT_FOUND;
1750 domain = find_domain_from_name_noinit(domain_name);
1751 if (domain == NULL) {
1752 DBG_ERR("Failed to find domain '%s'\n", domain_name);
1753 return NT_STATUS_NO_SUCH_DOMAIN;
1756 /* Alias support and whitespace replacement are mutually
1759 nt_status = resolve_username_to_alias(mem_ctx, domain,
1761 if (NT_STATUS_IS_OK(nt_status)) {
1762 /* special return code to let the caller know we
1763 mapped to an alias */
1764 return NT_STATUS_FILE_RENAMED;
1767 /* check for an unreachable domain */
1769 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1770 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1772 set_domain_offline(domain);
1776 /* deal with whitespace */
1778 *normalized = talloc_strdup(mem_ctx, name);
1779 if (!(*normalized)) {
1780 return NT_STATUS_NO_MEMORY;
1783 all_string_sub( *normalized, " ", "_", 0 );
1785 return NT_STATUS_OK;
1788 /*********************************************************************
1789 We use this to do the inverse of normalize_name_map()
1790 ********************************************************************/
1792 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1797 struct winbindd_domain *domain = find_our_domain();
1799 if (!name || !normalized) {
1800 return NT_STATUS_INVALID_PARAMETER;
1803 if (!lp_winbind_normalize_names()) {
1804 return NT_STATUS_PROCEDURE_NOT_FOUND;
1807 /* Alias support and whitespace replacement are mutally
1810 /* When mapping from an alias to a username, we don't know the
1811 domain. But we only need a domain structure to cache
1812 a successful lookup , so just our own domain structure for
1815 nt_status = resolve_alias_to_username(mem_ctx, domain,
1817 if (NT_STATUS_IS_OK(nt_status)) {
1818 /* Special return code to let the caller know we mapped
1820 return NT_STATUS_FILE_RENAMED;
1823 /* check for an unreachable domain */
1825 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1826 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1828 set_domain_offline(domain);
1832 /* deal with whitespace */
1834 *normalized = talloc_strdup(mem_ctx, name);
1835 if (!(*normalized)) {
1836 return NT_STATUS_NO_MEMORY;
1839 all_string_sub(*normalized, "_", " ", 0);
1841 return NT_STATUS_OK;
1844 /*********************************************************************
1845 ********************************************************************/
1847 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1849 struct winbindd_tdc_domain *tdc = NULL;
1850 TALLOC_CTX *frame = talloc_stackframe();
1853 /* We can contact the domain if it is our primary domain */
1855 if (domain->primary) {
1860 /* Trust the TDC cache and not the winbindd_domain flags */
1862 if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1863 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1869 /* Can always contact a domain that is in out forest */
1871 if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1877 * On a _member_ server, we cannot contact the domain if it
1878 * is running AD and we have no inbound trust.
1882 domain->active_directory &&
1883 ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1885 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1886 "and we have no inbound trust.\n", domain->name));
1890 /* Assume everything else is ok (probably not true but what
1896 talloc_destroy(frame);
1901 /*********************************************************************
1902 ********************************************************************/
1904 bool winbindd_internal_child(struct winbindd_child *child)
1906 if ((child == idmap_child()) || (child == locator_child())) {
1913 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1915 /*********************************************************************
1916 ********************************************************************/
1918 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1921 char addr[INET6_ADDRSTRLEN];
1922 const char *kdc = NULL;
1925 if (!domain || !domain->alt_name || !*domain->alt_name) {
1929 if (domain->initialized && !domain->active_directory) {
1930 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1935 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1938 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1940 kdc = domain->dcname;
1943 if (!kdc || !*kdc) {
1944 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1949 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1950 domain->alt_name) == -1) {
1954 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1957 setenv(var, kdc, 1);
1961 /*********************************************************************
1962 ********************************************************************/
1964 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1966 struct winbindd_domain *our_dom = find_our_domain();
1968 winbindd_set_locator_kdc_env(domain);
1970 if (domain != our_dom) {
1971 winbindd_set_locator_kdc_env(our_dom);
1975 /*********************************************************************
1976 ********************************************************************/
1978 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1982 if (!domain || !domain->alt_name || !*domain->alt_name) {
1986 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1987 domain->alt_name) == -1) {
1996 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
2001 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
2006 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
2008 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
2010 resp->data.auth.nt_status = NT_STATUS_V(result);
2011 fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
2013 /* we might have given a more useful error above */
2014 if (*resp->data.auth.error_string == '\0')
2015 fstrcpy(resp->data.auth.error_string,
2016 get_friendly_nt_error_msg(result));
2017 resp->data.auth.pam_error = nt_status_to_pam(result);
2020 bool is_domain_offline(const struct winbindd_domain *domain)
2022 if (get_global_winbindd_state_offline()) {
2025 return !domain->online;
2028 bool is_domain_online(const struct winbindd_domain *domain)
2030 return !is_domain_offline(domain);
2034 * Parse an char array into a list of sids.
2036 * The input sidstr should consist of 0-terminated strings
2037 * representing sids, separated by newline characters '\n'.
2038 * The list is terminated by an empty string, i.e.
2039 * character '\0' directly following a character '\n'
2040 * (or '\0' right at the start of sidstr).
2042 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
2043 struct dom_sid **sids, uint32_t *num_sids)
2051 while (p[0] != '\0') {
2053 const char *q = NULL;
2055 if (!dom_sid_parse_endp(p, &sid, &q)) {
2056 DEBUG(1, ("Could not parse sid %s\n", p));
2060 DEBUG(1, ("Got invalid sidstr: %s\n", p));
2063 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
2073 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
2074 struct unixid **pxids, uint32_t *pnum_xids)
2077 struct unixid *xids = NULL;
2078 uint32_t num_xids = 0;
2085 while (p[0] != '\0') {
2088 unsigned long long id;
2093 xid = (struct unixid) { .type = ID_TYPE_UID };
2096 xid = (struct unixid) { .type = ID_TYPE_GID };
2104 id = strtoull(p, &endp, 10);
2105 if ((id == ULLONG_MAX) && (errno == ERANGE)) {
2108 if (*endp != '\n') {
2114 if ((unsigned long long)xid.id != id) {
2118 tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
2124 xids[num_xids] = xid;
2129 *pnum_xids = num_xids;