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 passdb_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;
47 When was the last scan of trusted domains done?
52 static time_t last_trustdom_scan;
54 struct winbindd_domain *domain_list(void)
58 if ((!_domain_list) && (!init_domain_list())) {
59 smb_panic("Init_domain_list failed");
65 /* Free all entries in the trusted domain list */
67 void free_domain_list(void)
69 struct winbindd_domain *domain = _domain_list;
72 struct winbindd_domain *next = domain->next;
74 DLIST_REMOVE(_domain_list, domain);
80 static bool is_internal_domain(const DOM_SID *sid)
86 return sid_check_is_builtin(sid);
88 return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
91 static bool is_in_internal_domain(const DOM_SID *sid)
97 return sid_check_is_in_builtin(sid);
99 return (sid_check_is_in_our_domain(sid) || sid_check_is_in_builtin(sid));
103 /* Add a trusted domain to our list of domains */
104 static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
105 struct winbindd_methods *methods,
108 struct winbindd_domain *domain;
109 const char *alternative_name = NULL;
111 /* ignore alt_name if we are not in an AD domain */
113 if ( (lp_security() == SEC_ADS) && alt_name && *alt_name) {
114 alternative_name = alt_name;
117 /* We can't call domain_list() as this function is called from
118 init_domain_list() and we'll get stuck in a loop. */
119 for (domain = _domain_list; domain; domain = domain->next) {
120 if (strequal(domain_name, domain->name) ||
121 strequal(domain_name, domain->alt_name))
126 if (alternative_name && *alternative_name)
128 if (strequal(alternative_name, domain->name) ||
129 strequal(alternative_name, domain->alt_name))
137 if (is_null_sid(sid)) {
141 if (sid_equal(sid, &domain->sid)) {
147 /* See if we found a match. Check if we need to update the
150 if ( domain && sid) {
151 if ( sid_equal( &domain->sid, &global_sid_NULL ) )
152 sid_copy( &domain->sid, sid );
157 /* Create new domain entry */
159 if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
164 ZERO_STRUCTP(domain);
166 /* prioritise the short name */
167 if (strchr_m(domain_name, '.') && alternative_name && *alternative_name) {
168 fstrcpy(domain->name, alternative_name);
169 fstrcpy(domain->alt_name, domain_name);
171 fstrcpy(domain->name, domain_name);
172 if (alternative_name) {
173 fstrcpy(domain->alt_name, alternative_name);
177 domain->methods = methods;
178 domain->backend = NULL;
179 domain->internal = is_internal_domain(sid);
180 domain->sequence_number = DOM_SEQUENCE_NONE;
181 domain->last_seq_check = 0;
182 domain->initialized = False;
183 domain->online = is_internal_domain(sid);
184 domain->check_online_timeout = 0;
186 sid_copy(&domain->sid, sid);
189 /* Link to domain list */
190 DLIST_ADD_END(_domain_list, domain, struct winbindd_domain *);
192 wcache_tdc_add_domain( domain );
194 DEBUG(2,("Added domain %s %s %s\n",
195 domain->name, domain->alt_name,
196 &domain->sid?sid_string_static(&domain->sid):""));
201 /********************************************************************
202 rescan our domains looking for new trusted domains
203 ********************************************************************/
205 struct trustdom_state {
209 struct winbindd_response *response;
212 static void trustdom_recv(void *private_data, bool success);
213 static void rescan_forest_root_trusts( void );
214 static void rescan_forest_trusts( void );
216 static void add_trusted_domains( struct winbindd_domain *domain )
219 struct winbindd_request *request;
220 struct winbindd_response *response;
221 uint32 fr_flags = (DS_DOMAIN_TREE_ROOT|DS_DOMAIN_IN_FOREST);
223 struct trustdom_state *state;
225 mem_ctx = talloc_init("add_trusted_domains");
226 if (mem_ctx == NULL) {
227 DEBUG(0, ("talloc_init failed\n"));
231 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
232 response = TALLOC_P(mem_ctx, struct winbindd_response);
233 state = TALLOC_P(mem_ctx, struct trustdom_state);
235 if ((request == NULL) || (response == NULL) || (state == NULL)) {
236 DEBUG(0, ("talloc failed\n"));
237 talloc_destroy(mem_ctx);
241 state->mem_ctx = mem_ctx;
242 state->response = response;
244 /* Flags used to know how to continue the forest trust search */
246 state->primary = domain->primary;
247 state->forest_root = ((domain->domain_flags & fr_flags) == fr_flags );
249 request->length = sizeof(*request);
250 request->cmd = WINBINDD_LIST_TRUSTDOM;
252 async_domain_request(mem_ctx, domain, request, response,
253 trustdom_recv, state);
256 static void trustdom_recv(void *private_data, bool success)
258 struct trustdom_state *state =
259 talloc_get_type_abort(private_data, struct trustdom_state);
260 struct winbindd_response *response = state->response;
263 if ((!success) || (response->result != WINBINDD_OK)) {
264 DEBUG(1, ("Could not receive trustdoms\n"));
265 talloc_destroy(state->mem_ctx);
269 p = (char *)response->extra_data.data;
271 while ((p != NULL) && (*p != '\0')) {
272 char *q, *sidstr, *alt_name;
274 struct winbindd_domain *domain;
275 char *alternate_name = NULL;
277 alt_name = strchr(p, '\\');
278 if (alt_name == NULL) {
279 DEBUG(0, ("Got invalid trustdom response\n"));
286 sidstr = strchr(alt_name, '\\');
287 if (sidstr == NULL) {
288 DEBUG(0, ("Got invalid trustdom response\n"));
295 q = strchr(sidstr, '\n');
299 if (!string_to_sid(&sid, sidstr)) {
300 /* Allow NULL sid for sibling domains */
301 if ( strcmp(sidstr,"S-0-0") == 0) {
302 sid_copy( &sid, &global_sid_NULL);
304 DEBUG(0, ("Got invalid trustdom response\n"));
309 /* use the real alt_name if we have one, else pass in NULL */
311 if ( !strequal( alt_name, "(null)" ) )
312 alternate_name = alt_name;
314 /* If we have an existing domain structure, calling
315 add_trusted_domain() will update the SID if
316 necessary. This is important because we need the
317 SID for sibling domains */
319 if ( find_domain_from_name_noinit(p) != NULL ) {
320 domain = add_trusted_domain(p, alternate_name,
324 domain = add_trusted_domain(p, alternate_name,
328 setup_domain_child(domain,
330 domain_dispatch_table,
339 SAFE_FREE(response->extra_data.data);
342 Cases to consider when scanning trusts:
343 (a) we are calling from a child domain (primary && !forest_root)
344 (b) we are calling from the root of the forest (primary && forest_root)
345 (c) we are calling from a trusted forest domain (!primary
349 if ( state->primary ) {
350 /* If this is our primary domain and we are not the in the
351 forest root, we have to scan the root trusts first */
353 if ( !state->forest_root )
354 rescan_forest_root_trusts();
356 rescan_forest_trusts();
358 } else if ( state->forest_root ) {
359 /* Once we have done root forest trust search, we can
360 go on to search thing trusted forests */
362 rescan_forest_trusts();
365 talloc_destroy(state->mem_ctx);
370 /********************************************************************
371 Scan the trusts of our forest root
372 ********************************************************************/
374 static void rescan_forest_root_trusts( void )
376 struct winbindd_tdc_domain *dom_list = NULL;
377 size_t num_trusts = 0;
380 /* The only transitive trusts supported by Windows 2003 AD are
381 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
382 first two are handled in forest and listed by
383 DsEnumerateDomainTrusts(). Forest trusts are not so we
384 have to do that ourselves. */
386 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
389 for ( i=0; i<num_trusts; i++ ) {
390 struct winbindd_domain *d = NULL;
392 /* Find the forest root. Don't necessarily trust
393 the domain_list() as our primary domain may not
394 have been initialized. */
396 if ( !(dom_list[i].trust_flags & DS_DOMAIN_TREE_ROOT) ) {
400 /* Here's the forest root */
402 d = find_domain_from_name_noinit( dom_list[i].domain_name );
405 d = add_trusted_domain( dom_list[i].domain_name,
406 dom_list[i].dns_name,
411 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
412 "for domain tree root %s (%s)\n",
413 d->name, d->alt_name ));
415 d->domain_flags = dom_list[i].trust_flags;
416 d->domain_type = dom_list[i].trust_type;
417 d->domain_trust_attribs = dom_list[i].trust_attribs;
419 add_trusted_domains( d );
424 TALLOC_FREE( dom_list );
429 /********************************************************************
430 scan the transitive forest trists (not our own)
431 ********************************************************************/
434 static void rescan_forest_trusts( void )
436 struct winbindd_domain *d = NULL;
437 struct winbindd_tdc_domain *dom_list = NULL;
438 size_t num_trusts = 0;
441 /* The only transitive trusts supported by Windows 2003 AD are
442 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
443 first two are handled in forest and listed by
444 DsEnumerateDomainTrusts(). Forest trusts are not so we
445 have to do that ourselves. */
447 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
450 for ( i=0; i<num_trusts; i++ ) {
451 uint32 flags = dom_list[i].trust_flags;
452 uint32 type = dom_list[i].trust_type;
453 uint32 attribs = dom_list[i].trust_attribs;
455 d = find_domain_from_name_noinit( dom_list[i].domain_name );
457 /* ignore our primary and internal domains */
459 if ( d && (d->internal || d->primary ) )
462 if ( (flags & DS_DOMAIN_DIRECT_INBOUND) &&
463 (type == DS_DOMAIN_TRUST_TYPE_UPLEVEL) &&
464 (attribs == DS_DOMAIN_TRUST_ATTRIB_FOREST_TRANSITIVE) )
466 /* add the trusted domain if we don't know
470 d = add_trusted_domain( dom_list[i].domain_name,
471 dom_list[i].dns_name,
476 DEBUG(10,("Following trust path for domain %s (%s)\n",
477 d->name, d->alt_name ));
478 add_trusted_domains( d );
482 TALLOC_FREE( dom_list );
487 /*********************************************************************
488 The process of updating the trusted domain list is a three step
491 (b) ask the root domain in our forest
492 (c) ask the a DC in any Win2003 trusted forests
493 *********************************************************************/
495 void rescan_trusted_domains( void )
497 time_t now = time(NULL);
499 /* see if the time has come... */
501 if ((now >= last_trustdom_scan) &&
502 ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
505 /* clear the TRUSTDOM cache first */
509 /* this will only add new domains we didn't already know about
510 in the domain_list()*/
512 add_trusted_domains( find_our_domain() );
514 last_trustdom_scan = now;
519 struct init_child_state {
521 struct winbindd_domain *domain;
522 struct winbindd_request *request;
523 struct winbindd_response *response;
524 void (*continuation)(void *private_data, bool success);
528 static void init_child_recv(void *private_data, bool success);
529 static void init_child_getdc_recv(void *private_data, bool success);
531 enum winbindd_result init_child_connection(struct winbindd_domain *domain,
532 void (*continuation)(void *private_data,
537 struct winbindd_request *request;
538 struct winbindd_response *response;
539 struct init_child_state *state;
540 struct winbindd_domain *request_domain;
542 mem_ctx = talloc_init("init_child_connection");
543 if (mem_ctx == NULL) {
544 DEBUG(0, ("talloc_init failed\n"));
545 return WINBINDD_ERROR;
548 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
549 response = TALLOC_P(mem_ctx, struct winbindd_response);
550 state = TALLOC_P(mem_ctx, struct init_child_state);
552 if ((request == NULL) || (response == NULL) || (state == NULL)) {
553 DEBUG(0, ("talloc failed\n"));
554 TALLOC_FREE(mem_ctx);
555 continuation(private_data, False);
556 return WINBINDD_ERROR;
559 request->length = sizeof(*request);
561 state->mem_ctx = mem_ctx;
562 state->domain = domain;
563 state->request = request;
564 state->response = response;
565 state->continuation = continuation;
566 state->private_data = private_data;
568 if (IS_DC || domain->primary || domain->internal ) {
569 /* The primary domain has to find the DC name itself */
570 request->cmd = WINBINDD_INIT_CONNECTION;
571 fstrcpy(request->domain_name, domain->name);
572 request->data.init_conn.is_primary = domain->internal ? False : True;
573 fstrcpy(request->data.init_conn.dcname, "");
574 async_request(mem_ctx, &domain->child, request, response,
575 init_child_recv, state);
576 return WINBINDD_PENDING;
579 /* This is *not* the primary domain, let's ask our DC about a DC
582 request->cmd = WINBINDD_GETDCNAME;
583 fstrcpy(request->domain_name, domain->name);
585 request_domain = find_our_domain();
586 async_domain_request(mem_ctx, request_domain, request, response,
587 init_child_getdc_recv, state);
588 return WINBINDD_PENDING;
591 static void init_child_getdc_recv(void *private_data, bool success)
593 struct init_child_state *state =
594 talloc_get_type_abort(private_data, struct init_child_state);
595 const char *dcname = "";
597 DEBUG(10, ("Received getdcname response\n"));
599 if (success && (state->response->result == WINBINDD_OK)) {
600 dcname = state->response->data.dc_name;
603 state->request->cmd = WINBINDD_INIT_CONNECTION;
604 fstrcpy(state->request->domain_name, state->domain->name);
605 state->request->data.init_conn.is_primary = False;
606 fstrcpy(state->request->data.init_conn.dcname, dcname);
608 async_request(state->mem_ctx, &state->domain->child,
609 state->request, state->response,
610 init_child_recv, state);
613 static void init_child_recv(void *private_data, bool success)
615 struct init_child_state *state =
616 talloc_get_type_abort(private_data, struct init_child_state);
618 DEBUG(5, ("Received child initialization response for domain %s\n",
619 state->domain->name));
621 if ((!success) || (state->response->result != WINBINDD_OK)) {
622 DEBUG(3, ("Could not init child\n"));
623 state->continuation(state->private_data, False);
624 talloc_destroy(state->mem_ctx);
628 fstrcpy(state->domain->name,
629 state->response->data.domain_info.name);
630 fstrcpy(state->domain->alt_name,
631 state->response->data.domain_info.alt_name);
632 string_to_sid(&state->domain->sid,
633 state->response->data.domain_info.sid);
634 state->domain->native_mode =
635 state->response->data.domain_info.native_mode;
636 state->domain->active_directory =
637 state->response->data.domain_info.active_directory;
639 init_dc_connection(state->domain);
641 if (state->continuation != NULL)
642 state->continuation(state->private_data, True);
643 talloc_destroy(state->mem_ctx);
646 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
647 struct winbindd_cli_state *state)
649 /* Ensure null termination */
650 state->request.domain_name
651 [sizeof(state->request.domain_name)-1]='\0';
652 state->request.data.init_conn.dcname
653 [sizeof(state->request.data.init_conn.dcname)-1]='\0';
655 if (strlen(state->request.data.init_conn.dcname) > 0) {
656 fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
659 init_dc_connection(domain);
661 if (!domain->initialized) {
662 /* If we return error here we can't do any cached authentication,
663 but we may be in disconnected mode and can't initialize correctly.
664 Do what the previous code did and just return without initialization,
665 once we go online we'll re-initialize.
667 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
668 "online = %d\n", domain->name, (int)domain->online ));
671 fstrcpy(state->response.data.domain_info.name, domain->name);
672 fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
673 fstrcpy(state->response.data.domain_info.sid,
674 sid_string_static(&domain->sid));
676 state->response.data.domain_info.native_mode
677 = domain->native_mode;
678 state->response.data.domain_info.active_directory
679 = domain->active_directory;
680 state->response.data.domain_info.primary
686 /* Look up global info for the winbind daemon */
687 bool init_domain_list(void)
689 struct winbindd_domain *domain;
690 int role = lp_server_role();
692 /* Free existing list */
697 domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
698 &global_sid_Builtin);
700 setup_domain_child(domain,
702 domain_dispatch_table,
708 domain = add_trusted_domain(get_global_sam_name(), NULL,
709 &passdb_methods, get_global_sam_sid());
711 if ( role != ROLE_DOMAIN_MEMBER ) {
712 domain->primary = True;
714 setup_domain_child(domain,
716 domain_dispatch_table,
720 /* Add ourselves as the first entry. */
722 if ( role == ROLE_DOMAIN_MEMBER ) {
725 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
726 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
730 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
731 &cache_methods, &our_sid);
733 domain->primary = True;
734 setup_domain_child(domain,
736 domain_dispatch_table,
739 /* Even in the parent winbindd we'll need to
740 talk to the DC, so try and see if we can
741 contact it. Theoretically this isn't neccessary
742 as the init_dc_connection() in init_child_recv()
743 will do this, but we can start detecting the DC
745 set_domain_online_request(domain);
752 void check_domain_trusted( const char *name, const DOM_SID *user_sid )
754 struct winbindd_domain *domain;
758 domain = find_domain_from_name_noinit( name );
762 sid_copy( &dom_sid, user_sid );
763 if ( !sid_split_rid( &dom_sid, &rid ) )
766 /* add the newly discovered trusted domain */
768 domain = add_trusted_domain( name, NULL, &cache_methods,
774 /* assume this is a trust from a one-way transitive
777 domain->active_directory = True;
778 domain->domain_flags = DS_DOMAIN_DIRECT_OUTBOUND;
779 domain->domain_type = DS_DOMAIN_TRUST_TYPE_UPLEVEL;
780 domain->internal = False;
781 domain->online = True;
783 setup_domain_child(domain,
785 domain_dispatch_table,
788 wcache_tdc_add_domain( domain );
794 * Given a domain name, return the struct winbindd domain info for it
796 * @note Do *not* pass lp_workgroup() to this function. domain_list
797 * may modify it's value, and free that pointer. Instead, our local
798 * domain may be found by calling find_our_domain().
802 * @return The domain structure for the named domain, if it is working.
805 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
807 struct winbindd_domain *domain;
809 /* Search through list */
811 for (domain = domain_list(); domain != NULL; domain = domain->next) {
812 if (strequal(domain_name, domain->name) ||
813 (domain->alt_name[0] &&
814 strequal(domain_name, domain->alt_name))) {
824 struct winbindd_domain *find_domain_from_name(const char *domain_name)
826 struct winbindd_domain *domain;
828 domain = find_domain_from_name_noinit(domain_name);
833 if (!domain->initialized)
834 init_dc_connection(domain);
839 /* Given a domain sid, return the struct winbindd domain info for it */
841 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
843 struct winbindd_domain *domain;
845 /* Search through list */
847 for (domain = domain_list(); domain != NULL; domain = domain->next) {
848 if (sid_compare_domain(sid, &domain->sid) == 0)
857 /* Given a domain sid, return the struct winbindd domain info for it */
859 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
861 struct winbindd_domain *domain;
863 domain = find_domain_from_sid_noinit(sid);
868 if (!domain->initialized)
869 init_dc_connection(domain);
874 struct winbindd_domain *find_our_domain(void)
876 struct winbindd_domain *domain;
878 /* Search through list */
880 for (domain = domain_list(); domain != NULL; domain = domain->next) {
885 smb_panic("Could not find our domain");
889 struct winbindd_domain *find_root_domain(void)
891 struct winbindd_domain *ours = find_our_domain();
896 if ( strlen(ours->forest_name) == 0 )
899 return find_domain_from_name( ours->forest_name );
902 struct winbindd_domain *find_builtin_domain(void)
905 struct winbindd_domain *domain;
907 string_to_sid(&sid, "S-1-5-32");
908 domain = find_domain_from_sid(&sid);
910 if (domain == NULL) {
911 smb_panic("Could not find BUILTIN domain");
917 /* Find the appropriate domain to lookup a name or SID */
919 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
921 /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
923 if ( sid_check_is_in_unix_groups(sid) ||
924 sid_check_is_unix_groups(sid) ||
925 sid_check_is_in_unix_users(sid) ||
926 sid_check_is_unix_users(sid) )
928 return find_domain_from_sid(get_global_sam_sid());
931 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
932 * one to contact the external DC's. On member servers the internal
933 * domains are different: These are part of the local SAM. */
935 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n",
936 sid_string_static(sid)));
938 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
939 DEBUG(10, ("calling find_domain_from_sid\n"));
940 return find_domain_from_sid(sid);
943 /* On a member server a query for SID or name can always go to our
946 DEBUG(10, ("calling find_our_domain\n"));
947 return find_our_domain();
950 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
952 if ( strequal(domain_name, unix_users_domain_name() ) ||
953 strequal(domain_name, unix_groups_domain_name() ) )
955 return find_domain_from_name_noinit( get_global_sam_name() );
958 if (IS_DC || strequal(domain_name, "BUILTIN") ||
959 strequal(domain_name, get_global_sam_name()))
960 return find_domain_from_name_noinit(domain_name);
962 /* The "Unix User" and "Unix Group" domain our handled by passdb */
964 return find_our_domain();
967 /* Lookup a sid in a domain from a name */
969 bool winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
970 enum winbindd_cmd orig_cmd,
971 struct winbindd_domain *domain,
972 const char *domain_name,
973 const char *name, DOM_SID *sid,
974 enum lsa_SidType *type)
979 result = domain->methods->name_to_sid(domain, mem_ctx, orig_cmd,
980 domain_name, name, sid, type);
982 /* Return sid and type if lookup successful */
983 if (!NT_STATUS_IS_OK(result)) {
984 *type = SID_NAME_UNKNOWN;
987 return NT_STATUS_IS_OK(result);
991 * @brief Lookup a name in a domain from a sid.
993 * @param sid Security ID you want to look up.
994 * @param name On success, set to the name corresponding to @p sid.
995 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
996 * @param type On success, contains the type of name: alias, group or
998 * @retval True if the name exists, in which case @p name and @p type
999 * are set, otherwise False.
1001 bool winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
1002 struct winbindd_domain *domain,
1006 enum lsa_SidType *type)
1015 result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
1017 /* Return name and type if successful */
1019 if (NT_STATUS_IS_OK(result)) {
1023 *type = SID_NAME_UNKNOWN;
1028 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
1030 void free_getent_state(struct getent_state *state)
1032 struct getent_state *temp;
1034 /* Iterate over state list */
1038 while(temp != NULL) {
1039 struct getent_state *next;
1041 /* Free sam entries then list entry */
1043 SAFE_FREE(state->sam_entries);
1044 DLIST_REMOVE(state, state);
1052 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1054 static bool assume_domain(const char *domain)
1056 /* never assume the domain on a standalone server */
1058 if ( lp_server_role() == ROLE_STANDALONE )
1061 /* domain member servers may possibly assume for the domain name */
1063 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1064 if ( !strequal(lp_workgroup(), domain) )
1067 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1071 /* only left with a domain controller */
1073 if ( strequal(get_global_sam_name(), domain) ) {
1080 /* Parse a string of the form DOMAIN\user into a domain and a user */
1082 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1084 char *p = strchr(domuser,*lp_winbind_separator());
1087 fstrcpy(user, domuser);
1089 if ( assume_domain(lp_workgroup())) {
1090 fstrcpy(domain, lp_workgroup());
1091 } else if ((p = strchr(domuser, '@')) != NULL) {
1092 fstrcpy(domain, "");
1098 fstrcpy(domain, domuser);
1099 domain[PTR_DIFF(p, domuser)] = 0;
1107 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1108 char **domain, char **user)
1110 fstring fstr_domain, fstr_user;
1111 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1114 *domain = talloc_strdup(mem_ctx, fstr_domain);
1115 *user = talloc_strdup(mem_ctx, fstr_user);
1116 return ((*domain != NULL) && (*user != NULL));
1119 /* Ensure an incoming username from NSS is fully qualified. Replace the
1120 incoming fstring with DOMAIN <separator> user. Returns the same
1121 values as parse_domain_user() but also replaces the incoming username.
1122 Used to ensure all names are fully qualified within winbindd.
1123 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1124 The protocol definitions of auth_crap, chng_pswd_auth_crap
1125 really should be changed to use this instead of doing things
1128 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1130 if (!parse_domain_user(username_inout, domain, user)) {
1133 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1134 domain, *lp_winbind_separator(),
1140 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1141 'winbind separator' options.
1143 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1146 If we are a PDC or BDC, and this is for our domain, do likewise.
1148 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
1149 username is then unqualified in unix
1151 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1153 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1157 fstrcpy(tmp_user, user);
1158 strlower_m(tmp_user);
1160 if (can_assume && assume_domain(domain)) {
1161 strlcpy(name, tmp_user, sizeof(fstring));
1163 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1164 domain, *lp_winbind_separator(),
1170 * Winbindd socket accessor functions
1173 const char *get_winbind_pipe_dir(void)
1175 return lp_parm_const_string(-1, "winbindd", "socket dir", WINBINDD_SOCKET_DIR);
1178 char *get_winbind_priv_pipe_dir(void)
1180 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
1183 /* Open the winbindd socket */
1185 static int _winbindd_socket = -1;
1186 static int _winbindd_priv_socket = -1;
1188 int open_winbindd_socket(void)
1190 if (_winbindd_socket == -1) {
1191 _winbindd_socket = create_pipe_sock(
1192 get_winbind_pipe_dir(), WINBINDD_SOCKET_NAME, 0755);
1193 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
1197 return _winbindd_socket;
1200 int open_winbindd_priv_socket(void)
1202 if (_winbindd_priv_socket == -1) {
1203 _winbindd_priv_socket = create_pipe_sock(
1204 get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
1205 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
1206 _winbindd_priv_socket));
1209 return _winbindd_priv_socket;
1212 /* Close the winbindd socket */
1214 void close_winbindd_socket(void)
1216 if (_winbindd_socket != -1) {
1217 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
1219 close(_winbindd_socket);
1220 _winbindd_socket = -1;
1222 if (_winbindd_priv_socket != -1) {
1223 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
1224 _winbindd_priv_socket));
1225 close(_winbindd_priv_socket);
1226 _winbindd_priv_socket = -1;
1231 * Client list accessor functions
1234 static struct winbindd_cli_state *_client_list;
1235 static int _num_clients;
1237 /* Return list of all connected clients */
1239 struct winbindd_cli_state *winbindd_client_list(void)
1241 return _client_list;
1244 /* Add a connection to the list */
1246 void winbindd_add_client(struct winbindd_cli_state *cli)
1248 DLIST_ADD(_client_list, cli);
1252 /* Remove a client from the list */
1254 void winbindd_remove_client(struct winbindd_cli_state *cli)
1256 DLIST_REMOVE(_client_list, cli);
1260 /* Close all open clients */
1262 void winbindd_kill_all_clients(void)
1264 struct winbindd_cli_state *cl = winbindd_client_list();
1266 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1269 struct winbindd_cli_state *next;
1272 winbindd_remove_client(cl);
1277 /* Return number of open clients */
1279 int winbindd_num_clients(void)
1281 return _num_clients;
1284 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1285 TALLOC_CTX *mem_ctx,
1286 const DOM_SID *user_sid,
1287 uint32 *p_num_groups, DOM_SID **user_sids)
1289 NET_USER_INFO_3 *info3 = NULL;
1290 NTSTATUS status = NT_STATUS_NO_MEMORY;
1292 size_t num_groups = 0;
1293 DOM_SID group_sid, primary_group;
1295 DEBUG(3,(": lookup_usergroups_cached\n"));
1301 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1303 if (info3 == NULL) {
1304 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1307 if (info3->num_groups == 0) {
1309 return NT_STATUS_UNSUCCESSFUL;
1312 /* always add the primary group to the sid array */
1313 sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
1315 if (!add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups)) {
1317 return NT_STATUS_NO_MEMORY;
1320 for (i=0; i<info3->num_groups; i++) {
1321 sid_copy(&group_sid, &info3->dom_sid.sid);
1322 sid_append_rid(&group_sid, info3->gids[i].g_rid);
1324 if (!add_sid_to_array(mem_ctx, &group_sid, user_sids,
1327 return NT_STATUS_NO_MEMORY;
1331 /* Add any Universal groups in the other_sids list */
1333 for (i=0; i<info3->num_other_sids; i++) {
1334 /* Skip Domain local groups outside our domain.
1335 We'll get these from the getsidaliases() RPC call. */
1336 if (info3->other_sids_attrib[i] & SE_GROUP_RESOURCE)
1339 if (!add_sid_to_array(mem_ctx, &info3->other_sids[i].sid,
1340 user_sids, &num_groups))
1343 return NT_STATUS_NO_MEMORY;
1349 *p_num_groups = num_groups;
1350 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1352 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1357 /*********************************************************************
1358 We use this to remove spaces from user and group names
1359 ********************************************************************/
1361 void ws_name_replace( char *name, char replace )
1363 char replace_char[2] = { 0x0, 0x0 };
1365 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1368 replace_char[0] = replace;
1369 all_string_sub( name, " ", replace_char, 0 );
1374 /*********************************************************************
1375 We use this to do the inverse of ws_name_replace()
1376 ********************************************************************/
1378 void ws_name_return( char *name, char replace )
1380 char replace_char[2] = { 0x0, 0x0 };
1382 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1385 replace_char[0] = replace;
1386 all_string_sub( name, replace_char, " ", 0 );
1391 /*********************************************************************
1392 ********************************************************************/
1394 bool winbindd_can_contact_domain( struct winbindd_domain *domain )
1396 /* We can contact the domain if it is our primary domain */
1398 if ( domain->primary )
1401 /* Can always contact a domain that is in out forest */
1403 if ( domain->domain_flags & DS_DOMAIN_IN_FOREST )
1406 /* We cannot contact the domain if it is running AD and
1407 we have no inbound trust */
1409 if ( domain->active_directory &&
1410 ((domain->domain_flags&DS_DOMAIN_DIRECT_INBOUND) != DS_DOMAIN_DIRECT_INBOUND) )
1415 /* Assume everything else is ok (probably not true but what
1421 /*********************************************************************
1422 ********************************************************************/
1424 bool winbindd_internal_child(struct winbindd_child *child)
1426 if ((child == idmap_child()) || (child == locator_child())) {
1433 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1435 /*********************************************************************
1436 ********************************************************************/
1438 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1441 char addr[INET6_ADDRSTRLEN];
1442 const char *kdc = NULL;
1445 if (!domain || !domain->alt_name || !*domain->alt_name) {
1449 if (domain->initialized && !domain->active_directory) {
1450 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1455 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1458 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1460 kdc = domain->dcname;
1463 if (!kdc || !*kdc) {
1464 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1469 if (asprintf(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1470 strupper_static(domain->alt_name)) == -1) {
1474 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1477 setenv(var, kdc, 1);
1481 /*********************************************************************
1482 ********************************************************************/
1484 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1486 struct winbindd_domain *our_dom = find_our_domain();
1488 winbindd_set_locator_kdc_env(domain);
1490 if (domain != our_dom) {
1491 winbindd_set_locator_kdc_env(our_dom);
1495 /*********************************************************************
1496 ********************************************************************/
1498 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1502 if (!domain || !domain->alt_name || !*domain->alt_name) {
1506 if (asprintf(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1507 strupper_static(domain->alt_name)) == -1) {
1516 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1521 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1526 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */