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"
33 #include "libsmb/samlogon_cache.h"
36 #define DBGC_CLASS DBGC_WINBIND
38 static struct winbindd_domain *
39 add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc);
42 * @file winbindd_util.c
44 * Winbind daemon for NT domain authentication nss module.
48 /* The list of trusted domains. Note that the list can be deleted and
49 recreated using the init_domain_list() function so pointers to
50 individual winbindd_domain structures cannot be made. Keep a copy of
51 the domain name instead. */
53 static struct winbindd_domain *_domain_list = NULL;
55 struct winbindd_domain *domain_list(void)
59 if ((!_domain_list) && (!init_domain_list())) {
60 smb_panic("Init_domain_list failed");
66 /* Free all entries in the trusted domain list */
68 static void free_domain_list(void)
70 struct winbindd_domain *domain = _domain_list;
73 struct winbindd_domain *next = domain->next;
75 DLIST_REMOVE(_domain_list, domain);
82 * Iterator for winbindd's domain list.
83 * To be used (e.g.) in tevent based loops.
85 struct winbindd_domain *wb_next_domain(struct winbindd_domain *domain)
88 domain = domain_list();
90 domain = domain->next;
93 if ((domain != NULL) &&
94 (lp_server_role() != ROLE_ACTIVE_DIRECTORY_DC) &&
95 sid_check_is_our_sam(&domain->sid))
97 domain = domain->next;
103 static bool is_internal_domain(const struct dom_sid *sid)
108 return (sid_check_is_our_sam(sid) || sid_check_is_builtin(sid));
111 static bool is_in_internal_domain(const struct dom_sid *sid)
116 return (sid_check_is_in_our_sam(sid) || sid_check_is_in_builtin(sid));
120 /* Add a trusted domain to our list of domains.
121 If the domain already exists in the list,
122 return it and don't re-initialize. */
124 static struct winbindd_domain *
125 add_trusted_domain(const char *domain_name, const char *alt_name,
126 const struct dom_sid *sid)
128 struct winbindd_tdc_domain tdc;
132 tdc.domain_name = domain_name;
133 tdc.dns_name = alt_name;
135 sid_copy(&tdc.sid, sid);
138 return add_trusted_domain_from_tdc(&tdc);
141 /* Add a trusted domain out of a trusted domain cache
144 static struct winbindd_domain *
145 add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
147 struct winbindd_domain *domain;
148 const char *alternative_name = NULL;
149 const char **ignored_domains, **dom;
150 int role = lp_server_role();
151 const char *domain_name = tdc->domain_name;
152 const struct dom_sid *sid = &tdc->sid;
154 if (is_null_sid(sid)) {
158 ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
159 for (dom=ignored_domains; dom && *dom; dom++) {
160 if (gen_fnmatch(*dom, domain_name) == 0) {
161 DEBUG(2,("Ignoring domain '%s'\n", domain_name));
166 /* use alt_name if available to allow DNS lookups */
168 if (tdc->dns_name && *tdc->dns_name) {
169 alternative_name = tdc->dns_name;
172 /* We can't call domain_list() as this function is called from
173 init_domain_list() and we'll get stuck in a loop. */
174 for (domain = _domain_list; domain; domain = domain->next) {
175 if (strequal(domain_name, domain->name) ||
176 strequal(domain_name, domain->alt_name))
181 if (alternative_name) {
182 if (strequal(alternative_name, domain->name) ||
183 strequal(alternative_name, domain->alt_name))
190 if (dom_sid_equal(sid, &domain->sid)) {
196 if (domain != NULL) {
198 * We found a match on domain->name or
199 * domain->alt_name. Possibly update the SID
200 * if the stored SID was the NULL SID
201 * and return the matching entry.
204 && dom_sid_equal(&domain->sid, &global_sid_NULL)) {
205 sid_copy( &domain->sid, sid );
210 /* Create new domain entry */
211 domain = talloc_zero(NULL, struct winbindd_domain);
212 if (domain == NULL) {
216 domain->children = talloc_zero_array(domain,
217 struct winbindd_child,
218 lp_winbind_max_domain_connections());
219 if (domain->children == NULL) {
224 domain->name = talloc_strdup(domain, domain_name);
225 if (domain->name == NULL) {
230 if (alternative_name) {
231 domain->alt_name = talloc_strdup(domain, alternative_name);
232 if (domain->alt_name == NULL) {
238 domain->backend = NULL;
239 domain->internal = is_internal_domain(sid);
240 domain->sequence_number = DOM_SEQUENCE_NONE;
241 domain->last_seq_check = 0;
242 domain->initialized = false;
243 domain->online = is_internal_domain(sid);
244 domain->check_online_timeout = 0;
245 domain->dc_probe_pid = (pid_t)-1;
247 sid_copy(&domain->sid, sid);
249 domain->domain_flags = tdc->trust_flags;
250 domain->domain_type = tdc->trust_type;
251 domain->domain_trust_attribs = tdc->trust_attribs;
253 /* Is this our primary domain ? */
254 if (strequal(domain_name, get_global_sam_name()) &&
255 (role != ROLE_DOMAIN_MEMBER)) {
256 domain->primary = true;
257 } else if (strequal(domain_name, lp_workgroup()) &&
258 (role == ROLE_DOMAIN_MEMBER)) {
259 domain->primary = true;
262 if (domain->primary) {
263 if (role == ROLE_ACTIVE_DIRECTORY_DC) {
264 domain->active_directory = true;
266 if (lp_security() == SEC_ADS) {
267 domain->active_directory = true;
269 } else if (!domain->internal) {
270 if (domain->domain_type == LSA_TRUST_TYPE_UPLEVEL) {
271 domain->active_directory = true;
275 /* Link to domain list */
276 DLIST_ADD_END(_domain_list, domain);
278 wcache_tdc_add_domain( domain );
280 setup_domain_child(domain);
283 ("Added domain %s %s %s\n", domain->name, domain->alt_name,
284 !is_null_sid(&domain->sid) ? sid_string_dbg(&domain->sid) : ""));
289 bool domain_is_forest_root(const struct winbindd_domain *domain)
291 const uint32_t fr_flags =
292 (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
294 return ((domain->domain_flags & fr_flags) == fr_flags);
297 /********************************************************************
298 rescan our domains looking for new trusted domains
299 ********************************************************************/
301 struct trustdom_state {
302 struct winbindd_domain *domain;
303 struct winbindd_request request;
306 static void trustdom_list_done(struct tevent_req *req);
307 static void rescan_forest_root_trusts( void );
308 static void rescan_forest_trusts( void );
310 static void add_trusted_domains( struct winbindd_domain *domain )
312 struct trustdom_state *state;
313 struct tevent_req *req;
315 state = talloc_zero(NULL, struct trustdom_state);
317 DEBUG(0, ("talloc failed\n"));
320 state->domain = domain;
322 state->request.length = sizeof(state->request);
323 state->request.cmd = WINBINDD_LIST_TRUSTDOM;
325 req = wb_domain_request_send(state, winbind_event_context(),
326 domain, &state->request);
328 DEBUG(1, ("wb_domain_request_send failed\n"));
332 tevent_req_set_callback(req, trustdom_list_done, state);
335 static void trustdom_list_done(struct tevent_req *req)
337 struct trustdom_state *state = tevent_req_callback_data(
338 req, struct trustdom_state);
339 struct winbindd_response *response;
342 struct winbindd_tdc_domain trust_params = {0};
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);
430 * We always call add_trusted_domain() cause on an existing
431 * domain structure, it will update the SID if necessary.
432 * This is important because we need the SID for sibling
435 (void)add_trusted_domain_from_tdc(&trust_params);
437 p = q + strlen(q) + 1;
441 Cases to consider when scanning trusts:
442 (a) we are calling from a child domain (primary && !forest_root)
443 (b) we are calling from the root of the forest (primary && forest_root)
444 (c) we are calling from a trusted forest domain (!primary
448 if (state->domain->primary) {
449 /* If this is our primary domain and we are not in the
450 forest root, we have to scan the root trusts first */
452 if (!domain_is_forest_root(state->domain))
453 rescan_forest_root_trusts();
455 rescan_forest_trusts();
457 } else if (domain_is_forest_root(state->domain)) {
458 /* Once we have done root forest trust search, we can
459 go on to search the trusted forests */
461 rescan_forest_trusts();
469 /********************************************************************
470 Scan the trusts of our forest root
471 ********************************************************************/
473 static void rescan_forest_root_trusts( void )
475 struct winbindd_tdc_domain *dom_list = NULL;
476 size_t num_trusts = 0;
479 /* The only transitive trusts supported by Windows 2003 AD are
480 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
481 first two are handled in forest and listed by
482 DsEnumerateDomainTrusts(). Forest trusts are not so we
483 have to do that ourselves. */
485 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
488 for ( i=0; i<num_trusts; i++ ) {
489 struct winbindd_domain *d = NULL;
491 /* Find the forest root. Don't necessarily trust
492 the domain_list() as our primary domain may not
493 have been initialized. */
495 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
499 /* Here's the forest root */
501 d = find_domain_from_name_noinit( dom_list[i].domain_name );
504 d = add_trusted_domain_from_tdc(&dom_list[i]);
511 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
512 "for domain tree root %s (%s)\n",
513 d->name, d->alt_name ));
515 d->domain_flags = dom_list[i].trust_flags;
516 d->domain_type = dom_list[i].trust_type;
517 d->domain_trust_attribs = dom_list[i].trust_attribs;
519 add_trusted_domains( d );
524 TALLOC_FREE( dom_list );
529 /********************************************************************
530 scan the transitive forest trusts (not our own)
531 ********************************************************************/
534 static void rescan_forest_trusts( void )
536 struct winbindd_domain *d = NULL;
537 struct winbindd_tdc_domain *dom_list = NULL;
538 size_t num_trusts = 0;
541 /* The only transitive trusts supported by Windows 2003 AD are
542 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
543 first two are handled in forest and listed by
544 DsEnumerateDomainTrusts(). Forest trusts are not so we
545 have to do that ourselves. */
547 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
550 for ( i=0; i<num_trusts; i++ ) {
551 uint32_t flags = dom_list[i].trust_flags;
552 uint32_t type = dom_list[i].trust_type;
553 uint32_t attribs = dom_list[i].trust_attribs;
555 d = find_domain_from_name_noinit( dom_list[i].domain_name );
557 /* ignore our primary and internal domains */
559 if ( d && (d->internal || d->primary ) )
562 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
563 (type == LSA_TRUST_TYPE_UPLEVEL) &&
564 (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
566 /* add the trusted domain if we don't know
570 d = add_trusted_domain_from_tdc(&dom_list[i]);
577 DEBUG(10,("Following trust path for domain %s (%s)\n",
578 d->name, d->alt_name ));
579 add_trusted_domains( d );
583 TALLOC_FREE( dom_list );
588 /*********************************************************************
589 The process of updating the trusted domain list is a three step
592 (b) ask the root domain in our forest
593 (c) ask the a DC in any Win2003 trusted forests
594 *********************************************************************/
596 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
597 struct timeval now, void *private_data)
601 /* I use to clear the cache here and start over but that
602 caused problems in child processes that needed the
603 trust dom list early on. Removing it means we
604 could have some trusted domains listed that have been
605 removed from our primary domain's DC until a full
606 restart. This should be ok since I think this is what
607 Windows does as well. */
609 /* this will only add new domains we didn't already know about
610 in the domain_list()*/
612 add_trusted_domains( find_our_domain() );
614 te = tevent_add_timer(
615 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
616 rescan_trusted_domains, NULL);
618 * If te == NULL, there's not much we can do here. Don't fail, the
619 * only thing we miss is new trusted domains.
625 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
626 struct winbindd_cli_state *state)
628 /* Ensure null termination */
629 state->request->domain_name
630 [sizeof(state->request->domain_name)-1]='\0';
631 state->request->data.init_conn.dcname
632 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
634 if (strlen(state->request->data.init_conn.dcname) > 0) {
635 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
638 init_dc_connection(domain, false);
640 if (!domain->initialized) {
641 /* If we return error here we can't do any cached authentication,
642 but we may be in disconnected mode and can't initialize correctly.
643 Do what the previous code did and just return without initialization,
644 once we go online we'll re-initialize.
646 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
647 "online = %d\n", domain->name, (int)domain->online ));
650 fstrcpy(state->response->data.domain_info.name, domain->name);
651 fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
652 sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
654 state->response->data.domain_info.native_mode
655 = domain->native_mode;
656 state->response->data.domain_info.active_directory
657 = domain->active_directory;
658 state->response->data.domain_info.primary
664 static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
667 struct server_id server_id,
670 TALLOC_CTX *frame = talloc_stackframe();
671 struct lsa_TrustDomainInfoInfoEx info;
672 enum ndr_err_code ndr_err;
673 struct winbindd_domain *d = NULL;
675 DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
682 ndr_err = ndr_pull_struct_blob_all(data, frame, &info,
683 (ndr_pull_flags_fn_t)ndr_pull_lsa_TrustDomainInfoInfoEx);
684 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
689 d = find_domain_from_name_noinit(info.netbios_name.string);
695 d = add_trusted_domain(info.netbios_name.string,
696 info.domain_name.string,
713 if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
714 d->domain_flags |= NETR_TRUST_FLAG_INBOUND;
716 if (info.trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
717 d->domain_flags |= NETR_TRUST_FLAG_OUTBOUND;
719 if (info.trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
720 d->domain_flags |= NETR_TRUST_FLAG_IN_FOREST;
722 d->domain_type = info.trust_type;
723 d->domain_trust_attribs = info.trust_attributes;
729 * We did not get the secret when we queried secrets.tdb, so read it
730 * from secrets.tdb and re-sync the databases
732 static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
735 struct cli_credentials *creds;
736 NTSTATUS can_migrate = pdb_get_trust_credentials(domain->name,
737 NULL, domain, &creds);
738 if (!NT_STATUS_IS_OK(can_migrate)) {
739 DEBUG(0, ("Failed to fetch our own, local AD domain join "
740 "password for winbindd's internal use, both from "
741 "secrets.tdb and secrets.ldb: %s\n",
742 nt_errstr(can_migrate)));
747 * NOTE: It is very unlikely we end up here if there is an
748 * oldpass, because a new password is created at
749 * classicupgrade, so this is not a concern.
751 ok = secrets_store_machine_pw_sync(cli_credentials_get_password(creds),
753 cli_credentials_get_domain(creds),
754 cli_credentials_get_realm(creds),
755 cli_credentials_get_salt_principal(creds),
756 0, /* Supported enc types, unused */
758 cli_credentials_get_password_last_changed_time(creds),
759 cli_credentials_get_secure_channel_type(creds),
760 false /* do_delete: Do not delete */);
763 DEBUG(0, ("Failed to write our our own, "
764 "local AD domain join password for "
765 "winbindd's internal use into secrets.tdb\n"));
771 /* Look up global info for the winbind daemon */
772 bool init_domain_list(void)
774 int role = lp_server_role();
777 /* Free existing list */
782 (void)add_trusted_domain("BUILTIN", NULL, &global_sid_Builtin);
786 if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
787 struct winbindd_domain *domain;
788 enum netr_SchannelType sec_chan_type;
789 const char *account_name;
790 struct samr_Password current_nt_hash;
791 struct pdb_domain_info *pdb_domain_info;
794 pdb_domain_info = pdb_get_domain_info(talloc_tos());
795 if (pdb_domain_info == NULL) {
796 DEBUG(0, ("Failed to fetch our own, local AD "
797 "domain info from sam.ldb\n"));
800 domain = add_trusted_domain(pdb_domain_info->name,
801 pdb_domain_info->dns_domain,
802 &pdb_domain_info->sid);
803 TALLOC_FREE(pdb_domain_info);
804 if (domain == NULL) {
805 DEBUG(0, ("Failed to add our own, local AD "
806 "domain to winbindd's internal list\n"));
811 * We need to call this to find out if we are an RODC
813 ok = get_trust_pw_hash(domain->name,
814 current_nt_hash.hash,
819 * If get_trust_pw_hash() fails, then try and
820 * fetch the password from the more recent of
821 * secrets.{ldb,tdb} using the
822 * pdb_get_trust_credentials()
824 ok = migrate_secrets_tdb_to_ldb(domain);
827 DEBUG(0, ("Failed to migrate our own, "
828 "local AD domain join password for "
829 "winbindd's internal use into "
833 ok = get_trust_pw_hash(domain->name,
834 current_nt_hash.hash,
838 DEBUG(0, ("Failed to find our our own, just "
839 "written local AD domain join "
840 "password for winbindd's internal "
841 "use in secrets.tdb\n"));
845 if (sec_chan_type == SEC_CHAN_RODC) {
850 (void)add_trusted_domain(get_global_sam_name(), NULL,
851 get_global_sam_sid());
853 /* Add ourselves as the first entry. */
855 if ( role == ROLE_DOMAIN_MEMBER ) {
856 struct winbindd_domain *domain;
857 struct dom_sid our_sid;
859 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
860 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
864 domain = add_trusted_domain(lp_workgroup(), lp_realm(),
867 /* Even in the parent winbindd we'll need to
868 talk to the DC, so try and see if we can
869 contact it. Theoretically this isn't neccessary
870 as the init_dc_connection() in init_child_recv()
871 will do this, but we can start detecting the DC
873 set_domain_online_request(domain);
877 status = imessaging_register(winbind_imessaging_context(), NULL,
878 MSG_WINBIND_NEW_TRUSTED_DOMAIN,
879 wb_imsg_new_trusted_domain);
880 if (!NT_STATUS_IS_OK(status)) {
881 DEBUG(0, ("imessaging_register(MSG_WINBIND_NEW_TRUSTED_DOMAIN) - %s\n",
890 * Given a domain name, return the struct winbindd domain info for it
892 * @note Do *not* pass lp_workgroup() to this function. domain_list
893 * may modify it's value, and free that pointer. Instead, our local
894 * domain may be found by calling find_our_domain().
898 * @return The domain structure for the named domain, if it is working.
901 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
903 struct winbindd_domain *domain;
905 /* Search through list */
907 for (domain = domain_list(); domain != NULL; domain = domain->next) {
908 if (strequal(domain_name, domain->name) ||
909 (domain->alt_name != NULL &&
910 strequal(domain_name, domain->alt_name))) {
920 struct winbindd_domain *find_domain_from_name(const char *domain_name)
922 struct winbindd_domain *domain;
924 domain = find_domain_from_name_noinit(domain_name);
929 if (!domain->initialized)
930 init_dc_connection(domain, false);
935 /* Given a domain sid, return the struct winbindd domain info for it */
937 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
939 struct winbindd_domain *domain;
941 /* Search through list */
943 for (domain = domain_list(); domain != NULL; domain = domain->next) {
944 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
953 /* Given a domain sid, return the struct winbindd domain info for it */
955 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
957 struct winbindd_domain *domain;
959 domain = find_domain_from_sid_noinit(sid);
964 if (!domain->initialized)
965 init_dc_connection(domain, false);
970 struct winbindd_domain *find_our_domain(void)
972 struct winbindd_domain *domain;
974 /* Search through list */
976 for (domain = domain_list(); domain != NULL; domain = domain->next) {
981 smb_panic("Could not find our domain");
985 struct winbindd_domain *find_root_domain(void)
987 struct winbindd_domain *ours = find_our_domain();
989 if (ours->forest_name == NULL) {
993 return find_domain_from_name( ours->forest_name );
996 struct winbindd_domain *find_builtin_domain(void)
998 struct winbindd_domain *domain;
1000 domain = find_domain_from_sid(&global_sid_Builtin);
1001 if (domain == NULL) {
1002 smb_panic("Could not find BUILTIN domain");
1008 /* Find the appropriate domain to lookup a name or SID */
1010 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
1012 /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
1014 if ( sid_check_is_in_unix_groups(sid) ||
1015 sid_check_is_unix_groups(sid) ||
1016 sid_check_is_in_unix_users(sid) ||
1017 sid_check_is_unix_users(sid) )
1019 return find_domain_from_sid(get_global_sam_sid());
1022 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
1023 * one to contact the external DC's. On member servers the internal
1024 * domains are different: These are part of the local SAM. */
1026 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid)));
1028 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
1029 DEBUG(10, ("calling find_domain_from_sid\n"));
1030 return find_domain_from_sid(sid);
1033 /* On a member server a query for SID or name can always go to our
1036 DEBUG(10, ("calling find_our_domain\n"));
1037 return find_our_domain();
1040 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1042 if ( strequal(domain_name, unix_users_domain_name() ) ||
1043 strequal(domain_name, unix_groups_domain_name() ) )
1046 * The "Unix User" and "Unix Group" domain our handled by
1049 return find_domain_from_name_noinit( get_global_sam_name() );
1052 if (IS_DC || strequal(domain_name, "BUILTIN") ||
1053 strequal(domain_name, get_global_sam_name()))
1054 return find_domain_from_name_noinit(domain_name);
1057 return find_our_domain();
1060 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1062 static bool assume_domain(const char *domain)
1064 /* never assume the domain on a standalone server */
1066 if ( lp_server_role() == ROLE_STANDALONE )
1069 /* domain member servers may possibly assume for the domain name */
1071 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1072 if ( !strequal(lp_workgroup(), domain) )
1075 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1079 /* only left with a domain controller */
1081 if ( strequal(get_global_sam_name(), domain) ) {
1088 /* Parse a string of the form DOMAIN\user into a domain and a user */
1090 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1092 char *p = strchr(domuser,*lp_winbind_separator());
1095 fstrcpy(user, domuser);
1096 p = strchr(domuser, '@');
1098 if ( assume_domain(lp_workgroup()) && p == NULL) {
1099 fstrcpy(domain, lp_workgroup());
1100 } else if (p != NULL) {
1101 fstrcpy(domain, p + 1);
1102 user[PTR_DIFF(p, domuser)] = 0;
1108 fstrcpy(domain, domuser);
1109 domain[PTR_DIFF(p, domuser)] = 0;
1112 return strupper_m(domain);
1115 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1116 char **domain, char **user)
1118 fstring fstr_domain, fstr_user;
1119 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1122 *domain = talloc_strdup(mem_ctx, fstr_domain);
1123 *user = talloc_strdup(mem_ctx, fstr_user);
1124 return ((*domain != NULL) && (*user != NULL));
1127 /* Ensure an incoming username from NSS is fully qualified. Replace the
1128 incoming fstring with DOMAIN <separator> user. Returns the same
1129 values as parse_domain_user() but also replaces the incoming username.
1130 Used to ensure all names are fully qualified within winbindd.
1131 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1132 The protocol definitions of auth_crap, chng_pswd_auth_crap
1133 really should be changed to use this instead of doing things
1136 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1138 if (!parse_domain_user(username_inout, domain, user)) {
1141 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1142 domain, *lp_winbind_separator(),
1148 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1149 'winbind separator' options.
1151 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1154 If we are a PDC or BDC, and this is for our domain, do likewise.
1156 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
1157 username is then unqualified in unix
1159 On an AD DC we always fill DOMAIN\\USERNAME.
1161 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1163 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1167 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1171 fstrcpy(tmp_user, user);
1172 (void)strlower_m(tmp_user);
1174 if (can_assume && assume_domain(domain)) {
1175 strlcpy(name, tmp_user, sizeof(fstring));
1177 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1178 domain, *lp_winbind_separator(),
1184 * talloc version of fill_domain_username()
1185 * return NULL on talloc failure.
1187 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1192 char *tmp_user, *name;
1194 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1198 tmp_user = talloc_strdup(mem_ctx, user);
1199 if (!strlower_m(tmp_user)) {
1200 TALLOC_FREE(tmp_user);
1204 if (can_assume && assume_domain(domain)) {
1207 name = talloc_asprintf(mem_ctx, "%s%c%s",
1209 *lp_winbind_separator(),
1211 TALLOC_FREE(tmp_user);
1218 * Client list accessor functions
1221 static struct winbindd_cli_state *_client_list;
1222 static int _num_clients;
1224 /* Return list of all connected clients */
1226 struct winbindd_cli_state *winbindd_client_list(void)
1228 return _client_list;
1231 /* Return list-tail of all connected clients */
1233 struct winbindd_cli_state *winbindd_client_list_tail(void)
1235 return DLIST_TAIL(_client_list);
1238 /* Return previous (read:newer) client in list */
1240 struct winbindd_cli_state *
1241 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1243 return DLIST_PREV(cli);
1246 /* Add a connection to the list */
1248 void winbindd_add_client(struct winbindd_cli_state *cli)
1250 cli->last_access = time(NULL);
1251 DLIST_ADD(_client_list, cli);
1255 /* Remove a client from the list */
1257 void winbindd_remove_client(struct winbindd_cli_state *cli)
1259 DLIST_REMOVE(_client_list, cli);
1263 /* Move a client to head or list */
1265 void winbindd_promote_client(struct winbindd_cli_state *cli)
1267 cli->last_access = time(NULL);
1268 DLIST_PROMOTE(_client_list, cli);
1271 /* Return number of open clients */
1273 int winbindd_num_clients(void)
1275 return _num_clients;
1278 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1279 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;
1298 if (info3->base.groups.count == 0) {
1300 return NT_STATUS_UNSUCCESSFUL;
1304 * Before bug #7843 the "Domain Local" groups were added with a
1305 * lookupuseraliases call, but this isn't done anymore for our domain
1306 * so we need to resolve resource groups here.
1308 * When to use Resource Groups:
1309 * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1311 status = sid_array_from_info3(mem_ctx, info3,
1316 if (!NT_STATUS_IS_OK(status)) {
1322 *p_num_groups = num_groups;
1323 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1325 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1330 /*********************************************************************
1331 We use this to remove spaces from user and group names
1332 ********************************************************************/
1334 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1335 struct winbindd_domain *domain,
1341 if (!name || !normalized) {
1342 return NT_STATUS_INVALID_PARAMETER;
1345 if (!lp_winbind_normalize_names()) {
1346 return NT_STATUS_PROCEDURE_NOT_FOUND;
1349 /* Alias support and whitespace replacement are mutually
1352 nt_status = resolve_username_to_alias(mem_ctx, domain,
1354 if (NT_STATUS_IS_OK(nt_status)) {
1355 /* special return code to let the caller know we
1356 mapped to an alias */
1357 return NT_STATUS_FILE_RENAMED;
1360 /* check for an unreachable domain */
1362 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1363 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1365 set_domain_offline(domain);
1369 /* deal with whitespace */
1371 *normalized = talloc_strdup(mem_ctx, name);
1372 if (!(*normalized)) {
1373 return NT_STATUS_NO_MEMORY;
1376 all_string_sub( *normalized, " ", "_", 0 );
1378 return NT_STATUS_OK;
1381 /*********************************************************************
1382 We use this to do the inverse of normalize_name_map()
1383 ********************************************************************/
1385 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1390 struct winbindd_domain *domain = find_our_domain();
1392 if (!name || !normalized) {
1393 return NT_STATUS_INVALID_PARAMETER;
1396 if (!lp_winbind_normalize_names()) {
1397 return NT_STATUS_PROCEDURE_NOT_FOUND;
1400 /* Alias support and whitespace replacement are mutally
1403 /* When mapping from an alias to a username, we don't know the
1404 domain. But we only need a domain structure to cache
1405 a successful lookup , so just our own domain structure for
1408 nt_status = resolve_alias_to_username(mem_ctx, domain,
1410 if (NT_STATUS_IS_OK(nt_status)) {
1411 /* Special return code to let the caller know we mapped
1413 return NT_STATUS_FILE_RENAMED;
1416 /* check for an unreachable domain */
1418 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1419 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1421 set_domain_offline(domain);
1425 /* deal with whitespace */
1427 *normalized = talloc_strdup(mem_ctx, name);
1428 if (!(*normalized)) {
1429 return NT_STATUS_NO_MEMORY;
1432 all_string_sub(*normalized, "_", " ", 0);
1434 return NT_STATUS_OK;
1437 /*********************************************************************
1438 ********************************************************************/
1440 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1442 struct winbindd_tdc_domain *tdc = NULL;
1443 TALLOC_CTX *frame = talloc_stackframe();
1446 /* We can contact the domain if it is our primary domain */
1448 if (domain->primary) {
1453 /* Trust the TDC cache and not the winbindd_domain flags */
1455 if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1456 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1462 /* Can always contact a domain that is in out forest */
1464 if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1470 * On a _member_ server, we cannot contact the domain if it
1471 * is running AD and we have no inbound trust.
1475 domain->active_directory &&
1476 ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1478 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1479 "and we have no inbound trust.\n", domain->name));
1483 /* Assume everything else is ok (probably not true but what
1489 talloc_destroy(frame);
1494 /*********************************************************************
1495 ********************************************************************/
1497 bool winbindd_internal_child(struct winbindd_child *child)
1499 if ((child == idmap_child()) || (child == locator_child())) {
1506 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1508 /*********************************************************************
1509 ********************************************************************/
1511 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1514 char addr[INET6_ADDRSTRLEN];
1515 const char *kdc = NULL;
1518 if (!domain || !domain->alt_name || !*domain->alt_name) {
1522 if (domain->initialized && !domain->active_directory) {
1523 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1528 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1531 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1533 kdc = domain->dcname;
1536 if (!kdc || !*kdc) {
1537 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1542 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1543 domain->alt_name) == -1) {
1547 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1550 setenv(var, kdc, 1);
1554 /*********************************************************************
1555 ********************************************************************/
1557 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1559 struct winbindd_domain *our_dom = find_our_domain();
1561 winbindd_set_locator_kdc_env(domain);
1563 if (domain != our_dom) {
1564 winbindd_set_locator_kdc_env(our_dom);
1568 /*********************************************************************
1569 ********************************************************************/
1571 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1575 if (!domain || !domain->alt_name || !*domain->alt_name) {
1579 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1580 domain->alt_name) == -1) {
1589 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1594 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1599 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1601 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1603 resp->data.auth.nt_status = NT_STATUS_V(result);
1604 fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1606 /* we might have given a more useful error above */
1607 if (*resp->data.auth.error_string == '\0')
1608 fstrcpy(resp->data.auth.error_string,
1609 get_friendly_nt_error_msg(result));
1610 resp->data.auth.pam_error = nt_status_to_pam(result);
1613 bool is_domain_offline(const struct winbindd_domain *domain)
1615 if (!lp_winbind_offline_logon()) {
1618 if (get_global_winbindd_state_offline()) {
1621 return !domain->online;
1624 bool is_domain_online(const struct winbindd_domain *domain)
1626 return !is_domain_offline(domain);
1630 * Parse an char array into a list of sids.
1632 * The input sidstr should consist of 0-terminated strings
1633 * representing sids, separated by newline characters '\n'.
1634 * The list is terminated by an empty string, i.e.
1635 * character '\0' directly following a character '\n'
1636 * (or '\0' right at the start of sidstr).
1638 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
1639 struct dom_sid **sids, uint32_t *num_sids)
1647 while (p[0] != '\0') {
1649 const char *q = NULL;
1651 if (!dom_sid_parse_endp(p, &sid, &q)) {
1652 DEBUG(1, ("Could not parse sid %s\n", p));
1655 if ((q == NULL) || (q[0] != '\n')) {
1656 DEBUG(1, ("Got invalid sidstr: %s\n", p));
1659 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
1669 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
1670 struct unixid **pxids, uint32_t *pnum_xids)
1673 struct unixid *xids = NULL;
1674 uint32_t num_xids = 0;
1681 while (p[0] != '\0') {
1684 unsigned long long id;
1689 xid = (struct unixid) { .type = ID_TYPE_UID };
1692 xid = (struct unixid) { .type = ID_TYPE_GID };
1700 id = strtoull(p, &endp, 10);
1701 if ((id == ULLONG_MAX) && (errno == ERANGE)) {
1704 if (*endp != '\n') {
1710 if ((unsigned long long)xid.id != id) {
1714 tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
1720 xids[num_xids] = xid;
1725 *pnum_xids = num_xids;