test: not only pretend to call smbconftort - really do it :-}
[Samba.git] / source / winbindd / winbindd_util.c
blobec97b49428c2276f65a9a86a46bf73611662083d
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"
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_WINBIND
29 extern struct winbindd_methods cache_methods;
30 extern struct winbindd_methods passdb_methods;
32 /**
33 * @file winbindd_util.c
35 * Winbind daemon for NT domain authentication nss module.
36 **/
39 /* The list of trusted domains. Note that the list can be deleted and
40 recreated using the init_domain_list() function so pointers to
41 individual winbindd_domain structures cannot be made. Keep a copy of
42 the domain name instead. */
44 static struct winbindd_domain *_domain_list = NULL;
46 /**
47 When was the last scan of trusted domains done?
49 0 == not ever
52 static time_t last_trustdom_scan;
54 struct winbindd_domain *domain_list(void)
56 /* Initialise list */
58 if ((!_domain_list) && (!init_domain_list())) {
59 smb_panic("Init_domain_list failed");
62 return _domain_list;
65 /* Free all entries in the trusted domain list */
67 void free_domain_list(void)
69 struct winbindd_domain *domain = _domain_list;
71 while(domain) {
72 struct winbindd_domain *next = domain->next;
74 DLIST_REMOVE(_domain_list, domain);
75 SAFE_FREE(domain);
76 domain = next;
80 static bool is_internal_domain(const DOM_SID *sid)
82 if (sid == NULL)
83 return False;
85 return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
88 static bool is_in_internal_domain(const DOM_SID *sid)
90 if (sid == NULL)
91 return False;
93 return (sid_check_is_in_our_domain(sid) || sid_check_is_in_builtin(sid));
97 /* Add a trusted domain to our list of domains */
98 static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
99 struct winbindd_methods *methods,
100 const DOM_SID *sid)
102 struct winbindd_domain *domain;
103 const char *alternative_name = NULL;
105 /* ignore alt_name if we are not in an AD domain */
107 if ( (lp_security() == SEC_ADS) && alt_name && *alt_name) {
108 alternative_name = alt_name;
111 /* We can't call domain_list() as this function is called from
112 init_domain_list() and we'll get stuck in a loop. */
113 for (domain = _domain_list; domain; domain = domain->next) {
114 if (strequal(domain_name, domain->name) ||
115 strequal(domain_name, domain->alt_name))
117 break;
120 if (alternative_name && *alternative_name)
122 if (strequal(alternative_name, domain->name) ||
123 strequal(alternative_name, domain->alt_name))
125 break;
129 if (sid)
131 if (is_null_sid(sid)) {
132 continue;
135 if (sid_equal(sid, &domain->sid)) {
136 break;
141 /* See if we found a match. Check if we need to update the
142 SID. */
144 if ( domain && sid) {
145 if ( sid_equal( &domain->sid, &global_sid_NULL ) )
146 sid_copy( &domain->sid, sid );
148 return domain;
151 /* Create new domain entry */
153 if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
154 return NULL;
156 /* Fill in fields */
158 ZERO_STRUCTP(domain);
160 /* prioritise the short name */
161 if (strchr_m(domain_name, '.') && alternative_name && *alternative_name) {
162 fstrcpy(domain->name, alternative_name);
163 fstrcpy(domain->alt_name, domain_name);
164 } else {
165 fstrcpy(domain->name, domain_name);
166 if (alternative_name) {
167 fstrcpy(domain->alt_name, alternative_name);
171 domain->methods = methods;
172 domain->backend = NULL;
173 domain->internal = is_internal_domain(sid);
174 domain->sequence_number = DOM_SEQUENCE_NONE;
175 domain->last_seq_check = 0;
176 domain->initialized = False;
177 domain->online = is_internal_domain(sid);
178 domain->check_online_timeout = 0;
179 if (sid) {
180 sid_copy(&domain->sid, sid);
183 /* Link to domain list */
184 DLIST_ADD_END(_domain_list, domain, struct winbindd_domain *);
186 wcache_tdc_add_domain( domain );
188 DEBUG(2,("Added domain %s %s %s\n",
189 domain->name, domain->alt_name,
190 &domain->sid?sid_string_dbg(&domain->sid):""));
192 return domain;
195 /********************************************************************
196 rescan our domains looking for new trusted domains
197 ********************************************************************/
199 struct trustdom_state {
200 TALLOC_CTX *mem_ctx;
201 bool primary;
202 bool forest_root;
203 struct winbindd_response *response;
206 static void trustdom_recv(void *private_data, bool success);
207 static void rescan_forest_root_trusts( void );
208 static void rescan_forest_trusts( void );
210 static void add_trusted_domains( struct winbindd_domain *domain )
212 TALLOC_CTX *mem_ctx;
213 struct winbindd_request *request;
214 struct winbindd_response *response;
215 uint32 fr_flags = (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
217 struct trustdom_state *state;
219 mem_ctx = talloc_init("add_trusted_domains");
220 if (mem_ctx == NULL) {
221 DEBUG(0, ("talloc_init failed\n"));
222 return;
225 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
226 response = TALLOC_P(mem_ctx, struct winbindd_response);
227 state = TALLOC_P(mem_ctx, struct trustdom_state);
229 if ((request == NULL) || (response == NULL) || (state == NULL)) {
230 DEBUG(0, ("talloc failed\n"));
231 talloc_destroy(mem_ctx);
232 return;
235 state->mem_ctx = mem_ctx;
236 state->response = response;
238 /* Flags used to know how to continue the forest trust search */
240 state->primary = domain->primary;
241 state->forest_root = ((domain->domain_flags & fr_flags) == fr_flags );
243 request->length = sizeof(*request);
244 request->cmd = WINBINDD_LIST_TRUSTDOM;
246 async_domain_request(mem_ctx, domain, request, response,
247 trustdom_recv, state);
250 static void trustdom_recv(void *private_data, bool success)
252 struct trustdom_state *state =
253 talloc_get_type_abort(private_data, struct trustdom_state);
254 struct winbindd_response *response = state->response;
255 char *p;
257 if ((!success) || (response->result != WINBINDD_OK)) {
258 DEBUG(1, ("Could not receive trustdoms\n"));
259 talloc_destroy(state->mem_ctx);
260 return;
263 p = (char *)response->extra_data.data;
265 while ((p != NULL) && (*p != '\0')) {
266 char *q, *sidstr, *alt_name;
267 DOM_SID sid;
268 struct winbindd_domain *domain;
269 char *alternate_name = NULL;
271 alt_name = strchr(p, '\\');
272 if (alt_name == NULL) {
273 DEBUG(0, ("Got invalid trustdom response\n"));
274 break;
277 *alt_name = '\0';
278 alt_name += 1;
280 sidstr = strchr(alt_name, '\\');
281 if (sidstr == NULL) {
282 DEBUG(0, ("Got invalid trustdom response\n"));
283 break;
286 *sidstr = '\0';
287 sidstr += 1;
289 q = strchr(sidstr, '\n');
290 if (q != NULL)
291 *q = '\0';
293 if (!string_to_sid(&sid, sidstr)) {
294 /* Allow NULL sid for sibling domains */
295 if ( strcmp(sidstr,"S-0-0") == 0) {
296 sid_copy( &sid, &global_sid_NULL);
297 } else {
298 DEBUG(0, ("Got invalid trustdom response\n"));
299 break;
303 /* use the real alt_name if we have one, else pass in NULL */
305 if ( !strequal( alt_name, "(null)" ) )
306 alternate_name = alt_name;
308 /* If we have an existing domain structure, calling
309 add_trusted_domain() will update the SID if
310 necessary. This is important because we need the
311 SID for sibling domains */
313 if ( find_domain_from_name_noinit(p) != NULL ) {
314 domain = add_trusted_domain(p, alternate_name,
315 &cache_methods,
316 &sid);
317 } else {
318 domain = add_trusted_domain(p, alternate_name,
319 &cache_methods,
320 &sid);
321 if (domain) {
322 setup_domain_child(domain,
323 &domain->child);
326 p=q;
327 if (p != NULL)
328 p += 1;
331 SAFE_FREE(response->extra_data.data);
334 Cases to consider when scanning trusts:
335 (a) we are calling from a child domain (primary && !forest_root)
336 (b) we are calling from the root of the forest (primary && forest_root)
337 (c) we are calling from a trusted forest domain (!primary
338 && !forest_root)
341 if ( state->primary ) {
342 /* If this is our primary domain and we are not in the
343 forest root, we have to scan the root trusts first */
345 if ( !state->forest_root )
346 rescan_forest_root_trusts();
347 else
348 rescan_forest_trusts();
350 } else if ( state->forest_root ) {
351 /* Once we have done root forest trust search, we can
352 go on to search the trusted forests */
354 rescan_forest_trusts();
357 talloc_destroy(state->mem_ctx);
359 return;
362 /********************************************************************
363 Scan the trusts of our forest root
364 ********************************************************************/
366 static void rescan_forest_root_trusts( void )
368 struct winbindd_tdc_domain *dom_list = NULL;
369 size_t num_trusts = 0;
370 int i;
372 /* The only transitive trusts supported by Windows 2003 AD are
373 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
374 first two are handled in forest and listed by
375 DsEnumerateDomainTrusts(). Forest trusts are not so we
376 have to do that ourselves. */
378 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
379 return;
381 for ( i=0; i<num_trusts; i++ ) {
382 struct winbindd_domain *d = NULL;
384 /* Find the forest root. Don't necessarily trust
385 the domain_list() as our primary domain may not
386 have been initialized. */
388 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
389 continue;
392 /* Here's the forest root */
394 d = find_domain_from_name_noinit( dom_list[i].domain_name );
396 if ( !d ) {
397 d = add_trusted_domain( dom_list[i].domain_name,
398 dom_list[i].dns_name,
399 &cache_methods,
400 &dom_list[i].sid );
403 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
404 "for domain tree root %s (%s)\n",
405 d->name, d->alt_name ));
407 d->domain_flags = dom_list[i].trust_flags;
408 d->domain_type = dom_list[i].trust_type;
409 d->domain_trust_attribs = dom_list[i].trust_attribs;
411 add_trusted_domains( d );
413 break;
416 TALLOC_FREE( dom_list );
418 return;
421 /********************************************************************
422 scan the transitive forest trusts (not our own)
423 ********************************************************************/
426 static void rescan_forest_trusts( void )
428 struct winbindd_domain *d = NULL;
429 struct winbindd_tdc_domain *dom_list = NULL;
430 size_t num_trusts = 0;
431 int i;
433 /* The only transitive trusts supported by Windows 2003 AD are
434 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
435 first two are handled in forest and listed by
436 DsEnumerateDomainTrusts(). Forest trusts are not so we
437 have to do that ourselves. */
439 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
440 return;
442 for ( i=0; i<num_trusts; i++ ) {
443 uint32 flags = dom_list[i].trust_flags;
444 uint32 type = dom_list[i].trust_type;
445 uint32 attribs = dom_list[i].trust_attribs;
447 d = find_domain_from_name_noinit( dom_list[i].domain_name );
449 /* ignore our primary and internal domains */
451 if ( d && (d->internal || d->primary ) )
452 continue;
454 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
455 (type == NETR_TRUST_TYPE_UPLEVEL) &&
456 (attribs == NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
458 /* add the trusted domain if we don't know
459 about it */
461 if ( !d ) {
462 d = add_trusted_domain( dom_list[i].domain_name,
463 dom_list[i].dns_name,
464 &cache_methods,
465 &dom_list[i].sid );
468 DEBUG(10,("Following trust path for domain %s (%s)\n",
469 d->name, d->alt_name ));
470 add_trusted_domains( d );
474 TALLOC_FREE( dom_list );
476 return;
479 /*********************************************************************
480 The process of updating the trusted domain list is a three step
481 async process:
482 (a) ask our domain
483 (b) ask the root domain in our forest
484 (c) ask the a DC in any Win2003 trusted forests
485 *********************************************************************/
487 void rescan_trusted_domains( void )
489 time_t now = time(NULL);
491 /* see if the time has come... */
493 if ((now >= last_trustdom_scan) &&
494 ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
495 return;
497 /* I use to clear the cache here and start over but that
498 caused problems in child processes that needed the
499 trust dom list early on. Removing it means we
500 could have some trusted domains listed that have been
501 removed from our primary domain's DC until a full
502 restart. This should be ok since I think this is what
503 Windows does as well. */
505 /* this will only add new domains we didn't already know about
506 in the domain_list()*/
508 add_trusted_domains( find_our_domain() );
510 last_trustdom_scan = now;
512 return;
515 struct init_child_state {
516 TALLOC_CTX *mem_ctx;
517 struct winbindd_domain *domain;
518 struct winbindd_request *request;
519 struct winbindd_response *response;
520 void (*continuation)(void *private_data, bool success);
521 void *private_data;
524 static void init_child_recv(void *private_data, bool success);
525 static void init_child_getdc_recv(void *private_data, bool success);
527 enum winbindd_result init_child_connection(struct winbindd_domain *domain,
528 void (*continuation)(void *private_data,
529 bool success),
530 void *private_data)
532 TALLOC_CTX *mem_ctx;
533 struct winbindd_request *request;
534 struct winbindd_response *response;
535 struct init_child_state *state;
536 struct winbindd_domain *request_domain;
538 mem_ctx = talloc_init("init_child_connection");
539 if (mem_ctx == NULL) {
540 DEBUG(0, ("talloc_init failed\n"));
541 return WINBINDD_ERROR;
544 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
545 response = TALLOC_P(mem_ctx, struct winbindd_response);
546 state = TALLOC_P(mem_ctx, struct init_child_state);
548 if ((request == NULL) || (response == NULL) || (state == NULL)) {
549 DEBUG(0, ("talloc failed\n"));
550 TALLOC_FREE(mem_ctx);
551 continuation(private_data, False);
552 return WINBINDD_ERROR;
555 request->length = sizeof(*request);
557 state->mem_ctx = mem_ctx;
558 state->domain = domain;
559 state->request = request;
560 state->response = response;
561 state->continuation = continuation;
562 state->private_data = private_data;
564 if (IS_DC || domain->primary || domain->internal ) {
565 /* The primary domain has to find the DC name itself */
566 request->cmd = WINBINDD_INIT_CONNECTION;
567 fstrcpy(request->domain_name, domain->name);
568 request->data.init_conn.is_primary = domain->primary ? true : false;
569 fstrcpy(request->data.init_conn.dcname, "");
570 async_request(mem_ctx, &domain->child, request, response,
571 init_child_recv, state);
572 return WINBINDD_PENDING;
575 /* This is *not* the primary domain, let's ask our DC about a DC
576 * name */
578 request->cmd = WINBINDD_GETDCNAME;
579 fstrcpy(request->domain_name, domain->name);
581 request_domain = find_our_domain();
582 async_domain_request(mem_ctx, request_domain, request, response,
583 init_child_getdc_recv, state);
584 return WINBINDD_PENDING;
587 static void init_child_getdc_recv(void *private_data, bool success)
589 struct init_child_state *state =
590 talloc_get_type_abort(private_data, struct init_child_state);
591 const char *dcname = "";
593 DEBUG(10, ("Received getdcname response\n"));
595 if (success && (state->response->result == WINBINDD_OK)) {
596 dcname = state->response->data.dc_name;
599 state->request->cmd = WINBINDD_INIT_CONNECTION;
600 fstrcpy(state->request->domain_name, state->domain->name);
601 state->request->data.init_conn.is_primary = False;
602 fstrcpy(state->request->data.init_conn.dcname, dcname);
604 async_request(state->mem_ctx, &state->domain->child,
605 state->request, state->response,
606 init_child_recv, state);
609 static void init_child_recv(void *private_data, bool success)
611 struct init_child_state *state =
612 talloc_get_type_abort(private_data, struct init_child_state);
614 DEBUG(5, ("Received child initialization response for domain %s\n",
615 state->domain->name));
617 if ((!success) || (state->response->result != WINBINDD_OK)) {
618 DEBUG(3, ("Could not init child\n"));
619 state->continuation(state->private_data, False);
620 talloc_destroy(state->mem_ctx);
621 return;
624 fstrcpy(state->domain->name,
625 state->response->data.domain_info.name);
626 fstrcpy(state->domain->alt_name,
627 state->response->data.domain_info.alt_name);
628 string_to_sid(&state->domain->sid,
629 state->response->data.domain_info.sid);
630 state->domain->native_mode =
631 state->response->data.domain_info.native_mode;
632 state->domain->active_directory =
633 state->response->data.domain_info.active_directory;
635 init_dc_connection(state->domain);
637 if (state->continuation != NULL)
638 state->continuation(state->private_data, True);
639 talloc_destroy(state->mem_ctx);
642 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
643 struct winbindd_cli_state *state)
645 /* Ensure null termination */
646 state->request.domain_name
647 [sizeof(state->request.domain_name)-1]='\0';
648 state->request.data.init_conn.dcname
649 [sizeof(state->request.data.init_conn.dcname)-1]='\0';
651 if (strlen(state->request.data.init_conn.dcname) > 0) {
652 fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
655 init_dc_connection(domain);
657 if (!domain->initialized) {
658 /* If we return error here we can't do any cached authentication,
659 but we may be in disconnected mode and can't initialize correctly.
660 Do what the previous code did and just return without initialization,
661 once we go online we'll re-initialize.
663 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
664 "online = %d\n", domain->name, (int)domain->online ));
667 fstrcpy(state->response.data.domain_info.name, domain->name);
668 fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
669 sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
671 state->response.data.domain_info.native_mode
672 = domain->native_mode;
673 state->response.data.domain_info.active_directory
674 = domain->active_directory;
675 state->response.data.domain_info.primary
676 = domain->primary;
678 return WINBINDD_OK;
681 /* Look up global info for the winbind daemon */
682 bool init_domain_list(void)
684 struct winbindd_domain *domain;
685 int role = lp_server_role();
687 /* Free existing list */
688 free_domain_list();
690 /* BUILTIN domain */
692 domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
693 &global_sid_Builtin);
694 if (domain) {
695 setup_domain_child(domain,
696 &domain->child);
699 /* Local SAM */
701 domain = add_trusted_domain(get_global_sam_name(), NULL,
702 &passdb_methods, get_global_sam_sid());
703 if (domain) {
704 if ( role != ROLE_DOMAIN_MEMBER ) {
705 domain->primary = True;
707 setup_domain_child(domain,
708 &domain->child);
711 /* Add ourselves as the first entry. */
713 if ( role == ROLE_DOMAIN_MEMBER ) {
714 DOM_SID our_sid;
716 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
717 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
718 return False;
721 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
722 &cache_methods, &our_sid);
723 if (domain) {
724 domain->primary = True;
725 setup_domain_child(domain,
726 &domain->child);
728 /* Even in the parent winbindd we'll need to
729 talk to the DC, so try and see if we can
730 contact it. Theoretically this isn't neccessary
731 as the init_dc_connection() in init_child_recv()
732 will do this, but we can start detecting the DC
733 early here. */
734 set_domain_online_request(domain);
738 return True;
741 void check_domain_trusted( const char *name, const DOM_SID *user_sid )
743 struct winbindd_domain *domain;
744 DOM_SID dom_sid;
745 uint32 rid;
747 domain = find_domain_from_name_noinit( name );
748 if ( domain )
749 return;
751 sid_copy( &dom_sid, user_sid );
752 if ( !sid_split_rid( &dom_sid, &rid ) )
753 return;
755 /* add the newly discovered trusted domain */
757 domain = add_trusted_domain( name, NULL, &cache_methods,
758 &dom_sid);
760 if ( !domain )
761 return;
763 /* assume this is a trust from a one-way transitive
764 forest trust */
766 domain->active_directory = True;
767 domain->domain_flags = NETR_TRUST_FLAG_OUTBOUND;
768 domain->domain_type = NETR_TRUST_TYPE_UPLEVEL;
769 domain->internal = False;
770 domain->online = True;
772 setup_domain_child(domain,
773 &domain->child);
775 wcache_tdc_add_domain( domain );
777 return;
780 /**
781 * Given a domain name, return the struct winbindd domain info for it
783 * @note Do *not* pass lp_workgroup() to this function. domain_list
784 * may modify it's value, and free that pointer. Instead, our local
785 * domain may be found by calling find_our_domain().
786 * directly.
789 * @return The domain structure for the named domain, if it is working.
792 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
794 struct winbindd_domain *domain;
796 /* Search through list */
798 for (domain = domain_list(); domain != NULL; domain = domain->next) {
799 if (strequal(domain_name, domain->name) ||
800 (domain->alt_name[0] &&
801 strequal(domain_name, domain->alt_name))) {
802 return domain;
806 /* Not found */
808 return NULL;
811 struct winbindd_domain *find_domain_from_name(const char *domain_name)
813 struct winbindd_domain *domain;
815 domain = find_domain_from_name_noinit(domain_name);
817 if (domain == NULL)
818 return NULL;
820 if (!domain->initialized)
821 init_dc_connection(domain);
823 return domain;
826 /* Given a domain sid, return the struct winbindd domain info for it */
828 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
830 struct winbindd_domain *domain;
832 /* Search through list */
834 for (domain = domain_list(); domain != NULL; domain = domain->next) {
835 if (sid_compare_domain(sid, &domain->sid) == 0)
836 return domain;
839 /* Not found */
841 return NULL;
844 /* Given a domain sid, return the struct winbindd domain info for it */
846 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
848 struct winbindd_domain *domain;
850 domain = find_domain_from_sid_noinit(sid);
852 if (domain == NULL)
853 return NULL;
855 if (!domain->initialized)
856 init_dc_connection(domain);
858 return domain;
861 struct winbindd_domain *find_our_domain(void)
863 struct winbindd_domain *domain;
865 /* Search through list */
867 for (domain = domain_list(); domain != NULL; domain = domain->next) {
868 if (domain->primary)
869 return domain;
872 smb_panic("Could not find our domain");
873 return NULL;
876 struct winbindd_domain *find_root_domain(void)
878 struct winbindd_domain *ours = find_our_domain();
880 if ( !ours )
881 return NULL;
883 if ( strlen(ours->forest_name) == 0 )
884 return NULL;
886 return find_domain_from_name( ours->forest_name );
889 struct winbindd_domain *find_builtin_domain(void)
891 DOM_SID sid;
892 struct winbindd_domain *domain;
894 string_to_sid(&sid, "S-1-5-32");
895 domain = find_domain_from_sid(&sid);
897 if (domain == NULL) {
898 smb_panic("Could not find BUILTIN domain");
901 return domain;
904 /* Find the appropriate domain to lookup a name or SID */
906 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
908 /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
910 if ( sid_check_is_in_unix_groups(sid) ||
911 sid_check_is_unix_groups(sid) ||
912 sid_check_is_in_unix_users(sid) ||
913 sid_check_is_unix_users(sid) )
915 return find_domain_from_sid(get_global_sam_sid());
918 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
919 * one to contact the external DC's. On member servers the internal
920 * domains are different: These are part of the local SAM. */
922 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid)));
924 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
925 DEBUG(10, ("calling find_domain_from_sid\n"));
926 return find_domain_from_sid(sid);
929 /* On a member server a query for SID or name can always go to our
930 * primary DC. */
932 DEBUG(10, ("calling find_our_domain\n"));
933 return find_our_domain();
936 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
938 if ( strequal(domain_name, unix_users_domain_name() ) ||
939 strequal(domain_name, unix_groups_domain_name() ) )
941 return find_domain_from_name_noinit( get_global_sam_name() );
944 if (IS_DC || strequal(domain_name, "BUILTIN") ||
945 strequal(domain_name, get_global_sam_name()))
946 return find_domain_from_name_noinit(domain_name);
948 /* The "Unix User" and "Unix Group" domain our handled by passdb */
950 return find_our_domain();
953 /* Lookup a sid in a domain from a name */
955 bool winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
956 enum winbindd_cmd orig_cmd,
957 struct winbindd_domain *domain,
958 const char *domain_name,
959 const char *name, DOM_SID *sid,
960 enum lsa_SidType *type)
962 NTSTATUS result;
964 /* Lookup name */
965 result = domain->methods->name_to_sid(domain, mem_ctx, orig_cmd,
966 domain_name, name, sid, type);
968 /* Return sid and type if lookup successful */
969 if (!NT_STATUS_IS_OK(result)) {
970 *type = SID_NAME_UNKNOWN;
973 return NT_STATUS_IS_OK(result);
977 * @brief Lookup a name in a domain from a sid.
979 * @param sid Security ID you want to look up.
980 * @param name On success, set to the name corresponding to @p sid.
981 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
982 * @param type On success, contains the type of name: alias, group or
983 * user.
984 * @retval True if the name exists, in which case @p name and @p type
985 * are set, otherwise False.
987 bool winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
988 struct winbindd_domain *domain,
989 DOM_SID *sid,
990 char **dom_name,
991 char **name,
992 enum lsa_SidType *type)
994 NTSTATUS result;
996 *dom_name = NULL;
997 *name = NULL;
999 /* Lookup name */
1001 result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
1003 /* Return name and type if successful */
1005 if (NT_STATUS_IS_OK(result)) {
1006 return True;
1009 *type = SID_NAME_UNKNOWN;
1011 return False;
1014 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
1016 void free_getent_state(struct getent_state *state)
1018 struct getent_state *temp;
1020 /* Iterate over state list */
1022 temp = state;
1024 while(temp != NULL) {
1025 struct getent_state *next;
1027 /* Free sam entries then list entry */
1029 SAFE_FREE(state->sam_entries);
1030 DLIST_REMOVE(state, state);
1031 next = temp->next;
1033 SAFE_FREE(temp);
1034 temp = next;
1038 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1040 static bool assume_domain(const char *domain)
1042 /* never assume the domain on a standalone server */
1044 if ( lp_server_role() == ROLE_STANDALONE )
1045 return False;
1047 /* domain member servers may possibly assume for the domain name */
1049 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1050 if ( !strequal(lp_workgroup(), domain) )
1051 return False;
1053 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1054 return True;
1057 /* only left with a domain controller */
1059 if ( strequal(get_global_sam_name(), domain) ) {
1060 return True;
1063 return False;
1066 /* Parse a string of the form DOMAIN\user into a domain and a user */
1068 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1070 char *p = strchr(domuser,*lp_winbind_separator());
1072 if ( !p ) {
1073 fstrcpy(user, domuser);
1075 if ( assume_domain(lp_workgroup())) {
1076 fstrcpy(domain, lp_workgroup());
1077 } else if ((p = strchr(domuser, '@')) != NULL) {
1078 fstrcpy(domain, "");
1079 } else {
1080 return False;
1082 } else {
1083 fstrcpy(user, p+1);
1084 fstrcpy(domain, domuser);
1085 domain[PTR_DIFF(p, domuser)] = 0;
1088 strupper_m(domain);
1090 return True;
1093 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1094 char **domain, char **user)
1096 fstring fstr_domain, fstr_user;
1097 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1098 return False;
1100 *domain = talloc_strdup(mem_ctx, fstr_domain);
1101 *user = talloc_strdup(mem_ctx, fstr_user);
1102 return ((*domain != NULL) && (*user != NULL));
1105 /* Ensure an incoming username from NSS is fully qualified. Replace the
1106 incoming fstring with DOMAIN <separator> user. Returns the same
1107 values as parse_domain_user() but also replaces the incoming username.
1108 Used to ensure all names are fully qualified within winbindd.
1109 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1110 The protocol definitions of auth_crap, chng_pswd_auth_crap
1111 really should be changed to use this instead of doing things
1112 by hand. JRA. */
1114 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1116 if (!parse_domain_user(username_inout, domain, user)) {
1117 return False;
1119 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1120 domain, *lp_winbind_separator(),
1121 user);
1122 return True;
1126 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1127 'winbind separator' options.
1128 This means:
1129 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1130 lp_workgroup()
1132 If we are a PDC or BDC, and this is for our domain, do likewise.
1134 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
1135 username is then unqualified in unix
1137 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1139 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1141 fstring tmp_user;
1143 fstrcpy(tmp_user, user);
1144 strlower_m(tmp_user);
1146 if (can_assume && assume_domain(domain)) {
1147 strlcpy(name, tmp_user, sizeof(fstring));
1148 } else {
1149 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1150 domain, *lp_winbind_separator(),
1151 tmp_user);
1156 * Winbindd socket accessor functions
1159 const char *get_winbind_pipe_dir(void)
1161 return lp_parm_const_string(-1, "winbindd", "socket dir", WINBINDD_SOCKET_DIR);
1164 char *get_winbind_priv_pipe_dir(void)
1166 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
1169 /* Open the winbindd socket */
1171 static int _winbindd_socket = -1;
1172 static int _winbindd_priv_socket = -1;
1174 int open_winbindd_socket(void)
1176 if (_winbindd_socket == -1) {
1177 _winbindd_socket = create_pipe_sock(
1178 get_winbind_pipe_dir(), WINBINDD_SOCKET_NAME, 0755);
1179 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
1180 _winbindd_socket));
1183 return _winbindd_socket;
1186 int open_winbindd_priv_socket(void)
1188 if (_winbindd_priv_socket == -1) {
1189 _winbindd_priv_socket = create_pipe_sock(
1190 get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
1191 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
1192 _winbindd_priv_socket));
1195 return _winbindd_priv_socket;
1198 /* Close the winbindd socket */
1200 void close_winbindd_socket(void)
1202 if (_winbindd_socket != -1) {
1203 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
1204 _winbindd_socket));
1205 close(_winbindd_socket);
1206 _winbindd_socket = -1;
1208 if (_winbindd_priv_socket != -1) {
1209 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
1210 _winbindd_priv_socket));
1211 close(_winbindd_priv_socket);
1212 _winbindd_priv_socket = -1;
1217 * Client list accessor functions
1220 static struct winbindd_cli_state *_client_list;
1221 static int _num_clients;
1223 /* Return list of all connected clients */
1225 struct winbindd_cli_state *winbindd_client_list(void)
1227 return _client_list;
1230 /* Add a connection to the list */
1232 void winbindd_add_client(struct winbindd_cli_state *cli)
1234 DLIST_ADD(_client_list, cli);
1235 _num_clients++;
1238 /* Remove a client from the list */
1240 void winbindd_remove_client(struct winbindd_cli_state *cli)
1242 DLIST_REMOVE(_client_list, cli);
1243 _num_clients--;
1246 /* Close all open clients */
1248 void winbindd_kill_all_clients(void)
1250 struct winbindd_cli_state *cl = winbindd_client_list();
1252 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1254 while (cl) {
1255 struct winbindd_cli_state *next;
1257 next = cl->next;
1258 winbindd_remove_client(cl);
1259 cl = next;
1263 /* Return number of open clients */
1265 int winbindd_num_clients(void)
1267 return _num_clients;
1270 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1271 TALLOC_CTX *mem_ctx,
1272 const DOM_SID *user_sid,
1273 uint32 *p_num_groups, DOM_SID **user_sids)
1275 struct netr_SamInfo3 *info3 = NULL;
1276 NTSTATUS status = NT_STATUS_NO_MEMORY;
1277 size_t num_groups = 0;
1279 DEBUG(3,(": lookup_usergroups_cached\n"));
1281 *user_sids = NULL;
1282 *p_num_groups = 0;
1284 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1286 if (info3 == NULL) {
1287 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1290 if (info3->base.groups.count == 0) {
1291 TALLOC_FREE(info3);
1292 return NT_STATUS_UNSUCCESSFUL;
1295 /* Skip Domain local groups outside our domain.
1296 We'll get these from the getsidaliases() RPC call. */
1297 status = sid_array_from_info3(mem_ctx, info3,
1298 user_sids,
1299 &num_groups,
1300 true, true);
1302 if (!NT_STATUS_IS_OK(status)) {
1303 TALLOC_FREE(info3);
1304 return status;
1307 TALLOC_FREE(info3);
1308 *p_num_groups = num_groups;
1309 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1311 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1313 return status;
1316 /*********************************************************************
1317 We use this to remove spaces from user and group names
1318 ********************************************************************/
1320 void ws_name_replace( char *name, char replace )
1322 char replace_char[2] = { 0x0, 0x0 };
1324 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1325 return;
1327 replace_char[0] = replace;
1328 all_string_sub( name, " ", replace_char, 0 );
1330 return;
1333 /*********************************************************************
1334 We use this to do the inverse of ws_name_replace()
1335 ********************************************************************/
1337 void ws_name_return( char *name, char replace )
1339 char replace_char[2] = { 0x0, 0x0 };
1341 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1342 return;
1344 replace_char[0] = replace;
1345 all_string_sub( name, replace_char, " ", 0 );
1347 return;
1350 /*********************************************************************
1351 ********************************************************************/
1353 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1355 struct winbindd_tdc_domain *tdc = NULL;
1356 TALLOC_CTX *frame = talloc_stackframe();
1357 bool ret = false;
1359 /* We can contact the domain if it is our primary domain */
1361 if (domain->primary) {
1362 return true;
1365 /* Trust the TDC cache and not the winbindd_domain flags */
1367 if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1368 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1369 domain->name));
1370 return false;
1373 /* Can always contact a domain that is in out forest */
1375 if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1376 ret = true;
1377 goto done;
1381 * On a _member_ server, we cannot contact the domain if it
1382 * is running AD and we have no inbound trust.
1385 if (!IS_DC &&
1386 domain->active_directory &&
1387 ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1389 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1390 "and we have no inbound trust.\n", domain->name));
1391 goto done;
1394 /* Assume everything else is ok (probably not true but what
1395 can you do?) */
1397 ret = true;
1399 done:
1400 talloc_destroy(frame);
1402 return ret;
1405 /*********************************************************************
1406 ********************************************************************/
1408 bool winbindd_internal_child(struct winbindd_child *child)
1410 if ((child == idmap_child()) || (child == locator_child())) {
1411 return True;
1414 return False;
1417 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1419 /*********************************************************************
1420 ********************************************************************/
1422 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1424 char *var = NULL;
1425 char addr[INET6_ADDRSTRLEN];
1426 const char *kdc = NULL;
1427 int lvl = 11;
1429 if (!domain || !domain->alt_name || !*domain->alt_name) {
1430 return;
1433 if (domain->initialized && !domain->active_directory) {
1434 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1435 domain->alt_name));
1436 return;
1439 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1440 kdc = addr;
1441 if (!*kdc) {
1442 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1443 domain->alt_name));
1444 kdc = domain->dcname;
1447 if (!kdc || !*kdc) {
1448 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1449 domain->alt_name));
1450 return;
1453 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1454 domain->alt_name) == -1) {
1455 return;
1458 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1459 var, kdc));
1461 setenv(var, kdc, 1);
1462 free(var);
1465 /*********************************************************************
1466 ********************************************************************/
1468 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1470 struct winbindd_domain *our_dom = find_our_domain();
1472 winbindd_set_locator_kdc_env(domain);
1474 if (domain != our_dom) {
1475 winbindd_set_locator_kdc_env(our_dom);
1479 /*********************************************************************
1480 ********************************************************************/
1482 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1484 char *var = NULL;
1486 if (!domain || !domain->alt_name || !*domain->alt_name) {
1487 return;
1490 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1491 domain->alt_name) == -1) {
1492 return;
1495 unsetenv(var);
1496 free(var);
1498 #else
1500 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1502 return;
1505 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1507 return;
1510 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */