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
40 * @file winbindd_util.c
42 * Winbind daemon for NT domain authentication nss module.
46 /* The list of trusted domains. Note that the list can be deleted and
47 recreated using the init_domain_list() function so pointers to
48 individual winbindd_domain structures cannot be made. Keep a copy of
49 the domain name instead. */
51 static struct winbindd_domain *_domain_list = NULL;
53 struct winbindd_domain *domain_list(void)
57 if ((!_domain_list) && (!init_domain_list())) {
58 smb_panic("Init_domain_list failed");
64 /* Free all entries in the trusted domain list */
66 static void free_domain_list(void)
68 struct winbindd_domain *domain = _domain_list;
71 struct winbindd_domain *next = domain->next;
73 DLIST_REMOVE(_domain_list, domain);
80 * Iterator for winbindd's domain list.
81 * To be used (e.g.) in tevent based loops.
83 struct winbindd_domain *wb_next_domain(struct winbindd_domain *domain)
86 domain = domain_list();
88 domain = domain->next;
91 if ((domain != NULL) &&
92 (lp_server_role() != ROLE_ACTIVE_DIRECTORY_DC) &&
93 sid_check_is_our_sam(&domain->sid))
95 domain = domain->next;
101 static bool is_internal_domain(const struct dom_sid *sid)
106 return (sid_check_is_our_sam(sid) || sid_check_is_builtin(sid));
109 static bool is_in_internal_domain(const struct dom_sid *sid)
114 return (sid_check_is_in_our_sam(sid) || sid_check_is_in_builtin(sid));
118 /* Add a trusted domain to our list of domains.
119 If the domain already exists in the list,
120 return it and don't re-initialize. */
122 static NTSTATUS add_trusted_domain(const char *domain_name,
123 const char *dns_name,
124 const struct dom_sid *sid,
126 uint32_t trust_flags,
127 uint32_t trust_attribs,
128 enum netr_SchannelType secure_channel_type,
129 struct winbindd_domain **_d)
131 struct winbindd_domain *domain = NULL;
132 const char **ignored_domains = NULL;
133 const char **dom = NULL;
134 int role = lp_server_role();
136 if (is_null_sid(sid)) {
137 DBG_ERR("Got null SID for domain [%s]\n", domain_name);
138 return NT_STATUS_INVALID_PARAMETER;
141 ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
142 for (dom=ignored_domains; dom && *dom; dom++) {
143 if (gen_fnmatch(*dom, domain_name) == 0) {
144 DEBUG(2,("Ignoring domain '%s'\n", domain_name));
145 return NT_STATUS_NO_SUCH_DOMAIN;
150 * We can't call domain_list() as this function is called from
151 * init_domain_list() and we'll get stuck in a loop.
153 for (domain = _domain_list; domain; domain = domain->next) {
154 if (strequal(domain_name, domain->name)) {
159 if (domain != NULL) {
160 struct winbindd_domain *check_domain = NULL;
162 for (check_domain = _domain_list;
163 check_domain != NULL;
164 check_domain = check_domain->next)
166 if (check_domain == domain) {
170 if (dom_sid_equal(&check_domain->sid, sid)) {
175 if (check_domain != NULL) {
176 DBG_ERR("SID [%s] already used by domain [%s], "
178 sid_string_dbg(sid), check_domain->name,
180 return NT_STATUS_INVALID_PARAMETER;
184 if ((domain != NULL) && (dns_name != NULL)) {
185 struct winbindd_domain *check_domain = NULL;
187 for (check_domain = _domain_list;
188 check_domain != NULL;
189 check_domain = check_domain->next)
191 if (check_domain == domain) {
195 if (strequal(check_domain->alt_name, dns_name)) {
200 if (check_domain != NULL) {
201 DBG_ERR("DNS name [%s] used by domain [%s], "
203 dns_name, check_domain->name,
205 return NT_STATUS_INVALID_PARAMETER;
209 if (domain != NULL) {
214 /* Create new domain entry */
215 domain = talloc_zero(NULL, struct winbindd_domain);
216 if (domain == NULL) {
217 return NT_STATUS_NO_MEMORY;
220 domain->children = talloc_zero_array(domain,
221 struct winbindd_child,
222 lp_winbind_max_domain_connections());
223 if (domain->children == NULL) {
225 return NT_STATUS_NO_MEMORY;
228 domain->name = talloc_strdup(domain, domain_name);
229 if (domain->name == NULL) {
231 return NT_STATUS_NO_MEMORY;
234 if (dns_name != NULL) {
235 domain->alt_name = talloc_strdup(domain, dns_name);
236 if (domain->alt_name == NULL) {
238 return NT_STATUS_NO_MEMORY;
242 domain->backend = NULL;
243 domain->internal = is_internal_domain(sid);
244 domain->secure_channel_type = secure_channel_type;
245 domain->sequence_number = DOM_SEQUENCE_NONE;
246 domain->last_seq_check = 0;
247 domain->initialized = false;
248 domain->online = is_internal_domain(sid);
249 domain->check_online_timeout = 0;
250 domain->dc_probe_pid = (pid_t)-1;
251 domain->domain_flags = trust_flags;
252 domain->domain_type = trust_type;
253 domain->domain_trust_attribs = trust_attribs;
254 domain->secure_channel_type = secure_channel_type;
255 sid_copy(&domain->sid, sid);
257 /* Is this our primary domain ? */
258 if (role == ROLE_DOMAIN_MEMBER) {
259 domain->primary = strequal(domain_name, lp_workgroup());
261 domain->primary = strequal(domain_name, get_global_sam_name());
264 if (domain->primary) {
265 if (role == ROLE_ACTIVE_DIRECTORY_DC) {
266 domain->active_directory = true;
268 if (lp_security() == SEC_ADS) {
269 domain->active_directory = true;
271 } else if (!domain->internal) {
272 if (domain->domain_type == LSA_TRUST_TYPE_UPLEVEL) {
273 domain->active_directory = true;
277 /* Link to domain list */
278 DLIST_ADD_END(_domain_list, domain);
280 wcache_tdc_add_domain( domain );
282 setup_domain_child(domain);
284 DBG_NOTICE("Added domain [%s] [%s] [%s]\n",
285 domain->name, domain->alt_name,
286 sid_string_dbg(&domain->sid));
292 bool domain_is_forest_root(const struct winbindd_domain *domain)
294 const uint32_t fr_flags =
295 (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
297 return ((domain->domain_flags & fr_flags) == fr_flags);
300 /********************************************************************
301 rescan our domains looking for new trusted domains
302 ********************************************************************/
304 struct trustdom_state {
305 struct winbindd_domain *domain;
306 struct winbindd_request request;
309 static void trustdom_list_done(struct tevent_req *req);
310 static void rescan_forest_root_trusts( void );
311 static void rescan_forest_trusts( void );
313 static void add_trusted_domains( struct winbindd_domain *domain )
315 struct trustdom_state *state;
316 struct tevent_req *req;
318 state = talloc_zero(NULL, struct trustdom_state);
320 DEBUG(0, ("talloc failed\n"));
323 state->domain = domain;
325 state->request.length = sizeof(state->request);
326 state->request.cmd = WINBINDD_LIST_TRUSTDOM;
328 req = wb_domain_request_send(state, server_event_context(),
329 domain, &state->request);
331 DEBUG(1, ("wb_domain_request_send failed\n"));
335 tevent_req_set_callback(req, trustdom_list_done, state);
338 static void trustdom_list_done(struct tevent_req *req)
340 struct trustdom_state *state = tevent_req_callback_data(
341 req, struct trustdom_state);
342 struct winbindd_response *response;
346 bool within_forest = false;
350 * Only when we enumerate our primary domain
351 * or our forest root domain, we should keep
352 * the NETR_TRUST_FLAG_IN_FOREST flag, in
353 * all other cases we need to clear it as the domain
354 * is not part of our forest.
356 if (state->domain->primary) {
357 within_forest = true;
358 } else if (domain_is_forest_root(state->domain)) {
359 within_forest = true;
362 res = wb_domain_request_recv(req, state, &response, &err);
363 if ((res == -1) || (response->result != WINBINDD_OK)) {
364 DBG_WARNING("Could not receive trusts for domain %s\n",
365 state->domain->name);
370 if (response->length < sizeof(struct winbindd_response)) {
371 DBG_ERR("ill-formed trustdom response - short length\n");
376 extra_len = response->length - sizeof(struct winbindd_response);
378 p = (char *)response->extra_data.data;
380 while ((p - (char *)response->extra_data.data) < extra_len) {
381 struct winbindd_domain *domain = NULL;
382 char *name, *q, *sidstr, *alt_name;
385 uint32_t trust_attribs;
386 uint32_t trust_flags;
388 DBG_DEBUG("parsing response line '%s'\n", p);
392 alt_name = strchr(p, '\\');
393 if (alt_name == NULL) {
394 DBG_ERR("Got invalid trustdom response\n");
401 sidstr = strchr(alt_name, '\\');
402 if (sidstr == NULL) {
403 DBG_ERR("Got invalid trustdom response\n");
410 /* use the real alt_name if we have one, else pass in NULL */
411 if (strequal(alt_name, "(null)")) {
415 q = strtok(sidstr, "\\");
417 DBG_ERR("Got invalid trustdom response\n");
421 if (!string_to_sid(&sid, sidstr)) {
422 DEBUG(0, ("Got invalid trustdom response\n"));
426 q = strtok(NULL, "\\");
428 DBG_ERR("Got invalid trustdom response\n");
432 trust_flags = (uint32_t)strtoul(q, NULL, 10);
434 q = strtok(NULL, "\\");
436 DBG_ERR("Got invalid trustdom response\n");
440 trust_type = (uint32_t)strtoul(q, NULL, 10);
442 q = strtok(NULL, "\n");
444 DBG_ERR("Got invalid trustdom response\n");
448 trust_attribs = (uint32_t)strtoul(q, NULL, 10);
450 if (!within_forest) {
451 trust_flags &= ~NETR_TRUST_FLAG_IN_FOREST;
454 if (!state->domain->primary) {
455 trust_flags &= ~NETR_TRUST_FLAG_PRIMARY;
459 * We always call add_trusted_domain() cause on an existing
460 * domain structure, it will update the SID if necessary.
461 * This is important because we need the SID for sibling
464 status = add_trusted_domain(name,
472 if (!NT_STATUS_IS_OK(status) &&
473 !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
475 DBG_NOTICE("add_trusted_domain returned %s\n",
480 p = q + strlen(q) + 1;
484 Cases to consider when scanning trusts:
485 (a) we are calling from a child domain (primary && !forest_root)
486 (b) we are calling from the root of the forest (primary && forest_root)
487 (c) we are calling from a trusted forest domain (!primary
491 if (state->domain->primary) {
492 /* If this is our primary domain and we are not in the
493 forest root, we have to scan the root trusts first */
495 if (!domain_is_forest_root(state->domain))
496 rescan_forest_root_trusts();
498 rescan_forest_trusts();
500 } else if (domain_is_forest_root(state->domain)) {
501 /* Once we have done root forest trust search, we can
502 go on to search the trusted forests */
504 rescan_forest_trusts();
512 /********************************************************************
513 Scan the trusts of our forest root
514 ********************************************************************/
516 static void rescan_forest_root_trusts( void )
518 struct winbindd_tdc_domain *dom_list = NULL;
519 size_t num_trusts = 0;
523 /* The only transitive trusts supported by Windows 2003 AD are
524 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
525 first two are handled in forest and listed by
526 DsEnumerateDomainTrusts(). Forest trusts are not so we
527 have to do that ourselves. */
529 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
532 for ( i=0; i<num_trusts; i++ ) {
533 struct winbindd_domain *d = NULL;
535 /* Find the forest root. Don't necessarily trust
536 the domain_list() as our primary domain may not
537 have been initialized. */
539 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
543 /* Here's the forest root */
545 d = find_domain_from_name_noinit( dom_list[i].domain_name );
547 status = add_trusted_domain(dom_list[i].domain_name,
548 dom_list[i].dns_name,
550 dom_list[i].trust_type,
551 dom_list[i].trust_flags,
552 dom_list[i].trust_attribs,
556 if (!NT_STATUS_IS_OK(status) &&
557 NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
559 DBG_ERR("add_trusted_domain returned %s\n",
568 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
569 "for domain tree root %s (%s)\n",
570 d->name, d->alt_name ));
572 d->domain_flags = dom_list[i].trust_flags;
573 d->domain_type = dom_list[i].trust_type;
574 d->domain_trust_attribs = dom_list[i].trust_attribs;
576 add_trusted_domains( d );
581 TALLOC_FREE( dom_list );
586 /********************************************************************
587 scan the transitive forest trusts (not our own)
588 ********************************************************************/
591 static void rescan_forest_trusts( void )
593 struct winbindd_domain *d = NULL;
594 struct winbindd_tdc_domain *dom_list = NULL;
595 size_t num_trusts = 0;
599 /* The only transitive trusts supported by Windows 2003 AD are
600 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
601 first two are handled in forest and listed by
602 DsEnumerateDomainTrusts(). Forest trusts are not so we
603 have to do that ourselves. */
605 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
608 for ( i=0; i<num_trusts; i++ ) {
609 uint32_t flags = dom_list[i].trust_flags;
610 uint32_t type = dom_list[i].trust_type;
611 uint32_t attribs = dom_list[i].trust_attribs;
613 d = find_domain_from_name_noinit( dom_list[i].domain_name );
615 /* ignore our primary and internal domains */
617 if ( d && (d->internal || d->primary ) )
620 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
621 (type == LSA_TRUST_TYPE_UPLEVEL) &&
622 (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
624 /* add the trusted domain if we don't know
628 status = add_trusted_domain(
629 dom_list[i].domain_name,
630 dom_list[i].dns_name,
637 if (!NT_STATUS_IS_OK(status) &&
638 NT_STATUS_EQUAL(status,
639 NT_STATUS_NO_SUCH_DOMAIN))
641 DBG_ERR("add_trusted_domain: %s\n",
651 DEBUG(10,("Following trust path for domain %s (%s)\n",
652 d->name, d->alt_name ));
653 add_trusted_domains( d );
657 TALLOC_FREE( dom_list );
662 /*********************************************************************
663 The process of updating the trusted domain list is a three step
666 (b) ask the root domain in our forest
667 (c) ask the a DC in any Win2003 trusted forests
668 *********************************************************************/
670 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
671 struct timeval now, void *private_data)
675 /* I use to clear the cache here and start over but that
676 caused problems in child processes that needed the
677 trust dom list early on. Removing it means we
678 could have some trusted domains listed that have been
679 removed from our primary domain's DC until a full
680 restart. This should be ok since I think this is what
681 Windows does as well. */
683 /* this will only add new domains we didn't already know about
684 in the domain_list()*/
686 add_trusted_domains( find_our_domain() );
688 te = tevent_add_timer(
689 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
690 rescan_trusted_domains, NULL);
692 * If te == NULL, there's not much we can do here. Don't fail, the
693 * only thing we miss is new trusted domains.
699 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
700 struct winbindd_cli_state *state)
702 /* Ensure null termination */
703 state->request->domain_name
704 [sizeof(state->request->domain_name)-1]='\0';
705 state->request->data.init_conn.dcname
706 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
708 if (strlen(state->request->data.init_conn.dcname) > 0) {
709 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
712 init_dc_connection(domain, false);
714 if (!domain->initialized) {
715 /* If we return error here we can't do any cached authentication,
716 but we may be in disconnected mode and can't initialize correctly.
717 Do what the previous code did and just return without initialization,
718 once we go online we'll re-initialize.
720 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
721 "online = %d\n", domain->name, (int)domain->online ));
724 fstrcpy(state->response->data.domain_info.name, domain->name);
725 fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
726 sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
728 state->response->data.domain_info.native_mode
729 = domain->native_mode;
730 state->response->data.domain_info.active_directory
731 = domain->active_directory;
732 state->response->data.domain_info.primary
738 static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
741 struct server_id server_id,
744 TALLOC_CTX *frame = talloc_stackframe();
745 enum netr_SchannelType secure_channel_type = SEC_CHAN_DOMAIN;
746 struct lsa_TrustDomainInfoInfoEx info;
747 enum ndr_err_code ndr_err;
748 struct winbindd_domain *d = NULL;
749 uint32_t trust_flags = 0;
752 DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
759 ndr_err = ndr_pull_struct_blob_all(data, frame, &info,
760 (ndr_pull_flags_fn_t)ndr_pull_lsa_TrustDomainInfoInfoEx);
761 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
766 d = find_domain_from_name_noinit(info.netbios_name.string);
772 if (info.trust_type == LSA_TRUST_TYPE_UPLEVEL) {
773 secure_channel_type = SEC_CHAN_DNS_DOMAIN;
775 if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
776 trust_flags |= NETR_TRUST_FLAG_INBOUND;
778 if (info.trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
779 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
781 if (info.trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
782 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
785 status = add_trusted_domain(info.netbios_name.string,
786 info.domain_name.string,
790 info.trust_attributes,
793 if (!NT_STATUS_IS_OK(status) &&
794 !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
796 DBG_NOTICE("add_trusted_domain returned %s\n",
805 * We did not get the secret when we queried secrets.tdb, so read it
806 * from secrets.tdb and re-sync the databases
808 static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
811 struct cli_credentials *creds;
812 NTSTATUS can_migrate = pdb_get_trust_credentials(domain->name,
813 NULL, domain, &creds);
814 if (!NT_STATUS_IS_OK(can_migrate)) {
815 DEBUG(0, ("Failed to fetch our own, local AD domain join "
816 "password for winbindd's internal use, both from "
817 "secrets.tdb and secrets.ldb: %s\n",
818 nt_errstr(can_migrate)));
823 * NOTE: It is very unlikely we end up here if there is an
824 * oldpass, because a new password is created at
825 * classicupgrade, so this is not a concern.
827 ok = secrets_store_machine_pw_sync(cli_credentials_get_password(creds),
829 cli_credentials_get_domain(creds),
830 cli_credentials_get_realm(creds),
831 cli_credentials_get_salt_principal(creds),
832 0, /* Supported enc types, unused */
834 cli_credentials_get_password_last_changed_time(creds),
835 cli_credentials_get_secure_channel_type(creds),
836 false /* do_delete: Do not delete */);
839 DEBUG(0, ("Failed to write our our own, "
840 "local AD domain join password for "
841 "winbindd's internal use into secrets.tdb\n"));
847 /* Look up global info for the winbind daemon */
848 bool init_domain_list(void)
850 int role = lp_server_role();
851 struct pdb_domain_info *pdb_domain_info = NULL;
852 struct winbindd_domain *domain = NULL;
855 /* Free existing list */
860 status = add_trusted_domain("BUILTIN",
863 LSA_TRUST_TYPE_DOWNLEVEL,
865 0, /* trust_attribs */
868 if (!NT_STATUS_IS_OK(status)) {
869 DBG_ERR("add_trusted_domain BUILTIN returned %s\n",
877 * In case the passdb backend is passdb_dsdb the domain SID comes from
878 * dsdb, not from secrets.tdb. As we use the domain SID in various
879 * places, we must ensure the domain SID is migrated from dsdb to
880 * secrets.tdb before get_global_sam_sid() is called the first time.
882 * The migration is done as part of the passdb_dsdb initialisation,
883 * calling pdb_get_domain_info() triggers it.
885 pdb_domain_info = pdb_get_domain_info(talloc_tos());
887 if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
888 uint32_t trust_flags;
890 enum netr_SchannelType sec_chan_type;
891 const char *account_name;
892 struct samr_Password current_nt_hash;
895 if (pdb_domain_info == NULL) {
896 DEBUG(0, ("Failed to fetch our own, local AD "
897 "domain info from sam.ldb\n"));
901 trust_flags = NETR_TRUST_FLAG_PRIMARY;
902 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
903 trust_flags |= NETR_TRUST_FLAG_NATIVE;
904 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
906 is_root = strequal(pdb_domain_info->dns_domain,
907 pdb_domain_info->dns_forest);
909 trust_flags |= NETR_TRUST_FLAG_TREEROOT;
912 status = add_trusted_domain(pdb_domain_info->name,
913 pdb_domain_info->dns_domain,
914 &pdb_domain_info->sid,
915 LSA_TRUST_TYPE_UPLEVEL,
917 LSA_TRUST_ATTRIBUTE_WITHIN_FOREST,
920 TALLOC_FREE(pdb_domain_info);
921 if (!NT_STATUS_IS_OK(status)) {
922 DBG_ERR("Failed to add our own, local AD "
923 "domain to winbindd's internal list\n");
928 * We need to call this to find out if we are an RODC
930 ok = get_trust_pw_hash(domain->name,
931 current_nt_hash.hash,
936 * If get_trust_pw_hash() fails, then try and
937 * fetch the password from the more recent of
938 * secrets.{ldb,tdb} using the
939 * pdb_get_trust_credentials()
941 ok = migrate_secrets_tdb_to_ldb(domain);
944 DEBUG(0, ("Failed to migrate our own, "
945 "local AD domain join password for "
946 "winbindd's internal use into "
950 ok = get_trust_pw_hash(domain->name,
951 current_nt_hash.hash,
955 DEBUG(0, ("Failed to find our our own, just "
956 "written local AD domain join "
957 "password for winbindd's internal "
958 "use in secrets.tdb\n"));
963 domain->secure_channel_type = sec_chan_type;
964 if (sec_chan_type == SEC_CHAN_RODC) {
969 uint32_t trust_flags;
970 enum netr_SchannelType secure_channel_type;
972 trust_flags = NETR_TRUST_FLAG_OUTBOUND;
973 if (role != ROLE_DOMAIN_MEMBER) {
974 trust_flags |= NETR_TRUST_FLAG_PRIMARY;
977 if (role > ROLE_DOMAIN_MEMBER) {
978 secure_channel_type = SEC_CHAN_BDC;
980 secure_channel_type = SEC_CHAN_LOCAL;
983 status = add_trusted_domain(get_global_sam_name(),
985 get_global_sam_sid(),
986 LSA_TRUST_TYPE_DOWNLEVEL,
988 0, /* trust_attribs */
991 if (!NT_STATUS_IS_OK(status)) {
992 DBG_ERR("Failed to add local SAM to "
993 "domain to winbindd's internal list\n");
997 /* Add ourselves as the first entry. */
999 if ( role == ROLE_DOMAIN_MEMBER ) {
1000 struct dom_sid our_sid;
1001 uint32_t trust_type;
1003 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
1004 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
1008 if (lp_realm() != NULL) {
1009 trust_type = LSA_TRUST_TYPE_UPLEVEL;
1011 trust_type = LSA_TRUST_TYPE_DOWNLEVEL;
1014 status = add_trusted_domain(lp_workgroup(),
1018 NETR_TRUST_FLAG_PRIMARY|
1019 NETR_TRUST_FLAG_OUTBOUND,
1020 0, /* trust_attribs */
1023 if (!NT_STATUS_IS_OK(status)) {
1024 DBG_ERR("Failed to add local SAM to "
1025 "domain to winbindd's internal list\n");
1028 /* Even in the parent winbindd we'll need to
1029 talk to the DC, so try and see if we can
1030 contact it. Theoretically this isn't neccessary
1031 as the init_dc_connection() in init_child_recv()
1032 will do this, but we can start detecting the DC
1034 set_domain_online_request(domain);
1038 status = imessaging_register(winbind_imessaging_context(), NULL,
1039 MSG_WINBIND_NEW_TRUSTED_DOMAIN,
1040 wb_imsg_new_trusted_domain);
1041 if (!NT_STATUS_IS_OK(status)) {
1042 DEBUG(0, ("imessaging_register(MSG_WINBIND_NEW_TRUSTED_DOMAIN) - %s\n",
1043 nt_errstr(status)));
1051 * Given a domain name, return the struct winbindd domain info for it
1053 * @note Do *not* pass lp_workgroup() to this function. domain_list
1054 * may modify it's value, and free that pointer. Instead, our local
1055 * domain may be found by calling find_our_domain().
1059 * @return The domain structure for the named domain, if it is working.
1062 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
1064 struct winbindd_domain *domain;
1066 /* Search through list */
1068 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1069 if (strequal(domain_name, domain->name)) {
1072 if (domain->alt_name == NULL) {
1075 if (strequal(domain_name, domain->alt_name)) {
1086 * Given a domain name, return the struct winbindd domain if it's a direct
1089 * @return The domain structure for the named domain, if it is a direct outgoing trust
1091 struct winbindd_domain *find_trust_from_name_noinit(const char *domain_name)
1093 struct winbindd_domain *domain = NULL;
1095 domain = find_domain_from_name_noinit(domain_name);
1096 if (domain == NULL) {
1100 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1107 struct winbindd_domain *find_domain_from_name(const char *domain_name)
1109 struct winbindd_domain *domain;
1111 domain = find_domain_from_name_noinit(domain_name);
1116 if (!domain->initialized)
1117 init_dc_connection(domain, false);
1122 /* Given a domain sid, return the struct winbindd domain info for it */
1124 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
1126 struct winbindd_domain *domain;
1128 /* Search through list */
1130 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1131 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
1141 * Given a domain sid, return the struct winbindd domain if it's a direct
1144 * @return The domain structure for the specified domain, if it is a direct outgoing trust
1146 struct winbindd_domain *find_trust_from_sid_noinit(const struct dom_sid *sid)
1148 struct winbindd_domain *domain = NULL;
1150 domain = find_domain_from_sid_noinit(sid);
1151 if (domain == NULL) {
1155 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1162 /* Given a domain sid, return the struct winbindd domain info for it */
1164 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
1166 struct winbindd_domain *domain;
1168 domain = find_domain_from_sid_noinit(sid);
1173 if (!domain->initialized)
1174 init_dc_connection(domain, false);
1179 struct winbindd_domain *find_our_domain(void)
1181 struct winbindd_domain *domain;
1183 /* Search through list */
1185 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1186 if (domain->primary)
1190 smb_panic("Could not find our domain");
1194 /* Find the appropriate domain to lookup a name or SID */
1196 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
1198 DBG_DEBUG("SID [%s]\n", sid_string_dbg(sid));
1201 * SIDs in the S-1-22-{1,2} domain and well-known SIDs should be handled
1205 if ( sid_check_is_in_unix_groups(sid) ||
1206 sid_check_is_unix_groups(sid) ||
1207 sid_check_is_in_unix_users(sid) ||
1208 sid_check_is_unix_users(sid) ||
1209 sid_check_is_wellknown_domain(sid, NULL) ||
1210 sid_check_is_in_wellknown_domain(sid) )
1212 return find_domain_from_sid(get_global_sam_sid());
1215 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
1216 * one to contact the external DC's. On member servers the internal
1217 * domains are different: These are part of the local SAM. */
1219 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
1220 DEBUG(10, ("calling find_domain_from_sid\n"));
1221 return find_domain_from_sid(sid);
1224 /* On a member server a query for SID or name can always go to our
1227 DEBUG(10, ("calling find_our_domain\n"));
1228 return find_our_domain();
1231 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1233 if ( strequal(domain_name, unix_users_domain_name() ) ||
1234 strequal(domain_name, unix_groups_domain_name() ) )
1237 * The "Unix User" and "Unix Group" domain our handled by
1240 return find_domain_from_name_noinit( get_global_sam_name() );
1243 if (IS_DC || strequal(domain_name, "BUILTIN") ||
1244 strequal(domain_name, get_global_sam_name()))
1245 return find_domain_from_name_noinit(domain_name);
1248 return find_our_domain();
1251 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1253 static bool assume_domain(const char *domain)
1255 /* never assume the domain on a standalone server */
1257 if ( lp_server_role() == ROLE_STANDALONE )
1260 /* domain member servers may possibly assume for the domain name */
1262 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1263 if ( !strequal(lp_workgroup(), domain) )
1266 if ( lp_winbind_use_default_domain() )
1270 /* only left with a domain controller */
1272 if ( strequal(get_global_sam_name(), domain) ) {
1279 /* Parse a string of the form DOMAIN\user into a domain and a user */
1281 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1283 char *p = strchr(domuser,*lp_winbind_separator());
1286 fstrcpy(user, domuser);
1287 p = strchr(domuser, '@');
1289 if ( assume_domain(lp_workgroup()) && p == NULL) {
1290 fstrcpy(domain, lp_workgroup());
1291 } else if (p != NULL) {
1292 fstrcpy(domain, p + 1);
1293 user[PTR_DIFF(p, domuser)] = 0;
1299 fstrcpy(domain, domuser);
1300 domain[PTR_DIFF(p, domuser)] = 0;
1303 return strupper_m(domain);
1306 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1307 char **domain, char **user)
1309 fstring fstr_domain, fstr_user;
1310 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1313 *domain = talloc_strdup(mem_ctx, fstr_domain);
1314 *user = talloc_strdup(mem_ctx, fstr_user);
1315 return ((*domain != NULL) && (*user != NULL));
1318 /* Ensure an incoming username from NSS is fully qualified. Replace the
1319 incoming fstring with DOMAIN <separator> user. Returns the same
1320 values as parse_domain_user() but also replaces the incoming username.
1321 Used to ensure all names are fully qualified within winbindd.
1322 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1323 The protocol definitions of auth_crap, chng_pswd_auth_crap
1324 really should be changed to use this instead of doing things
1327 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1329 if (!parse_domain_user(username_inout, domain, user)) {
1332 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1333 domain, *lp_winbind_separator(),
1339 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1340 'winbind separator' options.
1342 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1345 If we are a PDC or BDC, and this is for our domain, do likewise.
1347 On an AD DC we always fill DOMAIN\\USERNAME.
1349 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1351 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1355 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1359 fstrcpy(tmp_user, user);
1360 (void)strlower_m(tmp_user);
1362 if (can_assume && assume_domain(domain)) {
1363 strlcpy(name, tmp_user, sizeof(fstring));
1365 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1366 domain, *lp_winbind_separator(),
1372 * talloc version of fill_domain_username()
1373 * return NULL on talloc failure.
1375 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1380 char *tmp_user, *name;
1382 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1386 tmp_user = talloc_strdup(mem_ctx, user);
1387 if (!strlower_m(tmp_user)) {
1388 TALLOC_FREE(tmp_user);
1392 if (can_assume && assume_domain(domain)) {
1395 name = talloc_asprintf(mem_ctx, "%s%c%s",
1397 *lp_winbind_separator(),
1399 TALLOC_FREE(tmp_user);
1406 * Client list accessor functions
1409 static struct winbindd_cli_state *_client_list;
1410 static int _num_clients;
1412 /* Return list of all connected clients */
1414 struct winbindd_cli_state *winbindd_client_list(void)
1416 return _client_list;
1419 /* Return list-tail of all connected clients */
1421 struct winbindd_cli_state *winbindd_client_list_tail(void)
1423 return DLIST_TAIL(_client_list);
1426 /* Return previous (read:newer) client in list */
1428 struct winbindd_cli_state *
1429 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1431 return DLIST_PREV(cli);
1434 /* Add a connection to the list */
1436 void winbindd_add_client(struct winbindd_cli_state *cli)
1438 cli->last_access = time(NULL);
1439 DLIST_ADD(_client_list, cli);
1443 /* Remove a client from the list */
1445 void winbindd_remove_client(struct winbindd_cli_state *cli)
1447 DLIST_REMOVE(_client_list, cli);
1451 /* Move a client to head or list */
1453 void winbindd_promote_client(struct winbindd_cli_state *cli)
1455 cli->last_access = time(NULL);
1456 DLIST_PROMOTE(_client_list, cli);
1459 /* Return number of open clients */
1461 int winbindd_num_clients(void)
1463 return _num_clients;
1466 NTSTATUS lookup_usergroups_cached(TALLOC_CTX *mem_ctx,
1467 const struct dom_sid *user_sid,
1468 uint32_t *p_num_groups, struct dom_sid **user_sids)
1470 struct netr_SamInfo3 *info3 = NULL;
1471 NTSTATUS status = NT_STATUS_NO_MEMORY;
1472 uint32_t num_groups = 0;
1474 DEBUG(3,(": lookup_usergroups_cached\n"));
1479 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1481 if (info3 == NULL) {
1482 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1486 * Before bug #7843 the "Domain Local" groups were added with a
1487 * lookupuseraliases call, but this isn't done anymore for our domain
1488 * so we need to resolve resource groups here.
1490 * When to use Resource Groups:
1491 * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1493 status = sid_array_from_info3(mem_ctx, info3,
1498 if (!NT_STATUS_IS_OK(status)) {
1504 *p_num_groups = num_groups;
1505 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1507 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1512 /*********************************************************************
1513 We use this to remove spaces from user and group names
1514 ********************************************************************/
1516 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1517 const char *domain_name,
1521 struct winbindd_domain *domain = NULL;
1524 if (!name || !normalized) {
1525 return NT_STATUS_INVALID_PARAMETER;
1528 if (!lp_winbind_normalize_names()) {
1529 return NT_STATUS_PROCEDURE_NOT_FOUND;
1532 domain = find_domain_from_name_noinit(domain_name);
1533 if (domain == NULL) {
1534 DBG_ERR("Failed to find domain '%s'\n", domain_name);
1535 return NT_STATUS_NO_SUCH_DOMAIN;
1538 /* Alias support and whitespace replacement are mutually
1541 nt_status = resolve_username_to_alias(mem_ctx, domain,
1543 if (NT_STATUS_IS_OK(nt_status)) {
1544 /* special return code to let the caller know we
1545 mapped to an alias */
1546 return NT_STATUS_FILE_RENAMED;
1549 /* check for an unreachable domain */
1551 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1552 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1554 set_domain_offline(domain);
1558 /* deal with whitespace */
1560 *normalized = talloc_strdup(mem_ctx, name);
1561 if (!(*normalized)) {
1562 return NT_STATUS_NO_MEMORY;
1565 all_string_sub( *normalized, " ", "_", 0 );
1567 return NT_STATUS_OK;
1570 /*********************************************************************
1571 We use this to do the inverse of normalize_name_map()
1572 ********************************************************************/
1574 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1579 struct winbindd_domain *domain = find_our_domain();
1581 if (!name || !normalized) {
1582 return NT_STATUS_INVALID_PARAMETER;
1585 if (!lp_winbind_normalize_names()) {
1586 return NT_STATUS_PROCEDURE_NOT_FOUND;
1589 /* Alias support and whitespace replacement are mutally
1592 /* When mapping from an alias to a username, we don't know the
1593 domain. But we only need a domain structure to cache
1594 a successful lookup , so just our own domain structure for
1597 nt_status = resolve_alias_to_username(mem_ctx, domain,
1599 if (NT_STATUS_IS_OK(nt_status)) {
1600 /* Special return code to let the caller know we mapped
1602 return NT_STATUS_FILE_RENAMED;
1605 /* check for an unreachable domain */
1607 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1608 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1610 set_domain_offline(domain);
1614 /* deal with whitespace */
1616 *normalized = talloc_strdup(mem_ctx, name);
1617 if (!(*normalized)) {
1618 return NT_STATUS_NO_MEMORY;
1621 all_string_sub(*normalized, "_", " ", 0);
1623 return NT_STATUS_OK;
1626 /*********************************************************************
1627 ********************************************************************/
1629 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1631 struct winbindd_tdc_domain *tdc = NULL;
1632 TALLOC_CTX *frame = talloc_stackframe();
1635 /* We can contact the domain if it is our primary domain */
1637 if (domain->primary) {
1642 /* Trust the TDC cache and not the winbindd_domain flags */
1644 if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1645 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1651 /* Can always contact a domain that is in out forest */
1653 if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1659 * On a _member_ server, we cannot contact the domain if it
1660 * is running AD and we have no inbound trust.
1664 domain->active_directory &&
1665 ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1667 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1668 "and we have no inbound trust.\n", domain->name));
1672 /* Assume everything else is ok (probably not true but what
1678 talloc_destroy(frame);
1683 /*********************************************************************
1684 ********************************************************************/
1686 bool winbindd_internal_child(struct winbindd_child *child)
1688 if ((child == idmap_child()) || (child == locator_child())) {
1695 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1697 /*********************************************************************
1698 ********************************************************************/
1700 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1703 char addr[INET6_ADDRSTRLEN];
1704 const char *kdc = NULL;
1707 if (!domain || !domain->alt_name || !*domain->alt_name) {
1711 if (domain->initialized && !domain->active_directory) {
1712 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1717 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1720 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1722 kdc = domain->dcname;
1725 if (!kdc || !*kdc) {
1726 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1731 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1732 domain->alt_name) == -1) {
1736 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1739 setenv(var, kdc, 1);
1743 /*********************************************************************
1744 ********************************************************************/
1746 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1748 struct winbindd_domain *our_dom = find_our_domain();
1750 winbindd_set_locator_kdc_env(domain);
1752 if (domain != our_dom) {
1753 winbindd_set_locator_kdc_env(our_dom);
1757 /*********************************************************************
1758 ********************************************************************/
1760 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1764 if (!domain || !domain->alt_name || !*domain->alt_name) {
1768 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1769 domain->alt_name) == -1) {
1778 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1783 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1788 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1790 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1792 resp->data.auth.nt_status = NT_STATUS_V(result);
1793 fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1795 /* we might have given a more useful error above */
1796 if (*resp->data.auth.error_string == '\0')
1797 fstrcpy(resp->data.auth.error_string,
1798 get_friendly_nt_error_msg(result));
1799 resp->data.auth.pam_error = nt_status_to_pam(result);
1802 bool is_domain_offline(const struct winbindd_domain *domain)
1804 if (get_global_winbindd_state_offline()) {
1807 return !domain->online;
1810 bool is_domain_online(const struct winbindd_domain *domain)
1812 return !is_domain_offline(domain);
1816 * Parse an char array into a list of sids.
1818 * The input sidstr should consist of 0-terminated strings
1819 * representing sids, separated by newline characters '\n'.
1820 * The list is terminated by an empty string, i.e.
1821 * character '\0' directly following a character '\n'
1822 * (or '\0' right at the start of sidstr).
1824 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
1825 struct dom_sid **sids, uint32_t *num_sids)
1833 while (p[0] != '\0') {
1835 const char *q = NULL;
1837 if (!dom_sid_parse_endp(p, &sid, &q)) {
1838 DEBUG(1, ("Could not parse sid %s\n", p));
1842 DEBUG(1, ("Got invalid sidstr: %s\n", p));
1845 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
1855 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
1856 struct unixid **pxids, uint32_t *pnum_xids)
1859 struct unixid *xids = NULL;
1860 uint32_t num_xids = 0;
1867 while (p[0] != '\0') {
1870 unsigned long long id;
1875 xid = (struct unixid) { .type = ID_TYPE_UID };
1878 xid = (struct unixid) { .type = ID_TYPE_GID };
1886 id = strtoull(p, &endp, 10);
1887 if ((id == ULLONG_MAX) && (errno == ERANGE)) {
1890 if (*endp != '\n') {
1896 if ((unsigned long long)xid.id != id) {
1900 tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
1906 xids[num_xids] = xid;
1911 *pnum_xids = num_xids;