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/>.
27 #define DBGC_CLASS DBGC_WINBIND
29 extern struct winbindd_methods cache_methods
;
30 extern struct winbindd_methods builtin_passdb_methods
;
31 extern struct winbindd_methods sam_passdb_methods
;
35 * @file winbindd_util.c
37 * Winbind daemon for NT domain authentication nss module.
41 /* The list of trusted domains. Note that the list can be deleted and
42 recreated using the init_domain_list() function so pointers to
43 individual winbindd_domain structures cannot be made. Keep a copy of
44 the domain name instead. */
46 static struct winbindd_domain
*_domain_list
= NULL
;
49 When was the last scan of trusted domains done?
54 static time_t last_trustdom_scan
;
56 struct winbindd_domain
*domain_list(void)
60 if ((!_domain_list
) && (!init_domain_list())) {
61 smb_panic("Init_domain_list failed");
67 /* Free all entries in the trusted domain list */
69 void free_domain_list(void)
71 struct winbindd_domain
*domain
= _domain_list
;
74 struct winbindd_domain
*next
= domain
->next
;
76 DLIST_REMOVE(_domain_list
, domain
);
82 static bool is_internal_domain(const DOM_SID
*sid
)
88 return sid_check_is_builtin(sid
);
90 return (sid_check_is_domain(sid
) || sid_check_is_builtin(sid
));
93 static bool is_in_internal_domain(const DOM_SID
*sid
)
99 return sid_check_is_in_builtin(sid
);
101 return (sid_check_is_in_our_domain(sid
) || sid_check_is_in_builtin(sid
));
105 /* Add a trusted domain to our list of domains */
106 static struct winbindd_domain
*add_trusted_domain(const char *domain_name
, const char *alt_name
,
107 struct winbindd_methods
*methods
,
110 struct winbindd_domain
*domain
;
111 const char *alternative_name
= NULL
;
112 char *idmap_config_option
;
114 const char **ignored_domains
, **dom
;
116 ignored_domains
= lp_parm_string_list(-1, "winbind", "ignore domains", NULL
);
117 for (dom
=ignored_domains
; dom
&& *dom
; dom
++) {
118 if (gen_fnmatch(*dom
, domain_name
) == 0) {
119 DEBUG(2,("Ignoring domain '%s'\n", domain_name
));
124 /* ignore alt_name if we are not in an AD domain */
126 if ( (lp_security() == SEC_ADS
) && alt_name
&& *alt_name
) {
127 alternative_name
= alt_name
;
130 /* We can't call domain_list() as this function is called from
131 init_domain_list() and we'll get stuck in a loop. */
132 for (domain
= _domain_list
; domain
; domain
= domain
->next
) {
133 if (strequal(domain_name
, domain
->name
) ||
134 strequal(domain_name
, domain
->alt_name
))
139 if (alternative_name
&& *alternative_name
)
141 if (strequal(alternative_name
, domain
->name
) ||
142 strequal(alternative_name
, domain
->alt_name
))
150 if (is_null_sid(sid
)) {
154 if (sid_equal(sid
, &domain
->sid
)) {
160 /* See if we found a match. Check if we need to update the
163 if ( domain
&& sid
) {
164 if ( sid_equal( &domain
->sid
, &global_sid_NULL
) )
165 sid_copy( &domain
->sid
, sid
);
170 /* Create new domain entry */
172 if ((domain
= SMB_MALLOC_P(struct winbindd_domain
)) == NULL
)
177 ZERO_STRUCTP(domain
);
179 fstrcpy(domain
->name
, domain_name
);
180 if (alternative_name
) {
181 fstrcpy(domain
->alt_name
, alternative_name
);
184 domain
->methods
= methods
;
185 domain
->backend
= NULL
;
186 domain
->internal
= is_internal_domain(sid
);
187 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
188 domain
->last_seq_check
= 0;
189 domain
->initialized
= False
;
190 domain
->online
= is_internal_domain(sid
);
191 domain
->check_online_timeout
= 0;
192 domain
->dc_probe_pid
= (pid_t
)-1;
194 sid_copy(&domain
->sid
, sid
);
197 /* Link to domain list */
198 DLIST_ADD_END(_domain_list
, domain
, struct winbindd_domain
*);
200 wcache_tdc_add_domain( domain
);
202 idmap_config_option
= talloc_asprintf(talloc_tos(), "idmap config %s",
204 if (idmap_config_option
== NULL
) {
205 DEBUG(0, ("talloc failed, not looking for idmap config\n"));
209 param
= lp_parm_const_string(-1, idmap_config_option
, "range", NULL
);
211 DEBUG(10, ("%s : range = %s\n", idmap_config_option
,
212 param
? param
: "not defined"));
215 unsigned low_id
, high_id
;
216 if (sscanf(param
, "%u - %u", &low_id
, &high_id
) != 2) {
217 DEBUG(1, ("invalid range syntax in %s: %s\n",
218 idmap_config_option
, param
));
221 if (low_id
> high_id
) {
222 DEBUG(1, ("invalid range in %s: %s\n",
223 idmap_config_option
, param
));
226 domain
->have_idmap_config
= true;
227 domain
->id_range_low
= low_id
;
228 domain
->id_range_high
= high_id
;
233 DEBUG(2,("Added domain %s %s %s\n",
234 domain
->name
, domain
->alt_name
,
235 &domain
->sid
?sid_string_dbg(&domain
->sid
):""));
240 /********************************************************************
241 rescan our domains looking for new trusted domains
242 ********************************************************************/
244 struct trustdom_state
{
248 struct winbindd_response
*response
;
251 static void trustdom_recv(void *private_data
, bool success
);
252 static void rescan_forest_root_trusts( void );
253 static void rescan_forest_trusts( void );
255 static void add_trusted_domains( struct winbindd_domain
*domain
)
258 struct winbindd_request
*request
;
259 struct winbindd_response
*response
;
260 uint32 fr_flags
= (NETR_TRUST_FLAG_TREEROOT
|NETR_TRUST_FLAG_IN_FOREST
);
262 struct trustdom_state
*state
;
264 mem_ctx
= talloc_init("add_trusted_domains");
265 if (mem_ctx
== NULL
) {
266 DEBUG(0, ("talloc_init failed\n"));
270 request
= TALLOC_ZERO_P(mem_ctx
, struct winbindd_request
);
271 response
= TALLOC_P(mem_ctx
, struct winbindd_response
);
272 state
= TALLOC_P(mem_ctx
, struct trustdom_state
);
274 if ((request
== NULL
) || (response
== NULL
) || (state
== NULL
)) {
275 DEBUG(0, ("talloc failed\n"));
276 talloc_destroy(mem_ctx
);
280 state
->mem_ctx
= mem_ctx
;
281 state
->response
= response
;
283 /* Flags used to know how to continue the forest trust search */
285 state
->primary
= domain
->primary
;
286 state
->forest_root
= ((domain
->domain_flags
& fr_flags
) == fr_flags
);
288 request
->length
= sizeof(*request
);
289 request
->cmd
= WINBINDD_LIST_TRUSTDOM
;
291 async_domain_request(mem_ctx
, domain
, request
, response
,
292 trustdom_recv
, state
);
295 static void trustdom_recv(void *private_data
, bool success
)
297 struct trustdom_state
*state
=
298 talloc_get_type_abort(private_data
, struct trustdom_state
);
299 struct winbindd_response
*response
= state
->response
;
302 if ((!success
) || (response
->result
!= WINBINDD_OK
)) {
303 DEBUG(1, ("Could not receive trustdoms\n"));
304 talloc_destroy(state
->mem_ctx
);
308 p
= (char *)response
->extra_data
.data
;
310 while ((p
!= NULL
) && (*p
!= '\0')) {
311 char *q
, *sidstr
, *alt_name
;
313 struct winbindd_domain
*domain
;
314 char *alternate_name
= NULL
;
316 alt_name
= strchr(p
, '\\');
317 if (alt_name
== NULL
) {
318 DEBUG(0, ("Got invalid trustdom response\n"));
325 sidstr
= strchr(alt_name
, '\\');
326 if (sidstr
== NULL
) {
327 DEBUG(0, ("Got invalid trustdom response\n"));
334 q
= strchr(sidstr
, '\n');
338 if (!string_to_sid(&sid
, sidstr
)) {
339 /* Allow NULL sid for sibling domains */
340 if ( strcmp(sidstr
,"S-0-0") == 0) {
341 sid_copy( &sid
, &global_sid_NULL
);
343 DEBUG(0, ("Got invalid trustdom response\n"));
348 /* use the real alt_name if we have one, else pass in NULL */
350 if ( !strequal( alt_name
, "(null)" ) )
351 alternate_name
= alt_name
;
353 /* If we have an existing domain structure, calling
354 add_trusted_domain() will update the SID if
355 necessary. This is important because we need the
356 SID for sibling domains */
358 if ( find_domain_from_name_noinit(p
) != NULL
) {
359 domain
= add_trusted_domain(p
, alternate_name
,
363 domain
= add_trusted_domain(p
, alternate_name
,
367 setup_domain_child(domain
,
376 SAFE_FREE(response
->extra_data
.data
);
379 Cases to consider when scanning trusts:
380 (a) we are calling from a child domain (primary && !forest_root)
381 (b) we are calling from the root of the forest (primary && forest_root)
382 (c) we are calling from a trusted forest domain (!primary
386 if ( state
->primary
) {
387 /* If this is our primary domain and we are not in the
388 forest root, we have to scan the root trusts first */
390 if ( !state
->forest_root
)
391 rescan_forest_root_trusts();
393 rescan_forest_trusts();
395 } else if ( state
->forest_root
) {
396 /* Once we have done root forest trust search, we can
397 go on to search the trusted forests */
399 rescan_forest_trusts();
402 talloc_destroy(state
->mem_ctx
);
407 /********************************************************************
408 Scan the trusts of our forest root
409 ********************************************************************/
411 static void rescan_forest_root_trusts( void )
413 struct winbindd_tdc_domain
*dom_list
= NULL
;
414 size_t num_trusts
= 0;
417 /* The only transitive trusts supported by Windows 2003 AD are
418 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
419 first two are handled in forest and listed by
420 DsEnumerateDomainTrusts(). Forest trusts are not so we
421 have to do that ourselves. */
423 if ( !wcache_tdc_fetch_list( &dom_list
, &num_trusts
) )
426 for ( i
=0; i
<num_trusts
; i
++ ) {
427 struct winbindd_domain
*d
= NULL
;
429 /* Find the forest root. Don't necessarily trust
430 the domain_list() as our primary domain may not
431 have been initialized. */
433 if ( !(dom_list
[i
].trust_flags
& NETR_TRUST_FLAG_TREEROOT
) ) {
437 /* Here's the forest root */
439 d
= find_domain_from_name_noinit( dom_list
[i
].domain_name
);
442 d
= add_trusted_domain( dom_list
[i
].domain_name
,
443 dom_list
[i
].dns_name
,
452 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
453 "for domain tree root %s (%s)\n",
454 d
->name
, d
->alt_name
));
456 d
->domain_flags
= dom_list
[i
].trust_flags
;
457 d
->domain_type
= dom_list
[i
].trust_type
;
458 d
->domain_trust_attribs
= dom_list
[i
].trust_attribs
;
460 add_trusted_domains( d
);
465 TALLOC_FREE( dom_list
);
470 /********************************************************************
471 scan the transitive forest trusts (not our own)
472 ********************************************************************/
475 static void rescan_forest_trusts( void )
477 struct winbindd_domain
*d
= NULL
;
478 struct winbindd_tdc_domain
*dom_list
= NULL
;
479 size_t num_trusts
= 0;
482 /* The only transitive trusts supported by Windows 2003 AD are
483 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
484 first two are handled in forest and listed by
485 DsEnumerateDomainTrusts(). Forest trusts are not so we
486 have to do that ourselves. */
488 if ( !wcache_tdc_fetch_list( &dom_list
, &num_trusts
) )
491 for ( i
=0; i
<num_trusts
; i
++ ) {
492 uint32 flags
= dom_list
[i
].trust_flags
;
493 uint32 type
= dom_list
[i
].trust_type
;
494 uint32 attribs
= dom_list
[i
].trust_attribs
;
496 d
= find_domain_from_name_noinit( dom_list
[i
].domain_name
);
498 /* ignore our primary and internal domains */
500 if ( d
&& (d
->internal
|| d
->primary
) )
503 if ( (flags
& NETR_TRUST_FLAG_INBOUND
) &&
504 (type
== NETR_TRUST_TYPE_UPLEVEL
) &&
505 (attribs
== NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) )
507 /* add the trusted domain if we don't know
511 d
= add_trusted_domain( dom_list
[i
].domain_name
,
512 dom_list
[i
].dns_name
,
521 DEBUG(10,("Following trust path for domain %s (%s)\n",
522 d
->name
, d
->alt_name
));
523 add_trusted_domains( d
);
527 TALLOC_FREE( dom_list
);
532 /*********************************************************************
533 The process of updating the trusted domain list is a three step
536 (b) ask the root domain in our forest
537 (c) ask the a DC in any Win2003 trusted forests
538 *********************************************************************/
540 void rescan_trusted_domains( void )
542 time_t now
= time(NULL
);
544 /* Check that we allow trusted domains at all */
545 if (!lp_allow_trusted_domains())
548 /* see if the time has come... */
550 if ((now
>= last_trustdom_scan
) &&
551 ((now
-last_trustdom_scan
) < WINBINDD_RESCAN_FREQ
) )
554 /* I use to clear the cache here and start over but that
555 caused problems in child processes that needed the
556 trust dom list early on. Removing it means we
557 could have some trusted domains listed that have been
558 removed from our primary domain's DC until a full
559 restart. This should be ok since I think this is what
560 Windows does as well. */
562 /* this will only add new domains we didn't already know about
563 in the domain_list()*/
565 add_trusted_domains( find_our_domain() );
567 last_trustdom_scan
= now
;
572 struct init_child_state
{
574 struct winbindd_domain
*domain
;
575 struct winbindd_request
*request
;
576 struct winbindd_response
*response
;
577 void (*continuation
)(void *private_data
, bool success
);
581 static void init_child_recv(void *private_data
, bool success
);
582 static void init_child_getdc_recv(void *private_data
, bool success
);
584 enum winbindd_result
init_child_connection(struct winbindd_domain
*domain
,
585 void (*continuation
)(void *private_data
,
590 struct winbindd_request
*request
;
591 struct winbindd_response
*response
;
592 struct init_child_state
*state
;
593 struct winbindd_domain
*request_domain
;
595 mem_ctx
= talloc_init("init_child_connection");
596 if (mem_ctx
== NULL
) {
597 DEBUG(0, ("talloc_init failed\n"));
598 return WINBINDD_ERROR
;
601 request
= TALLOC_ZERO_P(mem_ctx
, struct winbindd_request
);
602 response
= TALLOC_P(mem_ctx
, struct winbindd_response
);
603 state
= TALLOC_P(mem_ctx
, struct init_child_state
);
605 if ((request
== NULL
) || (response
== NULL
) || (state
== NULL
)) {
606 DEBUG(0, ("talloc failed\n"));
607 TALLOC_FREE(mem_ctx
);
608 continuation(private_data
, False
);
609 return WINBINDD_ERROR
;
612 request
->length
= sizeof(*request
);
614 state
->mem_ctx
= mem_ctx
;
615 state
->domain
= domain
;
616 state
->request
= request
;
617 state
->response
= response
;
618 state
->continuation
= continuation
;
619 state
->private_data
= private_data
;
621 if (IS_DC
|| domain
->primary
|| domain
->internal
) {
622 /* The primary domain has to find the DC name itself */
623 request
->cmd
= WINBINDD_INIT_CONNECTION
;
624 fstrcpy(request
->domain_name
, domain
->name
);
625 request
->data
.init_conn
.is_primary
= domain
->primary
? true : false;
626 fstrcpy(request
->data
.init_conn
.dcname
, "");
627 async_request(mem_ctx
, &domain
->child
, request
, response
,
628 init_child_recv
, state
);
629 return WINBINDD_PENDING
;
632 /* This is *not* the primary domain, let's ask our DC about a DC
635 request
->cmd
= WINBINDD_GETDCNAME
;
636 fstrcpy(request
->domain_name
, domain
->name
);
638 request_domain
= find_our_domain();
639 async_domain_request(mem_ctx
, request_domain
, request
, response
,
640 init_child_getdc_recv
, state
);
641 return WINBINDD_PENDING
;
644 static void init_child_getdc_recv(void *private_data
, bool success
)
646 struct init_child_state
*state
=
647 talloc_get_type_abort(private_data
, struct init_child_state
);
648 const char *dcname
= "";
650 DEBUG(10, ("Received getdcname response\n"));
652 if (success
&& (state
->response
->result
== WINBINDD_OK
)) {
653 dcname
= state
->response
->data
.dc_name
;
656 state
->request
->cmd
= WINBINDD_INIT_CONNECTION
;
657 fstrcpy(state
->request
->domain_name
, state
->domain
->name
);
658 state
->request
->data
.init_conn
.is_primary
= False
;
659 fstrcpy(state
->request
->data
.init_conn
.dcname
, dcname
);
661 async_request(state
->mem_ctx
, &state
->domain
->child
,
662 state
->request
, state
->response
,
663 init_child_recv
, state
);
666 static void init_child_recv(void *private_data
, bool success
)
668 struct init_child_state
*state
=
669 talloc_get_type_abort(private_data
, struct init_child_state
);
671 DEBUG(5, ("Received child initialization response for domain %s\n",
672 state
->domain
->name
));
674 if ((!success
) || (state
->response
->result
!= WINBINDD_OK
)) {
675 DEBUG(3, ("Could not init child\n"));
676 state
->continuation(state
->private_data
, False
);
677 talloc_destroy(state
->mem_ctx
);
681 fstrcpy(state
->domain
->name
,
682 state
->response
->data
.domain_info
.name
);
683 fstrcpy(state
->domain
->alt_name
,
684 state
->response
->data
.domain_info
.alt_name
);
685 if (!string_to_sid(&state
->domain
->sid
,
686 state
->response
->data
.domain_info
.sid
)) {
687 DEBUG(1,("init_child_recv: Could not convert sid %s "
689 state
->response
->data
.domain_info
.sid
));
690 state
->continuation(state
->private_data
, False
);
691 talloc_destroy(state
->mem_ctx
);
695 state
->domain
->native_mode
=
696 state
->response
->data
.domain_info
.native_mode
;
697 state
->domain
->active_directory
=
698 state
->response
->data
.domain_info
.active_directory
;
700 init_dc_connection(state
->domain
);
702 if (state
->continuation
!= NULL
)
703 state
->continuation(state
->private_data
, True
);
704 talloc_destroy(state
->mem_ctx
);
707 enum winbindd_result
winbindd_dual_init_connection(struct winbindd_domain
*domain
,
708 struct winbindd_cli_state
*state
)
710 /* Ensure null termination */
711 state
->request
.domain_name
712 [sizeof(state
->request
.domain_name
)-1]='\0';
713 state
->request
.data
.init_conn
.dcname
714 [sizeof(state
->request
.data
.init_conn
.dcname
)-1]='\0';
716 if (strlen(state
->request
.data
.init_conn
.dcname
) > 0) {
717 fstrcpy(domain
->dcname
, state
->request
.data
.init_conn
.dcname
);
720 init_dc_connection(domain
);
722 if (!domain
->initialized
) {
723 /* If we return error here we can't do any cached authentication,
724 but we may be in disconnected mode and can't initialize correctly.
725 Do what the previous code did and just return without initialization,
726 once we go online we'll re-initialize.
728 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
729 "online = %d\n", domain
->name
, (int)domain
->online
));
732 fstrcpy(state
->response
.data
.domain_info
.name
, domain
->name
);
733 fstrcpy(state
->response
.data
.domain_info
.alt_name
, domain
->alt_name
);
734 sid_to_fstring(state
->response
.data
.domain_info
.sid
, &domain
->sid
);
736 state
->response
.data
.domain_info
.native_mode
737 = domain
->native_mode
;
738 state
->response
.data
.domain_info
.active_directory
739 = domain
->active_directory
;
740 state
->response
.data
.domain_info
.primary
746 /* Look up global info for the winbind daemon */
747 bool init_domain_list(void)
749 struct winbindd_domain
*domain
;
750 int role
= lp_server_role();
752 /* Free existing list */
757 domain
= add_trusted_domain("BUILTIN", NULL
, &builtin_passdb_methods
,
758 &global_sid_Builtin
);
760 setup_domain_child(domain
,
766 domain
= add_trusted_domain(get_global_sam_name(), NULL
,
767 &sam_passdb_methods
, get_global_sam_sid());
769 if ( role
!= ROLE_DOMAIN_MEMBER
) {
770 domain
->primary
= True
;
772 setup_domain_child(domain
,
776 /* Add ourselves as the first entry. */
778 if ( role
== ROLE_DOMAIN_MEMBER
) {
781 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid
)) {
782 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
786 domain
= add_trusted_domain( lp_workgroup(), lp_realm(),
787 &cache_methods
, &our_sid
);
789 domain
->primary
= True
;
790 setup_domain_child(domain
,
793 /* Even in the parent winbindd we'll need to
794 talk to the DC, so try and see if we can
795 contact it. Theoretically this isn't neccessary
796 as the init_dc_connection() in init_child_recv()
797 will do this, but we can start detecting the DC
799 set_domain_online_request(domain
);
806 void check_domain_trusted( const char *name
, const DOM_SID
*user_sid
)
808 struct winbindd_domain
*domain
;
812 /* Check if we even care */
814 if (!lp_allow_trusted_domains())
817 domain
= find_domain_from_name_noinit( name
);
821 sid_copy( &dom_sid
, user_sid
);
822 if ( !sid_split_rid( &dom_sid
, &rid
) )
825 /* add the newly discovered trusted domain */
827 domain
= add_trusted_domain( name
, NULL
, &cache_methods
,
833 /* assume this is a trust from a one-way transitive
836 domain
->active_directory
= True
;
837 domain
->domain_flags
= NETR_TRUST_FLAG_OUTBOUND
;
838 domain
->domain_type
= NETR_TRUST_TYPE_UPLEVEL
;
839 domain
->internal
= False
;
840 domain
->online
= True
;
842 setup_domain_child(domain
,
845 wcache_tdc_add_domain( domain
);
851 * Given a domain name, return the struct winbindd domain info for it
853 * @note Do *not* pass lp_workgroup() to this function. domain_list
854 * may modify it's value, and free that pointer. Instead, our local
855 * domain may be found by calling find_our_domain().
859 * @return The domain structure for the named domain, if it is working.
862 struct winbindd_domain
*find_domain_from_name_noinit(const char *domain_name
)
864 struct winbindd_domain
*domain
;
866 /* Search through list */
868 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
869 if (strequal(domain_name
, domain
->name
) ||
870 (domain
->alt_name
[0] &&
871 strequal(domain_name
, domain
->alt_name
))) {
881 struct winbindd_domain
*find_domain_from_name(const char *domain_name
)
883 struct winbindd_domain
*domain
;
885 domain
= find_domain_from_name_noinit(domain_name
);
890 if (!domain
->initialized
)
891 init_dc_connection(domain
);
896 /* Given a domain sid, return the struct winbindd domain info for it */
898 struct winbindd_domain
*find_domain_from_sid_noinit(const DOM_SID
*sid
)
900 struct winbindd_domain
*domain
;
902 /* Search through list */
904 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
905 if (sid_compare_domain(sid
, &domain
->sid
) == 0)
914 /* Given a domain sid, return the struct winbindd domain info for it */
916 struct winbindd_domain
*find_domain_from_sid(const DOM_SID
*sid
)
918 struct winbindd_domain
*domain
;
920 domain
= find_domain_from_sid_noinit(sid
);
925 if (!domain
->initialized
)
926 init_dc_connection(domain
);
931 struct winbindd_domain
*find_our_domain(void)
933 struct winbindd_domain
*domain
;
935 /* Search through list */
937 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
942 smb_panic("Could not find our domain");
946 struct winbindd_domain
*find_root_domain(void)
948 struct winbindd_domain
*ours
= find_our_domain();
953 if ( strlen(ours
->forest_name
) == 0 )
956 return find_domain_from_name( ours
->forest_name
);
959 struct winbindd_domain
*find_builtin_domain(void)
962 struct winbindd_domain
*domain
;
964 string_to_sid(&sid
, "S-1-5-32");
965 domain
= find_domain_from_sid(&sid
);
967 if (domain
== NULL
) {
968 smb_panic("Could not find BUILTIN domain");
974 /* Find the appropriate domain to lookup a name or SID */
976 struct winbindd_domain
*find_lookup_domain_from_sid(const DOM_SID
*sid
)
978 /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
980 if ( sid_check_is_in_unix_groups(sid
) ||
981 sid_check_is_unix_groups(sid
) ||
982 sid_check_is_in_unix_users(sid
) ||
983 sid_check_is_unix_users(sid
) )
985 return find_domain_from_sid(get_global_sam_sid());
988 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
989 * one to contact the external DC's. On member servers the internal
990 * domains are different: These are part of the local SAM. */
992 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid
)));
994 if (IS_DC
|| is_internal_domain(sid
) || is_in_internal_domain(sid
)) {
995 DEBUG(10, ("calling find_domain_from_sid\n"));
996 return find_domain_from_sid(sid
);
999 /* On a member server a query for SID or name can always go to our
1002 DEBUG(10, ("calling find_our_domain\n"));
1003 return find_our_domain();
1006 struct winbindd_domain
*find_lookup_domain_from_name(const char *domain_name
)
1008 if ( strequal(domain_name
, unix_users_domain_name() ) ||
1009 strequal(domain_name
, unix_groups_domain_name() ) )
1011 return find_domain_from_name_noinit( get_global_sam_name() );
1014 if (IS_DC
|| strequal(domain_name
, "BUILTIN") ||
1015 strequal(domain_name
, get_global_sam_name()))
1016 return find_domain_from_name_noinit(domain_name
);
1018 /* The "Unix User" and "Unix Group" domain our handled by passdb */
1020 return find_our_domain();
1023 /* Lookup a sid in a domain from a name */
1025 bool winbindd_lookup_sid_by_name(TALLOC_CTX
*mem_ctx
,
1026 enum winbindd_cmd orig_cmd
,
1027 struct winbindd_domain
*domain
,
1028 const char *domain_name
,
1029 const char *name
, DOM_SID
*sid
,
1030 enum lsa_SidType
*type
)
1035 result
= domain
->methods
->name_to_sid(domain
, mem_ctx
, orig_cmd
,
1036 domain_name
, name
, sid
, type
);
1038 /* Return sid and type if lookup successful */
1039 if (!NT_STATUS_IS_OK(result
)) {
1040 *type
= SID_NAME_UNKNOWN
;
1043 return NT_STATUS_IS_OK(result
);
1047 * @brief Lookup a name in a domain from a sid.
1049 * @param sid Security ID you want to look up.
1050 * @param name On success, set to the name corresponding to @p sid.
1051 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
1052 * @param type On success, contains the type of name: alias, group or
1054 * @retval True if the name exists, in which case @p name and @p type
1055 * are set, otherwise False.
1057 bool winbindd_lookup_name_by_sid(TALLOC_CTX
*mem_ctx
,
1058 struct winbindd_domain
*domain
,
1062 enum lsa_SidType
*type
)
1071 result
= domain
->methods
->sid_to_name(domain
, mem_ctx
, sid
, dom_name
, name
, type
);
1073 /* Return name and type if successful */
1075 if (NT_STATUS_IS_OK(result
)) {
1079 *type
= SID_NAME_UNKNOWN
;
1084 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
1086 void free_getent_state(struct getent_state
*state
)
1088 struct getent_state
*temp
;
1090 /* Iterate over state list */
1094 while(temp
!= NULL
) {
1095 struct getent_state
*next
= temp
->next
;
1097 /* Free sam entries then list entry */
1099 SAFE_FREE(state
->sam_entries
);
1100 DLIST_REMOVE(state
, state
);
1107 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1109 static bool assume_domain(const char *domain
)
1111 /* never assume the domain on a standalone server */
1113 if ( lp_server_role() == ROLE_STANDALONE
)
1116 /* domain member servers may possibly assume for the domain name */
1118 if ( lp_server_role() == ROLE_DOMAIN_MEMBER
) {
1119 if ( !strequal(lp_workgroup(), domain
) )
1122 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1126 /* only left with a domain controller */
1128 if ( strequal(get_global_sam_name(), domain
) ) {
1135 /* Parse a string of the form DOMAIN\user into a domain and a user */
1137 bool parse_domain_user(const char *domuser
, fstring domain
, fstring user
)
1139 char *p
= strchr(domuser
,*lp_winbind_separator());
1142 fstrcpy(user
, domuser
);
1144 if ( assume_domain(lp_workgroup())) {
1145 fstrcpy(domain
, lp_workgroup());
1146 } else if ((p
= strchr(domuser
, '@')) != NULL
) {
1147 fstrcpy(domain
, "");
1153 fstrcpy(domain
, domuser
);
1154 domain
[PTR_DIFF(p
, domuser
)] = 0;
1162 bool parse_domain_user_talloc(TALLOC_CTX
*mem_ctx
, const char *domuser
,
1163 char **domain
, char **user
)
1165 fstring fstr_domain
, fstr_user
;
1166 if (!parse_domain_user(domuser
, fstr_domain
, fstr_user
)) {
1169 *domain
= talloc_strdup(mem_ctx
, fstr_domain
);
1170 *user
= talloc_strdup(mem_ctx
, fstr_user
);
1171 return ((*domain
!= NULL
) && (*user
!= NULL
));
1174 /* add a domain user name to a buffer */
1175 void parse_add_domuser(void *buf
, char *domuser
, int *len
)
1181 p
= strchr(domuser
, *lp_winbind_separator());
1185 fstrcpy(domain
, domuser
);
1186 domain
[PTR_DIFF(p
, domuser
)] = 0;
1189 if (assume_domain(domain
)) {
1192 *len
-= (PTR_DIFF(p
, domuser
));
1196 safe_strcpy((char *)buf
, user
, *len
);
1199 /* Ensure an incoming username from NSS is fully qualified. Replace the
1200 incoming fstring with DOMAIN <separator> user. Returns the same
1201 values as parse_domain_user() but also replaces the incoming username.
1202 Used to ensure all names are fully qualified within winbindd.
1203 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1204 The protocol definitions of auth_crap, chng_pswd_auth_crap
1205 really should be changed to use this instead of doing things
1208 bool canonicalize_username(fstring username_inout
, fstring domain
, fstring user
)
1210 if (!parse_domain_user(username_inout
, domain
, user
)) {
1213 slprintf(username_inout
, sizeof(fstring
) - 1, "%s%c%s",
1214 domain
, *lp_winbind_separator(),
1220 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1221 'winbind separator' options.
1223 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1226 If we are a PDC or BDC, and this is for our domain, do likewise.
1228 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
1229 username is then unqualified in unix
1231 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1233 void fill_domain_username(fstring name
, const char *domain
, const char *user
, bool can_assume
)
1237 fstrcpy(tmp_user
, user
);
1238 strlower_m(tmp_user
);
1240 if (can_assume
&& assume_domain(domain
)) {
1241 strlcpy(name
, tmp_user
, sizeof(fstring
));
1243 slprintf(name
, sizeof(fstring
) - 1, "%s%c%s",
1244 domain
, *lp_winbind_separator(),
1250 * talloc version of fill_domain_username()
1251 * return NULL on talloc failure.
1253 char *fill_domain_username_talloc(TALLOC_CTX
*mem_ctx
,
1258 char *tmp_user
, *name
;
1260 tmp_user
= talloc_strdup(mem_ctx
, user
);
1261 strlower_m(tmp_user
);
1263 if (can_assume
&& assume_domain(domain
)) {
1266 name
= talloc_asprintf(mem_ctx
, "%s%c%s",
1268 *lp_winbind_separator(),
1270 TALLOC_FREE(tmp_user
);
1277 * Winbindd socket accessor functions
1280 const char *get_winbind_pipe_dir(void)
1282 return lp_parm_const_string(-1, "winbindd", "socket dir", WINBINDD_SOCKET_DIR
);
1285 char *get_winbind_priv_pipe_dir(void)
1287 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR
);
1290 /* Open the winbindd socket */
1292 static int _winbindd_socket
= -1;
1293 static int _winbindd_priv_socket
= -1;
1295 int open_winbindd_socket(void)
1297 if (_winbindd_socket
== -1) {
1298 _winbindd_socket
= create_pipe_sock(
1299 get_winbind_pipe_dir(), WINBINDD_SOCKET_NAME
, 0755);
1300 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
1304 return _winbindd_socket
;
1307 int open_winbindd_priv_socket(void)
1309 if (_winbindd_priv_socket
== -1) {
1310 _winbindd_priv_socket
= create_pipe_sock(
1311 get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME
, 0750);
1312 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
1313 _winbindd_priv_socket
));
1316 return _winbindd_priv_socket
;
1319 /* Close the winbindd socket */
1321 void close_winbindd_socket(void)
1323 if (_winbindd_socket
!= -1) {
1324 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
1326 close(_winbindd_socket
);
1327 _winbindd_socket
= -1;
1329 if (_winbindd_priv_socket
!= -1) {
1330 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
1331 _winbindd_priv_socket
));
1332 close(_winbindd_priv_socket
);
1333 _winbindd_priv_socket
= -1;
1338 * Client list accessor functions
1341 static struct winbindd_cli_state
*_client_list
;
1342 static int _num_clients
;
1344 /* Return list of all connected clients */
1346 struct winbindd_cli_state
*winbindd_client_list(void)
1348 return _client_list
;
1351 /* Add a connection to the list */
1353 void winbindd_add_client(struct winbindd_cli_state
*cli
)
1355 DLIST_ADD(_client_list
, cli
);
1359 /* Remove a client from the list */
1361 void winbindd_remove_client(struct winbindd_cli_state
*cli
)
1363 DLIST_REMOVE(_client_list
, cli
);
1367 /* Close all open clients */
1369 void winbindd_kill_all_clients(void)
1371 struct winbindd_cli_state
*cl
= winbindd_client_list();
1373 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1376 struct winbindd_cli_state
*next
;
1379 winbindd_remove_client(cl
);
1384 /* Return number of open clients */
1386 int winbindd_num_clients(void)
1388 return _num_clients
;
1391 NTSTATUS
lookup_usergroups_cached(struct winbindd_domain
*domain
,
1392 TALLOC_CTX
*mem_ctx
,
1393 const DOM_SID
*user_sid
,
1394 uint32
*p_num_groups
, DOM_SID
**user_sids
)
1396 struct netr_SamInfo3
*info3
= NULL
;
1397 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1398 size_t num_groups
= 0;
1400 DEBUG(3,(": lookup_usergroups_cached\n"));
1405 info3
= netsamlogon_cache_get(mem_ctx
, user_sid
);
1407 if (info3
== NULL
) {
1408 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1411 if (info3
->base
.groups
.count
== 0) {
1413 return NT_STATUS_UNSUCCESSFUL
;
1416 /* Skip Domain local groups outside our domain.
1417 We'll get these from the getsidaliases() RPC call. */
1418 status
= sid_array_from_info3(mem_ctx
, info3
,
1423 if (!NT_STATUS_IS_OK(status
)) {
1429 *p_num_groups
= num_groups
;
1430 status
= (user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
1432 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1437 /*********************************************************************
1438 We use this to remove spaces from user and group names
1439 ********************************************************************/
1441 NTSTATUS
normalize_name_map(TALLOC_CTX
*mem_ctx
,
1442 struct winbindd_domain
*domain
,
1448 if (!name
|| !normalized
) {
1449 return NT_STATUS_INVALID_PARAMETER
;
1452 if (!lp_winbind_normalize_names()) {
1453 return NT_STATUS_PROCEDURE_NOT_FOUND
;
1456 /* Alias support and whitespace replacement are mutually
1459 nt_status
= resolve_username_to_alias(mem_ctx
, domain
,
1461 if (NT_STATUS_IS_OK(nt_status
)) {
1462 /* special return code to let the caller know we
1463 mapped to an alias */
1464 return NT_STATUS_FILE_RENAMED
;
1467 /* check for an unreachable domain */
1469 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1470 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1472 set_domain_offline(domain
);
1476 /* deal with whitespace */
1478 *normalized
= talloc_strdup(mem_ctx
, name
);
1479 if (!(*normalized
)) {
1480 return NT_STATUS_NO_MEMORY
;
1483 all_string_sub( *normalized
, " ", "_", 0 );
1485 return NT_STATUS_OK
;
1488 /*********************************************************************
1489 We use this to do the inverse of normalize_name_map()
1490 ********************************************************************/
1492 NTSTATUS
normalize_name_unmap(TALLOC_CTX
*mem_ctx
,
1497 struct winbindd_domain
*domain
= find_our_domain();
1499 if (!name
|| !normalized
) {
1500 return NT_STATUS_INVALID_PARAMETER
;
1503 if (!lp_winbind_normalize_names()) {
1504 return NT_STATUS_PROCEDURE_NOT_FOUND
;
1507 /* Alias support and whitespace replacement are mutally
1510 /* When mapping from an alias to a username, we don't know the
1511 domain. But we only need a domain structure to cache
1512 a successful lookup , so just our own domain structure for
1515 nt_status
= resolve_alias_to_username(mem_ctx
, domain
,
1517 if (NT_STATUS_IS_OK(nt_status
)) {
1518 /* Special return code to let the caller know we mapped
1520 return NT_STATUS_FILE_RENAMED
;
1523 /* check for an unreachable domain */
1525 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1526 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1528 set_domain_offline(domain
);
1532 /* deal with whitespace */
1534 *normalized
= talloc_strdup(mem_ctx
, name
);
1535 if (!(*normalized
)) {
1536 return NT_STATUS_NO_MEMORY
;
1539 all_string_sub(*normalized
, "_", " ", 0);
1541 return NT_STATUS_OK
;
1544 /*********************************************************************
1545 ********************************************************************/
1547 bool winbindd_can_contact_domain(struct winbindd_domain
*domain
)
1549 struct winbindd_tdc_domain
*tdc
= NULL
;
1550 TALLOC_CTX
*frame
= talloc_stackframe();
1553 /* We can contact the domain if it is our primary domain */
1555 if (domain
->primary
) {
1559 /* Trust the TDC cache and not the winbindd_domain flags */
1561 if ((tdc
= wcache_tdc_fetch_domain(frame
, domain
->name
)) == NULL
) {
1562 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1567 /* Can always contact a domain that is in out forest */
1569 if (tdc
->trust_flags
& NETR_TRUST_FLAG_IN_FOREST
) {
1575 * On a _member_ server, we cannot contact the domain if it
1576 * is running AD and we have no inbound trust.
1580 domain
->active_directory
&&
1581 ((tdc
->trust_flags
& NETR_TRUST_FLAG_INBOUND
) != NETR_TRUST_FLAG_INBOUND
))
1583 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1584 "and we have no inbound trust.\n", domain
->name
));
1588 /* Assume everything else is ok (probably not true but what
1594 talloc_destroy(frame
);
1599 /*********************************************************************
1600 ********************************************************************/
1602 bool winbindd_internal_child(struct winbindd_child
*child
)
1604 if ((child
== idmap_child()) || (child
== locator_child())) {
1611 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1613 /*********************************************************************
1614 ********************************************************************/
1616 static void winbindd_set_locator_kdc_env(const struct winbindd_domain
*domain
)
1619 char addr
[INET6_ADDRSTRLEN
];
1620 const char *kdc
= NULL
;
1623 if (!domain
|| !domain
->alt_name
|| !*domain
->alt_name
) {
1627 if (domain
->initialized
&& !domain
->active_directory
) {
1628 DEBUG(lvl
,("winbindd_set_locator_kdc_env: %s not AD\n",
1633 print_sockaddr(addr
, sizeof(addr
), &domain
->dcaddr
);
1636 DEBUG(lvl
,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1638 kdc
= domain
->dcname
;
1641 if (!kdc
|| !*kdc
) {
1642 DEBUG(lvl
,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1647 if (asprintf_strupper_m(&var
, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS
,
1648 domain
->alt_name
) == -1) {
1652 DEBUG(lvl
,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1655 setenv(var
, kdc
, 1);
1659 /*********************************************************************
1660 ********************************************************************/
1662 void winbindd_set_locator_kdc_envs(const struct winbindd_domain
*domain
)
1664 struct winbindd_domain
*our_dom
= find_our_domain();
1666 winbindd_set_locator_kdc_env(domain
);
1668 if (domain
!= our_dom
) {
1669 winbindd_set_locator_kdc_env(our_dom
);
1673 /*********************************************************************
1674 ********************************************************************/
1676 void winbindd_unset_locator_kdc_env(const struct winbindd_domain
*domain
)
1680 if (!domain
|| !domain
->alt_name
|| !*domain
->alt_name
) {
1684 if (asprintf_strupper_m(&var
, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS
,
1685 domain
->alt_name
) == -1) {
1694 void winbindd_set_locator_kdc_envs(const struct winbindd_domain
*domain
)
1699 void winbindd_unset_locator_kdc_env(const struct winbindd_domain
*domain
)
1704 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1706 void set_auth_errors(struct winbindd_response
*resp
, NTSTATUS result
)
1708 resp
->data
.auth
.nt_status
= NT_STATUS_V(result
);
1709 fstrcpy(resp
->data
.auth
.nt_status_string
, nt_errstr(result
));
1711 /* we might have given a more useful error above */
1712 if (*resp
->data
.auth
.error_string
== '\0')
1713 fstrcpy(resp
->data
.auth
.error_string
,
1714 get_friendly_nt_error_msg(result
));
1715 resp
->data
.auth
.pam_error
= nt_status_to_pam(result
);