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;
149 const char *alternative_name = NULL;
150 const char **ignored_domains, **dom;
151 int role = lp_server_role();
152 const char *domain_name = tdc->domain_name;
153 const struct dom_sid *sid = &tdc->sid;
155 if (is_null_sid(sid)) {
156 DBG_ERR("Got null SID for domain [%s]\n", domain_name);
160 ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
161 for (dom=ignored_domains; dom && *dom; dom++) {
162 if (gen_fnmatch(*dom, domain_name) == 0) {
163 DEBUG(2,("Ignoring domain '%s'\n", domain_name));
168 /* use alt_name if available to allow DNS lookups */
170 if (tdc->dns_name && *tdc->dns_name) {
171 alternative_name = tdc->dns_name;
174 /* We can't call domain_list() as this function is called from
175 init_domain_list() and we'll get stuck in a loop. */
176 for (domain = _domain_list; domain; domain = domain->next) {
177 if (strequal(domain_name, domain->name) ||
178 strequal(domain_name, domain->alt_name))
183 if (alternative_name) {
184 if (strequal(alternative_name, domain->name) ||
185 strequal(alternative_name, domain->alt_name))
191 if (dom_sid_equal(sid, &domain->sid)) {
196 if (domain != NULL) {
200 /* Create new domain entry */
201 domain = talloc_zero(NULL, struct winbindd_domain);
202 if (domain == NULL) {
206 domain->children = talloc_zero_array(domain,
207 struct winbindd_child,
208 lp_winbind_max_domain_connections());
209 if (domain->children == NULL) {
214 domain->name = talloc_strdup(domain, domain_name);
215 if (domain->name == NULL) {
220 if (alternative_name) {
221 domain->alt_name = talloc_strdup(domain, alternative_name);
222 if (domain->alt_name == NULL) {
228 domain->backend = NULL;
229 domain->internal = is_internal_domain(sid);
230 domain->sequence_number = DOM_SEQUENCE_NONE;
231 domain->last_seq_check = 0;
232 domain->initialized = false;
233 domain->online = is_internal_domain(sid);
234 domain->check_online_timeout = 0;
235 domain->dc_probe_pid = (pid_t)-1;
236 domain->domain_flags = tdc->trust_flags;
237 domain->domain_type = tdc->trust_type;
238 domain->domain_trust_attribs = tdc->trust_attribs;
239 sid_copy(&domain->sid, sid);
241 /* Is this our primary domain ? */
242 if (role == ROLE_DOMAIN_MEMBER) {
243 domain->primary = strequal(domain_name, lp_workgroup());
245 domain->primary = strequal(domain_name, get_global_sam_name());
248 if (domain->primary) {
249 if (role == ROLE_ACTIVE_DIRECTORY_DC) {
250 domain->active_directory = true;
252 if (lp_security() == SEC_ADS) {
253 domain->active_directory = true;
255 } else if (!domain->internal) {
256 if (domain->domain_type == LSA_TRUST_TYPE_UPLEVEL) {
257 domain->active_directory = true;
261 /* Link to domain list */
262 DLIST_ADD_END(_domain_list, domain);
264 wcache_tdc_add_domain( domain );
266 setup_domain_child(domain);
269 ("Added domain %s %s %s\n", domain->name, domain->alt_name,
270 !is_null_sid(&domain->sid) ? sid_string_dbg(&domain->sid) : ""));
275 bool domain_is_forest_root(const struct winbindd_domain *domain)
277 const uint32_t fr_flags =
278 (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
280 return ((domain->domain_flags & fr_flags) == fr_flags);
283 /********************************************************************
284 rescan our domains looking for new trusted domains
285 ********************************************************************/
287 struct trustdom_state {
288 struct winbindd_domain *domain;
289 struct winbindd_request request;
292 static void trustdom_list_done(struct tevent_req *req);
293 static void rescan_forest_root_trusts( void );
294 static void rescan_forest_trusts( void );
296 static void add_trusted_domains( struct winbindd_domain *domain )
298 struct trustdom_state *state;
299 struct tevent_req *req;
301 state = talloc_zero(NULL, struct trustdom_state);
303 DEBUG(0, ("talloc failed\n"));
306 state->domain = domain;
308 state->request.length = sizeof(state->request);
309 state->request.cmd = WINBINDD_LIST_TRUSTDOM;
311 req = wb_domain_request_send(state, server_event_context(),
312 domain, &state->request);
314 DEBUG(1, ("wb_domain_request_send failed\n"));
318 tevent_req_set_callback(req, trustdom_list_done, state);
321 static void trustdom_list_done(struct tevent_req *req)
323 struct trustdom_state *state = tevent_req_callback_data(
324 req, struct trustdom_state);
325 struct winbindd_response *response;
328 struct winbindd_tdc_domain trust_params = {0};
330 bool within_forest = false;
333 * Only when we enumerate our primary domain
334 * or our forest root domain, we should keep
335 * the NETR_TRUST_FLAG_IN_FOREST flag, in
336 * all other cases we need to clear it as the domain
337 * is not part of our forest.
339 if (state->domain->primary) {
340 within_forest = true;
341 } else if (domain_is_forest_root(state->domain)) {
342 within_forest = true;
345 res = wb_domain_request_recv(req, state, &response, &err);
346 if ((res == -1) || (response->result != WINBINDD_OK)) {
347 DBG_WARNING("Could not receive trusts for domain %s\n",
348 state->domain->name);
353 if (response->length < sizeof(struct winbindd_response)) {
354 DBG_ERR("ill-formed trustdom response - short length\n");
359 extra_len = response->length - sizeof(struct winbindd_response);
361 p = (char *)response->extra_data.data;
363 while ((p - (char *)response->extra_data.data) < extra_len) {
364 char *q, *sidstr, *alt_name;
366 DBG_DEBUG("parsing response line '%s'\n", p);
368 ZERO_STRUCT(trust_params);
369 trust_params.domain_name = p;
371 alt_name = strchr(p, '\\');
372 if (alt_name == NULL) {
373 DBG_ERR("Got invalid trustdom response\n");
380 sidstr = strchr(alt_name, '\\');
381 if (sidstr == NULL) {
382 DBG_ERR("Got invalid trustdom response\n");
389 /* use the real alt_name if we have one, else pass in NULL */
390 if (!strequal(alt_name, "(null)")) {
391 trust_params.dns_name = alt_name;
394 q = strtok(sidstr, "\\");
396 DBG_ERR("Got invalid trustdom response\n");
400 if (!string_to_sid(&trust_params.sid, sidstr)) {
401 DEBUG(0, ("Got invalid trustdom response\n"));
405 q = strtok(NULL, "\\");
407 DBG_ERR("Got invalid trustdom response\n");
411 trust_params.trust_flags = (uint32_t)strtoul(q, NULL, 10);
413 q = strtok(NULL, "\\");
415 DBG_ERR("Got invalid trustdom response\n");
419 trust_params.trust_type = (uint32_t)strtoul(q, NULL, 10);
421 q = strtok(NULL, "\n");
423 DBG_ERR("Got invalid trustdom response\n");
427 trust_params.trust_attribs = (uint32_t)strtoul(q, NULL, 10);
429 if (!within_forest) {
430 trust_params.trust_flags &= ~NETR_TRUST_FLAG_IN_FOREST;
433 if (!state->domain->primary) {
434 trust_params.trust_flags &= ~NETR_TRUST_FLAG_PRIMARY;
438 * We always call add_trusted_domain() cause on an existing
439 * domain structure, it will update the SID if necessary.
440 * This is important because we need the SID for sibling
443 (void)add_trusted_domain_from_tdc(&trust_params);
445 p = q + strlen(q) + 1;
449 Cases to consider when scanning trusts:
450 (a) we are calling from a child domain (primary && !forest_root)
451 (b) we are calling from the root of the forest (primary && forest_root)
452 (c) we are calling from a trusted forest domain (!primary
456 if (state->domain->primary) {
457 /* If this is our primary domain and we are not in the
458 forest root, we have to scan the root trusts first */
460 if (!domain_is_forest_root(state->domain))
461 rescan_forest_root_trusts();
463 rescan_forest_trusts();
465 } else if (domain_is_forest_root(state->domain)) {
466 /* Once we have done root forest trust search, we can
467 go on to search the trusted forests */
469 rescan_forest_trusts();
477 /********************************************************************
478 Scan the trusts of our forest root
479 ********************************************************************/
481 static void rescan_forest_root_trusts( void )
483 struct winbindd_tdc_domain *dom_list = NULL;
484 size_t num_trusts = 0;
487 /* The only transitive trusts supported by Windows 2003 AD are
488 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
489 first two are handled in forest and listed by
490 DsEnumerateDomainTrusts(). Forest trusts are not so we
491 have to do that ourselves. */
493 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
496 for ( i=0; i<num_trusts; i++ ) {
497 struct winbindd_domain *d = NULL;
499 /* Find the forest root. Don't necessarily trust
500 the domain_list() as our primary domain may not
501 have been initialized. */
503 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
507 /* Here's the forest root */
509 d = find_domain_from_name_noinit( dom_list[i].domain_name );
512 d = add_trusted_domain_from_tdc(&dom_list[i]);
519 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
520 "for domain tree root %s (%s)\n",
521 d->name, d->alt_name ));
523 d->domain_flags = dom_list[i].trust_flags;
524 d->domain_type = dom_list[i].trust_type;
525 d->domain_trust_attribs = dom_list[i].trust_attribs;
527 add_trusted_domains( d );
532 TALLOC_FREE( dom_list );
537 /********************************************************************
538 scan the transitive forest trusts (not our own)
539 ********************************************************************/
542 static void rescan_forest_trusts( void )
544 struct winbindd_domain *d = NULL;
545 struct winbindd_tdc_domain *dom_list = NULL;
546 size_t num_trusts = 0;
549 /* The only transitive trusts supported by Windows 2003 AD are
550 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
551 first two are handled in forest and listed by
552 DsEnumerateDomainTrusts(). Forest trusts are not so we
553 have to do that ourselves. */
555 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
558 for ( i=0; i<num_trusts; i++ ) {
559 uint32_t flags = dom_list[i].trust_flags;
560 uint32_t type = dom_list[i].trust_type;
561 uint32_t attribs = dom_list[i].trust_attribs;
563 d = find_domain_from_name_noinit( dom_list[i].domain_name );
565 /* ignore our primary and internal domains */
567 if ( d && (d->internal || d->primary ) )
570 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
571 (type == LSA_TRUST_TYPE_UPLEVEL) &&
572 (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
574 /* add the trusted domain if we don't know
578 d = add_trusted_domain_from_tdc(&dom_list[i]);
585 DEBUG(10,("Following trust path for domain %s (%s)\n",
586 d->name, d->alt_name ));
587 add_trusted_domains( d );
591 TALLOC_FREE( dom_list );
596 /*********************************************************************
597 The process of updating the trusted domain list is a three step
600 (b) ask the root domain in our forest
601 (c) ask the a DC in any Win2003 trusted forests
602 *********************************************************************/
604 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
605 struct timeval now, void *private_data)
609 /* I use to clear the cache here and start over but that
610 caused problems in child processes that needed the
611 trust dom list early on. Removing it means we
612 could have some trusted domains listed that have been
613 removed from our primary domain's DC until a full
614 restart. This should be ok since I think this is what
615 Windows does as well. */
617 /* this will only add new domains we didn't already know about
618 in the domain_list()*/
620 add_trusted_domains( find_our_domain() );
622 te = tevent_add_timer(
623 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
624 rescan_trusted_domains, NULL);
626 * If te == NULL, there's not much we can do here. Don't fail, the
627 * only thing we miss is new trusted domains.
633 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
634 struct winbindd_cli_state *state)
636 /* Ensure null termination */
637 state->request->domain_name
638 [sizeof(state->request->domain_name)-1]='\0';
639 state->request->data.init_conn.dcname
640 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
642 if (strlen(state->request->data.init_conn.dcname) > 0) {
643 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
646 init_dc_connection(domain, false);
648 if (!domain->initialized) {
649 /* If we return error here we can't do any cached authentication,
650 but we may be in disconnected mode and can't initialize correctly.
651 Do what the previous code did and just return without initialization,
652 once we go online we'll re-initialize.
654 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
655 "online = %d\n", domain->name, (int)domain->online ));
658 fstrcpy(state->response->data.domain_info.name, domain->name);
659 fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
660 sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
662 state->response->data.domain_info.native_mode
663 = domain->native_mode;
664 state->response->data.domain_info.active_directory
665 = domain->active_directory;
666 state->response->data.domain_info.primary
672 static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
675 struct server_id server_id,
678 TALLOC_CTX *frame = talloc_stackframe();
679 struct lsa_TrustDomainInfoInfoEx info;
680 enum ndr_err_code ndr_err;
681 struct winbindd_domain *d = NULL;
683 DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
690 ndr_err = ndr_pull_struct_blob_all(data, frame, &info,
691 (ndr_pull_flags_fn_t)ndr_pull_lsa_TrustDomainInfoInfoEx);
692 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
697 d = find_domain_from_name_noinit(info.netbios_name.string);
703 d = add_trusted_domain(info.netbios_name.string,
704 info.domain_name.string,
721 if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
722 d->domain_flags |= NETR_TRUST_FLAG_INBOUND;
724 if (info.trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
725 d->domain_flags |= NETR_TRUST_FLAG_OUTBOUND;
727 if (info.trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
728 d->domain_flags |= NETR_TRUST_FLAG_IN_FOREST;
730 d->domain_type = info.trust_type;
731 d->domain_trust_attribs = info.trust_attributes;
737 * We did not get the secret when we queried secrets.tdb, so read it
738 * from secrets.tdb and re-sync the databases
740 static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
743 struct cli_credentials *creds;
744 NTSTATUS can_migrate = pdb_get_trust_credentials(domain->name,
745 NULL, domain, &creds);
746 if (!NT_STATUS_IS_OK(can_migrate)) {
747 DEBUG(0, ("Failed to fetch our own, local AD domain join "
748 "password for winbindd's internal use, both from "
749 "secrets.tdb and secrets.ldb: %s\n",
750 nt_errstr(can_migrate)));
755 * NOTE: It is very unlikely we end up here if there is an
756 * oldpass, because a new password is created at
757 * classicupgrade, so this is not a concern.
759 ok = secrets_store_machine_pw_sync(cli_credentials_get_password(creds),
761 cli_credentials_get_domain(creds),
762 cli_credentials_get_realm(creds),
763 cli_credentials_get_salt_principal(creds),
764 0, /* Supported enc types, unused */
766 cli_credentials_get_password_last_changed_time(creds),
767 cli_credentials_get_secure_channel_type(creds),
768 false /* do_delete: Do not delete */);
771 DEBUG(0, ("Failed to write our our own, "
772 "local AD domain join password for "
773 "winbindd's internal use into secrets.tdb\n"));
779 /* Look up global info for the winbind daemon */
780 bool init_domain_list(void)
782 int role = lp_server_role();
783 struct pdb_domain_info *pdb_domain_info = NULL;
786 /* Free existing list */
791 (void)add_trusted_domain("BUILTIN", NULL, &global_sid_Builtin);
796 * In case the passdb backend is passdb_dsdb the domain SID comes from
797 * dsdb, not from secrets.tdb. As we use the domain SID in various
798 * places, we must ensure the domain SID is migrated from dsdb to
799 * secrets.tdb before get_global_sam_sid() is called the first time.
801 * The migration is done as part of the passdb_dsdb initialisation,
802 * calling pdb_get_domain_info() triggers it.
804 pdb_domain_info = pdb_get_domain_info(talloc_tos());
806 if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
807 struct winbindd_domain *domain;
808 enum netr_SchannelType sec_chan_type;
809 const char *account_name;
810 struct samr_Password current_nt_hash;
813 if (pdb_domain_info == NULL) {
814 DEBUG(0, ("Failed to fetch our own, local AD "
815 "domain info from sam.ldb\n"));
818 domain = add_trusted_domain(pdb_domain_info->name,
819 pdb_domain_info->dns_domain,
820 &pdb_domain_info->sid);
821 TALLOC_FREE(pdb_domain_info);
822 if (domain == NULL) {
823 DEBUG(0, ("Failed to add our own, local AD "
824 "domain to winbindd's internal list\n"));
829 * We need to call this to find out if we are an RODC
831 ok = get_trust_pw_hash(domain->name,
832 current_nt_hash.hash,
837 * If get_trust_pw_hash() fails, then try and
838 * fetch the password from the more recent of
839 * secrets.{ldb,tdb} using the
840 * pdb_get_trust_credentials()
842 ok = migrate_secrets_tdb_to_ldb(domain);
845 DEBUG(0, ("Failed to migrate our own, "
846 "local AD domain join password for "
847 "winbindd's internal use into "
851 ok = get_trust_pw_hash(domain->name,
852 current_nt_hash.hash,
856 DEBUG(0, ("Failed to find our our own, just "
857 "written local AD domain join "
858 "password for winbindd's internal "
859 "use in secrets.tdb\n"));
863 if (sec_chan_type == SEC_CHAN_RODC) {
868 (void)add_trusted_domain(get_global_sam_name(), NULL,
869 get_global_sam_sid());
871 /* Add ourselves as the first entry. */
873 if ( role == ROLE_DOMAIN_MEMBER ) {
874 struct winbindd_domain *domain;
875 struct dom_sid our_sid;
877 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
878 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
882 domain = add_trusted_domain(lp_workgroup(), lp_realm(),
885 /* Even in the parent winbindd we'll need to
886 talk to the DC, so try and see if we can
887 contact it. Theoretically this isn't neccessary
888 as the init_dc_connection() in init_child_recv()
889 will do this, but we can start detecting the DC
891 set_domain_online_request(domain);
895 status = imessaging_register(winbind_imessaging_context(), NULL,
896 MSG_WINBIND_NEW_TRUSTED_DOMAIN,
897 wb_imsg_new_trusted_domain);
898 if (!NT_STATUS_IS_OK(status)) {
899 DEBUG(0, ("imessaging_register(MSG_WINBIND_NEW_TRUSTED_DOMAIN) - %s\n",
908 * Given a domain name, return the struct winbindd domain info for it
910 * @note Do *not* pass lp_workgroup() to this function. domain_list
911 * may modify it's value, and free that pointer. Instead, our local
912 * domain may be found by calling find_our_domain().
916 * @return The domain structure for the named domain, if it is working.
919 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
921 struct winbindd_domain *domain;
923 /* Search through list */
925 for (domain = domain_list(); domain != NULL; domain = domain->next) {
926 if (strequal(domain_name, domain->name)) {
929 if (domain->alt_name == NULL) {
932 if (strequal(domain_name, domain->alt_name)) {
942 struct winbindd_domain *find_domain_from_name(const char *domain_name)
944 struct winbindd_domain *domain;
946 domain = find_domain_from_name_noinit(domain_name);
951 if (!domain->initialized)
952 init_dc_connection(domain, false);
957 /* Given a domain sid, return the struct winbindd domain info for it */
959 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
961 struct winbindd_domain *domain;
963 /* Search through list */
965 for (domain = domain_list(); domain != NULL; domain = domain->next) {
966 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
975 /* Given a domain sid, return the struct winbindd domain info for it */
977 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
979 struct winbindd_domain *domain;
981 domain = find_domain_from_sid_noinit(sid);
986 if (!domain->initialized)
987 init_dc_connection(domain, false);
992 struct winbindd_domain *find_our_domain(void)
994 struct winbindd_domain *domain;
996 /* Search through list */
998 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1003 smb_panic("Could not find our 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 DBG_DEBUG("SID [%s]\n", sid_string_dbg(sid));
1014 * SIDs in the S-1-22-{1,2} domain and well-known SIDs should be handled
1018 if ( sid_check_is_in_unix_groups(sid) ||
1019 sid_check_is_unix_groups(sid) ||
1020 sid_check_is_in_unix_users(sid) ||
1021 sid_check_is_unix_users(sid) ||
1022 sid_check_is_wellknown_domain(sid, NULL) ||
1023 sid_check_is_in_wellknown_domain(sid) )
1025 return find_domain_from_sid(get_global_sam_sid());
1028 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
1029 * one to contact the external DC's. On member servers the internal
1030 * domains are different: These are part of the local SAM. */
1032 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
1033 DEBUG(10, ("calling find_domain_from_sid\n"));
1034 return find_domain_from_sid(sid);
1037 /* On a member server a query for SID or name can always go to our
1040 DEBUG(10, ("calling find_our_domain\n"));
1041 return find_our_domain();
1044 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1046 if ( strequal(domain_name, unix_users_domain_name() ) ||
1047 strequal(domain_name, unix_groups_domain_name() ) )
1050 * The "Unix User" and "Unix Group" domain our handled by
1053 return find_domain_from_name_noinit( get_global_sam_name() );
1056 if (IS_DC || strequal(domain_name, "BUILTIN") ||
1057 strequal(domain_name, get_global_sam_name()))
1058 return find_domain_from_name_noinit(domain_name);
1061 return find_our_domain();
1064 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1066 static bool assume_domain(const char *domain)
1068 /* never assume the domain on a standalone server */
1070 if ( lp_server_role() == ROLE_STANDALONE )
1073 /* domain member servers may possibly assume for the domain name */
1075 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1076 if ( !strequal(lp_workgroup(), domain) )
1079 if ( lp_winbind_use_default_domain() )
1083 /* only left with a domain controller */
1085 if ( strequal(get_global_sam_name(), domain) ) {
1092 /* Parse a string of the form DOMAIN\user into a domain and a user */
1094 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1096 char *p = strchr(domuser,*lp_winbind_separator());
1099 fstrcpy(user, domuser);
1100 p = strchr(domuser, '@');
1102 if ( assume_domain(lp_workgroup()) && p == NULL) {
1103 fstrcpy(domain, lp_workgroup());
1104 } else if (p != NULL) {
1105 fstrcpy(domain, p + 1);
1106 user[PTR_DIFF(p, domuser)] = 0;
1112 fstrcpy(domain, domuser);
1113 domain[PTR_DIFF(p, domuser)] = 0;
1116 return strupper_m(domain);
1119 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1120 char **domain, char **user)
1122 fstring fstr_domain, fstr_user;
1123 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1126 *domain = talloc_strdup(mem_ctx, fstr_domain);
1127 *user = talloc_strdup(mem_ctx, fstr_user);
1128 return ((*domain != NULL) && (*user != NULL));
1131 /* Ensure an incoming username from NSS is fully qualified. Replace the
1132 incoming fstring with DOMAIN <separator> user. Returns the same
1133 values as parse_domain_user() but also replaces the incoming username.
1134 Used to ensure all names are fully qualified within winbindd.
1135 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1136 The protocol definitions of auth_crap, chng_pswd_auth_crap
1137 really should be changed to use this instead of doing things
1140 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1142 if (!parse_domain_user(username_inout, domain, user)) {
1145 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1146 domain, *lp_winbind_separator(),
1152 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1153 'winbind separator' options.
1155 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1158 If we are a PDC or BDC, and this is for our domain, do likewise.
1160 On an AD DC we always fill DOMAIN\\USERNAME.
1162 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1164 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1168 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1172 fstrcpy(tmp_user, user);
1173 (void)strlower_m(tmp_user);
1175 if (can_assume && assume_domain(domain)) {
1176 strlcpy(name, tmp_user, sizeof(fstring));
1178 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1179 domain, *lp_winbind_separator(),
1185 * talloc version of fill_domain_username()
1186 * return NULL on talloc failure.
1188 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1193 char *tmp_user, *name;
1195 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1199 tmp_user = talloc_strdup(mem_ctx, user);
1200 if (!strlower_m(tmp_user)) {
1201 TALLOC_FREE(tmp_user);
1205 if (can_assume && assume_domain(domain)) {
1208 name = talloc_asprintf(mem_ctx, "%s%c%s",
1210 *lp_winbind_separator(),
1212 TALLOC_FREE(tmp_user);
1219 * Client list accessor functions
1222 static struct winbindd_cli_state *_client_list;
1223 static int _num_clients;
1225 /* Return list of all connected clients */
1227 struct winbindd_cli_state *winbindd_client_list(void)
1229 return _client_list;
1232 /* Return list-tail of all connected clients */
1234 struct winbindd_cli_state *winbindd_client_list_tail(void)
1236 return DLIST_TAIL(_client_list);
1239 /* Return previous (read:newer) client in list */
1241 struct winbindd_cli_state *
1242 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1244 return DLIST_PREV(cli);
1247 /* Add a connection to the list */
1249 void winbindd_add_client(struct winbindd_cli_state *cli)
1251 cli->last_access = time(NULL);
1252 DLIST_ADD(_client_list, cli);
1256 /* Remove a client from the list */
1258 void winbindd_remove_client(struct winbindd_cli_state *cli)
1260 DLIST_REMOVE(_client_list, cli);
1264 /* Move a client to head or list */
1266 void winbindd_promote_client(struct winbindd_cli_state *cli)
1268 cli->last_access = time(NULL);
1269 DLIST_PROMOTE(_client_list, cli);
1272 /* Return number of open clients */
1274 int winbindd_num_clients(void)
1276 return _num_clients;
1279 NTSTATUS lookup_usergroups_cached(TALLOC_CTX *mem_ctx,
1280 const struct dom_sid *user_sid,
1281 uint32_t *p_num_groups, struct dom_sid **user_sids)
1283 struct netr_SamInfo3 *info3 = NULL;
1284 NTSTATUS status = NT_STATUS_NO_MEMORY;
1285 uint32_t num_groups = 0;
1287 DEBUG(3,(": lookup_usergroups_cached\n"));
1292 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1294 if (info3 == NULL) {
1295 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1299 * Before bug #7843 the "Domain Local" groups were added with a
1300 * lookupuseraliases call, but this isn't done anymore for our domain
1301 * so we need to resolve resource groups here.
1303 * When to use Resource Groups:
1304 * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1306 status = sid_array_from_info3(mem_ctx, info3,
1311 if (!NT_STATUS_IS_OK(status)) {
1317 *p_num_groups = num_groups;
1318 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1320 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1325 /*********************************************************************
1326 We use this to remove spaces from user and group names
1327 ********************************************************************/
1329 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1330 const char *domain_name,
1334 struct winbindd_domain *domain = NULL;
1337 if (!name || !normalized) {
1338 return NT_STATUS_INVALID_PARAMETER;
1341 if (!lp_winbind_normalize_names()) {
1342 return NT_STATUS_PROCEDURE_NOT_FOUND;
1345 domain = find_domain_from_name_noinit(domain_name);
1346 if (domain == NULL) {
1347 DBG_ERR("Failed to find domain '%s'\n", domain_name);
1348 return NT_STATUS_NO_SUCH_DOMAIN;
1351 /* Alias support and whitespace replacement are mutually
1354 nt_status = resolve_username_to_alias(mem_ctx, domain,
1356 if (NT_STATUS_IS_OK(nt_status)) {
1357 /* special return code to let the caller know we
1358 mapped to an alias */
1359 return NT_STATUS_FILE_RENAMED;
1362 /* check for an unreachable domain */
1364 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1365 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1367 set_domain_offline(domain);
1371 /* deal with whitespace */
1373 *normalized = talloc_strdup(mem_ctx, name);
1374 if (!(*normalized)) {
1375 return NT_STATUS_NO_MEMORY;
1378 all_string_sub( *normalized, " ", "_", 0 );
1380 return NT_STATUS_OK;
1383 /*********************************************************************
1384 We use this to do the inverse of normalize_name_map()
1385 ********************************************************************/
1387 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1392 struct winbindd_domain *domain = find_our_domain();
1394 if (!name || !normalized) {
1395 return NT_STATUS_INVALID_PARAMETER;
1398 if (!lp_winbind_normalize_names()) {
1399 return NT_STATUS_PROCEDURE_NOT_FOUND;
1402 /* Alias support and whitespace replacement are mutally
1405 /* When mapping from an alias to a username, we don't know the
1406 domain. But we only need a domain structure to cache
1407 a successful lookup , so just our own domain structure for
1410 nt_status = resolve_alias_to_username(mem_ctx, domain,
1412 if (NT_STATUS_IS_OK(nt_status)) {
1413 /* Special return code to let the caller know we mapped
1415 return NT_STATUS_FILE_RENAMED;
1418 /* check for an unreachable domain */
1420 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1421 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1423 set_domain_offline(domain);
1427 /* deal with whitespace */
1429 *normalized = talloc_strdup(mem_ctx, name);
1430 if (!(*normalized)) {
1431 return NT_STATUS_NO_MEMORY;
1434 all_string_sub(*normalized, "_", " ", 0);
1436 return NT_STATUS_OK;
1439 /*********************************************************************
1440 ********************************************************************/
1442 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1444 struct winbindd_tdc_domain *tdc = NULL;
1445 TALLOC_CTX *frame = talloc_stackframe();
1448 /* We can contact the domain if it is our primary domain */
1450 if (domain->primary) {
1455 /* Trust the TDC cache and not the winbindd_domain flags */
1457 if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1458 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1464 /* Can always contact a domain that is in out forest */
1466 if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1472 * On a _member_ server, we cannot contact the domain if it
1473 * is running AD and we have no inbound trust.
1477 domain->active_directory &&
1478 ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1480 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1481 "and we have no inbound trust.\n", domain->name));
1485 /* Assume everything else is ok (probably not true but what
1491 talloc_destroy(frame);
1496 /*********************************************************************
1497 ********************************************************************/
1499 bool winbindd_internal_child(struct winbindd_child *child)
1501 if ((child == idmap_child()) || (child == locator_child())) {
1508 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1510 /*********************************************************************
1511 ********************************************************************/
1513 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1516 char addr[INET6_ADDRSTRLEN];
1517 const char *kdc = NULL;
1520 if (!domain || !domain->alt_name || !*domain->alt_name) {
1524 if (domain->initialized && !domain->active_directory) {
1525 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1530 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1533 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1535 kdc = domain->dcname;
1538 if (!kdc || !*kdc) {
1539 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1544 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1545 domain->alt_name) == -1) {
1549 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1552 setenv(var, kdc, 1);
1556 /*********************************************************************
1557 ********************************************************************/
1559 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1561 struct winbindd_domain *our_dom = find_our_domain();
1563 winbindd_set_locator_kdc_env(domain);
1565 if (domain != our_dom) {
1566 winbindd_set_locator_kdc_env(our_dom);
1570 /*********************************************************************
1571 ********************************************************************/
1573 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1577 if (!domain || !domain->alt_name || !*domain->alt_name) {
1581 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1582 domain->alt_name) == -1) {
1591 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1596 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1601 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1603 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1605 resp->data.auth.nt_status = NT_STATUS_V(result);
1606 fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1608 /* we might have given a more useful error above */
1609 if (*resp->data.auth.error_string == '\0')
1610 fstrcpy(resp->data.auth.error_string,
1611 get_friendly_nt_error_msg(result));
1612 resp->data.auth.pam_error = nt_status_to_pam(result);
1615 bool is_domain_offline(const struct winbindd_domain *domain)
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));
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;