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 "auth/credentials/credentials.h"
34 #include "libsmb/samlogon_cache.h"
37 #define DBGC_CLASS DBGC_WINBIND
39 static struct winbindd_domain *
40 add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc);
43 * @file winbindd_util.c
45 * Winbind daemon for NT domain authentication nss module.
49 /* The list of trusted domains. Note that the list can be deleted and
50 recreated using the init_domain_list() function so pointers to
51 individual winbindd_domain structures cannot be made. Keep a copy of
52 the domain name instead. */
54 static struct winbindd_domain *_domain_list = NULL;
56 struct winbindd_domain *domain_list(void)
60 if ((!_domain_list) && (!init_domain_list())) {
61 smb_panic("Init_domain_list failed");
67 /* Free all entries in the trusted domain list */
69 static void free_domain_list(void)
71 struct winbindd_domain *domain = _domain_list;
74 struct winbindd_domain *next = domain->next;
76 DLIST_REMOVE(_domain_list, domain);
83 * Iterator for winbindd's domain list.
84 * To be used (e.g.) in tevent based loops.
86 struct winbindd_domain *wb_next_domain(struct winbindd_domain *domain)
89 domain = domain_list();
91 domain = domain->next;
94 if ((domain != NULL) &&
95 (lp_server_role() != ROLE_ACTIVE_DIRECTORY_DC) &&
96 sid_check_is_our_sam(&domain->sid))
98 domain = domain->next;
104 static bool is_internal_domain(const struct dom_sid *sid)
109 return (sid_check_is_our_sam(sid) || sid_check_is_builtin(sid));
112 static bool is_in_internal_domain(const struct dom_sid *sid)
117 return (sid_check_is_in_our_sam(sid) || sid_check_is_in_builtin(sid));
121 /* Add a trusted domain to our list of domains.
122 If the domain already exists in the list,
123 return it and don't re-initialize. */
125 static struct winbindd_domain *
126 add_trusted_domain(const char *domain_name, const char *alt_name,
127 const struct dom_sid *sid)
129 struct winbindd_tdc_domain tdc;
133 tdc.domain_name = domain_name;
134 tdc.dns_name = alt_name;
136 sid_copy(&tdc.sid, sid);
139 return add_trusted_domain_from_tdc(&tdc);
142 /* Add a trusted domain out of a trusted domain cache
145 static struct winbindd_domain *
146 add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
148 struct winbindd_domain *domain = NULL;
149 const char *dns_name = NULL;
150 const char **ignored_domains = NULL;
151 const char **dom = NULL;
152 int role = lp_server_role();
153 const char *domain_name = tdc->domain_name;
154 const struct dom_sid *sid = &tdc->sid;
156 if (is_null_sid(sid)) {
157 DBG_ERR("Got null SID for domain [%s]\n", domain_name);
161 ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
162 for (dom=ignored_domains; dom && *dom; dom++) {
163 if (gen_fnmatch(*dom, domain_name) == 0) {
164 DEBUG(2,("Ignoring domain '%s'\n", domain_name));
169 /* use alt_name if available to allow DNS lookups */
171 if (tdc->dns_name && *tdc->dns_name) {
172 dns_name = tdc->dns_name;
175 /* We can't call domain_list() as this function is called from
176 init_domain_list() and we'll get stuck in a loop. */
177 for (domain = _domain_list; domain; domain = domain->next) {
178 if (strequal(domain_name, domain->name)) {
183 if (domain != NULL) {
184 struct winbindd_domain *check_domain = NULL;
186 for (check_domain = _domain_list;
187 check_domain != NULL;
188 check_domain = check_domain->next)
190 if (check_domain == domain) {
194 if (dom_sid_equal(&check_domain->sid, sid)) {
199 if (check_domain != NULL) {
200 DBG_ERR("SID [%s] already used by domain [%s], "
202 sid_string_dbg(sid), check_domain->name,
208 if ((domain != NULL) && (dns_name != NULL)) {
209 struct winbindd_domain *check_domain = NULL;
211 for (check_domain = _domain_list;
212 check_domain != NULL;
213 check_domain = check_domain->next)
215 if (check_domain == domain) {
219 if (strequal(check_domain->alt_name, dns_name)) {
224 if (check_domain != NULL) {
225 DBG_ERR("DNS name [%s] used by domain [%s], "
227 dns_name, check_domain->name,
233 if (domain != NULL) {
237 /* Create new domain entry */
238 domain = talloc_zero(NULL, struct winbindd_domain);
239 if (domain == NULL) {
243 domain->children = talloc_zero_array(domain,
244 struct winbindd_child,
245 lp_winbind_max_domain_connections());
246 if (domain->children == NULL) {
251 domain->name = talloc_strdup(domain, domain_name);
252 if (domain->name == NULL) {
257 if (dns_name != NULL) {
258 domain->alt_name = talloc_strdup(domain, dns_name);
259 if (domain->alt_name == NULL) {
265 domain->backend = NULL;
266 domain->internal = is_internal_domain(sid);
267 domain->sequence_number = DOM_SEQUENCE_NONE;
268 domain->last_seq_check = 0;
269 domain->initialized = false;
270 domain->online = is_internal_domain(sid);
271 domain->check_online_timeout = 0;
272 domain->dc_probe_pid = (pid_t)-1;
273 domain->domain_flags = tdc->trust_flags;
274 domain->domain_type = tdc->trust_type;
275 domain->domain_trust_attribs = tdc->trust_attribs;
276 sid_copy(&domain->sid, sid);
278 /* Is this our primary domain ? */
279 if (role == ROLE_DOMAIN_MEMBER) {
280 domain->primary = strequal(domain_name, lp_workgroup());
282 domain->primary = strequal(domain_name, get_global_sam_name());
285 if (domain->primary) {
286 if (role == ROLE_ACTIVE_DIRECTORY_DC) {
287 domain->active_directory = true;
289 if (lp_security() == SEC_ADS) {
290 domain->active_directory = true;
292 } else if (!domain->internal) {
293 if (domain->domain_type == LSA_TRUST_TYPE_UPLEVEL) {
294 domain->active_directory = true;
298 /* Link to domain list */
299 DLIST_ADD_END(_domain_list, domain);
301 wcache_tdc_add_domain( domain );
303 setup_domain_child(domain);
306 ("Added domain %s %s %s\n", domain->name, domain->alt_name,
307 !is_null_sid(&domain->sid) ? sid_string_dbg(&domain->sid) : ""));
312 bool domain_is_forest_root(const struct winbindd_domain *domain)
314 const uint32_t fr_flags =
315 (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
317 return ((domain->domain_flags & fr_flags) == fr_flags);
320 /********************************************************************
321 rescan our domains looking for new trusted domains
322 ********************************************************************/
324 struct trustdom_state {
325 struct winbindd_domain *domain;
326 struct winbindd_request request;
329 static void trustdom_list_done(struct tevent_req *req);
330 static void rescan_forest_root_trusts( void );
331 static void rescan_forest_trusts( void );
333 static void add_trusted_domains( struct winbindd_domain *domain )
335 struct trustdom_state *state;
336 struct tevent_req *req;
338 state = talloc_zero(NULL, struct trustdom_state);
340 DEBUG(0, ("talloc failed\n"));
343 state->domain = domain;
345 state->request.length = sizeof(state->request);
346 state->request.cmd = WINBINDD_LIST_TRUSTDOM;
348 req = wb_domain_request_send(state, server_event_context(),
349 domain, &state->request);
351 DEBUG(1, ("wb_domain_request_send failed\n"));
355 tevent_req_set_callback(req, trustdom_list_done, state);
358 static void trustdom_list_done(struct tevent_req *req)
360 struct trustdom_state *state = tevent_req_callback_data(
361 req, struct trustdom_state);
362 struct winbindd_response *response;
365 struct winbindd_tdc_domain trust_params = {0};
367 bool within_forest = false;
370 * Only when we enumerate our primary domain
371 * or our forest root domain, we should keep
372 * the NETR_TRUST_FLAG_IN_FOREST flag, in
373 * all other cases we need to clear it as the domain
374 * is not part of our forest.
376 if (state->domain->primary) {
377 within_forest = true;
378 } else if (domain_is_forest_root(state->domain)) {
379 within_forest = true;
382 res = wb_domain_request_recv(req, state, &response, &err);
383 if ((res == -1) || (response->result != WINBINDD_OK)) {
384 DBG_WARNING("Could not receive trusts for domain %s\n",
385 state->domain->name);
390 if (response->length < sizeof(struct winbindd_response)) {
391 DBG_ERR("ill-formed trustdom response - short length\n");
396 extra_len = response->length - sizeof(struct winbindd_response);
398 p = (char *)response->extra_data.data;
400 while ((p - (char *)response->extra_data.data) < extra_len) {
401 char *q, *sidstr, *alt_name;
403 DBG_DEBUG("parsing response line '%s'\n", p);
405 ZERO_STRUCT(trust_params);
406 trust_params.domain_name = p;
408 alt_name = strchr(p, '\\');
409 if (alt_name == NULL) {
410 DBG_ERR("Got invalid trustdom response\n");
417 sidstr = strchr(alt_name, '\\');
418 if (sidstr == NULL) {
419 DBG_ERR("Got invalid trustdom response\n");
426 /* use the real alt_name if we have one, else pass in NULL */
427 if (!strequal(alt_name, "(null)")) {
428 trust_params.dns_name = alt_name;
431 q = strtok(sidstr, "\\");
433 DBG_ERR("Got invalid trustdom response\n");
437 if (!string_to_sid(&trust_params.sid, sidstr)) {
438 DEBUG(0, ("Got invalid trustdom response\n"));
442 q = strtok(NULL, "\\");
444 DBG_ERR("Got invalid trustdom response\n");
448 trust_params.trust_flags = (uint32_t)strtoul(q, NULL, 10);
450 q = strtok(NULL, "\\");
452 DBG_ERR("Got invalid trustdom response\n");
456 trust_params.trust_type = (uint32_t)strtoul(q, NULL, 10);
458 q = strtok(NULL, "\n");
460 DBG_ERR("Got invalid trustdom response\n");
464 trust_params.trust_attribs = (uint32_t)strtoul(q, NULL, 10);
466 if (!within_forest) {
467 trust_params.trust_flags &= ~NETR_TRUST_FLAG_IN_FOREST;
470 if (!state->domain->primary) {
471 trust_params.trust_flags &= ~NETR_TRUST_FLAG_PRIMARY;
475 * We always call add_trusted_domain() cause on an existing
476 * domain structure, it will update the SID if necessary.
477 * This is important because we need the SID for sibling
480 (void)add_trusted_domain_from_tdc(&trust_params);
482 p = q + strlen(q) + 1;
486 Cases to consider when scanning trusts:
487 (a) we are calling from a child domain (primary && !forest_root)
488 (b) we are calling from the root of the forest (primary && forest_root)
489 (c) we are calling from a trusted forest domain (!primary
493 if (state->domain->primary) {
494 /* If this is our primary domain and we are not in the
495 forest root, we have to scan the root trusts first */
497 if (!domain_is_forest_root(state->domain))
498 rescan_forest_root_trusts();
500 rescan_forest_trusts();
502 } else if (domain_is_forest_root(state->domain)) {
503 /* Once we have done root forest trust search, we can
504 go on to search the trusted forests */
506 rescan_forest_trusts();
514 /********************************************************************
515 Scan the trusts of our forest root
516 ********************************************************************/
518 static void rescan_forest_root_trusts( void )
520 struct winbindd_tdc_domain *dom_list = NULL;
521 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 );
549 d = add_trusted_domain_from_tdc(&dom_list[i]);
556 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
557 "for domain tree root %s (%s)\n",
558 d->name, d->alt_name ));
560 d->domain_flags = dom_list[i].trust_flags;
561 d->domain_type = dom_list[i].trust_type;
562 d->domain_trust_attribs = dom_list[i].trust_attribs;
564 add_trusted_domains( d );
569 TALLOC_FREE( dom_list );
574 /********************************************************************
575 scan the transitive forest trusts (not our own)
576 ********************************************************************/
579 static void rescan_forest_trusts( void )
581 struct winbindd_domain *d = NULL;
582 struct winbindd_tdc_domain *dom_list = NULL;
583 size_t num_trusts = 0;
586 /* The only transitive trusts supported by Windows 2003 AD are
587 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
588 first two are handled in forest and listed by
589 DsEnumerateDomainTrusts(). Forest trusts are not so we
590 have to do that ourselves. */
592 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
595 for ( i=0; i<num_trusts; i++ ) {
596 uint32_t flags = dom_list[i].trust_flags;
597 uint32_t type = dom_list[i].trust_type;
598 uint32_t attribs = dom_list[i].trust_attribs;
600 d = find_domain_from_name_noinit( dom_list[i].domain_name );
602 /* ignore our primary and internal domains */
604 if ( d && (d->internal || d->primary ) )
607 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
608 (type == LSA_TRUST_TYPE_UPLEVEL) &&
609 (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
611 /* add the trusted domain if we don't know
615 d = add_trusted_domain_from_tdc(&dom_list[i]);
622 DEBUG(10,("Following trust path for domain %s (%s)\n",
623 d->name, d->alt_name ));
624 add_trusted_domains( d );
628 TALLOC_FREE( dom_list );
633 /*********************************************************************
634 The process of updating the trusted domain list is a three step
637 (b) ask the root domain in our forest
638 (c) ask the a DC in any Win2003 trusted forests
639 *********************************************************************/
641 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
642 struct timeval now, void *private_data)
646 /* I use to clear the cache here and start over but that
647 caused problems in child processes that needed the
648 trust dom list early on. Removing it means we
649 could have some trusted domains listed that have been
650 removed from our primary domain's DC until a full
651 restart. This should be ok since I think this is what
652 Windows does as well. */
654 /* this will only add new domains we didn't already know about
655 in the domain_list()*/
657 add_trusted_domains( find_our_domain() );
659 te = tevent_add_timer(
660 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
661 rescan_trusted_domains, NULL);
663 * If te == NULL, there's not much we can do here. Don't fail, the
664 * only thing we miss is new trusted domains.
670 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
671 struct winbindd_cli_state *state)
673 /* Ensure null termination */
674 state->request->domain_name
675 [sizeof(state->request->domain_name)-1]='\0';
676 state->request->data.init_conn.dcname
677 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
679 if (strlen(state->request->data.init_conn.dcname) > 0) {
680 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
683 init_dc_connection(domain, false);
685 if (!domain->initialized) {
686 /* If we return error here we can't do any cached authentication,
687 but we may be in disconnected mode and can't initialize correctly.
688 Do what the previous code did and just return without initialization,
689 once we go online we'll re-initialize.
691 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
692 "online = %d\n", domain->name, (int)domain->online ));
695 fstrcpy(state->response->data.domain_info.name, domain->name);
696 fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
697 sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
699 state->response->data.domain_info.native_mode
700 = domain->native_mode;
701 state->response->data.domain_info.active_directory
702 = domain->active_directory;
703 state->response->data.domain_info.primary
709 static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
712 struct server_id server_id,
715 TALLOC_CTX *frame = talloc_stackframe();
716 struct lsa_TrustDomainInfoInfoEx info;
717 enum ndr_err_code ndr_err;
718 struct winbindd_domain *d = NULL;
720 DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
727 ndr_err = ndr_pull_struct_blob_all(data, frame, &info,
728 (ndr_pull_flags_fn_t)ndr_pull_lsa_TrustDomainInfoInfoEx);
729 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
734 d = find_domain_from_name_noinit(info.netbios_name.string);
740 d = add_trusted_domain(info.netbios_name.string,
741 info.domain_name.string,
758 if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
759 d->domain_flags |= NETR_TRUST_FLAG_INBOUND;
761 if (info.trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
762 d->domain_flags |= NETR_TRUST_FLAG_OUTBOUND;
764 if (info.trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
765 d->domain_flags |= NETR_TRUST_FLAG_IN_FOREST;
767 d->domain_type = info.trust_type;
768 d->domain_trust_attribs = info.trust_attributes;
774 * We did not get the secret when we queried secrets.tdb, so read it
775 * from secrets.tdb and re-sync the databases
777 static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
780 struct cli_credentials *creds;
781 NTSTATUS can_migrate = pdb_get_trust_credentials(domain->name,
782 NULL, domain, &creds);
783 if (!NT_STATUS_IS_OK(can_migrate)) {
784 DEBUG(0, ("Failed to fetch our own, local AD domain join "
785 "password for winbindd's internal use, both from "
786 "secrets.tdb and secrets.ldb: %s\n",
787 nt_errstr(can_migrate)));
792 * NOTE: It is very unlikely we end up here if there is an
793 * oldpass, because a new password is created at
794 * classicupgrade, so this is not a concern.
796 ok = secrets_store_machine_pw_sync(cli_credentials_get_password(creds),
798 cli_credentials_get_domain(creds),
799 cli_credentials_get_realm(creds),
800 cli_credentials_get_salt_principal(creds),
801 0, /* Supported enc types, unused */
803 cli_credentials_get_password_last_changed_time(creds),
804 cli_credentials_get_secure_channel_type(creds),
805 false /* do_delete: Do not delete */);
808 DEBUG(0, ("Failed to write our our own, "
809 "local AD domain join password for "
810 "winbindd's internal use into secrets.tdb\n"));
816 /* Look up global info for the winbind daemon */
817 bool init_domain_list(void)
819 int role = lp_server_role();
820 struct pdb_domain_info *pdb_domain_info = NULL;
823 /* Free existing list */
828 (void)add_trusted_domain("BUILTIN", NULL, &global_sid_Builtin);
833 * In case the passdb backend is passdb_dsdb the domain SID comes from
834 * dsdb, not from secrets.tdb. As we use the domain SID in various
835 * places, we must ensure the domain SID is migrated from dsdb to
836 * secrets.tdb before get_global_sam_sid() is called the first time.
838 * The migration is done as part of the passdb_dsdb initialisation,
839 * calling pdb_get_domain_info() triggers it.
841 pdb_domain_info = pdb_get_domain_info(talloc_tos());
843 if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
844 struct winbindd_domain *domain;
845 enum netr_SchannelType sec_chan_type;
846 const char *account_name;
847 struct samr_Password current_nt_hash;
850 if (pdb_domain_info == NULL) {
851 DEBUG(0, ("Failed to fetch our own, local AD "
852 "domain info from sam.ldb\n"));
855 domain = add_trusted_domain(pdb_domain_info->name,
856 pdb_domain_info->dns_domain,
857 &pdb_domain_info->sid);
858 TALLOC_FREE(pdb_domain_info);
859 if (domain == NULL) {
860 DEBUG(0, ("Failed to add our own, local AD "
861 "domain to winbindd's internal list\n"));
866 * We need to call this to find out if we are an RODC
868 ok = get_trust_pw_hash(domain->name,
869 current_nt_hash.hash,
874 * If get_trust_pw_hash() fails, then try and
875 * fetch the password from the more recent of
876 * secrets.{ldb,tdb} using the
877 * pdb_get_trust_credentials()
879 ok = migrate_secrets_tdb_to_ldb(domain);
882 DEBUG(0, ("Failed to migrate our own, "
883 "local AD domain join password for "
884 "winbindd's internal use into "
888 ok = get_trust_pw_hash(domain->name,
889 current_nt_hash.hash,
893 DEBUG(0, ("Failed to find our our own, just "
894 "written local AD domain join "
895 "password for winbindd's internal "
896 "use in secrets.tdb\n"));
900 if (sec_chan_type == SEC_CHAN_RODC) {
905 (void)add_trusted_domain(get_global_sam_name(), NULL,
906 get_global_sam_sid());
908 /* Add ourselves as the first entry. */
910 if ( role == ROLE_DOMAIN_MEMBER ) {
911 struct winbindd_domain *domain;
912 struct dom_sid our_sid;
914 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
915 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
919 domain = add_trusted_domain(lp_workgroup(), lp_realm(),
922 /* Even in the parent winbindd we'll need to
923 talk to the DC, so try and see if we can
924 contact it. Theoretically this isn't neccessary
925 as the init_dc_connection() in init_child_recv()
926 will do this, but we can start detecting the DC
928 set_domain_online_request(domain);
932 status = imessaging_register(winbind_imessaging_context(), NULL,
933 MSG_WINBIND_NEW_TRUSTED_DOMAIN,
934 wb_imsg_new_trusted_domain);
935 if (!NT_STATUS_IS_OK(status)) {
936 DEBUG(0, ("imessaging_register(MSG_WINBIND_NEW_TRUSTED_DOMAIN) - %s\n",
945 * Given a domain name, return the struct winbindd domain info for it
947 * @note Do *not* pass lp_workgroup() to this function. domain_list
948 * may modify it's value, and free that pointer. Instead, our local
949 * domain may be found by calling find_our_domain().
953 * @return The domain structure for the named domain, if it is working.
956 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
958 struct winbindd_domain *domain;
960 /* Search through list */
962 for (domain = domain_list(); domain != NULL; domain = domain->next) {
963 if (strequal(domain_name, domain->name)) {
966 if (domain->alt_name == NULL) {
969 if (strequal(domain_name, domain->alt_name)) {
979 struct winbindd_domain *find_domain_from_name(const char *domain_name)
981 struct winbindd_domain *domain;
983 domain = find_domain_from_name_noinit(domain_name);
988 if (!domain->initialized)
989 init_dc_connection(domain, false);
994 /* Given a domain sid, return the struct winbindd domain info for it */
996 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
998 struct winbindd_domain *domain;
1000 /* Search through list */
1002 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1003 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
1012 /* Given a domain sid, return the struct winbindd domain info for it */
1014 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
1016 struct winbindd_domain *domain;
1018 domain = find_domain_from_sid_noinit(sid);
1023 if (!domain->initialized)
1024 init_dc_connection(domain, false);
1029 struct winbindd_domain *find_our_domain(void)
1031 struct winbindd_domain *domain;
1033 /* Search through list */
1035 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1036 if (domain->primary)
1040 smb_panic("Could not find our domain");
1044 /* Find the appropriate domain to lookup a name or SID */
1046 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
1048 DBG_DEBUG("SID [%s]\n", sid_string_dbg(sid));
1051 * SIDs in the S-1-22-{1,2} domain and well-known SIDs should be handled
1055 if ( sid_check_is_in_unix_groups(sid) ||
1056 sid_check_is_unix_groups(sid) ||
1057 sid_check_is_in_unix_users(sid) ||
1058 sid_check_is_unix_users(sid) ||
1059 sid_check_is_wellknown_domain(sid, NULL) ||
1060 sid_check_is_in_wellknown_domain(sid) )
1062 return find_domain_from_sid(get_global_sam_sid());
1065 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
1066 * one to contact the external DC's. On member servers the internal
1067 * domains are different: These are part of the local SAM. */
1069 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
1070 DEBUG(10, ("calling find_domain_from_sid\n"));
1071 return find_domain_from_sid(sid);
1074 /* On a member server a query for SID or name can always go to our
1077 DEBUG(10, ("calling find_our_domain\n"));
1078 return find_our_domain();
1081 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1083 if ( strequal(domain_name, unix_users_domain_name() ) ||
1084 strequal(domain_name, unix_groups_domain_name() ) )
1087 * The "Unix User" and "Unix Group" domain our handled by
1090 return find_domain_from_name_noinit( get_global_sam_name() );
1093 if (IS_DC || strequal(domain_name, "BUILTIN") ||
1094 strequal(domain_name, get_global_sam_name()))
1095 return find_domain_from_name_noinit(domain_name);
1098 return find_our_domain();
1101 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1103 static bool assume_domain(const char *domain)
1105 /* never assume the domain on a standalone server */
1107 if ( lp_server_role() == ROLE_STANDALONE )
1110 /* domain member servers may possibly assume for the domain name */
1112 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1113 if ( !strequal(lp_workgroup(), domain) )
1116 if ( lp_winbind_use_default_domain() )
1120 /* only left with a domain controller */
1122 if ( strequal(get_global_sam_name(), domain) ) {
1129 /* Parse a string of the form DOMAIN\user into a domain and a user */
1131 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1133 char *p = strchr(domuser,*lp_winbind_separator());
1136 fstrcpy(user, domuser);
1137 p = strchr(domuser, '@');
1139 if ( assume_domain(lp_workgroup()) && p == NULL) {
1140 fstrcpy(domain, lp_workgroup());
1141 } else if (p != NULL) {
1142 fstrcpy(domain, p + 1);
1143 user[PTR_DIFF(p, domuser)] = 0;
1149 fstrcpy(domain, domuser);
1150 domain[PTR_DIFF(p, domuser)] = 0;
1153 return strupper_m(domain);
1156 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1157 char **domain, char **user)
1159 fstring fstr_domain, fstr_user;
1160 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1163 *domain = talloc_strdup(mem_ctx, fstr_domain);
1164 *user = talloc_strdup(mem_ctx, fstr_user);
1165 return ((*domain != NULL) && (*user != NULL));
1168 /* Ensure an incoming username from NSS is fully qualified. Replace the
1169 incoming fstring with DOMAIN <separator> user. Returns the same
1170 values as parse_domain_user() but also replaces the incoming username.
1171 Used to ensure all names are fully qualified within winbindd.
1172 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1173 The protocol definitions of auth_crap, chng_pswd_auth_crap
1174 really should be changed to use this instead of doing things
1177 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1179 if (!parse_domain_user(username_inout, domain, user)) {
1182 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1183 domain, *lp_winbind_separator(),
1189 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1190 'winbind separator' options.
1192 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1195 If we are a PDC or BDC, and this is for our domain, do likewise.
1197 On an AD DC we always fill DOMAIN\\USERNAME.
1199 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1201 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1205 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1209 fstrcpy(tmp_user, user);
1210 (void)strlower_m(tmp_user);
1212 if (can_assume && assume_domain(domain)) {
1213 strlcpy(name, tmp_user, sizeof(fstring));
1215 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1216 domain, *lp_winbind_separator(),
1222 * talloc version of fill_domain_username()
1223 * return NULL on talloc failure.
1225 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1230 char *tmp_user, *name;
1232 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1236 tmp_user = talloc_strdup(mem_ctx, user);
1237 if (!strlower_m(tmp_user)) {
1238 TALLOC_FREE(tmp_user);
1242 if (can_assume && assume_domain(domain)) {
1245 name = talloc_asprintf(mem_ctx, "%s%c%s",
1247 *lp_winbind_separator(),
1249 TALLOC_FREE(tmp_user);
1256 * Client list accessor functions
1259 static struct winbindd_cli_state *_client_list;
1260 static int _num_clients;
1262 /* Return list of all connected clients */
1264 struct winbindd_cli_state *winbindd_client_list(void)
1266 return _client_list;
1269 /* Return list-tail of all connected clients */
1271 struct winbindd_cli_state *winbindd_client_list_tail(void)
1273 return DLIST_TAIL(_client_list);
1276 /* Return previous (read:newer) client in list */
1278 struct winbindd_cli_state *
1279 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1281 return DLIST_PREV(cli);
1284 /* Add a connection to the list */
1286 void winbindd_add_client(struct winbindd_cli_state *cli)
1288 cli->last_access = time(NULL);
1289 DLIST_ADD(_client_list, cli);
1293 /* Remove a client from the list */
1295 void winbindd_remove_client(struct winbindd_cli_state *cli)
1297 DLIST_REMOVE(_client_list, cli);
1301 /* Move a client to head or list */
1303 void winbindd_promote_client(struct winbindd_cli_state *cli)
1305 cli->last_access = time(NULL);
1306 DLIST_PROMOTE(_client_list, cli);
1309 /* Return number of open clients */
1311 int winbindd_num_clients(void)
1313 return _num_clients;
1316 NTSTATUS lookup_usergroups_cached(TALLOC_CTX *mem_ctx,
1317 const struct dom_sid *user_sid,
1318 uint32_t *p_num_groups, struct dom_sid **user_sids)
1320 struct netr_SamInfo3 *info3 = NULL;
1321 NTSTATUS status = NT_STATUS_NO_MEMORY;
1322 uint32_t num_groups = 0;
1324 DEBUG(3,(": lookup_usergroups_cached\n"));
1329 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1331 if (info3 == NULL) {
1332 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1336 * Before bug #7843 the "Domain Local" groups were added with a
1337 * lookupuseraliases call, but this isn't done anymore for our domain
1338 * so we need to resolve resource groups here.
1340 * When to use Resource Groups:
1341 * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1343 status = sid_array_from_info3(mem_ctx, info3,
1348 if (!NT_STATUS_IS_OK(status)) {
1354 *p_num_groups = num_groups;
1355 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1357 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1362 /*********************************************************************
1363 We use this to remove spaces from user and group names
1364 ********************************************************************/
1366 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1367 const char *domain_name,
1371 struct winbindd_domain *domain = NULL;
1374 if (!name || !normalized) {
1375 return NT_STATUS_INVALID_PARAMETER;
1378 if (!lp_winbind_normalize_names()) {
1379 return NT_STATUS_PROCEDURE_NOT_FOUND;
1382 domain = find_domain_from_name_noinit(domain_name);
1383 if (domain == NULL) {
1384 DBG_ERR("Failed to find domain '%s'\n", domain_name);
1385 return NT_STATUS_NO_SUCH_DOMAIN;
1388 /* Alias support and whitespace replacement are mutually
1391 nt_status = resolve_username_to_alias(mem_ctx, domain,
1393 if (NT_STATUS_IS_OK(nt_status)) {
1394 /* special return code to let the caller know we
1395 mapped to an alias */
1396 return NT_STATUS_FILE_RENAMED;
1399 /* check for an unreachable domain */
1401 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1402 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1404 set_domain_offline(domain);
1408 /* deal with whitespace */
1410 *normalized = talloc_strdup(mem_ctx, name);
1411 if (!(*normalized)) {
1412 return NT_STATUS_NO_MEMORY;
1415 all_string_sub( *normalized, " ", "_", 0 );
1417 return NT_STATUS_OK;
1420 /*********************************************************************
1421 We use this to do the inverse of normalize_name_map()
1422 ********************************************************************/
1424 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1429 struct winbindd_domain *domain = find_our_domain();
1431 if (!name || !normalized) {
1432 return NT_STATUS_INVALID_PARAMETER;
1435 if (!lp_winbind_normalize_names()) {
1436 return NT_STATUS_PROCEDURE_NOT_FOUND;
1439 /* Alias support and whitespace replacement are mutally
1442 /* When mapping from an alias to a username, we don't know the
1443 domain. But we only need a domain structure to cache
1444 a successful lookup , so just our own domain structure for
1447 nt_status = resolve_alias_to_username(mem_ctx, domain,
1449 if (NT_STATUS_IS_OK(nt_status)) {
1450 /* Special return code to let the caller know we mapped
1452 return NT_STATUS_FILE_RENAMED;
1455 /* check for an unreachable domain */
1457 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1458 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1460 set_domain_offline(domain);
1464 /* deal with whitespace */
1466 *normalized = talloc_strdup(mem_ctx, name);
1467 if (!(*normalized)) {
1468 return NT_STATUS_NO_MEMORY;
1471 all_string_sub(*normalized, "_", " ", 0);
1473 return NT_STATUS_OK;
1476 /*********************************************************************
1477 ********************************************************************/
1479 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1481 struct winbindd_tdc_domain *tdc = NULL;
1482 TALLOC_CTX *frame = talloc_stackframe();
1485 /* We can contact the domain if it is our primary domain */
1487 if (domain->primary) {
1492 /* Trust the TDC cache and not the winbindd_domain flags */
1494 if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1495 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1501 /* Can always contact a domain that is in out forest */
1503 if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1509 * On a _member_ server, we cannot contact the domain if it
1510 * is running AD and we have no inbound trust.
1514 domain->active_directory &&
1515 ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1517 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1518 "and we have no inbound trust.\n", domain->name));
1522 /* Assume everything else is ok (probably not true but what
1528 talloc_destroy(frame);
1533 /*********************************************************************
1534 ********************************************************************/
1536 bool winbindd_internal_child(struct winbindd_child *child)
1538 if ((child == idmap_child()) || (child == locator_child())) {
1545 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1547 /*********************************************************************
1548 ********************************************************************/
1550 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1553 char addr[INET6_ADDRSTRLEN];
1554 const char *kdc = NULL;
1557 if (!domain || !domain->alt_name || !*domain->alt_name) {
1561 if (domain->initialized && !domain->active_directory) {
1562 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1567 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1570 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1572 kdc = domain->dcname;
1575 if (!kdc || !*kdc) {
1576 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1581 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1582 domain->alt_name) == -1) {
1586 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1589 setenv(var, kdc, 1);
1593 /*********************************************************************
1594 ********************************************************************/
1596 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1598 struct winbindd_domain *our_dom = find_our_domain();
1600 winbindd_set_locator_kdc_env(domain);
1602 if (domain != our_dom) {
1603 winbindd_set_locator_kdc_env(our_dom);
1607 /*********************************************************************
1608 ********************************************************************/
1610 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1614 if (!domain || !domain->alt_name || !*domain->alt_name) {
1618 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1619 domain->alt_name) == -1) {
1628 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1633 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1638 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1640 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1642 resp->data.auth.nt_status = NT_STATUS_V(result);
1643 fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1645 /* we might have given a more useful error above */
1646 if (*resp->data.auth.error_string == '\0')
1647 fstrcpy(resp->data.auth.error_string,
1648 get_friendly_nt_error_msg(result));
1649 resp->data.auth.pam_error = nt_status_to_pam(result);
1652 bool is_domain_offline(const struct winbindd_domain *domain)
1654 if (get_global_winbindd_state_offline()) {
1657 return !domain->online;
1660 bool is_domain_online(const struct winbindd_domain *domain)
1662 return !is_domain_offline(domain);
1666 * Parse an char array into a list of sids.
1668 * The input sidstr should consist of 0-terminated strings
1669 * representing sids, separated by newline characters '\n'.
1670 * The list is terminated by an empty string, i.e.
1671 * character '\0' directly following a character '\n'
1672 * (or '\0' right at the start of sidstr).
1674 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
1675 struct dom_sid **sids, uint32_t *num_sids)
1683 while (p[0] != '\0') {
1685 const char *q = NULL;
1687 if (!dom_sid_parse_endp(p, &sid, &q)) {
1688 DEBUG(1, ("Could not parse sid %s\n", p));
1692 DEBUG(1, ("Got invalid sidstr: %s\n", p));
1695 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
1705 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
1706 struct unixid **pxids, uint32_t *pnum_xids)
1709 struct unixid *xids = NULL;
1710 uint32_t num_xids = 0;
1717 while (p[0] != '\0') {
1720 unsigned long long id;
1725 xid = (struct unixid) { .type = ID_TYPE_UID };
1728 xid = (struct unixid) { .type = ID_TYPE_GID };
1736 id = strtoull(p, &endp, 10);
1737 if ((id == ULLONG_MAX) && (errno == ERANGE)) {
1740 if (*endp != '\n') {
1746 if ((unsigned long long)xid.id != id) {
1750 tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
1756 xids[num_xids] = xid;
1761 *pnum_xids = num_xids;