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/>.
26 #include "../libcli/security/security.h"
27 #include "../libcli/auth/pam_errors.h"
28 #include "passdb/machine_sid.h"
30 #include "source4/lib/messaging/messaging.h"
31 #include "librpc/gen_ndr/ndr_lsa.h"
32 #include "auth/credentials/credentials.h"
35 #define DBGC_CLASS DBGC_WINBIND
37 static struct winbindd_domain *
38 add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc);
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 struct winbindd_domain *
124 add_trusted_domain(const char *domain_name, const char *alt_name,
125 const struct dom_sid *sid)
127 struct winbindd_tdc_domain tdc;
131 tdc.domain_name = domain_name;
132 tdc.dns_name = alt_name;
134 sid_copy(&tdc.sid, sid);
137 return add_trusted_domain_from_tdc(&tdc);
140 /* Add a trusted domain out of a trusted domain cache
143 static struct winbindd_domain *
144 add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
146 struct winbindd_domain *domain;
147 const char *alternative_name = NULL;
148 const char **ignored_domains, **dom;
149 int role = lp_server_role();
150 const char *domain_name = tdc->domain_name;
151 const struct dom_sid *sid = &tdc->sid;
153 if (is_null_sid(sid)) {
157 ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
158 for (dom=ignored_domains; dom && *dom; dom++) {
159 if (gen_fnmatch(*dom, domain_name) == 0) {
160 DEBUG(2,("Ignoring domain '%s'\n", domain_name));
165 /* use alt_name if available to allow DNS lookups */
167 if (tdc->dns_name && *tdc->dns_name) {
168 alternative_name = tdc->dns_name;
171 /* We can't call domain_list() as this function is called from
172 init_domain_list() and we'll get stuck in a loop. */
173 for (domain = _domain_list; domain; domain = domain->next) {
174 if (strequal(domain_name, domain->name) ||
175 strequal(domain_name, domain->alt_name))
180 if (alternative_name) {
181 if (strequal(alternative_name, domain->name) ||
182 strequal(alternative_name, domain->alt_name))
189 if (dom_sid_equal(sid, &domain->sid)) {
195 if (domain != NULL) {
197 * We found a match on domain->name or
198 * domain->alt_name. Possibly update the SID
199 * if the stored SID was the NULL SID
200 * and return the matching entry.
203 && dom_sid_equal(&domain->sid, &global_sid_NULL)) {
204 sid_copy( &domain->sid, sid );
209 /* Create new domain entry */
210 domain = talloc_zero(NULL, struct winbindd_domain);
211 if (domain == NULL) {
215 domain->children = talloc_zero_array(domain,
216 struct winbindd_child,
217 lp_winbind_max_domain_connections());
218 if (domain->children == NULL) {
223 domain->name = talloc_strdup(domain, domain_name);
224 if (domain->name == NULL) {
229 if (alternative_name) {
230 domain->alt_name = talloc_strdup(domain, alternative_name);
231 if (domain->alt_name == NULL) {
237 domain->backend = NULL;
238 domain->internal = is_internal_domain(sid);
239 domain->sequence_number = DOM_SEQUENCE_NONE;
240 domain->last_seq_check = 0;
241 domain->initialized = false;
242 domain->online = is_internal_domain(sid);
243 domain->check_online_timeout = 0;
244 domain->dc_probe_pid = (pid_t)-1;
246 sid_copy(&domain->sid, sid);
248 domain->domain_flags = tdc->trust_flags;
249 domain->domain_type = tdc->trust_type;
250 domain->domain_trust_attribs = tdc->trust_attribs;
252 /* Is this our primary domain ? */
253 if (strequal(domain_name, get_global_sam_name()) &&
254 (role != ROLE_DOMAIN_MEMBER)) {
255 domain->primary = true;
256 } else if (strequal(domain_name, lp_workgroup()) &&
257 (role == ROLE_DOMAIN_MEMBER)) {
258 domain->primary = true;
261 if (domain->primary) {
262 if (role == ROLE_ACTIVE_DIRECTORY_DC) {
263 domain->active_directory = true;
265 if (lp_security() == SEC_ADS) {
266 domain->active_directory = true;
268 } else if (!domain->internal) {
269 if (domain->domain_type == LSA_TRUST_TYPE_UPLEVEL) {
270 domain->active_directory = true;
274 /* Link to domain list */
275 DLIST_ADD_END(_domain_list, domain);
277 wcache_tdc_add_domain( domain );
279 setup_domain_child(domain);
282 ("Added domain %s %s %s\n", domain->name, domain->alt_name,
283 !is_null_sid(&domain->sid) ? sid_string_dbg(&domain->sid) : ""));
288 bool domain_is_forest_root(const struct winbindd_domain *domain)
290 const uint32_t fr_flags =
291 (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
293 return ((domain->domain_flags & fr_flags) == fr_flags);
296 /********************************************************************
297 rescan our domains looking for new trusted domains
298 ********************************************************************/
300 struct trustdom_state {
301 struct winbindd_domain *domain;
302 struct winbindd_request request;
305 static void trustdom_list_done(struct tevent_req *req);
306 static void rescan_forest_root_trusts( void );
307 static void rescan_forest_trusts( void );
309 static void add_trusted_domains( struct winbindd_domain *domain )
311 struct trustdom_state *state;
312 struct tevent_req *req;
314 state = talloc_zero(NULL, struct trustdom_state);
316 DEBUG(0, ("talloc failed\n"));
319 state->domain = domain;
321 state->request.length = sizeof(state->request);
322 state->request.cmd = WINBINDD_LIST_TRUSTDOM;
324 req = wb_domain_request_send(state, winbind_event_context(),
325 domain, &state->request);
327 DEBUG(1, ("wb_domain_request_send failed\n"));
331 tevent_req_set_callback(req, trustdom_list_done, state);
334 static void trustdom_list_done(struct tevent_req *req)
336 struct trustdom_state *state = tevent_req_callback_data(
337 req, struct trustdom_state);
338 struct winbindd_response *response;
341 struct winbindd_tdc_domain trust_params = {0};
344 res = wb_domain_request_recv(req, state, &response, &err);
345 if ((res == -1) || (response->result != WINBINDD_OK)) {
346 DBG_WARNING("Could not receive trusts for domain %s\n",
347 state->domain->name);
352 if (response->length < sizeof(struct winbindd_response)) {
353 DBG_ERR("ill-formed trustdom response - short length\n");
358 extra_len = response->length - sizeof(struct winbindd_response);
360 p = (char *)response->extra_data.data;
362 while ((p - (char *)response->extra_data.data) < extra_len) {
363 char *q, *sidstr, *alt_name;
365 DBG_DEBUG("parsing response line '%s'\n", p);
367 ZERO_STRUCT(trust_params);
368 trust_params.domain_name = p;
370 alt_name = strchr(p, '\\');
371 if (alt_name == NULL) {
372 DBG_ERR("Got invalid trustdom response\n");
379 sidstr = strchr(alt_name, '\\');
380 if (sidstr == NULL) {
381 DBG_ERR("Got invalid trustdom response\n");
388 /* use the real alt_name if we have one, else pass in NULL */
389 if (!strequal(alt_name, "(null)")) {
390 trust_params.dns_name = alt_name;
393 q = strtok(sidstr, "\\");
395 DBG_ERR("Got invalid trustdom response\n");
399 if (!string_to_sid(&trust_params.sid, sidstr)) {
400 DEBUG(0, ("Got invalid trustdom response\n"));
404 q = strtok(NULL, "\\");
406 DBG_ERR("Got invalid trustdom response\n");
410 trust_params.trust_flags = (uint32_t)strtoul(q, NULL, 10);
412 q = strtok(NULL, "\\");
414 DBG_ERR("Got invalid trustdom response\n");
418 trust_params.trust_type = (uint32_t)strtoul(q, NULL, 10);
420 q = strtok(NULL, "\n");
422 DBG_ERR("Got invalid trustdom response\n");
426 trust_params.trust_attribs = (uint32_t)strtoul(q, NULL, 10);
429 * We always call add_trusted_domain() cause on an existing
430 * domain structure, it will update the SID if necessary.
431 * This is important because we need the SID for sibling
434 (void)add_trusted_domain_from_tdc(&trust_params);
436 p = q + strlen(q) + 1;
440 Cases to consider when scanning trusts:
441 (a) we are calling from a child domain (primary && !forest_root)
442 (b) we are calling from the root of the forest (primary && forest_root)
443 (c) we are calling from a trusted forest domain (!primary
447 if (state->domain->primary) {
448 /* If this is our primary domain and we are not in the
449 forest root, we have to scan the root trusts first */
451 if (!domain_is_forest_root(state->domain))
452 rescan_forest_root_trusts();
454 rescan_forest_trusts();
456 } else if (domain_is_forest_root(state->domain)) {
457 /* Once we have done root forest trust search, we can
458 go on to search the trusted forests */
460 rescan_forest_trusts();
468 /********************************************************************
469 Scan the trusts of our forest root
470 ********************************************************************/
472 static void rescan_forest_root_trusts( void )
474 struct winbindd_tdc_domain *dom_list = NULL;
475 size_t num_trusts = 0;
478 /* The only transitive trusts supported by Windows 2003 AD are
479 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
480 first two are handled in forest and listed by
481 DsEnumerateDomainTrusts(). Forest trusts are not so we
482 have to do that ourselves. */
484 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
487 for ( i=0; i<num_trusts; i++ ) {
488 struct winbindd_domain *d = NULL;
490 /* Find the forest root. Don't necessarily trust
491 the domain_list() as our primary domain may not
492 have been initialized. */
494 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
498 /* Here's the forest root */
500 d = find_domain_from_name_noinit( dom_list[i].domain_name );
503 d = add_trusted_domain_from_tdc(&dom_list[i]);
510 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
511 "for domain tree root %s (%s)\n",
512 d->name, d->alt_name ));
514 d->domain_flags = dom_list[i].trust_flags;
515 d->domain_type = dom_list[i].trust_type;
516 d->domain_trust_attribs = dom_list[i].trust_attribs;
518 add_trusted_domains( d );
523 TALLOC_FREE( dom_list );
528 /********************************************************************
529 scan the transitive forest trusts (not our own)
530 ********************************************************************/
533 static void rescan_forest_trusts( void )
535 struct winbindd_domain *d = NULL;
536 struct winbindd_tdc_domain *dom_list = NULL;
537 size_t num_trusts = 0;
540 /* The only transitive trusts supported by Windows 2003 AD are
541 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
542 first two are handled in forest and listed by
543 DsEnumerateDomainTrusts(). Forest trusts are not so we
544 have to do that ourselves. */
546 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
549 for ( i=0; i<num_trusts; i++ ) {
550 uint32_t flags = dom_list[i].trust_flags;
551 uint32_t type = dom_list[i].trust_type;
552 uint32_t attribs = dom_list[i].trust_attribs;
554 d = find_domain_from_name_noinit( dom_list[i].domain_name );
556 /* ignore our primary and internal domains */
558 if ( d && (d->internal || d->primary ) )
561 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
562 (type == LSA_TRUST_TYPE_UPLEVEL) &&
563 (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
565 /* add the trusted domain if we don't know
569 d = add_trusted_domain_from_tdc(&dom_list[i]);
576 DEBUG(10,("Following trust path for domain %s (%s)\n",
577 d->name, d->alt_name ));
578 add_trusted_domains( d );
582 TALLOC_FREE( dom_list );
587 /*********************************************************************
588 The process of updating the trusted domain list is a three step
591 (b) ask the root domain in our forest
592 (c) ask the a DC in any Win2003 trusted forests
593 *********************************************************************/
595 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
596 struct timeval now, void *private_data)
600 /* I use to clear the cache here and start over but that
601 caused problems in child processes that needed the
602 trust dom list early on. Removing it means we
603 could have some trusted domains listed that have been
604 removed from our primary domain's DC until a full
605 restart. This should be ok since I think this is what
606 Windows does as well. */
608 /* this will only add new domains we didn't already know about
609 in the domain_list()*/
611 add_trusted_domains( find_our_domain() );
613 te = tevent_add_timer(
614 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
615 rescan_trusted_domains, NULL);
617 * If te == NULL, there's not much we can do here. Don't fail, the
618 * only thing we miss is new trusted domains.
624 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
625 struct winbindd_cli_state *state)
627 /* Ensure null termination */
628 state->request->domain_name
629 [sizeof(state->request->domain_name)-1]='\0';
630 state->request->data.init_conn.dcname
631 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
633 if (strlen(state->request->data.init_conn.dcname) > 0) {
634 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
637 init_dc_connection(domain, false);
639 if (!domain->initialized) {
640 /* If we return error here we can't do any cached authentication,
641 but we may be in disconnected mode and can't initialize correctly.
642 Do what the previous code did and just return without initialization,
643 once we go online we'll re-initialize.
645 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
646 "online = %d\n", domain->name, (int)domain->online ));
649 fstrcpy(state->response->data.domain_info.name, domain->name);
650 fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
651 sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
653 state->response->data.domain_info.native_mode
654 = domain->native_mode;
655 state->response->data.domain_info.active_directory
656 = domain->active_directory;
657 state->response->data.domain_info.primary
663 static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
666 struct server_id server_id,
669 TALLOC_CTX *frame = talloc_stackframe();
670 struct lsa_TrustDomainInfoInfoEx info;
671 enum ndr_err_code ndr_err;
672 struct winbindd_domain *d = NULL;
674 DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
681 ndr_err = ndr_pull_struct_blob_all(data, frame, &info,
682 (ndr_pull_flags_fn_t)ndr_pull_lsa_TrustDomainInfoInfoEx);
683 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
688 d = find_domain_from_name_noinit(info.netbios_name.string);
694 d = add_trusted_domain(info.netbios_name.string,
695 info.domain_name.string,
712 if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
713 d->domain_flags |= NETR_TRUST_FLAG_INBOUND;
715 if (info.trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
716 d->domain_flags |= NETR_TRUST_FLAG_OUTBOUND;
718 if (info.trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
719 d->domain_flags |= NETR_TRUST_FLAG_IN_FOREST;
721 d->domain_type = info.trust_type;
722 d->domain_trust_attribs = info.trust_attributes;
728 * We did not get the secret when we queried secrets.tdb, so read it
729 * from secrets.tdb and re-sync the databases
731 static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
734 struct cli_credentials *creds;
735 NTSTATUS can_migrate = pdb_get_trust_credentials(domain->name,
736 NULL, domain, &creds);
737 if (!NT_STATUS_IS_OK(can_migrate)) {
738 DEBUG(0, ("Failed to fetch our own, local AD domain join "
739 "password for winbindd's internal use, both from "
740 "secrets.tdb and secrets.ldb: %s\n",
741 nt_errstr(can_migrate)));
746 * NOTE: It is very unlikely we end up here if there is an
747 * oldpass, because a new password is created at
748 * classicupgrade, so this is not a concern.
750 ok = secrets_store_machine_pw_sync(cli_credentials_get_password(creds),
752 cli_credentials_get_domain(creds),
753 cli_credentials_get_realm(creds),
754 cli_credentials_get_salt_principal(creds),
755 0, /* Supported enc types, unused */
757 cli_credentials_get_password_last_changed_time(creds),
758 cli_credentials_get_secure_channel_type(creds),
759 false /* do_delete: Do not delete */);
762 DEBUG(0, ("Failed to write our our own, "
763 "local AD domain join password for "
764 "winbindd's internal use into secrets.tdb\n"));
770 /* Look up global info for the winbind daemon */
771 bool init_domain_list(void)
773 int role = lp_server_role();
776 /* Free existing list */
781 (void)add_trusted_domain("BUILTIN", NULL, &global_sid_Builtin);
785 if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
786 struct winbindd_domain *domain;
787 enum netr_SchannelType sec_chan_type;
788 const char *account_name;
789 struct samr_Password current_nt_hash;
790 struct pdb_domain_info *pdb_domain_info;
793 pdb_domain_info = pdb_get_domain_info(talloc_tos());
794 if (pdb_domain_info == NULL) {
795 DEBUG(0, ("Failed to fetch our own, local AD "
796 "domain info from sam.ldb\n"));
799 domain = add_trusted_domain(pdb_domain_info->name,
800 pdb_domain_info->dns_domain,
801 &pdb_domain_info->sid);
802 TALLOC_FREE(pdb_domain_info);
803 if (domain == NULL) {
804 DEBUG(0, ("Failed to add our own, local AD "
805 "domain to winbindd's internal list\n"));
810 * We need to call this to find out if we are an RODC
812 ok = get_trust_pw_hash(domain->name,
813 current_nt_hash.hash,
818 * If get_trust_pw_hash() fails, then try and
819 * fetch the password from the more recent of
820 * secrets.{ldb,tdb} using the
821 * pdb_get_trust_credentials()
823 ok = migrate_secrets_tdb_to_ldb(domain);
826 DEBUG(0, ("Failed to migrate our own, "
827 "local AD domain join password for "
828 "winbindd's internal use into "
832 ok = get_trust_pw_hash(domain->name,
833 current_nt_hash.hash,
837 DEBUG(0, ("Failed to find our our own, just "
838 "written local AD domain join "
839 "password for winbindd's internal "
840 "use in secrets.tdb\n"));
844 if (sec_chan_type == SEC_CHAN_RODC) {
849 (void)add_trusted_domain(get_global_sam_name(), NULL,
850 get_global_sam_sid());
852 /* Add ourselves as the first entry. */
854 if ( role == ROLE_DOMAIN_MEMBER ) {
855 struct winbindd_domain *domain;
856 struct dom_sid our_sid;
858 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
859 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
863 domain = add_trusted_domain(lp_workgroup(), lp_realm(),
866 /* Even in the parent winbindd we'll need to
867 talk to the DC, so try and see if we can
868 contact it. Theoretically this isn't neccessary
869 as the init_dc_connection() in init_child_recv()
870 will do this, but we can start detecting the DC
872 set_domain_online_request(domain);
876 status = imessaging_register(winbind_imessaging_context(), NULL,
877 MSG_WINBIND_NEW_TRUSTED_DOMAIN,
878 wb_imsg_new_trusted_domain);
879 if (!NT_STATUS_IS_OK(status)) {
880 DEBUG(0, ("imessaging_register(MSG_WINBIND_NEW_TRUSTED_DOMAIN) - %s\n",
889 * Given a domain name, return the struct winbindd domain info for it
891 * @note Do *not* pass lp_workgroup() to this function. domain_list
892 * may modify it's value, and free that pointer. Instead, our local
893 * domain may be found by calling find_our_domain().
897 * @return The domain structure for the named domain, if it is working.
900 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
902 struct winbindd_domain *domain;
904 /* Search through list */
906 for (domain = domain_list(); domain != NULL; domain = domain->next) {
907 if (strequal(domain_name, domain->name) ||
908 (domain->alt_name != NULL &&
909 strequal(domain_name, domain->alt_name))) {
919 struct winbindd_domain *find_domain_from_name(const char *domain_name)
921 struct winbindd_domain *domain;
923 domain = find_domain_from_name_noinit(domain_name);
928 if (!domain->initialized)
929 init_dc_connection(domain, false);
934 /* Given a domain sid, return the struct winbindd domain info for it */
936 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
938 struct winbindd_domain *domain;
940 /* Search through list */
942 for (domain = domain_list(); domain != NULL; domain = domain->next) {
943 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
952 /* Given a domain sid, return the struct winbindd domain info for it */
954 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
956 struct winbindd_domain *domain;
958 domain = find_domain_from_sid_noinit(sid);
963 if (!domain->initialized)
964 init_dc_connection(domain, false);
969 struct winbindd_domain *find_our_domain(void)
971 struct winbindd_domain *domain;
973 /* Search through list */
975 for (domain = domain_list(); domain != NULL; domain = domain->next) {
980 smb_panic("Could not find our domain");
984 struct winbindd_domain *find_root_domain(void)
986 struct winbindd_domain *ours = find_our_domain();
988 if (ours->forest_name == NULL) {
992 return find_domain_from_name( ours->forest_name );
995 struct winbindd_domain *find_builtin_domain(void)
997 struct winbindd_domain *domain;
999 domain = find_domain_from_sid(&global_sid_Builtin);
1000 if (domain == NULL) {
1001 smb_panic("Could not find BUILTIN domain");
1007 /* Find the appropriate domain to lookup a name or SID */
1009 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
1011 /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
1013 if ( sid_check_is_in_unix_groups(sid) ||
1014 sid_check_is_unix_groups(sid) ||
1015 sid_check_is_in_unix_users(sid) ||
1016 sid_check_is_unix_users(sid) )
1018 return find_domain_from_sid(get_global_sam_sid());
1021 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
1022 * one to contact the external DC's. On member servers the internal
1023 * domains are different: These are part of the local SAM. */
1025 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid)));
1027 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
1028 DEBUG(10, ("calling find_domain_from_sid\n"));
1029 return find_domain_from_sid(sid);
1032 /* On a member server a query for SID or name can always go to our
1035 DEBUG(10, ("calling find_our_domain\n"));
1036 return find_our_domain();
1039 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1041 if ( strequal(domain_name, unix_users_domain_name() ) ||
1042 strequal(domain_name, unix_groups_domain_name() ) )
1045 * The "Unix User" and "Unix Group" domain our handled by
1048 return find_domain_from_name_noinit( get_global_sam_name() );
1051 if (IS_DC || strequal(domain_name, "BUILTIN") ||
1052 strequal(domain_name, get_global_sam_name()))
1053 return find_domain_from_name_noinit(domain_name);
1056 return find_our_domain();
1059 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1061 static bool assume_domain(const char *domain)
1063 /* never assume the domain on a standalone server */
1065 if ( lp_server_role() == ROLE_STANDALONE )
1068 /* domain member servers may possibly assume for the domain name */
1070 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1071 if ( !strequal(lp_workgroup(), domain) )
1074 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1078 /* only left with a domain controller */
1080 if ( strequal(get_global_sam_name(), domain) ) {
1087 /* Parse a string of the form DOMAIN\user into a domain and a user */
1089 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1091 char *p = strchr(domuser,*lp_winbind_separator());
1094 fstrcpy(user, domuser);
1095 p = strchr(domuser, '@');
1097 if ( assume_domain(lp_workgroup()) && p == NULL) {
1098 fstrcpy(domain, lp_workgroup());
1099 } else if (p != NULL) {
1100 fstrcpy(domain, p + 1);
1101 user[PTR_DIFF(p, domuser)] = 0;
1107 fstrcpy(domain, domuser);
1108 domain[PTR_DIFF(p, domuser)] = 0;
1111 return strupper_m(domain);
1114 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1115 char **domain, char **user)
1117 fstring fstr_domain, fstr_user;
1118 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1121 *domain = talloc_strdup(mem_ctx, fstr_domain);
1122 *user = talloc_strdup(mem_ctx, fstr_user);
1123 return ((*domain != NULL) && (*user != NULL));
1126 /* Ensure an incoming username from NSS is fully qualified. Replace the
1127 incoming fstring with DOMAIN <separator> user. Returns the same
1128 values as parse_domain_user() but also replaces the incoming username.
1129 Used to ensure all names are fully qualified within winbindd.
1130 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1131 The protocol definitions of auth_crap, chng_pswd_auth_crap
1132 really should be changed to use this instead of doing things
1135 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1137 if (!parse_domain_user(username_inout, domain, user)) {
1140 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1141 domain, *lp_winbind_separator(),
1147 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1148 'winbind separator' options.
1150 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1153 If we are a PDC or BDC, and this is for our domain, do likewise.
1155 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
1156 username is then unqualified in unix
1158 On an AD DC we always fill DOMAIN\\USERNAME.
1160 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1162 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1166 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1170 fstrcpy(tmp_user, user);
1171 (void)strlower_m(tmp_user);
1173 if (can_assume && assume_domain(domain)) {
1174 strlcpy(name, tmp_user, sizeof(fstring));
1176 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1177 domain, *lp_winbind_separator(),
1183 * talloc version of fill_domain_username()
1184 * return NULL on talloc failure.
1186 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1191 char *tmp_user, *name;
1193 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1197 tmp_user = talloc_strdup(mem_ctx, user);
1198 if (!strlower_m(tmp_user)) {
1199 TALLOC_FREE(tmp_user);
1203 if (can_assume && assume_domain(domain)) {
1206 name = talloc_asprintf(mem_ctx, "%s%c%s",
1208 *lp_winbind_separator(),
1210 TALLOC_FREE(tmp_user);
1217 * Client list accessor functions
1220 static struct winbindd_cli_state *_client_list;
1221 static int _num_clients;
1223 /* Return list of all connected clients */
1225 struct winbindd_cli_state *winbindd_client_list(void)
1227 return _client_list;
1230 /* Return list-tail of all connected clients */
1232 struct winbindd_cli_state *winbindd_client_list_tail(void)
1234 return DLIST_TAIL(_client_list);
1237 /* Return previous (read:newer) client in list */
1239 struct winbindd_cli_state *
1240 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1242 return DLIST_PREV(cli);
1245 /* Add a connection to the list */
1247 void winbindd_add_client(struct winbindd_cli_state *cli)
1249 cli->last_access = time(NULL);
1250 DLIST_ADD(_client_list, cli);
1254 /* Remove a client from the list */
1256 void winbindd_remove_client(struct winbindd_cli_state *cli)
1258 DLIST_REMOVE(_client_list, cli);
1262 /* Move a client to head or list */
1264 void winbindd_promote_client(struct winbindd_cli_state *cli)
1266 cli->last_access = time(NULL);
1267 DLIST_PROMOTE(_client_list, cli);
1270 /* Return number of open clients */
1272 int winbindd_num_clients(void)
1274 return _num_clients;
1277 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1278 TALLOC_CTX *mem_ctx,
1279 const struct dom_sid *user_sid,
1280 uint32_t *p_num_groups, struct dom_sid **user_sids)
1282 struct netr_SamInfo3 *info3 = NULL;
1283 NTSTATUS status = NT_STATUS_NO_MEMORY;
1284 uint32_t num_groups = 0;
1286 DEBUG(3,(": lookup_usergroups_cached\n"));
1291 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1293 if (info3 == NULL) {
1294 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1297 if (info3->base.groups.count == 0) {
1299 return NT_STATUS_UNSUCCESSFUL;
1303 * Before bug #7843 the "Domain Local" groups were added with a
1304 * lookupuseraliases call, but this isn't done anymore for our domain
1305 * so we need to resolve resource groups here.
1307 * When to use Resource Groups:
1308 * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1310 status = sid_array_from_info3(mem_ctx, info3,
1315 if (!NT_STATUS_IS_OK(status)) {
1321 *p_num_groups = num_groups;
1322 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1324 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1329 /*********************************************************************
1330 We use this to remove spaces from user and group names
1331 ********************************************************************/
1333 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1334 struct winbindd_domain *domain,
1340 if (!name || !normalized) {
1341 return NT_STATUS_INVALID_PARAMETER;
1344 if (!lp_winbind_normalize_names()) {
1345 return NT_STATUS_PROCEDURE_NOT_FOUND;
1348 /* Alias support and whitespace replacement are mutually
1351 nt_status = resolve_username_to_alias(mem_ctx, domain,
1353 if (NT_STATUS_IS_OK(nt_status)) {
1354 /* special return code to let the caller know we
1355 mapped to an alias */
1356 return NT_STATUS_FILE_RENAMED;
1359 /* check for an unreachable domain */
1361 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1362 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1364 set_domain_offline(domain);
1368 /* deal with whitespace */
1370 *normalized = talloc_strdup(mem_ctx, name);
1371 if (!(*normalized)) {
1372 return NT_STATUS_NO_MEMORY;
1375 all_string_sub( *normalized, " ", "_", 0 );
1377 return NT_STATUS_OK;
1380 /*********************************************************************
1381 We use this to do the inverse of normalize_name_map()
1382 ********************************************************************/
1384 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1389 struct winbindd_domain *domain = find_our_domain();
1391 if (!name || !normalized) {
1392 return NT_STATUS_INVALID_PARAMETER;
1395 if (!lp_winbind_normalize_names()) {
1396 return NT_STATUS_PROCEDURE_NOT_FOUND;
1399 /* Alias support and whitespace replacement are mutally
1402 /* When mapping from an alias to a username, we don't know the
1403 domain. But we only need a domain structure to cache
1404 a successful lookup , so just our own domain structure for
1407 nt_status = resolve_alias_to_username(mem_ctx, domain,
1409 if (NT_STATUS_IS_OK(nt_status)) {
1410 /* Special return code to let the caller know we mapped
1412 return NT_STATUS_FILE_RENAMED;
1415 /* check for an unreachable domain */
1417 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1418 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1420 set_domain_offline(domain);
1424 /* deal with whitespace */
1426 *normalized = talloc_strdup(mem_ctx, name);
1427 if (!(*normalized)) {
1428 return NT_STATUS_NO_MEMORY;
1431 all_string_sub(*normalized, "_", " ", 0);
1433 return NT_STATUS_OK;
1436 /*********************************************************************
1437 ********************************************************************/
1439 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1441 struct winbindd_tdc_domain *tdc = NULL;
1442 TALLOC_CTX *frame = talloc_stackframe();
1445 /* We can contact the domain if it is our primary domain */
1447 if (domain->primary) {
1452 /* Trust the TDC cache and not the winbindd_domain flags */
1454 if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1455 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1461 /* Can always contact a domain that is in out forest */
1463 if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1469 * On a _member_ server, we cannot contact the domain if it
1470 * is running AD and we have no inbound trust.
1474 domain->active_directory &&
1475 ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1477 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1478 "and we have no inbound trust.\n", domain->name));
1482 /* Assume everything else is ok (probably not true but what
1488 talloc_destroy(frame);
1493 /*********************************************************************
1494 ********************************************************************/
1496 bool winbindd_internal_child(struct winbindd_child *child)
1498 if ((child == idmap_child()) || (child == locator_child())) {
1505 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1507 /*********************************************************************
1508 ********************************************************************/
1510 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1513 char addr[INET6_ADDRSTRLEN];
1514 const char *kdc = NULL;
1517 if (!domain || !domain->alt_name || !*domain->alt_name) {
1521 if (domain->initialized && !domain->active_directory) {
1522 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1527 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1530 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1532 kdc = domain->dcname;
1535 if (!kdc || !*kdc) {
1536 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1541 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1542 domain->alt_name) == -1) {
1546 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1549 setenv(var, kdc, 1);
1553 /*********************************************************************
1554 ********************************************************************/
1556 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1558 struct winbindd_domain *our_dom = find_our_domain();
1560 winbindd_set_locator_kdc_env(domain);
1562 if (domain != our_dom) {
1563 winbindd_set_locator_kdc_env(our_dom);
1567 /*********************************************************************
1568 ********************************************************************/
1570 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1574 if (!domain || !domain->alt_name || !*domain->alt_name) {
1578 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1579 domain->alt_name) == -1) {
1588 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1593 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1598 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1600 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1602 resp->data.auth.nt_status = NT_STATUS_V(result);
1603 fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1605 /* we might have given a more useful error above */
1606 if (*resp->data.auth.error_string == '\0')
1607 fstrcpy(resp->data.auth.error_string,
1608 get_friendly_nt_error_msg(result));
1609 resp->data.auth.pam_error = nt_status_to_pam(result);
1612 bool is_domain_offline(const struct winbindd_domain *domain)
1614 if (!lp_winbind_offline_logon()) {
1617 if (get_global_winbindd_state_offline()) {
1620 return !domain->online;
1623 bool is_domain_online(const struct winbindd_domain *domain)
1625 return !is_domain_offline(domain);
1629 * Parse an char array into a list of sids.
1631 * The input sidstr should consist of 0-terminated strings
1632 * representing sids, separated by newline characters '\n'.
1633 * The list is terminated by an empty string, i.e.
1634 * character '\0' directly following a character '\n'
1635 * (or '\0' right at the start of sidstr).
1637 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
1638 struct dom_sid **sids, uint32_t *num_sids)
1646 while (p[0] != '\0') {
1648 const char *q = NULL;
1650 if (!dom_sid_parse_endp(p, &sid, &q)) {
1651 DEBUG(1, ("Could not parse sid %s\n", p));
1654 if ((q == NULL) || (q[0] != '\n')) {
1655 DEBUG(1, ("Got invalid sidstr: %s\n", p));
1658 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
1668 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
1669 struct unixid **pxids, uint32_t *pnum_xids)
1672 struct unixid *xids = NULL;
1673 uint32_t num_xids = 0;
1680 while (p[0] != '\0') {
1683 unsigned long long id;
1688 xid = (struct unixid) { .type = ID_TYPE_UID };
1691 xid = (struct unixid) { .type = ID_TYPE_GID };
1699 id = strtoull(p, &endp, 10);
1700 if ((id == ULLONG_MAX) && (errno == ERANGE)) {
1703 if (*endp != '\n') {
1709 if ((unsigned long long)xid.id != id) {
1713 tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
1719 xids[num_xids] = xid;
1724 *pnum_xids = num_xids;