winbind: Remove "have_idmap_config" from winbindd_domain
[Samba.git] / source3 / winbindd / winbindd_util.c
blob57ee40c052b8914662136cbe4bfac7cb2f6beec2
1 /*
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/>.
23 #include "includes.h"
24 #include "winbindd.h"
25 #include "secrets.h"
26 #include "../libcli/security/security.h"
27 #include "../libcli/auth/pam_errors.h"
28 #include "passdb/machine_sid.h"
29 #include "passdb.h"
30 #include "source4/lib/messaging/messaging.h"
31 #include "librpc/gen_ndr/ndr_lsa.h"
32 #include "auth/credentials/credentials.h"
34 #undef DBGC_CLASS
35 #define DBGC_CLASS DBGC_WINBIND
37 extern struct winbindd_methods cache_methods;
39 /**
40 * @file winbindd_util.c
42 * Winbind daemon for NT domain authentication nss module.
43 **/
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)
55 /* Initialise list */
57 if ((!_domain_list) && (!init_domain_list())) {
58 smb_panic("Init_domain_list failed");
61 return _domain_list;
64 /* Free all entries in the trusted domain list */
66 static void free_domain_list(void)
68 struct winbindd_domain *domain = _domain_list;
70 while(domain) {
71 struct winbindd_domain *next = domain->next;
73 DLIST_REMOVE(_domain_list, domain);
74 TALLOC_FREE(domain);
75 domain = next;
79 /**
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)
85 if (domain == NULL) {
86 domain = domain_list();
87 } else {
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;
98 return domain;
101 static bool is_internal_domain(const struct dom_sid *sid)
103 if (sid == NULL)
104 return False;
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)
111 if (sid == NULL)
112 return False;
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));
135 return NULL;
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))
151 break;
154 if (alternative_name && *alternative_name)
156 if (strequal(alternative_name, domain->name) ||
157 strequal(alternative_name, domain->alt_name))
159 break;
163 if (sid)
165 if (is_null_sid(sid)) {
166 continue;
169 if (dom_sid_equal(sid, &domain->sid)) {
170 break;
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.
182 if ((sid != NULL)
183 && dom_sid_equal(&domain->sid, &global_sid_NULL)) {
184 sid_copy( &domain->sid, sid );
186 return domain;
189 /* Create new domain entry */
190 domain = talloc_zero(NULL, struct winbindd_domain);
191 if (domain == NULL) {
192 return NULL;
195 domain->children = talloc_zero_array(domain,
196 struct winbindd_child,
197 lp_winbind_max_domain_connections());
198 if (domain->children == NULL) {
199 TALLOC_FREE(domain);
200 return NULL;
203 domain->name = talloc_strdup(domain, domain_name);
204 if (domain->name == NULL) {
205 TALLOC_FREE(domain);
206 return NULL;
209 if (alternative_name) {
210 domain->alt_name = talloc_strdup(domain, alternative_name);
211 if (domain->alt_name == NULL) {
212 TALLOC_FREE(domain);
213 return 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;
226 if (sid) {
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, struct winbindd_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):""));
259 return domain;
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);
289 if (state == NULL) {
290 DEBUG(0, ("talloc failed\n"));
291 return;
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);
300 if (req == NULL) {
301 DEBUG(1, ("wb_domain_request_send failed\n"));
302 TALLOC_FREE(state);
303 return;
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;
313 int res, err;
314 char *p;
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"));
319 TALLOC_FREE(state);
320 return;
323 p = (char *)response->extra_data.data;
325 while ((p != NULL) && (*p != '\0')) {
326 char *q, *sidstr, *alt_name;
327 struct dom_sid sid;
328 char *alternate_name = NULL;
330 alt_name = strchr(p, '\\');
331 if (alt_name == NULL) {
332 DEBUG(0, ("Got invalid trustdom response\n"));
333 break;
336 *alt_name = '\0';
337 alt_name += 1;
339 sidstr = strchr(alt_name, '\\');
340 if (sidstr == NULL) {
341 DEBUG(0, ("Got invalid trustdom response\n"));
342 break;
345 *sidstr = '\0';
346 sidstr += 1;
348 q = strchr(sidstr, '\n');
349 if (q != NULL)
350 *q = '\0';
352 if (!string_to_sid(&sid, sidstr)) {
353 DEBUG(0, ("Got invalid trustdom response\n"));
354 break;
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
366 * domains.
368 (void)add_trusted_domain(p, alternate_name,
369 &cache_methods,
370 &sid);
372 p=q;
373 if (p != NULL)
374 p += 1;
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
382 && !forest_root)
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();
391 else
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();
401 TALLOC_FREE(state);
403 return;
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;
414 int i;
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 ) )
423 return;
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) ) {
433 continue;
436 /* Here's the forest root */
438 d = find_domain_from_name_noinit( dom_list[i].domain_name );
440 if ( !d ) {
441 d = add_trusted_domain( dom_list[i].domain_name,
442 dom_list[i].dns_name,
443 &cache_methods,
444 &dom_list[i].sid );
447 if (d == NULL) {
448 continue;
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 );
461 break;
464 TALLOC_FREE( dom_list );
466 return;
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;
479 int i;
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 ) )
488 return;
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 ) )
500 continue;
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
507 about it */
509 if ( !d ) {
510 d = add_trusted_domain( dom_list[i].domain_name,
511 dom_list[i].dns_name,
512 &cache_methods,
513 &dom_list[i].sid );
516 if (d == NULL) {
517 continue;
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 );
528 return;
531 /*********************************************************************
532 The process of updating the trusted domain list is a three step
533 async process:
534 (a) ask our domain
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)
542 TALLOC_FREE(te);
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.
565 return;
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
602 = domain->primary;
604 return WINBINDD_OK;
607 static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
608 void *private_data,
609 uint32_t msg_type,
610 struct server_id server_id,
611 DATA_BLOB *data)
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"));
620 if (data == NULL) {
621 TALLOC_FREE(frame);
622 return;
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)) {
628 TALLOC_FREE(frame);
629 return;
632 d = find_domain_from_name_noinit(info.netbios_name.string);
633 if (d != NULL) {
634 TALLOC_FREE(frame);
635 return;
638 d = add_trusted_domain(info.netbios_name.string,
639 info.domain_name.string,
640 &cache_methods,
641 info.sid);
642 if (d == NULL) {
643 TALLOC_FREE(frame);
644 return;
647 if (d->internal) {
648 TALLOC_FREE(frame);
649 return;
652 if (d->primary) {
653 TALLOC_FREE(frame);
654 return;
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;
669 TALLOC_FREE(frame);
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)
678 bool ok;
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)));
687 return false;
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),
696 NULL /* oldpass */,
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 */
701 &domain->sid,
702 cli_credentials_get_password_last_changed_time(creds),
703 cli_credentials_get_secure_channel_type(creds),
704 false /* do_delete: Do not delete */);
705 TALLOC_FREE(creds);
706 if (ok == false) {
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"));
710 return false;
712 return true;
715 /* Look up global info for the winbind daemon */
716 bool init_domain_list(void)
718 int role = lp_server_role();
719 NTSTATUS status;
721 /* Free existing list */
722 free_domain_list();
724 /* BUILTIN domain */
726 (void)add_trusted_domain("BUILTIN", NULL, &cache_methods,
727 &global_sid_Builtin);
729 /* Local SAM */
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;
737 bool ok;
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"));
743 return false;
745 domain = add_trusted_domain(pdb_domain_info->name,
746 pdb_domain_info->dns_domain,
747 &cache_methods,
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"));
753 return false;
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,
761 &account_name,
762 &sec_chan_type);
763 if (!ok) {
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);
772 if (ok == false) {
773 DEBUG(0, ("Failed to migrate our own, "
774 "local AD domain join password for "
775 "winbindd's internal use into "
776 "secrets.tdb\n"));
777 return false;
779 ok = get_trust_pw_hash(domain->name,
780 current_nt_hash.hash,
781 &account_name,
782 &sec_chan_type);
783 if (ok == false) {
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"));
788 return false;
791 if (sec_chan_type == SEC_CHAN_RODC) {
792 domain->rodc = true;
795 } else {
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"));
807 return False;
810 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
811 &cache_methods, &our_sid);
812 if (domain) {
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
818 early here. */
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",
828 nt_errstr(status)));
829 return false;
832 return True;
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().
841 * directly.
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))) {
857 return domain;
861 /* Not found */
863 return NULL;
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);
872 if (domain == NULL)
873 return NULL;
875 if (!domain->initialized)
876 init_dc_connection(domain, false);
878 return domain;
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)
891 return domain;
894 /* Not found */
896 return NULL;
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);
907 if (domain == NULL)
908 return NULL;
910 if (!domain->initialized)
911 init_dc_connection(domain, false);
913 return domain;
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) {
923 if (domain->primary)
924 return domain;
927 smb_panic("Could not find our domain");
928 return NULL;
931 struct winbindd_domain *find_root_domain(void)
933 struct winbindd_domain *ours = find_our_domain();
935 if (ours->forest_name == NULL) {
936 return 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");
951 return 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
980 * primary DC. */
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
993 * passdb
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 )
1013 return False;
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) )
1019 return False;
1021 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1022 return True;
1025 /* only left with a domain controller */
1027 if ( strequal(get_global_sam_name(), domain) ) {
1028 return True;
1031 return False;
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());
1040 if ( !p ) {
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;
1048 } else {
1049 return False;
1051 } else {
1052 fstrcpy(user, p+1);
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)) {
1065 return False;
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
1079 by hand. JRA. */
1081 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1083 if (!parse_domain_user(username_inout, domain, user)) {
1084 return False;
1086 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1087 domain, *lp_winbind_separator(),
1088 user);
1089 return True;
1093 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1094 'winbind separator' options.
1095 This means:
1096 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1097 lp_workgroup()
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)
1110 fstring tmp_user;
1112 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1113 can_assume = false;
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));
1121 } else {
1122 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1123 domain, *lp_winbind_separator(),
1124 tmp_user);
1129 * talloc version of fill_domain_username()
1130 * return NULL on talloc failure.
1132 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1133 const char *domain,
1134 const char *user,
1135 bool can_assume)
1137 char *tmp_user, *name;
1139 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1140 can_assume = false;
1143 tmp_user = talloc_strdup(mem_ctx, user);
1144 if (!strlower_m(tmp_user)) {
1145 TALLOC_FREE(tmp_user);
1146 return NULL;
1149 if (can_assume && assume_domain(domain)) {
1150 name = tmp_user;
1151 } else {
1152 name = talloc_asprintf(mem_ctx, "%s%c%s",
1153 domain,
1154 *lp_winbind_separator(),
1155 tmp_user);
1156 TALLOC_FREE(tmp_user);
1159 return name;
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);
1197 _num_clients++;
1200 /* Remove a client from the list */
1202 void winbindd_remove_client(struct winbindd_cli_state *cli)
1204 DLIST_REMOVE(_client_list, cli);
1205 _num_clients--;
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"));
1234 *user_sids = NULL;
1235 *p_num_groups = 0;
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) {
1244 TALLOC_FREE(info3);
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,
1257 user_sids,
1258 &num_groups,
1259 false);
1261 if (!NT_STATUS_IS_OK(status)) {
1262 TALLOC_FREE(info3);
1263 return status;
1266 TALLOC_FREE(info3);
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"));
1272 return status;
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,
1281 const char *name,
1282 char **normalized)
1284 NTSTATUS nt_status;
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
1295 exclusive */
1297 nt_status = resolve_username_to_alias(mem_ctx, domain,
1298 name, normalized );
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",
1309 domain->name));
1310 set_domain_offline(domain);
1311 return nt_status;
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,
1331 char *name,
1332 char **normalized)
1334 NTSTATUS nt_status;
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
1346 exclusive */
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
1351 the seqnum. */
1353 nt_status = resolve_alias_to_username(mem_ctx, domain,
1354 name, normalized);
1355 if (NT_STATUS_IS_OK(nt_status)) {
1356 /* Special return code to let the caller know we mapped
1357 from an alias */
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",
1365 domain->name));
1366 set_domain_offline(domain);
1367 return nt_status;
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();
1389 bool ret = false;
1391 /* We can contact the domain if it is our primary domain */
1393 if (domain->primary) {
1394 ret = true;
1395 goto done;
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",
1402 domain->name));
1403 ret = false;
1404 goto done;
1407 /* Can always contact a domain that is in out forest */
1409 if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1410 ret = true;
1411 goto done;
1415 * On a _member_ server, we cannot contact the domain if it
1416 * is running AD and we have no inbound trust.
1419 if (!IS_DC &&
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));
1425 goto done;
1428 /* Assume everything else is ok (probably not true but what
1429 can you do?) */
1431 ret = true;
1433 done:
1434 talloc_destroy(frame);
1436 return ret;
1439 /*********************************************************************
1440 ********************************************************************/
1442 bool winbindd_internal_child(struct winbindd_child *child)
1444 if ((child == idmap_child()) || (child == locator_child())) {
1445 return True;
1448 return False;
1451 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1453 /*********************************************************************
1454 ********************************************************************/
1456 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1458 char *var = NULL;
1459 char addr[INET6_ADDRSTRLEN];
1460 const char *kdc = NULL;
1461 int lvl = 11;
1463 if (!domain || !domain->alt_name || !*domain->alt_name) {
1464 return;
1467 if (domain->initialized && !domain->active_directory) {
1468 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1469 domain->alt_name));
1470 return;
1473 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1474 kdc = addr;
1475 if (!*kdc) {
1476 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1477 domain->alt_name));
1478 kdc = domain->dcname;
1481 if (!kdc || !*kdc) {
1482 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1483 domain->alt_name));
1484 return;
1487 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1488 domain->alt_name) == -1) {
1489 return;
1492 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1493 var, kdc));
1495 setenv(var, kdc, 1);
1496 free(var);
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)
1518 char *var = NULL;
1520 if (!domain || !domain->alt_name || !*domain->alt_name) {
1521 return;
1524 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1525 domain->alt_name) == -1) {
1526 return;
1529 unsetenv(var);
1530 free(var);
1532 #else
1534 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1536 return;
1539 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1541 return;
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()) {
1561 return false;
1563 if (get_global_winbindd_state_offline()) {
1564 return true;
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)
1586 const char *p;
1588 p = sidstr;
1589 if (p == NULL)
1590 return False;
1592 while (p[0] != '\0') {
1593 struct dom_sid sid;
1594 const char *q = NULL;
1596 if (!dom_sid_parse_endp(p, &sid, &q)) {
1597 DEBUG(1, ("Could not parse sid %s\n", p));
1598 return false;
1600 if ((q == NULL) || (q[0] != '\n')) {
1601 DEBUG(1, ("Got invalid sidstr: %s\n", p));
1602 return false;
1604 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
1605 num_sids)))
1607 return False;
1609 p = q+1;
1611 return True;