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 struct winbindd_domain **_d)
130 struct winbindd_domain *domain = NULL;
131 const char **ignored_domains = NULL;
132 const char **dom = NULL;
133 int role = lp_server_role();
135 if (is_null_sid(sid)) {
136 DBG_ERR("Got null SID for domain [%s]\n", domain_name);
137 return NT_STATUS_INVALID_PARAMETER;
140 ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
141 for (dom=ignored_domains; dom && *dom; dom++) {
142 if (gen_fnmatch(*dom, domain_name) == 0) {
143 DEBUG(2,("Ignoring domain '%s'\n", domain_name));
144 return NT_STATUS_NO_SUCH_DOMAIN;
149 * We can't call domain_list() as this function is called from
150 * init_domain_list() and we'll get stuck in a loop.
152 for (domain = _domain_list; domain; domain = domain->next) {
153 if (strequal(domain_name, domain->name)) {
158 if (domain != NULL) {
159 struct winbindd_domain *check_domain = NULL;
161 for (check_domain = _domain_list;
162 check_domain != NULL;
163 check_domain = check_domain->next)
165 if (check_domain == domain) {
169 if (dom_sid_equal(&check_domain->sid, sid)) {
174 if (check_domain != NULL) {
175 DBG_ERR("SID [%s] already used by domain [%s], "
177 sid_string_dbg(sid), check_domain->name,
179 return NT_STATUS_INVALID_PARAMETER;
183 if ((domain != NULL) && (dns_name != NULL)) {
184 struct winbindd_domain *check_domain = NULL;
186 for (check_domain = _domain_list;
187 check_domain != NULL;
188 check_domain = check_domain->next)
190 if (check_domain == domain) {
194 if (strequal(check_domain->alt_name, dns_name)) {
199 if (check_domain != NULL) {
200 DBG_ERR("DNS name [%s] used by domain [%s], "
202 dns_name, check_domain->name,
204 return NT_STATUS_INVALID_PARAMETER;
208 if (domain != NULL) {
213 /* Create new domain entry */
214 domain = talloc_zero(NULL, struct winbindd_domain);
215 if (domain == NULL) {
216 return NT_STATUS_NO_MEMORY;
219 domain->children = talloc_zero_array(domain,
220 struct winbindd_child,
221 lp_winbind_max_domain_connections());
222 if (domain->children == NULL) {
224 return NT_STATUS_NO_MEMORY;
227 domain->name = talloc_strdup(domain, domain_name);
228 if (domain->name == NULL) {
230 return NT_STATUS_NO_MEMORY;
233 if (dns_name != NULL) {
234 domain->alt_name = talloc_strdup(domain, dns_name);
235 if (domain->alt_name == NULL) {
237 return NT_STATUS_NO_MEMORY;
241 domain->backend = NULL;
242 domain->internal = is_internal_domain(sid);
243 domain->sequence_number = DOM_SEQUENCE_NONE;
244 domain->last_seq_check = 0;
245 domain->initialized = false;
246 domain->online = is_internal_domain(sid);
247 domain->check_online_timeout = 0;
248 domain->dc_probe_pid = (pid_t)-1;
249 domain->domain_flags = trust_flags;
250 domain->domain_type = trust_type;
251 domain->domain_trust_attribs = trust_attribs;
252 sid_copy(&domain->sid, sid);
254 /* Is this our primary domain ? */
255 if (role == ROLE_DOMAIN_MEMBER) {
256 domain->primary = strequal(domain_name, lp_workgroup());
258 domain->primary = strequal(domain_name, get_global_sam_name());
261 if (domain->primary) {
262 if (role == ROLE_ACTIVE_DIRECTORY_DC) {
263 domain->active_directory = true;
265 if (lp_security() == SEC_ADS) {
266 domain->active_directory = true;
268 } else if (!domain->internal) {
269 if (domain->domain_type == LSA_TRUST_TYPE_UPLEVEL) {
270 domain->active_directory = true;
274 /* Link to domain list */
275 DLIST_ADD_END(_domain_list, domain);
277 wcache_tdc_add_domain( domain );
279 setup_domain_child(domain);
281 DBG_NOTICE("Added domain [%s] [%s] [%s]\n",
282 domain->name, domain->alt_name,
283 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, server_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;
343 bool within_forest = false;
347 * Only when we enumerate our primary domain
348 * or our forest root domain, we should keep
349 * the NETR_TRUST_FLAG_IN_FOREST flag, in
350 * all other cases we need to clear it as the domain
351 * is not part of our forest.
353 if (state->domain->primary) {
354 within_forest = true;
355 } else if (domain_is_forest_root(state->domain)) {
356 within_forest = true;
359 res = wb_domain_request_recv(req, state, &response, &err);
360 if ((res == -1) || (response->result != WINBINDD_OK)) {
361 DBG_WARNING("Could not receive trusts for domain %s\n",
362 state->domain->name);
367 if (response->length < sizeof(struct winbindd_response)) {
368 DBG_ERR("ill-formed trustdom response - short length\n");
373 extra_len = response->length - sizeof(struct winbindd_response);
375 p = (char *)response->extra_data.data;
377 while ((p - (char *)response->extra_data.data) < extra_len) {
378 struct winbindd_domain *domain = NULL;
379 char *name, *q, *sidstr, *alt_name;
382 uint32_t trust_attribs;
383 uint32_t trust_flags;
385 DBG_DEBUG("parsing response line '%s'\n", p);
389 alt_name = strchr(p, '\\');
390 if (alt_name == NULL) {
391 DBG_ERR("Got invalid trustdom response\n");
398 sidstr = strchr(alt_name, '\\');
399 if (sidstr == NULL) {
400 DBG_ERR("Got invalid trustdom response\n");
407 /* use the real alt_name if we have one, else pass in NULL */
408 if (strequal(alt_name, "(null)")) {
412 q = strtok(sidstr, "\\");
414 DBG_ERR("Got invalid trustdom response\n");
418 if (!string_to_sid(&sid, sidstr)) {
419 DEBUG(0, ("Got invalid trustdom response\n"));
423 q = strtok(NULL, "\\");
425 DBG_ERR("Got invalid trustdom response\n");
429 trust_flags = (uint32_t)strtoul(q, NULL, 10);
431 q = strtok(NULL, "\\");
433 DBG_ERR("Got invalid trustdom response\n");
437 trust_type = (uint32_t)strtoul(q, NULL, 10);
439 q = strtok(NULL, "\n");
441 DBG_ERR("Got invalid trustdom response\n");
445 trust_attribs = (uint32_t)strtoul(q, NULL, 10);
447 if (!within_forest) {
448 trust_flags &= ~NETR_TRUST_FLAG_IN_FOREST;
451 if (!state->domain->primary) {
452 trust_flags &= ~NETR_TRUST_FLAG_PRIMARY;
456 * We always call add_trusted_domain() cause on an existing
457 * domain structure, it will update the SID if necessary.
458 * This is important because we need the SID for sibling
461 status = add_trusted_domain(name,
468 if (!NT_STATUS_IS_OK(status) &&
469 !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
471 DBG_NOTICE("add_trusted_domain returned %s\n",
476 p = q + strlen(q) + 1;
480 Cases to consider when scanning trusts:
481 (a) we are calling from a child domain (primary && !forest_root)
482 (b) we are calling from the root of the forest (primary && forest_root)
483 (c) we are calling from a trusted forest domain (!primary
487 if (state->domain->primary) {
488 /* If this is our primary domain and we are not in the
489 forest root, we have to scan the root trusts first */
491 if (!domain_is_forest_root(state->domain))
492 rescan_forest_root_trusts();
494 rescan_forest_trusts();
496 } else if (domain_is_forest_root(state->domain)) {
497 /* Once we have done root forest trust search, we can
498 go on to search the trusted forests */
500 rescan_forest_trusts();
508 /********************************************************************
509 Scan the trusts of our forest root
510 ********************************************************************/
512 static void rescan_forest_root_trusts( void )
514 struct winbindd_tdc_domain *dom_list = NULL;
515 size_t num_trusts = 0;
519 /* The only transitive trusts supported by Windows 2003 AD are
520 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
521 first two are handled in forest and listed by
522 DsEnumerateDomainTrusts(). Forest trusts are not so we
523 have to do that ourselves. */
525 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
528 for ( i=0; i<num_trusts; i++ ) {
529 struct winbindd_domain *d = NULL;
531 /* Find the forest root. Don't necessarily trust
532 the domain_list() as our primary domain may not
533 have been initialized. */
535 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
539 /* Here's the forest root */
541 d = find_domain_from_name_noinit( dom_list[i].domain_name );
543 status = add_trusted_domain(dom_list[i].domain_name,
544 dom_list[i].dns_name,
546 dom_list[i].trust_type,
547 dom_list[i].trust_flags,
548 dom_list[i].trust_attribs,
551 if (!NT_STATUS_IS_OK(status) &&
552 NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
554 DBG_ERR("add_trusted_domain returned %s\n",
563 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
564 "for domain tree root %s (%s)\n",
565 d->name, d->alt_name ));
567 d->domain_flags = dom_list[i].trust_flags;
568 d->domain_type = dom_list[i].trust_type;
569 d->domain_trust_attribs = dom_list[i].trust_attribs;
571 add_trusted_domains( d );
576 TALLOC_FREE( dom_list );
581 /********************************************************************
582 scan the transitive forest trusts (not our own)
583 ********************************************************************/
586 static void rescan_forest_trusts( void )
588 struct winbindd_domain *d = NULL;
589 struct winbindd_tdc_domain *dom_list = NULL;
590 size_t num_trusts = 0;
594 /* The only transitive trusts supported by Windows 2003 AD are
595 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
596 first two are handled in forest and listed by
597 DsEnumerateDomainTrusts(). Forest trusts are not so we
598 have to do that ourselves. */
600 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
603 for ( i=0; i<num_trusts; i++ ) {
604 uint32_t flags = dom_list[i].trust_flags;
605 uint32_t type = dom_list[i].trust_type;
606 uint32_t attribs = dom_list[i].trust_attribs;
608 d = find_domain_from_name_noinit( dom_list[i].domain_name );
610 /* ignore our primary and internal domains */
612 if ( d && (d->internal || d->primary ) )
615 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
616 (type == LSA_TRUST_TYPE_UPLEVEL) &&
617 (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
619 /* add the trusted domain if we don't know
623 status = add_trusted_domain(
624 dom_list[i].domain_name,
625 dom_list[i].dns_name,
631 if (!NT_STATUS_IS_OK(status) &&
632 NT_STATUS_EQUAL(status,
633 NT_STATUS_NO_SUCH_DOMAIN))
635 DBG_ERR("add_trusted_domain: %s\n",
645 DEBUG(10,("Following trust path for domain %s (%s)\n",
646 d->name, d->alt_name ));
647 add_trusted_domains( d );
651 TALLOC_FREE( dom_list );
656 /*********************************************************************
657 The process of updating the trusted domain list is a three step
660 (b) ask the root domain in our forest
661 (c) ask the a DC in any Win2003 trusted forests
662 *********************************************************************/
664 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
665 struct timeval now, void *private_data)
669 /* I use to clear the cache here and start over but that
670 caused problems in child processes that needed the
671 trust dom list early on. Removing it means we
672 could have some trusted domains listed that have been
673 removed from our primary domain's DC until a full
674 restart. This should be ok since I think this is what
675 Windows does as well. */
677 /* this will only add new domains we didn't already know about
678 in the domain_list()*/
680 add_trusted_domains( find_our_domain() );
682 te = tevent_add_timer(
683 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
684 rescan_trusted_domains, NULL);
686 * If te == NULL, there's not much we can do here. Don't fail, the
687 * only thing we miss is new trusted domains.
693 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
694 struct winbindd_cli_state *state)
696 /* Ensure null termination */
697 state->request->domain_name
698 [sizeof(state->request->domain_name)-1]='\0';
699 state->request->data.init_conn.dcname
700 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
702 if (strlen(state->request->data.init_conn.dcname) > 0) {
703 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
706 init_dc_connection(domain, false);
708 if (!domain->initialized) {
709 /* If we return error here we can't do any cached authentication,
710 but we may be in disconnected mode and can't initialize correctly.
711 Do what the previous code did and just return without initialization,
712 once we go online we'll re-initialize.
714 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
715 "online = %d\n", domain->name, (int)domain->online ));
718 fstrcpy(state->response->data.domain_info.name, domain->name);
719 fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
720 sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
722 state->response->data.domain_info.native_mode
723 = domain->native_mode;
724 state->response->data.domain_info.active_directory
725 = domain->active_directory;
726 state->response->data.domain_info.primary
732 static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
735 struct server_id server_id,
738 TALLOC_CTX *frame = talloc_stackframe();
739 struct lsa_TrustDomainInfoInfoEx info;
740 enum ndr_err_code ndr_err;
741 struct winbindd_domain *d = NULL;
742 uint32_t trust_flags = 0;
745 DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
752 ndr_err = ndr_pull_struct_blob_all(data, frame, &info,
753 (ndr_pull_flags_fn_t)ndr_pull_lsa_TrustDomainInfoInfoEx);
754 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
759 d = find_domain_from_name_noinit(info.netbios_name.string);
765 if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
766 trust_flags |= NETR_TRUST_FLAG_INBOUND;
768 if (info.trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
769 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
771 if (info.trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
772 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
775 status = add_trusted_domain(info.netbios_name.string,
776 info.domain_name.string,
780 info.trust_attributes,
782 if (!NT_STATUS_IS_OK(status) &&
783 !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
785 DBG_NOTICE("add_trusted_domain returned %s\n",
794 * We did not get the secret when we queried secrets.tdb, so read it
795 * from secrets.tdb and re-sync the databases
797 static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
800 struct cli_credentials *creds;
801 NTSTATUS can_migrate = pdb_get_trust_credentials(domain->name,
802 NULL, domain, &creds);
803 if (!NT_STATUS_IS_OK(can_migrate)) {
804 DEBUG(0, ("Failed to fetch our own, local AD domain join "
805 "password for winbindd's internal use, both from "
806 "secrets.tdb and secrets.ldb: %s\n",
807 nt_errstr(can_migrate)));
812 * NOTE: It is very unlikely we end up here if there is an
813 * oldpass, because a new password is created at
814 * classicupgrade, so this is not a concern.
816 ok = secrets_store_machine_pw_sync(cli_credentials_get_password(creds),
818 cli_credentials_get_domain(creds),
819 cli_credentials_get_realm(creds),
820 cli_credentials_get_salt_principal(creds),
821 0, /* Supported enc types, unused */
823 cli_credentials_get_password_last_changed_time(creds),
824 cli_credentials_get_secure_channel_type(creds),
825 false /* do_delete: Do not delete */);
828 DEBUG(0, ("Failed to write our our own, "
829 "local AD domain join password for "
830 "winbindd's internal use into secrets.tdb\n"));
836 /* Look up global info for the winbind daemon */
837 bool init_domain_list(void)
839 int role = lp_server_role();
840 struct pdb_domain_info *pdb_domain_info = NULL;
841 struct winbindd_domain *domain = NULL;
844 /* Free existing list */
849 status = add_trusted_domain("BUILTIN",
852 LSA_TRUST_TYPE_DOWNLEVEL,
854 0, /* trust_attribs */
856 if (!NT_STATUS_IS_OK(status)) {
857 DBG_ERR("add_trusted_domain BUILTIN returned %s\n",
865 * In case the passdb backend is passdb_dsdb the domain SID comes from
866 * dsdb, not from secrets.tdb. As we use the domain SID in various
867 * places, we must ensure the domain SID is migrated from dsdb to
868 * secrets.tdb before get_global_sam_sid() is called the first time.
870 * The migration is done as part of the passdb_dsdb initialisation,
871 * calling pdb_get_domain_info() triggers it.
873 pdb_domain_info = pdb_get_domain_info(talloc_tos());
875 if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
876 uint32_t trust_flags;
878 enum netr_SchannelType sec_chan_type;
879 const char *account_name;
880 struct samr_Password current_nt_hash;
883 if (pdb_domain_info == NULL) {
884 DEBUG(0, ("Failed to fetch our own, local AD "
885 "domain info from sam.ldb\n"));
889 trust_flags = NETR_TRUST_FLAG_PRIMARY;
890 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
891 trust_flags |= NETR_TRUST_FLAG_NATIVE;
892 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
894 is_root = strequal(pdb_domain_info->dns_domain,
895 pdb_domain_info->dns_forest);
897 trust_flags |= NETR_TRUST_FLAG_TREEROOT;
900 status = add_trusted_domain(pdb_domain_info->name,
901 pdb_domain_info->dns_domain,
902 &pdb_domain_info->sid,
903 LSA_TRUST_TYPE_UPLEVEL,
905 LSA_TRUST_ATTRIBUTE_WITHIN_FOREST,
907 TALLOC_FREE(pdb_domain_info);
908 if (!NT_STATUS_IS_OK(status)) {
909 DBG_ERR("Failed to add our own, local AD "
910 "domain to winbindd's internal list\n");
915 * We need to call this to find out if we are an RODC
917 ok = get_trust_pw_hash(domain->name,
918 current_nt_hash.hash,
923 * If get_trust_pw_hash() fails, then try and
924 * fetch the password from the more recent of
925 * secrets.{ldb,tdb} using the
926 * pdb_get_trust_credentials()
928 ok = migrate_secrets_tdb_to_ldb(domain);
931 DEBUG(0, ("Failed to migrate our own, "
932 "local AD domain join password for "
933 "winbindd's internal use into "
937 ok = get_trust_pw_hash(domain->name,
938 current_nt_hash.hash,
942 DEBUG(0, ("Failed to find our our own, just "
943 "written local AD domain join "
944 "password for winbindd's internal "
945 "use in secrets.tdb\n"));
949 if (sec_chan_type == SEC_CHAN_RODC) {
954 uint32_t trust_flags;
956 trust_flags = NETR_TRUST_FLAG_OUTBOUND;
957 if (role != ROLE_DOMAIN_MEMBER) {
958 trust_flags |= NETR_TRUST_FLAG_PRIMARY;
961 status = add_trusted_domain(get_global_sam_name(),
963 get_global_sam_sid(),
964 LSA_TRUST_TYPE_DOWNLEVEL,
966 0, /* trust_attribs */
968 if (!NT_STATUS_IS_OK(status)) {
969 DBG_ERR("Failed to add local SAM to "
970 "domain to winbindd's internal list\n");
974 /* Add ourselves as the first entry. */
976 if ( role == ROLE_DOMAIN_MEMBER ) {
977 struct dom_sid our_sid;
980 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
981 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
985 if (lp_realm() != NULL) {
986 trust_type = LSA_TRUST_TYPE_UPLEVEL;
988 trust_type = LSA_TRUST_TYPE_DOWNLEVEL;
991 status = add_trusted_domain(lp_workgroup(),
995 NETR_TRUST_FLAG_PRIMARY|
996 NETR_TRUST_FLAG_OUTBOUND,
997 0, /* trust_attribs */
999 if (!NT_STATUS_IS_OK(status)) {
1000 DBG_ERR("Failed to add local SAM to "
1001 "domain to winbindd's internal list\n");
1004 /* Even in the parent winbindd we'll need to
1005 talk to the DC, so try and see if we can
1006 contact it. Theoretically this isn't neccessary
1007 as the init_dc_connection() in init_child_recv()
1008 will do this, but we can start detecting the DC
1010 set_domain_online_request(domain);
1014 status = imessaging_register(winbind_imessaging_context(), NULL,
1015 MSG_WINBIND_NEW_TRUSTED_DOMAIN,
1016 wb_imsg_new_trusted_domain);
1017 if (!NT_STATUS_IS_OK(status)) {
1018 DEBUG(0, ("imessaging_register(MSG_WINBIND_NEW_TRUSTED_DOMAIN) - %s\n",
1019 nt_errstr(status)));
1027 * Given a domain name, return the struct winbindd domain info for it
1029 * @note Do *not* pass lp_workgroup() to this function. domain_list
1030 * may modify it's value, and free that pointer. Instead, our local
1031 * domain may be found by calling find_our_domain().
1035 * @return The domain structure for the named domain, if it is working.
1038 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
1040 struct winbindd_domain *domain;
1042 /* Search through list */
1044 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1045 if (strequal(domain_name, domain->name)) {
1048 if (domain->alt_name == NULL) {
1051 if (strequal(domain_name, domain->alt_name)) {
1061 struct winbindd_domain *find_domain_from_name(const char *domain_name)
1063 struct winbindd_domain *domain;
1065 domain = find_domain_from_name_noinit(domain_name);
1070 if (!domain->initialized)
1071 init_dc_connection(domain, false);
1076 /* Given a domain sid, return the struct winbindd domain info for it */
1078 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
1080 struct winbindd_domain *domain;
1082 /* Search through list */
1084 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1085 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
1094 /* Given a domain sid, return the struct winbindd domain info for it */
1096 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
1098 struct winbindd_domain *domain;
1100 domain = find_domain_from_sid_noinit(sid);
1105 if (!domain->initialized)
1106 init_dc_connection(domain, false);
1111 struct winbindd_domain *find_our_domain(void)
1113 struct winbindd_domain *domain;
1115 /* Search through list */
1117 for (domain = domain_list(); domain != NULL; domain = domain->next) {
1118 if (domain->primary)
1122 smb_panic("Could not find our domain");
1126 /* Find the appropriate domain to lookup a name or SID */
1128 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
1130 DBG_DEBUG("SID [%s]\n", sid_string_dbg(sid));
1133 * SIDs in the S-1-22-{1,2} domain and well-known SIDs should be handled
1137 if ( sid_check_is_in_unix_groups(sid) ||
1138 sid_check_is_unix_groups(sid) ||
1139 sid_check_is_in_unix_users(sid) ||
1140 sid_check_is_unix_users(sid) ||
1141 sid_check_is_wellknown_domain(sid, NULL) ||
1142 sid_check_is_in_wellknown_domain(sid) )
1144 return find_domain_from_sid(get_global_sam_sid());
1147 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
1148 * one to contact the external DC's. On member servers the internal
1149 * domains are different: These are part of the local SAM. */
1151 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
1152 DEBUG(10, ("calling find_domain_from_sid\n"));
1153 return find_domain_from_sid(sid);
1156 /* On a member server a query for SID or name can always go to our
1159 DEBUG(10, ("calling find_our_domain\n"));
1160 return find_our_domain();
1163 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1165 if ( strequal(domain_name, unix_users_domain_name() ) ||
1166 strequal(domain_name, unix_groups_domain_name() ) )
1169 * The "Unix User" and "Unix Group" domain our handled by
1172 return find_domain_from_name_noinit( get_global_sam_name() );
1175 if (IS_DC || strequal(domain_name, "BUILTIN") ||
1176 strequal(domain_name, get_global_sam_name()))
1177 return find_domain_from_name_noinit(domain_name);
1180 return find_our_domain();
1183 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1185 static bool assume_domain(const char *domain)
1187 /* never assume the domain on a standalone server */
1189 if ( lp_server_role() == ROLE_STANDALONE )
1192 /* domain member servers may possibly assume for the domain name */
1194 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1195 if ( !strequal(lp_workgroup(), domain) )
1198 if ( lp_winbind_use_default_domain() )
1202 /* only left with a domain controller */
1204 if ( strequal(get_global_sam_name(), domain) ) {
1211 /* Parse a string of the form DOMAIN\user into a domain and a user */
1213 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1215 char *p = strchr(domuser,*lp_winbind_separator());
1218 fstrcpy(user, domuser);
1219 p = strchr(domuser, '@');
1221 if ( assume_domain(lp_workgroup()) && p == NULL) {
1222 fstrcpy(domain, lp_workgroup());
1223 } else if (p != NULL) {
1224 fstrcpy(domain, p + 1);
1225 user[PTR_DIFF(p, domuser)] = 0;
1231 fstrcpy(domain, domuser);
1232 domain[PTR_DIFF(p, domuser)] = 0;
1235 return strupper_m(domain);
1238 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1239 char **domain, char **user)
1241 fstring fstr_domain, fstr_user;
1242 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1245 *domain = talloc_strdup(mem_ctx, fstr_domain);
1246 *user = talloc_strdup(mem_ctx, fstr_user);
1247 return ((*domain != NULL) && (*user != NULL));
1250 /* Ensure an incoming username from NSS is fully qualified. Replace the
1251 incoming fstring with DOMAIN <separator> user. Returns the same
1252 values as parse_domain_user() but also replaces the incoming username.
1253 Used to ensure all names are fully qualified within winbindd.
1254 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1255 The protocol definitions of auth_crap, chng_pswd_auth_crap
1256 really should be changed to use this instead of doing things
1259 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1261 if (!parse_domain_user(username_inout, domain, user)) {
1264 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1265 domain, *lp_winbind_separator(),
1271 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1272 'winbind separator' options.
1274 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1277 If we are a PDC or BDC, and this is for our domain, do likewise.
1279 On an AD DC we always fill DOMAIN\\USERNAME.
1281 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1283 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1287 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1291 fstrcpy(tmp_user, user);
1292 (void)strlower_m(tmp_user);
1294 if (can_assume && assume_domain(domain)) {
1295 strlcpy(name, tmp_user, sizeof(fstring));
1297 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1298 domain, *lp_winbind_separator(),
1304 * talloc version of fill_domain_username()
1305 * return NULL on talloc failure.
1307 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1312 char *tmp_user, *name;
1314 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1318 tmp_user = talloc_strdup(mem_ctx, user);
1319 if (!strlower_m(tmp_user)) {
1320 TALLOC_FREE(tmp_user);
1324 if (can_assume && assume_domain(domain)) {
1327 name = talloc_asprintf(mem_ctx, "%s%c%s",
1329 *lp_winbind_separator(),
1331 TALLOC_FREE(tmp_user);
1338 * Client list accessor functions
1341 static struct winbindd_cli_state *_client_list;
1342 static int _num_clients;
1344 /* Return list of all connected clients */
1346 struct winbindd_cli_state *winbindd_client_list(void)
1348 return _client_list;
1351 /* Return list-tail of all connected clients */
1353 struct winbindd_cli_state *winbindd_client_list_tail(void)
1355 return DLIST_TAIL(_client_list);
1358 /* Return previous (read:newer) client in list */
1360 struct winbindd_cli_state *
1361 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1363 return DLIST_PREV(cli);
1366 /* Add a connection to the list */
1368 void winbindd_add_client(struct winbindd_cli_state *cli)
1370 cli->last_access = time(NULL);
1371 DLIST_ADD(_client_list, cli);
1375 /* Remove a client from the list */
1377 void winbindd_remove_client(struct winbindd_cli_state *cli)
1379 DLIST_REMOVE(_client_list, cli);
1383 /* Move a client to head or list */
1385 void winbindd_promote_client(struct winbindd_cli_state *cli)
1387 cli->last_access = time(NULL);
1388 DLIST_PROMOTE(_client_list, cli);
1391 /* Return number of open clients */
1393 int winbindd_num_clients(void)
1395 return _num_clients;
1398 NTSTATUS lookup_usergroups_cached(TALLOC_CTX *mem_ctx,
1399 const struct dom_sid *user_sid,
1400 uint32_t *p_num_groups, struct dom_sid **user_sids)
1402 struct netr_SamInfo3 *info3 = NULL;
1403 NTSTATUS status = NT_STATUS_NO_MEMORY;
1404 uint32_t num_groups = 0;
1406 DEBUG(3,(": lookup_usergroups_cached\n"));
1411 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1413 if (info3 == NULL) {
1414 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1418 * Before bug #7843 the "Domain Local" groups were added with a
1419 * lookupuseraliases call, but this isn't done anymore for our domain
1420 * so we need to resolve resource groups here.
1422 * When to use Resource Groups:
1423 * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1425 status = sid_array_from_info3(mem_ctx, info3,
1430 if (!NT_STATUS_IS_OK(status)) {
1436 *p_num_groups = num_groups;
1437 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1439 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1444 /*********************************************************************
1445 We use this to remove spaces from user and group names
1446 ********************************************************************/
1448 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1449 const char *domain_name,
1453 struct winbindd_domain *domain = NULL;
1456 if (!name || !normalized) {
1457 return NT_STATUS_INVALID_PARAMETER;
1460 if (!lp_winbind_normalize_names()) {
1461 return NT_STATUS_PROCEDURE_NOT_FOUND;
1464 domain = find_domain_from_name_noinit(domain_name);
1465 if (domain == NULL) {
1466 DBG_ERR("Failed to find domain '%s'\n", domain_name);
1467 return NT_STATUS_NO_SUCH_DOMAIN;
1470 /* Alias support and whitespace replacement are mutually
1473 nt_status = resolve_username_to_alias(mem_ctx, domain,
1475 if (NT_STATUS_IS_OK(nt_status)) {
1476 /* special return code to let the caller know we
1477 mapped to an alias */
1478 return NT_STATUS_FILE_RENAMED;
1481 /* check for an unreachable domain */
1483 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1484 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1486 set_domain_offline(domain);
1490 /* deal with whitespace */
1492 *normalized = talloc_strdup(mem_ctx, name);
1493 if (!(*normalized)) {
1494 return NT_STATUS_NO_MEMORY;
1497 all_string_sub( *normalized, " ", "_", 0 );
1499 return NT_STATUS_OK;
1502 /*********************************************************************
1503 We use this to do the inverse of normalize_name_map()
1504 ********************************************************************/
1506 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1511 struct winbindd_domain *domain = find_our_domain();
1513 if (!name || !normalized) {
1514 return NT_STATUS_INVALID_PARAMETER;
1517 if (!lp_winbind_normalize_names()) {
1518 return NT_STATUS_PROCEDURE_NOT_FOUND;
1521 /* Alias support and whitespace replacement are mutally
1524 /* When mapping from an alias to a username, we don't know the
1525 domain. But we only need a domain structure to cache
1526 a successful lookup , so just our own domain structure for
1529 nt_status = resolve_alias_to_username(mem_ctx, domain,
1531 if (NT_STATUS_IS_OK(nt_status)) {
1532 /* Special return code to let the caller know we mapped
1534 return NT_STATUS_FILE_RENAMED;
1537 /* check for an unreachable domain */
1539 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1540 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1542 set_domain_offline(domain);
1546 /* deal with whitespace */
1548 *normalized = talloc_strdup(mem_ctx, name);
1549 if (!(*normalized)) {
1550 return NT_STATUS_NO_MEMORY;
1553 all_string_sub(*normalized, "_", " ", 0);
1555 return NT_STATUS_OK;
1558 /*********************************************************************
1559 ********************************************************************/
1561 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1563 struct winbindd_tdc_domain *tdc = NULL;
1564 TALLOC_CTX *frame = talloc_stackframe();
1567 /* We can contact the domain if it is our primary domain */
1569 if (domain->primary) {
1574 /* Trust the TDC cache and not the winbindd_domain flags */
1576 if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1577 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1583 /* Can always contact a domain that is in out forest */
1585 if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1591 * On a _member_ server, we cannot contact the domain if it
1592 * is running AD and we have no inbound trust.
1596 domain->active_directory &&
1597 ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1599 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1600 "and we have no inbound trust.\n", domain->name));
1604 /* Assume everything else is ok (probably not true but what
1610 talloc_destroy(frame);
1615 /*********************************************************************
1616 ********************************************************************/
1618 bool winbindd_internal_child(struct winbindd_child *child)
1620 if ((child == idmap_child()) || (child == locator_child())) {
1627 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1629 /*********************************************************************
1630 ********************************************************************/
1632 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1635 char addr[INET6_ADDRSTRLEN];
1636 const char *kdc = NULL;
1639 if (!domain || !domain->alt_name || !*domain->alt_name) {
1643 if (domain->initialized && !domain->active_directory) {
1644 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1649 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1652 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1654 kdc = domain->dcname;
1657 if (!kdc || !*kdc) {
1658 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1663 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1664 domain->alt_name) == -1) {
1668 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1671 setenv(var, kdc, 1);
1675 /*********************************************************************
1676 ********************************************************************/
1678 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1680 struct winbindd_domain *our_dom = find_our_domain();
1682 winbindd_set_locator_kdc_env(domain);
1684 if (domain != our_dom) {
1685 winbindd_set_locator_kdc_env(our_dom);
1689 /*********************************************************************
1690 ********************************************************************/
1692 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1696 if (!domain || !domain->alt_name || !*domain->alt_name) {
1700 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1701 domain->alt_name) == -1) {
1710 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1715 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1720 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1722 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1724 resp->data.auth.nt_status = NT_STATUS_V(result);
1725 fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1727 /* we might have given a more useful error above */
1728 if (*resp->data.auth.error_string == '\0')
1729 fstrcpy(resp->data.auth.error_string,
1730 get_friendly_nt_error_msg(result));
1731 resp->data.auth.pam_error = nt_status_to_pam(result);
1734 bool is_domain_offline(const struct winbindd_domain *domain)
1736 if (get_global_winbindd_state_offline()) {
1739 return !domain->online;
1742 bool is_domain_online(const struct winbindd_domain *domain)
1744 return !is_domain_offline(domain);
1748 * Parse an char array into a list of sids.
1750 * The input sidstr should consist of 0-terminated strings
1751 * representing sids, separated by newline characters '\n'.
1752 * The list is terminated by an empty string, i.e.
1753 * character '\0' directly following a character '\n'
1754 * (or '\0' right at the start of sidstr).
1756 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
1757 struct dom_sid **sids, uint32_t *num_sids)
1765 while (p[0] != '\0') {
1767 const char *q = NULL;
1769 if (!dom_sid_parse_endp(p, &sid, &q)) {
1770 DEBUG(1, ("Could not parse sid %s\n", p));
1774 DEBUG(1, ("Got invalid sidstr: %s\n", p));
1777 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
1787 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
1788 struct unixid **pxids, uint32_t *pnum_xids)
1791 struct unixid *xids = NULL;
1792 uint32_t num_xids = 0;
1799 while (p[0] != '\0') {
1802 unsigned long long id;
1807 xid = (struct unixid) { .type = ID_TYPE_UID };
1810 xid = (struct unixid) { .type = ID_TYPE_GID };
1818 id = strtoull(p, &endp, 10);
1819 if ((id == ULLONG_MAX) && (errno == ERANGE)) {
1822 if (*endp != '\n') {
1828 if ((unsigned long long)xid.id != id) {
1832 tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
1838 xids[num_xids] = xid;
1843 *pnum_xids = num_xids;