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 = NULL;
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_dbg(&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,
337 SAFE_FREE(response->extra_data.data);
340 Cases to consider when scanning trusts:
341 (a) we are calling from a child domain (primary && !forest_root)
342 (b) we are calling from the root of the forest (primary && forest_root)
343 (c) we are calling from a trusted forest domain (!primary
347 if ( state->primary ) {
348 /* If this is our primary domain and we are not the in the
349 forest root, we have to scan the root trusts first */
351 if ( !state->forest_root )
352 rescan_forest_root_trusts();
354 rescan_forest_trusts();
356 } else if ( state->forest_root ) {
357 /* Once we have done root forest trust search, we can
358 go on to search thing trusted forests */
360 rescan_forest_trusts();
363 talloc_destroy(state->mem_ctx);
368 /********************************************************************
369 Scan the trusts of our forest root
370 ********************************************************************/
372 static void rescan_forest_root_trusts( void )
374 struct winbindd_tdc_domain *dom_list = NULL;
375 size_t num_trusts = 0;
378 /* The only transitive trusts supported by Windows 2003 AD are
379 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
380 first two are handled in forest and listed by
381 DsEnumerateDomainTrusts(). Forest trusts are not so we
382 have to do that ourselves. */
384 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
387 for ( i=0; i<num_trusts; i++ ) {
388 struct winbindd_domain *d = NULL;
390 /* Find the forest root. Don't necessarily trust
391 the domain_list() as our primary domain may not
392 have been initialized. */
394 if ( !(dom_list[i].trust_flags & DS_DOMAIN_TREE_ROOT) ) {
398 /* Here's the forest root */
400 d = find_domain_from_name_noinit( dom_list[i].domain_name );
403 d = add_trusted_domain( dom_list[i].domain_name,
404 dom_list[i].dns_name,
409 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
410 "for domain tree root %s (%s)\n",
411 d->name, d->alt_name ));
413 d->domain_flags = dom_list[i].trust_flags;
414 d->domain_type = dom_list[i].trust_type;
415 d->domain_trust_attribs = dom_list[i].trust_attribs;
417 add_trusted_domains( d );
422 TALLOC_FREE( dom_list );
427 /********************************************************************
428 scan the transitive forest trists (not our own)
429 ********************************************************************/
432 static void rescan_forest_trusts( void )
434 struct winbindd_domain *d = NULL;
435 struct winbindd_tdc_domain *dom_list = NULL;
436 size_t num_trusts = 0;
439 /* The only transitive trusts supported by Windows 2003 AD are
440 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
441 first two are handled in forest and listed by
442 DsEnumerateDomainTrusts(). Forest trusts are not so we
443 have to do that ourselves. */
445 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
448 for ( i=0; i<num_trusts; i++ ) {
449 uint32 flags = dom_list[i].trust_flags;
450 uint32 type = dom_list[i].trust_type;
451 uint32 attribs = dom_list[i].trust_attribs;
453 d = find_domain_from_name_noinit( dom_list[i].domain_name );
455 /* ignore our primary and internal domains */
457 if ( d && (d->internal || d->primary ) )
460 if ( (flags & DS_DOMAIN_DIRECT_INBOUND) &&
461 (type == DS_DOMAIN_TRUST_TYPE_UPLEVEL) &&
462 (attribs == DS_DOMAIN_TRUST_ATTRIB_FOREST_TRANSITIVE) )
464 /* add the trusted domain if we don't know
468 d = add_trusted_domain( dom_list[i].domain_name,
469 dom_list[i].dns_name,
474 DEBUG(10,("Following trust path for domain %s (%s)\n",
475 d->name, d->alt_name ));
476 add_trusted_domains( d );
480 TALLOC_FREE( dom_list );
485 /*********************************************************************
486 The process of updating the trusted domain list is a three step
489 (b) ask the root domain in our forest
490 (c) ask the a DC in any Win2003 trusted forests
491 *********************************************************************/
493 void rescan_trusted_domains( void )
495 time_t now = time(NULL);
497 /* see if the time has come... */
499 if ((now >= last_trustdom_scan) &&
500 ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
503 /* I use to clear the cache here and start over but that
504 caused problems in child processes that needed the
505 trust dom list early on. Removing it means we
506 could have some trusted domains listed that have been
507 removed from our primary domain's DC until a full
508 restart. This should be ok since I think this is what
509 Windows does as well. */
511 /* this will only add new domains we didn't already know about
512 in the domain_list()*/
514 add_trusted_domains( find_our_domain() );
516 last_trustdom_scan = now;
521 struct init_child_state {
523 struct winbindd_domain *domain;
524 struct winbindd_request *request;
525 struct winbindd_response *response;
526 void (*continuation)(void *private_data, bool success);
530 static void init_child_recv(void *private_data, bool success);
531 static void init_child_getdc_recv(void *private_data, bool success);
533 enum winbindd_result init_child_connection(struct winbindd_domain *domain,
534 void (*continuation)(void *private_data,
539 struct winbindd_request *request;
540 struct winbindd_response *response;
541 struct init_child_state *state;
542 struct winbindd_domain *request_domain;
544 mem_ctx = talloc_init("init_child_connection");
545 if (mem_ctx == NULL) {
546 DEBUG(0, ("talloc_init failed\n"));
547 return WINBINDD_ERROR;
550 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
551 response = TALLOC_P(mem_ctx, struct winbindd_response);
552 state = TALLOC_P(mem_ctx, struct init_child_state);
554 if ((request == NULL) || (response == NULL) || (state == NULL)) {
555 DEBUG(0, ("talloc failed\n"));
556 TALLOC_FREE(mem_ctx);
557 continuation(private_data, False);
558 return WINBINDD_ERROR;
561 request->length = sizeof(*request);
563 state->mem_ctx = mem_ctx;
564 state->domain = domain;
565 state->request = request;
566 state->response = response;
567 state->continuation = continuation;
568 state->private_data = private_data;
570 if (IS_DC || domain->primary || domain->internal ) {
571 /* The primary domain has to find the DC name itself */
572 request->cmd = WINBINDD_INIT_CONNECTION;
573 fstrcpy(request->domain_name, domain->name);
574 request->data.init_conn.is_primary = domain->internal ? False : True;
575 fstrcpy(request->data.init_conn.dcname, "");
576 async_request(mem_ctx, &domain->child, request, response,
577 init_child_recv, state);
578 return WINBINDD_PENDING;
581 /* This is *not* the primary domain, let's ask our DC about a DC
584 request->cmd = WINBINDD_GETDCNAME;
585 fstrcpy(request->domain_name, domain->name);
587 request_domain = find_our_domain();
588 async_domain_request(mem_ctx, request_domain, request, response,
589 init_child_getdc_recv, state);
590 return WINBINDD_PENDING;
593 static void init_child_getdc_recv(void *private_data, bool success)
595 struct init_child_state *state =
596 talloc_get_type_abort(private_data, struct init_child_state);
597 const char *dcname = "";
599 DEBUG(10, ("Received getdcname response\n"));
601 if (success && (state->response->result == WINBINDD_OK)) {
602 dcname = state->response->data.dc_name;
605 state->request->cmd = WINBINDD_INIT_CONNECTION;
606 fstrcpy(state->request->domain_name, state->domain->name);
607 state->request->data.init_conn.is_primary = False;
608 fstrcpy(state->request->data.init_conn.dcname, dcname);
610 async_request(state->mem_ctx, &state->domain->child,
611 state->request, state->response,
612 init_child_recv, state);
615 static void init_child_recv(void *private_data, bool success)
617 struct init_child_state *state =
618 talloc_get_type_abort(private_data, struct init_child_state);
620 DEBUG(5, ("Received child initialization response for domain %s\n",
621 state->domain->name));
623 if ((!success) || (state->response->result != WINBINDD_OK)) {
624 DEBUG(3, ("Could not init child\n"));
625 state->continuation(state->private_data, False);
626 talloc_destroy(state->mem_ctx);
630 fstrcpy(state->domain->name,
631 state->response->data.domain_info.name);
632 fstrcpy(state->domain->alt_name,
633 state->response->data.domain_info.alt_name);
634 string_to_sid(&state->domain->sid,
635 state->response->data.domain_info.sid);
636 state->domain->native_mode =
637 state->response->data.domain_info.native_mode;
638 state->domain->active_directory =
639 state->response->data.domain_info.active_directory;
641 init_dc_connection(state->domain);
643 if (state->continuation != NULL)
644 state->continuation(state->private_data, True);
645 talloc_destroy(state->mem_ctx);
648 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
649 struct winbindd_cli_state *state)
651 /* Ensure null termination */
652 state->request.domain_name
653 [sizeof(state->request.domain_name)-1]='\0';
654 state->request.data.init_conn.dcname
655 [sizeof(state->request.data.init_conn.dcname)-1]='\0';
657 if (strlen(state->request.data.init_conn.dcname) > 0) {
658 fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
661 init_dc_connection(domain);
663 if (!domain->initialized) {
664 /* If we return error here we can't do any cached authentication,
665 but we may be in disconnected mode and can't initialize correctly.
666 Do what the previous code did and just return without initialization,
667 once we go online we'll re-initialize.
669 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
670 "online = %d\n", domain->name, (int)domain->online ));
673 fstrcpy(state->response.data.domain_info.name, domain->name);
674 fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
675 sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
677 state->response.data.domain_info.native_mode
678 = domain->native_mode;
679 state->response.data.domain_info.active_directory
680 = domain->active_directory;
681 state->response.data.domain_info.primary
687 /* Look up global info for the winbind daemon */
688 bool init_domain_list(void)
690 struct winbindd_domain *domain;
691 int role = lp_server_role();
693 /* Free existing list */
698 domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
699 &global_sid_Builtin);
701 setup_domain_child(domain,
707 domain = add_trusted_domain(get_global_sam_name(), NULL,
708 &passdb_methods, get_global_sam_sid());
710 if ( role != ROLE_DOMAIN_MEMBER ) {
711 domain->primary = True;
713 setup_domain_child(domain,
717 /* Add ourselves as the first entry. */
719 if ( role == ROLE_DOMAIN_MEMBER ) {
722 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
723 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
727 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
728 &cache_methods, &our_sid);
730 domain->primary = True;
731 setup_domain_child(domain,
734 /* Even in the parent winbindd we'll need to
735 talk to the DC, so try and see if we can
736 contact it. Theoretically this isn't neccessary
737 as the init_dc_connection() in init_child_recv()
738 will do this, but we can start detecting the DC
740 set_domain_online_request(domain);
747 void check_domain_trusted( const char *name, const DOM_SID *user_sid )
749 struct winbindd_domain *domain;
753 domain = find_domain_from_name_noinit( name );
757 sid_copy( &dom_sid, user_sid );
758 if ( !sid_split_rid( &dom_sid, &rid ) )
761 /* add the newly discovered trusted domain */
763 domain = add_trusted_domain( name, NULL, &cache_methods,
769 /* assume this is a trust from a one-way transitive
772 domain->active_directory = True;
773 domain->domain_flags = DS_DOMAIN_DIRECT_OUTBOUND;
774 domain->domain_type = DS_DOMAIN_TRUST_TYPE_UPLEVEL;
775 domain->internal = False;
776 domain->online = True;
778 setup_domain_child(domain,
781 wcache_tdc_add_domain( domain );
787 * Given a domain name, return the struct winbindd domain info for it
789 * @note Do *not* pass lp_workgroup() to this function. domain_list
790 * may modify it's value, and free that pointer. Instead, our local
791 * domain may be found by calling find_our_domain().
795 * @return The domain structure for the named domain, if it is working.
798 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
800 struct winbindd_domain *domain;
802 /* Search through list */
804 for (domain = domain_list(); domain != NULL; domain = domain->next) {
805 if (strequal(domain_name, domain->name) ||
806 (domain->alt_name[0] &&
807 strequal(domain_name, domain->alt_name))) {
817 struct winbindd_domain *find_domain_from_name(const char *domain_name)
819 struct winbindd_domain *domain;
821 domain = find_domain_from_name_noinit(domain_name);
826 if (!domain->initialized)
827 init_dc_connection(domain);
832 /* Given a domain sid, return the struct winbindd domain info for it */
834 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
836 struct winbindd_domain *domain;
838 /* Search through list */
840 for (domain = domain_list(); domain != NULL; domain = domain->next) {
841 if (sid_compare_domain(sid, &domain->sid) == 0)
850 /* Given a domain sid, return the struct winbindd domain info for it */
852 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
854 struct winbindd_domain *domain;
856 domain = find_domain_from_sid_noinit(sid);
861 if (!domain->initialized)
862 init_dc_connection(domain);
867 struct winbindd_domain *find_our_domain(void)
869 struct winbindd_domain *domain;
871 /* Search through list */
873 for (domain = domain_list(); domain != NULL; domain = domain->next) {
878 smb_panic("Could not find our domain");
882 struct winbindd_domain *find_root_domain(void)
884 struct winbindd_domain *ours = find_our_domain();
889 if ( strlen(ours->forest_name) == 0 )
892 return find_domain_from_name( ours->forest_name );
895 struct winbindd_domain *find_builtin_domain(void)
898 struct winbindd_domain *domain;
900 string_to_sid(&sid, "S-1-5-32");
901 domain = find_domain_from_sid(&sid);
903 if (domain == NULL) {
904 smb_panic("Could not find BUILTIN domain");
910 /* Find the appropriate domain to lookup a name or SID */
912 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
914 /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
916 if ( sid_check_is_in_unix_groups(sid) ||
917 sid_check_is_unix_groups(sid) ||
918 sid_check_is_in_unix_users(sid) ||
919 sid_check_is_unix_users(sid) )
921 return find_domain_from_sid(get_global_sam_sid());
924 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
925 * one to contact the external DC's. On member servers the internal
926 * domains are different: These are part of the local SAM. */
928 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid)));
930 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
931 DEBUG(10, ("calling find_domain_from_sid\n"));
932 return find_domain_from_sid(sid);
935 /* On a member server a query for SID or name can always go to our
938 DEBUG(10, ("calling find_our_domain\n"));
939 return find_our_domain();
942 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
944 if ( strequal(domain_name, unix_users_domain_name() ) ||
945 strequal(domain_name, unix_groups_domain_name() ) )
947 return find_domain_from_name_noinit( get_global_sam_name() );
950 if (IS_DC || strequal(domain_name, "BUILTIN") ||
951 strequal(domain_name, get_global_sam_name()))
952 return find_domain_from_name_noinit(domain_name);
954 /* The "Unix User" and "Unix Group" domain our handled by passdb */
956 return find_our_domain();
959 /* Lookup a sid in a domain from a name */
961 bool winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
962 enum winbindd_cmd orig_cmd,
963 struct winbindd_domain *domain,
964 const char *domain_name,
965 const char *name, DOM_SID *sid,
966 enum lsa_SidType *type)
971 result = domain->methods->name_to_sid(domain, mem_ctx, orig_cmd,
972 domain_name, name, sid, type);
974 /* Return sid and type if lookup successful */
975 if (!NT_STATUS_IS_OK(result)) {
976 *type = SID_NAME_UNKNOWN;
979 return NT_STATUS_IS_OK(result);
983 * @brief Lookup a name in a domain from a sid.
985 * @param sid Security ID you want to look up.
986 * @param name On success, set to the name corresponding to @p sid.
987 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
988 * @param type On success, contains the type of name: alias, group or
990 * @retval True if the name exists, in which case @p name and @p type
991 * are set, otherwise False.
993 bool winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
994 struct winbindd_domain *domain,
998 enum lsa_SidType *type)
1007 result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
1009 /* Return name and type if successful */
1011 if (NT_STATUS_IS_OK(result)) {
1015 *type = SID_NAME_UNKNOWN;
1020 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
1022 void free_getent_state(struct getent_state *state)
1024 struct getent_state *temp;
1026 /* Iterate over state list */
1030 while(temp != NULL) {
1031 struct getent_state *next;
1033 /* Free sam entries then list entry */
1035 SAFE_FREE(state->sam_entries);
1036 DLIST_REMOVE(state, state);
1044 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1046 static bool assume_domain(const char *domain)
1048 /* never assume the domain on a standalone server */
1050 if ( lp_server_role() == ROLE_STANDALONE )
1053 /* domain member servers may possibly assume for the domain name */
1055 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1056 if ( !strequal(lp_workgroup(), domain) )
1059 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1063 /* only left with a domain controller */
1065 if ( strequal(get_global_sam_name(), domain) ) {
1072 /* Parse a string of the form DOMAIN\user into a domain and a user */
1074 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1076 char *p = strchr(domuser,*lp_winbind_separator());
1079 fstrcpy(user, domuser);
1081 if ( assume_domain(lp_workgroup())) {
1082 fstrcpy(domain, lp_workgroup());
1083 } else if ((p = strchr(domuser, '@')) != NULL) {
1084 fstrcpy(domain, "");
1090 fstrcpy(domain, domuser);
1091 domain[PTR_DIFF(p, domuser)] = 0;
1099 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1100 char **domain, char **user)
1102 fstring fstr_domain, fstr_user;
1103 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1106 *domain = talloc_strdup(mem_ctx, fstr_domain);
1107 *user = talloc_strdup(mem_ctx, fstr_user);
1108 return ((*domain != NULL) && (*user != NULL));
1111 /* Ensure an incoming username from NSS is fully qualified. Replace the
1112 incoming fstring with DOMAIN <separator> user. Returns the same
1113 values as parse_domain_user() but also replaces the incoming username.
1114 Used to ensure all names are fully qualified within winbindd.
1115 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1116 The protocol definitions of auth_crap, chng_pswd_auth_crap
1117 really should be changed to use this instead of doing things
1120 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1122 if (!parse_domain_user(username_inout, domain, user)) {
1125 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1126 domain, *lp_winbind_separator(),
1132 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1133 'winbind separator' options.
1135 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1138 If we are a PDC or BDC, and this is for our domain, do likewise.
1140 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
1141 username is then unqualified in unix
1143 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1145 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1149 fstrcpy(tmp_user, user);
1150 strlower_m(tmp_user);
1152 if (can_assume && assume_domain(domain)) {
1153 strlcpy(name, tmp_user, sizeof(fstring));
1155 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1156 domain, *lp_winbind_separator(),
1162 * Winbindd socket accessor functions
1165 const char *get_winbind_pipe_dir(void)
1167 return lp_parm_const_string(-1, "winbindd", "socket dir", WINBINDD_SOCKET_DIR);
1170 char *get_winbind_priv_pipe_dir(void)
1172 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
1175 /* Open the winbindd socket */
1177 static int _winbindd_socket = -1;
1178 static int _winbindd_priv_socket = -1;
1180 int open_winbindd_socket(void)
1182 if (_winbindd_socket == -1) {
1183 _winbindd_socket = create_pipe_sock(
1184 get_winbind_pipe_dir(), WINBINDD_SOCKET_NAME, 0755);
1185 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
1189 return _winbindd_socket;
1192 int open_winbindd_priv_socket(void)
1194 if (_winbindd_priv_socket == -1) {
1195 _winbindd_priv_socket = create_pipe_sock(
1196 get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
1197 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
1198 _winbindd_priv_socket));
1201 return _winbindd_priv_socket;
1204 /* Close the winbindd socket */
1206 void close_winbindd_socket(void)
1208 if (_winbindd_socket != -1) {
1209 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
1211 close(_winbindd_socket);
1212 _winbindd_socket = -1;
1214 if (_winbindd_priv_socket != -1) {
1215 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
1216 _winbindd_priv_socket));
1217 close(_winbindd_priv_socket);
1218 _winbindd_priv_socket = -1;
1223 * Client list accessor functions
1226 static struct winbindd_cli_state *_client_list;
1227 static int _num_clients;
1229 /* Return list of all connected clients */
1231 struct winbindd_cli_state *winbindd_client_list(void)
1233 return _client_list;
1236 /* Add a connection to the list */
1238 void winbindd_add_client(struct winbindd_cli_state *cli)
1240 DLIST_ADD(_client_list, cli);
1244 /* Remove a client from the list */
1246 void winbindd_remove_client(struct winbindd_cli_state *cli)
1248 DLIST_REMOVE(_client_list, cli);
1252 /* Close all open clients */
1254 void winbindd_kill_all_clients(void)
1256 struct winbindd_cli_state *cl = winbindd_client_list();
1258 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1261 struct winbindd_cli_state *next;
1264 winbindd_remove_client(cl);
1269 /* Return number of open clients */
1271 int winbindd_num_clients(void)
1273 return _num_clients;
1276 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1277 TALLOC_CTX *mem_ctx,
1278 const DOM_SID *user_sid,
1279 uint32 *p_num_groups, DOM_SID **user_sids)
1281 NET_USER_INFO_3 *info3 = NULL;
1282 NTSTATUS status = NT_STATUS_NO_MEMORY;
1284 size_t num_groups = 0;
1285 DOM_SID group_sid, primary_group;
1287 DEBUG(3,(": lookup_usergroups_cached\n"));
1293 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1295 if (info3 == NULL) {
1296 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1299 if (info3->num_groups == 0) {
1301 return NT_STATUS_UNSUCCESSFUL;
1304 /* always add the primary group to the sid array */
1305 sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
1307 status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
1309 if (!NT_STATUS_IS_OK(status)) {
1314 for (i=0; i<info3->num_groups; i++) {
1315 sid_copy(&group_sid, &info3->dom_sid.sid);
1316 sid_append_rid(&group_sid, info3->gids[i].g_rid);
1318 status = add_sid_to_array(mem_ctx, &group_sid, user_sids,
1320 if (!NT_STATUS_IS_OK(status)) {
1326 /* Add any Universal groups in the other_sids list */
1328 for (i=0; i<info3->num_other_sids; i++) {
1329 /* Skip Domain local groups outside our domain.
1330 We'll get these from the getsidaliases() RPC call. */
1331 if (info3->other_sids_attrib[i] & SE_GROUP_RESOURCE)
1334 status = add_sid_to_array(mem_ctx, &info3->other_sids[i].sid,
1335 user_sids, &num_groups);
1336 if (!NT_STATUS_IS_OK(status)) {
1344 *p_num_groups = num_groups;
1345 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1347 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1352 /*********************************************************************
1353 We use this to remove spaces from user and group names
1354 ********************************************************************/
1356 void ws_name_replace( char *name, char replace )
1358 char replace_char[2] = { 0x0, 0x0 };
1360 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1363 replace_char[0] = replace;
1364 all_string_sub( name, " ", replace_char, 0 );
1369 /*********************************************************************
1370 We use this to do the inverse of ws_name_replace()
1371 ********************************************************************/
1373 void ws_name_return( char *name, char replace )
1375 char replace_char[2] = { 0x0, 0x0 };
1377 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1380 replace_char[0] = replace;
1381 all_string_sub( name, replace_char, " ", 0 );
1386 /*********************************************************************
1387 ********************************************************************/
1389 bool winbindd_can_contact_domain( struct winbindd_domain *domain )
1391 /* We can contact the domain if it is our primary domain */
1393 if ( domain->primary )
1396 /* Can always contact a domain that is in out forest */
1398 if ( domain->domain_flags & DS_DOMAIN_IN_FOREST )
1401 /* We cannot contact the domain if it is running AD and
1402 we have no inbound trust */
1404 if ( domain->active_directory &&
1405 ((domain->domain_flags&DS_DOMAIN_DIRECT_INBOUND) != DS_DOMAIN_DIRECT_INBOUND) )
1410 /* Assume everything else is ok (probably not true but what
1416 /*********************************************************************
1417 ********************************************************************/
1419 bool winbindd_internal_child(struct winbindd_child *child)
1421 if ((child == idmap_child()) || (child == locator_child())) {
1428 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1430 /*********************************************************************
1431 ********************************************************************/
1433 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1436 char addr[INET6_ADDRSTRLEN];
1437 const char *kdc = NULL;
1440 if (!domain || !domain->alt_name || !*domain->alt_name) {
1444 if (domain->initialized && !domain->active_directory) {
1445 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1450 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1453 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1455 kdc = domain->dcname;
1458 if (!kdc || !*kdc) {
1459 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1464 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1465 domain->alt_name) == -1) {
1469 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1472 setenv(var, kdc, 1);
1476 /*********************************************************************
1477 ********************************************************************/
1479 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1481 struct winbindd_domain *our_dom = find_our_domain();
1483 winbindd_set_locator_kdc_env(domain);
1485 if (domain != our_dom) {
1486 winbindd_set_locator_kdc_env(our_dom);
1490 /*********************************************************************
1491 ********************************************************************/
1493 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1497 if (!domain || !domain->alt_name || !*domain->alt_name) {
1501 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1502 domain->alt_name) == -1) {
1511 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1516 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1521 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */