2 Unix SMB/CIFS implementation.
4 Winbind daemon for ntdom nss module
6 Copyright (C) Tim Potter 2000-2001
7 Copyright (C) 2001 by Martin Pool <mbp@samba.org>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "../libcli/security/security.h"
27 #include "../libcli/auth/pam_errors.h"
28 #include "passdb/machine_sid.h"
30 #include "source4/lib/messaging/messaging.h"
31 #include "librpc/gen_ndr/ndr_lsa.h"
32 #include "auth/credentials/credentials.h"
35 #define DBGC_CLASS DBGC_WINBIND
37 extern struct winbindd_methods cache_methods;
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 struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
123 struct winbindd_methods *methods,
124 const struct dom_sid *sid)
126 struct winbindd_domain *domain;
127 const char *alternative_name = NULL;
128 const char **ignored_domains, **dom;
129 int role = lp_server_role();
131 ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
132 for (dom=ignored_domains; dom && *dom; dom++) {
133 if (gen_fnmatch(*dom, domain_name) == 0) {
134 DEBUG(2,("Ignoring domain '%s'\n", domain_name));
139 /* use alt_name if available to allow DNS lookups */
141 if (alt_name && *alt_name) {
142 alternative_name = alt_name;
145 /* We can't call domain_list() as this function is called from
146 init_domain_list() and we'll get stuck in a loop. */
147 for (domain = _domain_list; domain; domain = domain->next) {
148 if (strequal(domain_name, domain->name) ||
149 strequal(domain_name, domain->alt_name))
154 if (alternative_name && *alternative_name)
156 if (strequal(alternative_name, domain->name) ||
157 strequal(alternative_name, domain->alt_name))
165 if (is_null_sid(sid)) {
169 if (dom_sid_equal(sid, &domain->sid)) {
175 if (domain != NULL) {
177 * We found a match on domain->name or
178 * domain->alt_name. Possibly update the SID
179 * if the stored SID was the NULL SID
180 * and return the matching entry.
183 && dom_sid_equal(&domain->sid, &global_sid_NULL)) {
184 sid_copy( &domain->sid, sid );
189 /* Create new domain entry */
190 domain = talloc_zero(NULL, struct winbindd_domain);
191 if (domain == NULL) {
195 domain->children = talloc_zero_array(domain,
196 struct winbindd_child,
197 lp_winbind_max_domain_connections());
198 if (domain->children == NULL) {
203 domain->name = talloc_strdup(domain, domain_name);
204 if (domain->name == NULL) {
209 if (alternative_name) {
210 domain->alt_name = talloc_strdup(domain, alternative_name);
211 if (domain->alt_name == NULL) {
217 domain->methods = methods;
218 domain->backend = NULL;
219 domain->internal = is_internal_domain(sid);
220 domain->sequence_number = DOM_SEQUENCE_NONE;
221 domain->last_seq_check = 0;
222 domain->initialized = False;
223 domain->online = is_internal_domain(sid);
224 domain->check_online_timeout = 0;
225 domain->dc_probe_pid = (pid_t)-1;
227 sid_copy(&domain->sid, sid);
230 /* Is this our primary domain ? */
231 if (strequal(domain_name, get_global_sam_name()) &&
232 (role != ROLE_DOMAIN_MEMBER)) {
233 domain->primary = true;
234 } else if (strequal(domain_name, lp_workgroup()) &&
235 (role == ROLE_DOMAIN_MEMBER)) {
236 domain->primary = true;
239 if (domain->primary) {
240 if (role == ROLE_ACTIVE_DIRECTORY_DC) {
241 domain->active_directory = true;
243 if (lp_security() == SEC_ADS) {
244 domain->active_directory = true;
248 /* Link to domain list */
249 DLIST_ADD_END(_domain_list, domain);
251 wcache_tdc_add_domain( domain );
253 setup_domain_child(domain);
255 DEBUG(2,("Added domain %s %s %s\n",
256 domain->name, domain->alt_name,
257 &domain->sid?sid_string_dbg(&domain->sid):""));
262 bool domain_is_forest_root(const struct winbindd_domain *domain)
264 const uint32_t fr_flags =
265 (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
267 return ((domain->domain_flags & fr_flags) == fr_flags);
270 /********************************************************************
271 rescan our domains looking for new trusted domains
272 ********************************************************************/
274 struct trustdom_state {
275 struct winbindd_domain *domain;
276 struct winbindd_request request;
279 static void trustdom_list_done(struct tevent_req *req);
280 static void rescan_forest_root_trusts( void );
281 static void rescan_forest_trusts( void );
283 static void add_trusted_domains( struct winbindd_domain *domain )
285 struct trustdom_state *state;
286 struct tevent_req *req;
288 state = talloc_zero(NULL, struct trustdom_state);
290 DEBUG(0, ("talloc failed\n"));
293 state->domain = domain;
295 state->request.length = sizeof(state->request);
296 state->request.cmd = WINBINDD_LIST_TRUSTDOM;
298 req = wb_domain_request_send(state, winbind_event_context(),
299 domain, &state->request);
301 DEBUG(1, ("wb_domain_request_send failed\n"));
305 tevent_req_set_callback(req, trustdom_list_done, state);
308 static void trustdom_list_done(struct tevent_req *req)
310 struct trustdom_state *state = tevent_req_callback_data(
311 req, struct trustdom_state);
312 struct winbindd_response *response;
316 res = wb_domain_request_recv(req, state, &response, &err);
317 if ((res == -1) || (response->result != WINBINDD_OK)) {
318 DEBUG(1, ("Could not receive trustdoms\n"));
323 p = (char *)response->extra_data.data;
325 while ((p != NULL) && (*p != '\0')) {
326 char *q, *sidstr, *alt_name;
328 char *alternate_name = NULL;
330 alt_name = strchr(p, '\\');
331 if (alt_name == NULL) {
332 DEBUG(0, ("Got invalid trustdom response\n"));
339 sidstr = strchr(alt_name, '\\');
340 if (sidstr == NULL) {
341 DEBUG(0, ("Got invalid trustdom response\n"));
348 q = strchr(sidstr, '\n');
352 if (!string_to_sid(&sid, sidstr)) {
353 DEBUG(0, ("Got invalid trustdom response\n"));
357 /* use the real alt_name if we have one, else pass in NULL */
359 if ( !strequal( alt_name, "(null)" ) )
360 alternate_name = alt_name;
363 * We always call add_trusted_domain() cause on an existing
364 * domain structure, it will update the SID if necessary.
365 * This is important because we need the SID for sibling
368 (void)add_trusted_domain(p, alternate_name,
378 Cases to consider when scanning trusts:
379 (a) we are calling from a child domain (primary && !forest_root)
380 (b) we are calling from the root of the forest (primary && forest_root)
381 (c) we are calling from a trusted forest domain (!primary
385 if (state->domain->primary) {
386 /* If this is our primary domain and we are not in the
387 forest root, we have to scan the root trusts first */
389 if (!domain_is_forest_root(state->domain))
390 rescan_forest_root_trusts();
392 rescan_forest_trusts();
394 } else if (domain_is_forest_root(state->domain)) {
395 /* Once we have done root forest trust search, we can
396 go on to search the trusted forests */
398 rescan_forest_trusts();
406 /********************************************************************
407 Scan the trusts of our forest root
408 ********************************************************************/
410 static void rescan_forest_root_trusts( void )
412 struct winbindd_tdc_domain *dom_list = NULL;
413 size_t num_trusts = 0;
416 /* The only transitive trusts supported by Windows 2003 AD are
417 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
418 first two are handled in forest and listed by
419 DsEnumerateDomainTrusts(). Forest trusts are not so we
420 have to do that ourselves. */
422 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
425 for ( i=0; i<num_trusts; i++ ) {
426 struct winbindd_domain *d = NULL;
428 /* Find the forest root. Don't necessarily trust
429 the domain_list() as our primary domain may not
430 have been initialized. */
432 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
436 /* Here's the forest root */
438 d = find_domain_from_name_noinit( dom_list[i].domain_name );
441 d = add_trusted_domain( dom_list[i].domain_name,
442 dom_list[i].dns_name,
451 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
452 "for domain tree root %s (%s)\n",
453 d->name, d->alt_name ));
455 d->domain_flags = dom_list[i].trust_flags;
456 d->domain_type = dom_list[i].trust_type;
457 d->domain_trust_attribs = dom_list[i].trust_attribs;
459 add_trusted_domains( d );
464 TALLOC_FREE( dom_list );
469 /********************************************************************
470 scan the transitive forest trusts (not our own)
471 ********************************************************************/
474 static void rescan_forest_trusts( void )
476 struct winbindd_domain *d = NULL;
477 struct winbindd_tdc_domain *dom_list = NULL;
478 size_t num_trusts = 0;
481 /* The only transitive trusts supported by Windows 2003 AD are
482 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
483 first two are handled in forest and listed by
484 DsEnumerateDomainTrusts(). Forest trusts are not so we
485 have to do that ourselves. */
487 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
490 for ( i=0; i<num_trusts; i++ ) {
491 uint32_t flags = dom_list[i].trust_flags;
492 uint32_t type = dom_list[i].trust_type;
493 uint32_t attribs = dom_list[i].trust_attribs;
495 d = find_domain_from_name_noinit( dom_list[i].domain_name );
497 /* ignore our primary and internal domains */
499 if ( d && (d->internal || d->primary ) )
502 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
503 (type == LSA_TRUST_TYPE_UPLEVEL) &&
504 (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
506 /* add the trusted domain if we don't know
510 d = add_trusted_domain( dom_list[i].domain_name,
511 dom_list[i].dns_name,
520 DEBUG(10,("Following trust path for domain %s (%s)\n",
521 d->name, d->alt_name ));
522 add_trusted_domains( d );
526 TALLOC_FREE( dom_list );
531 /*********************************************************************
532 The process of updating the trusted domain list is a three step
535 (b) ask the root domain in our forest
536 (c) ask the a DC in any Win2003 trusted forests
537 *********************************************************************/
539 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
540 struct timeval now, void *private_data)
544 /* I use to clear the cache here and start over but that
545 caused problems in child processes that needed the
546 trust dom list early on. Removing it means we
547 could have some trusted domains listed that have been
548 removed from our primary domain's DC until a full
549 restart. This should be ok since I think this is what
550 Windows does as well. */
552 /* this will only add new domains we didn't already know about
553 in the domain_list()*/
555 add_trusted_domains( find_our_domain() );
557 te = tevent_add_timer(
558 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
559 rescan_trusted_domains, NULL);
561 * If te == NULL, there's not much we can do here. Don't fail, the
562 * only thing we miss is new trusted domains.
568 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
569 struct winbindd_cli_state *state)
571 /* Ensure null termination */
572 state->request->domain_name
573 [sizeof(state->request->domain_name)-1]='\0';
574 state->request->data.init_conn.dcname
575 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
577 if (strlen(state->request->data.init_conn.dcname) > 0) {
578 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
581 init_dc_connection(domain, false);
583 if (!domain->initialized) {
584 /* If we return error here we can't do any cached authentication,
585 but we may be in disconnected mode and can't initialize correctly.
586 Do what the previous code did and just return without initialization,
587 once we go online we'll re-initialize.
589 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
590 "online = %d\n", domain->name, (int)domain->online ));
593 fstrcpy(state->response->data.domain_info.name, domain->name);
594 fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
595 sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
597 state->response->data.domain_info.native_mode
598 = domain->native_mode;
599 state->response->data.domain_info.active_directory
600 = domain->active_directory;
601 state->response->data.domain_info.primary
607 static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
610 struct server_id server_id,
613 TALLOC_CTX *frame = talloc_stackframe();
614 struct lsa_TrustDomainInfoInfoEx info;
615 enum ndr_err_code ndr_err;
616 struct winbindd_domain *d = NULL;
618 DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
625 ndr_err = ndr_pull_struct_blob_all(data, frame, &info,
626 (ndr_pull_flags_fn_t)ndr_pull_lsa_TrustDomainInfoInfoEx);
627 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
632 d = find_domain_from_name_noinit(info.netbios_name.string);
638 d = add_trusted_domain(info.netbios_name.string,
639 info.domain_name.string,
657 if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
658 d->domain_flags |= NETR_TRUST_FLAG_INBOUND;
660 if (info.trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
661 d->domain_flags |= NETR_TRUST_FLAG_OUTBOUND;
663 if (info.trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
664 d->domain_flags |= NETR_TRUST_FLAG_IN_FOREST;
666 d->domain_type = info.trust_type;
667 d->domain_trust_attribs = info.trust_attributes;
673 * We did not get the secret when we queried secrets.tdb, so read it
674 * from secrets.tdb and re-sync the databases
676 static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
679 struct cli_credentials *creds;
680 NTSTATUS can_migrate = pdb_get_trust_credentials(domain->name,
681 NULL, domain, &creds);
682 if (!NT_STATUS_IS_OK(can_migrate)) {
683 DEBUG(0, ("Failed to fetch our own, local AD domain join "
684 "password for winbindd's internal use, both from "
685 "secrets.tdb and secrets.ldb: %s\n",
686 nt_errstr(can_migrate)));
691 * NOTE: It is very unlikely we end up here if there is an
692 * oldpass, because a new password is created at
693 * classicupgrade, so this is not a concern.
695 ok = secrets_store_machine_pw_sync(cli_credentials_get_password(creds),
697 cli_credentials_get_domain(creds),
698 cli_credentials_get_realm(creds),
699 cli_credentials_get_salt_principal(creds),
700 0, /* Supported enc types, unused */
702 cli_credentials_get_password_last_changed_time(creds),
703 cli_credentials_get_secure_channel_type(creds),
704 false /* do_delete: Do not delete */);
707 DEBUG(0, ("Failed to write our our own, "
708 "local AD domain join password for "
709 "winbindd's internal use into secrets.tdb\n"));
715 /* Look up global info for the winbind daemon */
716 bool init_domain_list(void)
718 int role = lp_server_role();
721 /* Free existing list */
726 (void)add_trusted_domain("BUILTIN", NULL, &cache_methods,
727 &global_sid_Builtin);
731 if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
732 struct winbindd_domain *domain;
733 enum netr_SchannelType sec_chan_type;
734 const char *account_name;
735 struct samr_Password current_nt_hash;
736 struct pdb_domain_info *pdb_domain_info;
739 pdb_domain_info = pdb_get_domain_info(talloc_tos());
740 if (pdb_domain_info == NULL) {
741 DEBUG(0, ("Failed to fetch our own, local AD "
742 "domain info from sam.ldb\n"));
745 domain = add_trusted_domain(pdb_domain_info->name,
746 pdb_domain_info->dns_domain,
748 &pdb_domain_info->sid);
749 TALLOC_FREE(pdb_domain_info);
750 if (domain == NULL) {
751 DEBUG(0, ("Failed to add our own, local AD "
752 "domain to winbindd's internal list\n"));
757 * We need to call this to find out if we are an RODC
759 ok = get_trust_pw_hash(domain->name,
760 current_nt_hash.hash,
765 * If get_trust_pw_hash() fails, then try and
766 * fetch the password from the more recent of
767 * secrets.{ldb,tdb} using the
768 * pdb_get_trust_credentials()
770 ok = migrate_secrets_tdb_to_ldb(domain);
773 DEBUG(0, ("Failed to migrate our own, "
774 "local AD domain join password for "
775 "winbindd's internal use into "
779 ok = get_trust_pw_hash(domain->name,
780 current_nt_hash.hash,
784 DEBUG(0, ("Failed to find our our own, just "
785 "written local AD domain join "
786 "password for winbindd's internal "
787 "use in secrets.tdb\n"));
791 if (sec_chan_type == SEC_CHAN_RODC) {
796 (void)add_trusted_domain(get_global_sam_name(), NULL,
797 &cache_methods, get_global_sam_sid());
799 /* Add ourselves as the first entry. */
801 if ( role == ROLE_DOMAIN_MEMBER ) {
802 struct winbindd_domain *domain;
803 struct dom_sid our_sid;
805 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
806 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
810 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
811 &cache_methods, &our_sid);
813 /* Even in the parent winbindd we'll need to
814 talk to the DC, so try and see if we can
815 contact it. Theoretically this isn't neccessary
816 as the init_dc_connection() in init_child_recv()
817 will do this, but we can start detecting the DC
819 set_domain_online_request(domain);
823 status = imessaging_register(winbind_imessaging_context(), NULL,
824 MSG_WINBIND_NEW_TRUSTED_DOMAIN,
825 wb_imsg_new_trusted_domain);
826 if (!NT_STATUS_IS_OK(status)) {
827 DEBUG(0, ("imessaging_register(MSG_WINBIND_NEW_TRUSTED_DOMAIN) - %s\n",
836 * Given a domain name, return the struct winbindd domain info for it
838 * @note Do *not* pass lp_workgroup() to this function. domain_list
839 * may modify it's value, and free that pointer. Instead, our local
840 * domain may be found by calling find_our_domain().
844 * @return The domain structure for the named domain, if it is working.
847 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
849 struct winbindd_domain *domain;
851 /* Search through list */
853 for (domain = domain_list(); domain != NULL; domain = domain->next) {
854 if (strequal(domain_name, domain->name) ||
855 (domain->alt_name != NULL &&
856 strequal(domain_name, domain->alt_name))) {
866 struct winbindd_domain *find_domain_from_name(const char *domain_name)
868 struct winbindd_domain *domain;
870 domain = find_domain_from_name_noinit(domain_name);
875 if (!domain->initialized)
876 init_dc_connection(domain, false);
881 /* Given a domain sid, return the struct winbindd domain info for it */
883 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
885 struct winbindd_domain *domain;
887 /* Search through list */
889 for (domain = domain_list(); domain != NULL; domain = domain->next) {
890 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
899 /* Given a domain sid, return the struct winbindd domain info for it */
901 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
903 struct winbindd_domain *domain;
905 domain = find_domain_from_sid_noinit(sid);
910 if (!domain->initialized)
911 init_dc_connection(domain, false);
916 struct winbindd_domain *find_our_domain(void)
918 struct winbindd_domain *domain;
920 /* Search through list */
922 for (domain = domain_list(); domain != NULL; domain = domain->next) {
927 smb_panic("Could not find our domain");
931 struct winbindd_domain *find_root_domain(void)
933 struct winbindd_domain *ours = find_our_domain();
935 if (ours->forest_name == NULL) {
939 return find_domain_from_name( ours->forest_name );
942 struct winbindd_domain *find_builtin_domain(void)
944 struct winbindd_domain *domain;
946 domain = find_domain_from_sid(&global_sid_Builtin);
947 if (domain == NULL) {
948 smb_panic("Could not find BUILTIN domain");
954 /* Find the appropriate domain to lookup a name or SID */
956 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
958 /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
960 if ( sid_check_is_in_unix_groups(sid) ||
961 sid_check_is_unix_groups(sid) ||
962 sid_check_is_in_unix_users(sid) ||
963 sid_check_is_unix_users(sid) )
965 return find_domain_from_sid(get_global_sam_sid());
968 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
969 * one to contact the external DC's. On member servers the internal
970 * domains are different: These are part of the local SAM. */
972 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid)));
974 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
975 DEBUG(10, ("calling find_domain_from_sid\n"));
976 return find_domain_from_sid(sid);
979 /* On a member server a query for SID or name can always go to our
982 DEBUG(10, ("calling find_our_domain\n"));
983 return find_our_domain();
986 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
988 if ( strequal(domain_name, unix_users_domain_name() ) ||
989 strequal(domain_name, unix_groups_domain_name() ) )
992 * The "Unix User" and "Unix Group" domain our handled by
995 return find_domain_from_name_noinit( get_global_sam_name() );
998 if (IS_DC || strequal(domain_name, "BUILTIN") ||
999 strequal(domain_name, get_global_sam_name()))
1000 return find_domain_from_name_noinit(domain_name);
1003 return find_our_domain();
1006 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1008 static bool assume_domain(const char *domain)
1010 /* never assume the domain on a standalone server */
1012 if ( lp_server_role() == ROLE_STANDALONE )
1015 /* domain member servers may possibly assume for the domain name */
1017 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1018 if ( !strequal(lp_workgroup(), domain) )
1021 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1025 /* only left with a domain controller */
1027 if ( strequal(get_global_sam_name(), domain) ) {
1034 /* Parse a string of the form DOMAIN\user into a domain and a user */
1036 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1038 char *p = strchr(domuser,*lp_winbind_separator());
1041 fstrcpy(user, domuser);
1043 if ( assume_domain(lp_workgroup())) {
1044 fstrcpy(domain, lp_workgroup());
1045 } else if ((p = strchr(domuser, '@')) != NULL) {
1046 fstrcpy(domain, p + 1);
1047 user[PTR_DIFF(p, domuser)] = 0;
1053 fstrcpy(domain, domuser);
1054 domain[PTR_DIFF(p, domuser)] = 0;
1057 return strupper_m(domain);
1060 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1061 char **domain, char **user)
1063 fstring fstr_domain, fstr_user;
1064 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1067 *domain = talloc_strdup(mem_ctx, fstr_domain);
1068 *user = talloc_strdup(mem_ctx, fstr_user);
1069 return ((*domain != NULL) && (*user != NULL));
1072 /* Ensure an incoming username from NSS is fully qualified. Replace the
1073 incoming fstring with DOMAIN <separator> user. Returns the same
1074 values as parse_domain_user() but also replaces the incoming username.
1075 Used to ensure all names are fully qualified within winbindd.
1076 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1077 The protocol definitions of auth_crap, chng_pswd_auth_crap
1078 really should be changed to use this instead of doing things
1081 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1083 if (!parse_domain_user(username_inout, domain, user)) {
1086 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1087 domain, *lp_winbind_separator(),
1093 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1094 'winbind separator' options.
1096 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1099 If we are a PDC or BDC, and this is for our domain, do likewise.
1101 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
1102 username is then unqualified in unix
1104 On an AD DC we always fill DOMAIN\\USERNAME.
1106 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1108 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1112 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1116 fstrcpy(tmp_user, user);
1117 (void)strlower_m(tmp_user);
1119 if (can_assume && assume_domain(domain)) {
1120 strlcpy(name, tmp_user, sizeof(fstring));
1122 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1123 domain, *lp_winbind_separator(),
1129 * talloc version of fill_domain_username()
1130 * return NULL on talloc failure.
1132 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1137 char *tmp_user, *name;
1139 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1143 tmp_user = talloc_strdup(mem_ctx, user);
1144 if (!strlower_m(tmp_user)) {
1145 TALLOC_FREE(tmp_user);
1149 if (can_assume && assume_domain(domain)) {
1152 name = talloc_asprintf(mem_ctx, "%s%c%s",
1154 *lp_winbind_separator(),
1156 TALLOC_FREE(tmp_user);
1163 * Client list accessor functions
1166 static struct winbindd_cli_state *_client_list;
1167 static int _num_clients;
1169 /* Return list of all connected clients */
1171 struct winbindd_cli_state *winbindd_client_list(void)
1173 return _client_list;
1176 /* Return list-tail of all connected clients */
1178 struct winbindd_cli_state *winbindd_client_list_tail(void)
1180 return DLIST_TAIL(_client_list);
1183 /* Return previous (read:newer) client in list */
1185 struct winbindd_cli_state *
1186 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1188 return DLIST_PREV(cli);
1191 /* Add a connection to the list */
1193 void winbindd_add_client(struct winbindd_cli_state *cli)
1195 cli->last_access = time(NULL);
1196 DLIST_ADD(_client_list, cli);
1200 /* Remove a client from the list */
1202 void winbindd_remove_client(struct winbindd_cli_state *cli)
1204 DLIST_REMOVE(_client_list, cli);
1208 /* Move a client to head or list */
1210 void winbindd_promote_client(struct winbindd_cli_state *cli)
1212 cli->last_access = time(NULL);
1213 DLIST_PROMOTE(_client_list, cli);
1216 /* Return number of open clients */
1218 int winbindd_num_clients(void)
1220 return _num_clients;
1223 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1224 TALLOC_CTX *mem_ctx,
1225 const struct dom_sid *user_sid,
1226 uint32_t *p_num_groups, struct dom_sid **user_sids)
1228 struct netr_SamInfo3 *info3 = NULL;
1229 NTSTATUS status = NT_STATUS_NO_MEMORY;
1230 uint32_t num_groups = 0;
1232 DEBUG(3,(": lookup_usergroups_cached\n"));
1237 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1239 if (info3 == NULL) {
1240 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1243 if (info3->base.groups.count == 0) {
1245 return NT_STATUS_UNSUCCESSFUL;
1249 * Before bug #7843 the "Domain Local" groups were added with a
1250 * lookupuseraliases call, but this isn't done anymore for our domain
1251 * so we need to resolve resource groups here.
1253 * When to use Resource Groups:
1254 * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1256 status = sid_array_from_info3(mem_ctx, info3,
1261 if (!NT_STATUS_IS_OK(status)) {
1267 *p_num_groups = num_groups;
1268 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1270 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1275 /*********************************************************************
1276 We use this to remove spaces from user and group names
1277 ********************************************************************/
1279 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1280 struct winbindd_domain *domain,
1286 if (!name || !normalized) {
1287 return NT_STATUS_INVALID_PARAMETER;
1290 if (!lp_winbind_normalize_names()) {
1291 return NT_STATUS_PROCEDURE_NOT_FOUND;
1294 /* Alias support and whitespace replacement are mutually
1297 nt_status = resolve_username_to_alias(mem_ctx, domain,
1299 if (NT_STATUS_IS_OK(nt_status)) {
1300 /* special return code to let the caller know we
1301 mapped to an alias */
1302 return NT_STATUS_FILE_RENAMED;
1305 /* check for an unreachable domain */
1307 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1308 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1310 set_domain_offline(domain);
1314 /* deal with whitespace */
1316 *normalized = talloc_strdup(mem_ctx, name);
1317 if (!(*normalized)) {
1318 return NT_STATUS_NO_MEMORY;
1321 all_string_sub( *normalized, " ", "_", 0 );
1323 return NT_STATUS_OK;
1326 /*********************************************************************
1327 We use this to do the inverse of normalize_name_map()
1328 ********************************************************************/
1330 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1335 struct winbindd_domain *domain = find_our_domain();
1337 if (!name || !normalized) {
1338 return NT_STATUS_INVALID_PARAMETER;
1341 if (!lp_winbind_normalize_names()) {
1342 return NT_STATUS_PROCEDURE_NOT_FOUND;
1345 /* Alias support and whitespace replacement are mutally
1348 /* When mapping from an alias to a username, we don't know the
1349 domain. But we only need a domain structure to cache
1350 a successful lookup , so just our own domain structure for
1353 nt_status = resolve_alias_to_username(mem_ctx, domain,
1355 if (NT_STATUS_IS_OK(nt_status)) {
1356 /* Special return code to let the caller know we mapped
1358 return NT_STATUS_FILE_RENAMED;
1361 /* check for an unreachable domain */
1363 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1364 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1366 set_domain_offline(domain);
1370 /* deal with whitespace */
1372 *normalized = talloc_strdup(mem_ctx, name);
1373 if (!(*normalized)) {
1374 return NT_STATUS_NO_MEMORY;
1377 all_string_sub(*normalized, "_", " ", 0);
1379 return NT_STATUS_OK;
1382 /*********************************************************************
1383 ********************************************************************/
1385 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1387 struct winbindd_tdc_domain *tdc = NULL;
1388 TALLOC_CTX *frame = talloc_stackframe();
1391 /* We can contact the domain if it is our primary domain */
1393 if (domain->primary) {
1398 /* Trust the TDC cache and not the winbindd_domain flags */
1400 if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1401 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1407 /* Can always contact a domain that is in out forest */
1409 if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1415 * On a _member_ server, we cannot contact the domain if it
1416 * is running AD and we have no inbound trust.
1420 domain->active_directory &&
1421 ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1423 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1424 "and we have no inbound trust.\n", domain->name));
1428 /* Assume everything else is ok (probably not true but what
1434 talloc_destroy(frame);
1439 /*********************************************************************
1440 ********************************************************************/
1442 bool winbindd_internal_child(struct winbindd_child *child)
1444 if ((child == idmap_child()) || (child == locator_child())) {
1451 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1453 /*********************************************************************
1454 ********************************************************************/
1456 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1459 char addr[INET6_ADDRSTRLEN];
1460 const char *kdc = NULL;
1463 if (!domain || !domain->alt_name || !*domain->alt_name) {
1467 if (domain->initialized && !domain->active_directory) {
1468 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1473 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1476 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1478 kdc = domain->dcname;
1481 if (!kdc || !*kdc) {
1482 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1487 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1488 domain->alt_name) == -1) {
1492 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1495 setenv(var, kdc, 1);
1499 /*********************************************************************
1500 ********************************************************************/
1502 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1504 struct winbindd_domain *our_dom = find_our_domain();
1506 winbindd_set_locator_kdc_env(domain);
1508 if (domain != our_dom) {
1509 winbindd_set_locator_kdc_env(our_dom);
1513 /*********************************************************************
1514 ********************************************************************/
1516 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1520 if (!domain || !domain->alt_name || !*domain->alt_name) {
1524 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1525 domain->alt_name) == -1) {
1534 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1539 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1544 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1546 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1548 resp->data.auth.nt_status = NT_STATUS_V(result);
1549 fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1551 /* we might have given a more useful error above */
1552 if (*resp->data.auth.error_string == '\0')
1553 fstrcpy(resp->data.auth.error_string,
1554 get_friendly_nt_error_msg(result));
1555 resp->data.auth.pam_error = nt_status_to_pam(result);
1558 bool is_domain_offline(const struct winbindd_domain *domain)
1560 if (!lp_winbind_offline_logon()) {
1563 if (get_global_winbindd_state_offline()) {
1566 return !domain->online;
1569 bool is_domain_online(const struct winbindd_domain *domain)
1571 return !is_domain_offline(domain);
1575 * Parse an char array into a list of sids.
1577 * The input sidstr should consist of 0-terminated strings
1578 * representing sids, separated by newline characters '\n'.
1579 * The list is terminated by an empty string, i.e.
1580 * character '\0' directly following a character '\n'
1581 * (or '\0' right at the start of sidstr).
1583 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
1584 struct dom_sid **sids, uint32_t *num_sids)
1592 while (p[0] != '\0') {
1594 const char *q = NULL;
1596 if (!dom_sid_parse_endp(p, &sid, &q)) {
1597 DEBUG(1, ("Could not parse sid %s\n", p));
1600 if ((q == NULL) || (q[0] != '\n')) {
1601 DEBUG(1, ("Got invalid sidstr: %s\n", p));
1604 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
1614 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
1615 struct unixid **pxids, uint32_t *pnum_xids)
1618 struct unixid *xids = NULL;
1619 uint32_t num_xids = 0;
1626 while (p[0] != '\0') {
1629 unsigned long long id;
1634 xid = (struct unixid) { .type = ID_TYPE_UID };
1637 xid = (struct unixid) { .type = ID_TYPE_GID };
1645 id = strtoull(p, &endp, 10);
1646 if ((id == ULLONG_MAX) && (errno == ERANGE)) {
1649 if (*endp != '\n') {
1655 if ((unsigned long long)xid.id != id) {
1659 tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
1665 xids[num_xids] = xid;
1670 *pnum_xids = num_xids;