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/>.
28 #define DBGC_CLASS DBGC_WINBIND
30 extern struct winbindd_methods cache_methods
;
33 * @file winbindd_util.c
35 * Winbind daemon for NT domain authentication nss module.
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 struct winbindd_domain
*domain_list(void)
50 if ((!_domain_list
) && (!init_domain_list())) {
51 smb_panic("Init_domain_list failed");
57 /* Free all entries in the trusted domain list */
59 static void free_domain_list(void)
61 struct winbindd_domain
*domain
= _domain_list
;
64 struct winbindd_domain
*next
= domain
->next
;
66 DLIST_REMOVE(_domain_list
, domain
);
72 static bool is_internal_domain(const struct dom_sid
*sid
)
77 return (sid_check_is_domain(sid
) || sid_check_is_builtin(sid
));
80 static bool is_in_internal_domain(const struct dom_sid
*sid
)
85 return (sid_check_is_in_our_domain(sid
) || sid_check_is_in_builtin(sid
));
89 /* Add a trusted domain to our list of domains */
90 static struct winbindd_domain
*add_trusted_domain(const char *domain_name
, const char *alt_name
,
91 struct winbindd_methods
*methods
,
92 const struct dom_sid
*sid
)
94 struct winbindd_domain
*domain
;
95 const char *alternative_name
= NULL
;
96 char *idmap_config_option
;
98 const char **ignored_domains
, **dom
;
100 ignored_domains
= lp_parm_string_list(-1, "winbind", "ignore domains", NULL
);
101 for (dom
=ignored_domains
; dom
&& *dom
; dom
++) {
102 if (gen_fnmatch(*dom
, domain_name
) == 0) {
103 DEBUG(2,("Ignoring domain '%s'\n", domain_name
));
108 /* ignore alt_name if we are not in an AD domain */
110 if ( (lp_security() == SEC_ADS
) && alt_name
&& *alt_name
) {
111 alternative_name
= alt_name
;
114 /* We can't call domain_list() as this function is called from
115 init_domain_list() and we'll get stuck in a loop. */
116 for (domain
= _domain_list
; domain
; domain
= domain
->next
) {
117 if (strequal(domain_name
, domain
->name
) ||
118 strequal(domain_name
, domain
->alt_name
))
123 if (alternative_name
&& *alternative_name
)
125 if (strequal(alternative_name
, domain
->name
) ||
126 strequal(alternative_name
, domain
->alt_name
))
134 if (is_null_sid(sid
)) {
138 if (sid_equal(sid
, &domain
->sid
)) {
144 if (domain
!= NULL
) {
146 * We found a match. Possibly update the SID
149 && sid_equal(&domain
->sid
, &global_sid_NULL
)) {
150 sid_copy( &domain
->sid
, sid
);
155 /* Create new domain entry */
157 if ((domain
= SMB_MALLOC_P(struct winbindd_domain
)) == NULL
)
162 ZERO_STRUCTP(domain
);
164 fstrcpy(domain
->name
, domain_name
);
165 if (alternative_name
) {
166 fstrcpy(domain
->alt_name
, alternative_name
);
169 domain
->methods
= methods
;
170 domain
->backend
= NULL
;
171 domain
->internal
= is_internal_domain(sid
);
172 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
173 domain
->last_seq_check
= 0;
174 domain
->initialized
= False
;
175 domain
->online
= is_internal_domain(sid
);
176 domain
->check_online_timeout
= 0;
177 domain
->dc_probe_pid
= (pid_t
)-1;
179 sid_copy(&domain
->sid
, sid
);
182 /* Link to domain list */
183 DLIST_ADD_END(_domain_list
, domain
, struct winbindd_domain
*);
185 wcache_tdc_add_domain( domain
);
187 idmap_config_option
= talloc_asprintf(talloc_tos(), "idmap config %s",
189 if (idmap_config_option
== NULL
) {
190 DEBUG(0, ("talloc failed, not looking for idmap config\n"));
194 param
= lp_parm_const_string(-1, idmap_config_option
, "range", NULL
);
196 DEBUG(10, ("%s : range = %s\n", idmap_config_option
,
197 param
? param
: "not defined"));
200 unsigned low_id
, high_id
;
201 if (sscanf(param
, "%u - %u", &low_id
, &high_id
) != 2) {
202 DEBUG(1, ("invalid range syntax in %s: %s\n",
203 idmap_config_option
, param
));
206 if (low_id
> high_id
) {
207 DEBUG(1, ("invalid range in %s: %s\n",
208 idmap_config_option
, param
));
211 domain
->have_idmap_config
= true;
212 domain
->id_range_low
= low_id
;
213 domain
->id_range_high
= high_id
;
218 DEBUG(2,("Added domain %s %s %s\n",
219 domain
->name
, domain
->alt_name
,
220 &domain
->sid
?sid_string_dbg(&domain
->sid
):""));
225 bool domain_is_forest_root(const struct winbindd_domain
*domain
)
227 const uint32_t fr_flags
=
228 (NETR_TRUST_FLAG_TREEROOT
|NETR_TRUST_FLAG_IN_FOREST
);
230 return ((domain
->domain_flags
& fr_flags
) == fr_flags
);
233 /********************************************************************
234 rescan our domains looking for new trusted domains
235 ********************************************************************/
237 struct trustdom_state
{
238 struct winbindd_domain
*domain
;
239 struct winbindd_request request
;
242 static void trustdom_list_done(struct tevent_req
*req
);
243 static void rescan_forest_root_trusts( void );
244 static void rescan_forest_trusts( void );
246 static void add_trusted_domains( struct winbindd_domain
*domain
)
248 struct trustdom_state
*state
;
249 struct tevent_req
*req
;
251 state
= TALLOC_ZERO_P(NULL
, struct trustdom_state
);
253 DEBUG(0, ("talloc failed\n"));
256 state
->domain
= domain
;
258 state
->request
.length
= sizeof(state
->request
);
259 state
->request
.cmd
= WINBINDD_LIST_TRUSTDOM
;
261 req
= wb_domain_request_send(state
, winbind_event_context(),
262 domain
, &state
->request
);
264 DEBUG(1, ("wb_domain_request_send failed\n"));
268 tevent_req_set_callback(req
, trustdom_list_done
, state
);
271 static void trustdom_list_done(struct tevent_req
*req
)
273 struct trustdom_state
*state
= tevent_req_callback_data(
274 req
, struct trustdom_state
);
275 struct winbindd_response
*response
;
279 res
= wb_domain_request_recv(req
, state
, &response
, &err
);
280 if ((res
== -1) || (response
->result
!= WINBINDD_OK
)) {
281 DEBUG(1, ("Could not receive trustdoms\n"));
286 p
= (char *)response
->extra_data
.data
;
288 while ((p
!= NULL
) && (*p
!= '\0')) {
289 char *q
, *sidstr
, *alt_name
;
291 struct winbindd_domain
*domain
;
292 char *alternate_name
= NULL
;
294 alt_name
= strchr(p
, '\\');
295 if (alt_name
== NULL
) {
296 DEBUG(0, ("Got invalid trustdom response\n"));
303 sidstr
= strchr(alt_name
, '\\');
304 if (sidstr
== NULL
) {
305 DEBUG(0, ("Got invalid trustdom response\n"));
312 q
= strchr(sidstr
, '\n');
316 if (!string_to_sid(&sid
, sidstr
)) {
317 DEBUG(0, ("Got invalid trustdom response\n"));
321 /* use the real alt_name if we have one, else pass in NULL */
323 if ( !strequal( alt_name
, "(null)" ) )
324 alternate_name
= alt_name
;
326 /* If we have an existing domain structure, calling
327 add_trusted_domain() will update the SID if
328 necessary. This is important because we need the
329 SID for sibling domains */
331 if ( find_domain_from_name_noinit(p
) != NULL
) {
332 domain
= add_trusted_domain(p
, alternate_name
,
336 domain
= add_trusted_domain(p
, alternate_name
,
340 setup_domain_child(domain
);
349 Cases to consider when scanning trusts:
350 (a) we are calling from a child domain (primary && !forest_root)
351 (b) we are calling from the root of the forest (primary && forest_root)
352 (c) we are calling from a trusted forest domain (!primary
356 if (state
->domain
->primary
) {
357 /* If this is our primary domain and we are not in the
358 forest root, we have to scan the root trusts first */
360 if (!domain_is_forest_root(state
->domain
))
361 rescan_forest_root_trusts();
363 rescan_forest_trusts();
365 } else if (domain_is_forest_root(state
->domain
)) {
366 /* Once we have done root forest trust search, we can
367 go on to search the trusted forests */
369 rescan_forest_trusts();
377 /********************************************************************
378 Scan the trusts of our forest root
379 ********************************************************************/
381 static void rescan_forest_root_trusts( void )
383 struct winbindd_tdc_domain
*dom_list
= NULL
;
384 size_t num_trusts
= 0;
387 /* The only transitive trusts supported by Windows 2003 AD are
388 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
389 first two are handled in forest and listed by
390 DsEnumerateDomainTrusts(). Forest trusts are not so we
391 have to do that ourselves. */
393 if ( !wcache_tdc_fetch_list( &dom_list
, &num_trusts
) )
396 for ( i
=0; i
<num_trusts
; i
++ ) {
397 struct winbindd_domain
*d
= NULL
;
399 /* Find the forest root. Don't necessarily trust
400 the domain_list() as our primary domain may not
401 have been initialized. */
403 if ( !(dom_list
[i
].trust_flags
& NETR_TRUST_FLAG_TREEROOT
) ) {
407 /* Here's the forest root */
409 d
= find_domain_from_name_noinit( dom_list
[i
].domain_name
);
412 d
= add_trusted_domain( dom_list
[i
].domain_name
,
413 dom_list
[i
].dns_name
,
417 setup_domain_child(d
);
425 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
426 "for domain tree root %s (%s)\n",
427 d
->name
, d
->alt_name
));
429 d
->domain_flags
= dom_list
[i
].trust_flags
;
430 d
->domain_type
= dom_list
[i
].trust_type
;
431 d
->domain_trust_attribs
= dom_list
[i
].trust_attribs
;
433 add_trusted_domains( d
);
438 TALLOC_FREE( dom_list
);
443 /********************************************************************
444 scan the transitive forest trusts (not our own)
445 ********************************************************************/
448 static void rescan_forest_trusts( void )
450 struct winbindd_domain
*d
= NULL
;
451 struct winbindd_tdc_domain
*dom_list
= NULL
;
452 size_t num_trusts
= 0;
455 /* The only transitive trusts supported by Windows 2003 AD are
456 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
457 first two are handled in forest and listed by
458 DsEnumerateDomainTrusts(). Forest trusts are not so we
459 have to do that ourselves. */
461 if ( !wcache_tdc_fetch_list( &dom_list
, &num_trusts
) )
464 for ( i
=0; i
<num_trusts
; i
++ ) {
465 uint32 flags
= dom_list
[i
].trust_flags
;
466 uint32 type
= dom_list
[i
].trust_type
;
467 uint32 attribs
= dom_list
[i
].trust_attribs
;
469 d
= find_domain_from_name_noinit( dom_list
[i
].domain_name
);
471 /* ignore our primary and internal domains */
473 if ( d
&& (d
->internal
|| d
->primary
) )
476 if ( (flags
& NETR_TRUST_FLAG_INBOUND
) &&
477 (type
== NETR_TRUST_TYPE_UPLEVEL
) &&
478 (attribs
== NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) )
480 /* add the trusted domain if we don't know
484 d
= add_trusted_domain( dom_list
[i
].domain_name
,
485 dom_list
[i
].dns_name
,
489 setup_domain_child(d
);
497 DEBUG(10,("Following trust path for domain %s (%s)\n",
498 d
->name
, d
->alt_name
));
499 add_trusted_domains( d
);
503 TALLOC_FREE( dom_list
);
508 /*********************************************************************
509 The process of updating the trusted domain list is a three step
512 (b) ask the root domain in our forest
513 (c) ask the a DC in any Win2003 trusted forests
514 *********************************************************************/
516 void rescan_trusted_domains(struct tevent_context
*ev
, struct tevent_timer
*te
,
517 struct timeval now
, void *private_data
)
521 /* I use to clear the cache here and start over but that
522 caused problems in child processes that needed the
523 trust dom list early on. Removing it means we
524 could have some trusted domains listed that have been
525 removed from our primary domain's DC until a full
526 restart. This should be ok since I think this is what
527 Windows does as well. */
529 /* this will only add new domains we didn't already know about
530 in the domain_list()*/
532 add_trusted_domains( find_our_domain() );
534 te
= tevent_add_timer(
535 ev
, NULL
, timeval_current_ofs(WINBINDD_RESCAN_FREQ
, 0),
536 rescan_trusted_domains
, NULL
);
538 * If te == NULL, there's not much we can do here. Don't fail, the
539 * only thing we miss is new trusted domains.
545 enum winbindd_result
winbindd_dual_init_connection(struct winbindd_domain
*domain
,
546 struct winbindd_cli_state
*state
)
548 /* Ensure null termination */
549 state
->request
->domain_name
550 [sizeof(state
->request
->domain_name
)-1]='\0';
551 state
->request
->data
.init_conn
.dcname
552 [sizeof(state
->request
->data
.init_conn
.dcname
)-1]='\0';
554 if (strlen(state
->request
->data
.init_conn
.dcname
) > 0) {
555 fstrcpy(domain
->dcname
, state
->request
->data
.init_conn
.dcname
);
558 if (domain
->internal
) {
559 domain
->initialized
= true;
561 init_dc_connection(domain
);
564 if (!domain
->initialized
) {
565 /* If we return error here we can't do any cached authentication,
566 but we may be in disconnected mode and can't initialize correctly.
567 Do what the previous code did and just return without initialization,
568 once we go online we'll re-initialize.
570 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
571 "online = %d\n", domain
->name
, (int)domain
->online
));
574 fstrcpy(state
->response
->data
.domain_info
.name
, domain
->name
);
575 fstrcpy(state
->response
->data
.domain_info
.alt_name
, domain
->alt_name
);
576 sid_to_fstring(state
->response
->data
.domain_info
.sid
, &domain
->sid
);
578 state
->response
->data
.domain_info
.native_mode
579 = domain
->native_mode
;
580 state
->response
->data
.domain_info
.active_directory
581 = domain
->active_directory
;
582 state
->response
->data
.domain_info
.primary
588 /* Look up global info for the winbind daemon */
589 bool init_domain_list(void)
591 struct winbindd_domain
*domain
;
592 int role
= lp_server_role();
594 /* Free existing list */
599 domain
= add_trusted_domain("BUILTIN", NULL
, &cache_methods
,
600 &global_sid_Builtin
);
602 setup_domain_child(domain
);
607 domain
= add_trusted_domain(get_global_sam_name(), NULL
,
608 &cache_methods
, get_global_sam_sid());
610 if ( role
!= ROLE_DOMAIN_MEMBER
) {
611 domain
->primary
= True
;
613 setup_domain_child(domain
);
616 /* Add ourselves as the first entry. */
618 if ( role
== ROLE_DOMAIN_MEMBER
) {
619 struct dom_sid our_sid
;
621 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid
)) {
622 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
626 domain
= add_trusted_domain( lp_workgroup(), lp_realm(),
627 &cache_methods
, &our_sid
);
629 domain
->primary
= True
;
630 setup_domain_child(domain
);
632 /* Even in the parent winbindd we'll need to
633 talk to the DC, so try and see if we can
634 contact it. Theoretically this isn't neccessary
635 as the init_dc_connection() in init_child_recv()
636 will do this, but we can start detecting the DC
638 set_domain_online_request(domain
);
645 void check_domain_trusted( const char *name
, const struct dom_sid
*user_sid
)
647 struct winbindd_domain
*domain
;
648 struct dom_sid dom_sid
;
651 /* Check if we even care */
653 if (!lp_allow_trusted_domains())
656 domain
= find_domain_from_name_noinit( name
);
660 sid_copy( &dom_sid
, user_sid
);
661 if ( !sid_split_rid( &dom_sid
, &rid
) )
664 /* add the newly discovered trusted domain */
666 domain
= add_trusted_domain( name
, NULL
, &cache_methods
,
672 /* assume this is a trust from a one-way transitive
675 domain
->active_directory
= True
;
676 domain
->domain_flags
= NETR_TRUST_FLAG_OUTBOUND
;
677 domain
->domain_type
= NETR_TRUST_TYPE_UPLEVEL
;
678 domain
->internal
= False
;
679 domain
->online
= True
;
681 setup_domain_child(domain
);
683 wcache_tdc_add_domain( domain
);
689 * Given a domain name, return the struct winbindd domain info for it
691 * @note Do *not* pass lp_workgroup() to this function. domain_list
692 * may modify it's value, and free that pointer. Instead, our local
693 * domain may be found by calling find_our_domain().
697 * @return The domain structure for the named domain, if it is working.
700 struct winbindd_domain
*find_domain_from_name_noinit(const char *domain_name
)
702 struct winbindd_domain
*domain
;
704 /* Search through list */
706 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
707 if (strequal(domain_name
, domain
->name
) ||
708 (domain
->alt_name
[0] &&
709 strequal(domain_name
, domain
->alt_name
))) {
719 struct winbindd_domain
*find_domain_from_name(const char *domain_name
)
721 struct winbindd_domain
*domain
;
723 domain
= find_domain_from_name_noinit(domain_name
);
728 if (!domain
->initialized
)
729 init_dc_connection(domain
);
734 /* Given a domain sid, return the struct winbindd domain info for it */
736 struct winbindd_domain
*find_domain_from_sid_noinit(const struct dom_sid
*sid
)
738 struct winbindd_domain
*domain
;
740 /* Search through list */
742 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
743 if (sid_compare_domain(sid
, &domain
->sid
) == 0)
752 /* Given a domain sid, return the struct winbindd domain info for it */
754 struct winbindd_domain
*find_domain_from_sid(const struct dom_sid
*sid
)
756 struct winbindd_domain
*domain
;
758 domain
= find_domain_from_sid_noinit(sid
);
763 if (!domain
->initialized
)
764 init_dc_connection(domain
);
769 struct winbindd_domain
*find_our_domain(void)
771 struct winbindd_domain
*domain
;
773 /* Search through list */
775 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
780 smb_panic("Could not find our domain");
784 struct winbindd_domain
*find_root_domain(void)
786 struct winbindd_domain
*ours
= find_our_domain();
788 if (ours
->forest_name
[0] == '\0') {
792 return find_domain_from_name( ours
->forest_name
);
795 struct winbindd_domain
*find_builtin_domain(void)
797 struct winbindd_domain
*domain
;
799 domain
= find_domain_from_sid(&global_sid_Builtin
);
800 if (domain
== NULL
) {
801 smb_panic("Could not find BUILTIN domain");
807 /* Find the appropriate domain to lookup a name or SID */
809 struct winbindd_domain
*find_lookup_domain_from_sid(const struct dom_sid
*sid
)
811 /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
813 if ( sid_check_is_in_unix_groups(sid
) ||
814 sid_check_is_unix_groups(sid
) ||
815 sid_check_is_in_unix_users(sid
) ||
816 sid_check_is_unix_users(sid
) )
818 return find_domain_from_sid(get_global_sam_sid());
821 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
822 * one to contact the external DC's. On member servers the internal
823 * domains are different: These are part of the local SAM. */
825 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid
)));
827 if (IS_DC
|| is_internal_domain(sid
) || is_in_internal_domain(sid
)) {
828 DEBUG(10, ("calling find_domain_from_sid\n"));
829 return find_domain_from_sid(sid
);
832 /* On a member server a query for SID or name can always go to our
835 DEBUG(10, ("calling find_our_domain\n"));
836 return find_our_domain();
839 struct winbindd_domain
*find_lookup_domain_from_name(const char *domain_name
)
841 if ( strequal(domain_name
, unix_users_domain_name() ) ||
842 strequal(domain_name
, unix_groups_domain_name() ) )
845 * The "Unix User" and "Unix Group" domain our handled by
848 return find_domain_from_name_noinit( get_global_sam_name() );
851 if (IS_DC
|| strequal(domain_name
, "BUILTIN") ||
852 strequal(domain_name
, get_global_sam_name()))
853 return find_domain_from_name_noinit(domain_name
);
856 return find_our_domain();
859 /* Is this a domain which we may assume no DOMAIN\ prefix? */
861 static bool assume_domain(const char *domain
)
863 /* never assume the domain on a standalone server */
865 if ( lp_server_role() == ROLE_STANDALONE
)
868 /* domain member servers may possibly assume for the domain name */
870 if ( lp_server_role() == ROLE_DOMAIN_MEMBER
) {
871 if ( !strequal(lp_workgroup(), domain
) )
874 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
878 /* only left with a domain controller */
880 if ( strequal(get_global_sam_name(), domain
) ) {
887 /* Parse a string of the form DOMAIN\user into a domain and a user */
889 bool parse_domain_user(const char *domuser
, fstring domain
, fstring user
)
891 char *p
= strchr(domuser
,*lp_winbind_separator());
894 fstrcpy(user
, domuser
);
896 if ( assume_domain(lp_workgroup())) {
897 fstrcpy(domain
, lp_workgroup());
898 } else if ((p
= strchr(domuser
, '@')) != NULL
) {
899 fstrcpy(domain
, p
+ 1);
900 user
[PTR_DIFF(p
, domuser
)] = 0;
906 fstrcpy(domain
, domuser
);
907 domain
[PTR_DIFF(p
, domuser
)] = 0;
915 bool parse_domain_user_talloc(TALLOC_CTX
*mem_ctx
, const char *domuser
,
916 char **domain
, char **user
)
918 fstring fstr_domain
, fstr_user
;
919 if (!parse_domain_user(domuser
, fstr_domain
, fstr_user
)) {
922 *domain
= talloc_strdup(mem_ctx
, fstr_domain
);
923 *user
= talloc_strdup(mem_ctx
, fstr_user
);
924 return ((*domain
!= NULL
) && (*user
!= NULL
));
927 /* add a domain user name to a buffer */
928 void parse_add_domuser(void *buf
, char *domuser
, int *len
)
934 p
= strchr(domuser
, *lp_winbind_separator());
938 fstrcpy(domain
, domuser
);
939 domain
[PTR_DIFF(p
, domuser
)] = 0;
942 if (assume_domain(domain
)) {
945 *len
-= (PTR_DIFF(p
, domuser
));
949 safe_strcpy((char *)buf
, user
, *len
);
952 /* Ensure an incoming username from NSS is fully qualified. Replace the
953 incoming fstring with DOMAIN <separator> user. Returns the same
954 values as parse_domain_user() but also replaces the incoming username.
955 Used to ensure all names are fully qualified within winbindd.
956 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
957 The protocol definitions of auth_crap, chng_pswd_auth_crap
958 really should be changed to use this instead of doing things
961 bool canonicalize_username(fstring username_inout
, fstring domain
, fstring user
)
963 if (!parse_domain_user(username_inout
, domain
, user
)) {
966 slprintf(username_inout
, sizeof(fstring
) - 1, "%s%c%s",
967 domain
, *lp_winbind_separator(),
973 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
974 'winbind separator' options.
976 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
979 If we are a PDC or BDC, and this is for our domain, do likewise.
981 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
982 username is then unqualified in unix
984 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
986 void fill_domain_username(fstring name
, const char *domain
, const char *user
, bool can_assume
)
990 fstrcpy(tmp_user
, user
);
991 strlower_m(tmp_user
);
993 if (can_assume
&& assume_domain(domain
)) {
994 strlcpy(name
, tmp_user
, sizeof(fstring
));
996 slprintf(name
, sizeof(fstring
) - 1, "%s%c%s",
997 domain
, *lp_winbind_separator(),
1003 * talloc version of fill_domain_username()
1004 * return NULL on talloc failure.
1006 char *fill_domain_username_talloc(TALLOC_CTX
*mem_ctx
,
1011 char *tmp_user
, *name
;
1013 tmp_user
= talloc_strdup(mem_ctx
, user
);
1014 strlower_m(tmp_user
);
1016 if (can_assume
&& assume_domain(domain
)) {
1019 name
= talloc_asprintf(mem_ctx
, "%s%c%s",
1021 *lp_winbind_separator(),
1023 TALLOC_FREE(tmp_user
);
1030 * Client list accessor functions
1033 static struct winbindd_cli_state
*_client_list
;
1034 static int _num_clients
;
1036 /* Return list of all connected clients */
1038 struct winbindd_cli_state
*winbindd_client_list(void)
1040 return _client_list
;
1043 /* Add a connection to the list */
1045 void winbindd_add_client(struct winbindd_cli_state
*cli
)
1047 DLIST_ADD(_client_list
, cli
);
1051 /* Remove a client from the list */
1053 void winbindd_remove_client(struct winbindd_cli_state
*cli
)
1055 DLIST_REMOVE(_client_list
, cli
);
1059 /* Return number of open clients */
1061 int winbindd_num_clients(void)
1063 return _num_clients
;
1066 NTSTATUS
lookup_usergroups_cached(struct winbindd_domain
*domain
,
1067 TALLOC_CTX
*mem_ctx
,
1068 const struct dom_sid
*user_sid
,
1069 uint32
*p_num_groups
, struct dom_sid
**user_sids
)
1071 struct netr_SamInfo3
*info3
= NULL
;
1072 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1073 size_t num_groups
= 0;
1075 DEBUG(3,(": lookup_usergroups_cached\n"));
1080 info3
= netsamlogon_cache_get(mem_ctx
, user_sid
);
1082 if (info3
== NULL
) {
1083 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1086 if (info3
->base
.groups
.count
== 0) {
1088 return NT_STATUS_UNSUCCESSFUL
;
1091 /* Skip Domain local groups outside our domain.
1092 We'll get these from the getsidaliases() RPC call. */
1093 status
= sid_array_from_info3(mem_ctx
, info3
,
1098 if (!NT_STATUS_IS_OK(status
)) {
1104 *p_num_groups
= num_groups
;
1105 status
= (user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
1107 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1112 /*********************************************************************
1113 We use this to remove spaces from user and group names
1114 ********************************************************************/
1116 NTSTATUS
normalize_name_map(TALLOC_CTX
*mem_ctx
,
1117 struct winbindd_domain
*domain
,
1123 if (!name
|| !normalized
) {
1124 return NT_STATUS_INVALID_PARAMETER
;
1127 if (!lp_winbind_normalize_names()) {
1128 return NT_STATUS_PROCEDURE_NOT_FOUND
;
1131 /* Alias support and whitespace replacement are mutually
1134 nt_status
= resolve_username_to_alias(mem_ctx
, domain
,
1136 if (NT_STATUS_IS_OK(nt_status
)) {
1137 /* special return code to let the caller know we
1138 mapped to an alias */
1139 return NT_STATUS_FILE_RENAMED
;
1142 /* check for an unreachable domain */
1144 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1145 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1147 set_domain_offline(domain
);
1151 /* deal with whitespace */
1153 *normalized
= talloc_strdup(mem_ctx
, name
);
1154 if (!(*normalized
)) {
1155 return NT_STATUS_NO_MEMORY
;
1158 all_string_sub( *normalized
, " ", "_", 0 );
1160 return NT_STATUS_OK
;
1163 /*********************************************************************
1164 We use this to do the inverse of normalize_name_map()
1165 ********************************************************************/
1167 NTSTATUS
normalize_name_unmap(TALLOC_CTX
*mem_ctx
,
1172 struct winbindd_domain
*domain
= find_our_domain();
1174 if (!name
|| !normalized
) {
1175 return NT_STATUS_INVALID_PARAMETER
;
1178 if (!lp_winbind_normalize_names()) {
1179 return NT_STATUS_PROCEDURE_NOT_FOUND
;
1182 /* Alias support and whitespace replacement are mutally
1185 /* When mapping from an alias to a username, we don't know the
1186 domain. But we only need a domain structure to cache
1187 a successful lookup , so just our own domain structure for
1190 nt_status
= resolve_alias_to_username(mem_ctx
, domain
,
1192 if (NT_STATUS_IS_OK(nt_status
)) {
1193 /* Special return code to let the caller know we mapped
1195 return NT_STATUS_FILE_RENAMED
;
1198 /* check for an unreachable domain */
1200 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1201 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1203 set_domain_offline(domain
);
1207 /* deal with whitespace */
1209 *normalized
= talloc_strdup(mem_ctx
, name
);
1210 if (!(*normalized
)) {
1211 return NT_STATUS_NO_MEMORY
;
1214 all_string_sub(*normalized
, "_", " ", 0);
1216 return NT_STATUS_OK
;
1219 /*********************************************************************
1220 ********************************************************************/
1222 bool winbindd_can_contact_domain(struct winbindd_domain
*domain
)
1224 struct winbindd_tdc_domain
*tdc
= NULL
;
1225 TALLOC_CTX
*frame
= talloc_stackframe();
1228 /* We can contact the domain if it is our primary domain */
1230 if (domain
->primary
) {
1234 /* Trust the TDC cache and not the winbindd_domain flags */
1236 if ((tdc
= wcache_tdc_fetch_domain(frame
, domain
->name
)) == NULL
) {
1237 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1242 /* Can always contact a domain that is in out forest */
1244 if (tdc
->trust_flags
& NETR_TRUST_FLAG_IN_FOREST
) {
1250 * On a _member_ server, we cannot contact the domain if it
1251 * is running AD and we have no inbound trust.
1255 domain
->active_directory
&&
1256 ((tdc
->trust_flags
& NETR_TRUST_FLAG_INBOUND
) != NETR_TRUST_FLAG_INBOUND
))
1258 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1259 "and we have no inbound trust.\n", domain
->name
));
1263 /* Assume everything else is ok (probably not true but what
1269 talloc_destroy(frame
);
1274 /*********************************************************************
1275 ********************************************************************/
1277 bool winbindd_internal_child(struct winbindd_child
*child
)
1279 if ((child
== idmap_child()) || (child
== locator_child())) {
1286 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1288 /*********************************************************************
1289 ********************************************************************/
1291 static void winbindd_set_locator_kdc_env(const struct winbindd_domain
*domain
)
1294 char addr
[INET6_ADDRSTRLEN
];
1295 const char *kdc
= NULL
;
1298 if (!domain
|| !domain
->alt_name
|| !*domain
->alt_name
) {
1302 if (domain
->initialized
&& !domain
->active_directory
) {
1303 DEBUG(lvl
,("winbindd_set_locator_kdc_env: %s not AD\n",
1308 print_sockaddr(addr
, sizeof(addr
), &domain
->dcaddr
);
1311 DEBUG(lvl
,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1313 kdc
= domain
->dcname
;
1316 if (!kdc
|| !*kdc
) {
1317 DEBUG(lvl
,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1322 if (asprintf_strupper_m(&var
, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS
,
1323 domain
->alt_name
) == -1) {
1327 DEBUG(lvl
,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1330 setenv(var
, kdc
, 1);
1334 /*********************************************************************
1335 ********************************************************************/
1337 void winbindd_set_locator_kdc_envs(const struct winbindd_domain
*domain
)
1339 struct winbindd_domain
*our_dom
= find_our_domain();
1341 winbindd_set_locator_kdc_env(domain
);
1343 if (domain
!= our_dom
) {
1344 winbindd_set_locator_kdc_env(our_dom
);
1348 /*********************************************************************
1349 ********************************************************************/
1351 void winbindd_unset_locator_kdc_env(const struct winbindd_domain
*domain
)
1355 if (!domain
|| !domain
->alt_name
|| !*domain
->alt_name
) {
1359 if (asprintf_strupper_m(&var
, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS
,
1360 domain
->alt_name
) == -1) {
1369 void winbindd_set_locator_kdc_envs(const struct winbindd_domain
*domain
)
1374 void winbindd_unset_locator_kdc_env(const struct winbindd_domain
*domain
)
1379 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1381 void set_auth_errors(struct winbindd_response
*resp
, NTSTATUS result
)
1383 resp
->data
.auth
.nt_status
= NT_STATUS_V(result
);
1384 fstrcpy(resp
->data
.auth
.nt_status_string
, nt_errstr(result
));
1386 /* we might have given a more useful error above */
1387 if (*resp
->data
.auth
.error_string
== '\0')
1388 fstrcpy(resp
->data
.auth
.error_string
,
1389 get_friendly_nt_error_msg(result
));
1390 resp
->data
.auth
.pam_error
= nt_status_to_pam(result
);
1393 bool is_domain_offline(const struct winbindd_domain
*domain
)
1395 if (!lp_winbind_offline_logon()) {
1398 if (get_global_winbindd_state_offline()) {
1401 return !domain
->online
;