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.
38 /* The list of trusted domains. Note that the list can be deleted and
39 recreated using the init_domain_list() function so pointers to
40 individual winbindd_domain structures cannot be made. Keep a copy of
41 the domain name instead. */
43 static struct winbindd_domain *_domain_list;
46 When was the last scan of trusted domains done?
51 static time_t last_trustdom_scan;
53 struct winbindd_domain *domain_list(void)
57 if ((!_domain_list) && (!init_domain_list())) {
58 smb_panic("Init_domain_list failed");
64 /* Free all entries in the trusted domain list */
66 void free_domain_list(void)
68 struct winbindd_domain *domain = _domain_list;
71 struct winbindd_domain *next = domain->next;
73 DLIST_REMOVE(_domain_list, domain);
79 static BOOL is_internal_domain(const DOM_SID *sid)
85 return sid_check_is_builtin(sid);
87 return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
90 static BOOL is_in_internal_domain(const DOM_SID *sid)
96 return sid_check_is_in_builtin(sid);
98 return (sid_check_is_in_our_domain(sid) || sid_check_is_in_builtin(sid));
102 /* Add a trusted domain to our list of domains */
103 static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
104 struct winbindd_methods *methods,
107 struct winbindd_domain *domain;
108 const char *alternative_name = NULL;
110 /* ignore alt_name if we are not in an AD domain */
112 if ( (lp_security() == SEC_ADS) && alt_name && *alt_name) {
113 alternative_name = alt_name;
116 /* We can't call domain_list() as this function is called from
117 init_domain_list() and we'll get stuck in a loop. */
118 for (domain = _domain_list; domain; domain = domain->next) {
119 if (strequal(domain_name, domain->name) ||
120 strequal(domain_name, domain->alt_name))
125 if (alternative_name && *alternative_name)
127 if (strequal(alternative_name, domain->name) ||
128 strequal(alternative_name, domain->alt_name))
136 if (is_null_sid(sid)) {
140 if (sid_equal(sid, &domain->sid)) {
146 /* See if we found a match. Check if we need to update the
149 if ( domain && sid) {
150 if ( sid_equal( &domain->sid, &global_sid_NULL ) )
151 sid_copy( &domain->sid, sid );
156 /* Create new domain entry */
158 if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
163 ZERO_STRUCTP(domain);
165 /* prioritise the short name */
166 if (strchr_m(domain_name, '.') && alternative_name && *alternative_name) {
167 fstrcpy(domain->name, alternative_name);
168 fstrcpy(domain->alt_name, domain_name);
170 fstrcpy(domain->name, domain_name);
171 if (alternative_name) {
172 fstrcpy(domain->alt_name, alternative_name);
176 domain->methods = methods;
177 domain->backend = NULL;
178 domain->internal = is_internal_domain(sid);
179 domain->sequence_number = DOM_SEQUENCE_NONE;
180 domain->last_seq_check = 0;
181 domain->initialized = False;
182 domain->online = is_internal_domain(sid);
183 domain->check_online_timeout = 0;
185 sid_copy(&domain->sid, sid);
188 /* Link to domain list */
189 DLIST_ADD_END(_domain_list, domain, struct winbindd_domain *);
191 wcache_tdc_add_domain( domain );
193 DEBUG(2,("Added domain %s %s %s\n",
194 domain->name, domain->alt_name,
195 &domain->sid?sid_string_static(&domain->sid):""));
200 /********************************************************************
201 rescan our domains looking for new trusted domains
202 ********************************************************************/
204 struct trustdom_state {
208 struct winbindd_response *response;
211 static void trustdom_recv(void *private_data, BOOL success);
212 static void rescan_forest_root_trusts( void );
213 static void rescan_forest_trusts( void );
215 static void add_trusted_domains( struct winbindd_domain *domain )
218 struct winbindd_request *request;
219 struct winbindd_response *response;
220 uint32 fr_flags = (DS_DOMAIN_TREE_ROOT|DS_DOMAIN_IN_FOREST);
222 struct trustdom_state *state;
224 mem_ctx = talloc_init("add_trusted_domains");
225 if (mem_ctx == NULL) {
226 DEBUG(0, ("talloc_init failed\n"));
230 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
231 response = TALLOC_P(mem_ctx, struct winbindd_response);
232 state = TALLOC_P(mem_ctx, struct trustdom_state);
234 if ((request == NULL) || (response == NULL) || (state == NULL)) {
235 DEBUG(0, ("talloc failed\n"));
236 talloc_destroy(mem_ctx);
240 state->mem_ctx = mem_ctx;
241 state->response = response;
243 /* Flags used to know how to continue the forest trust search */
245 state->primary = domain->primary;
246 state->forest_root = ((domain->domain_flags & fr_flags) == fr_flags );
248 request->length = sizeof(*request);
249 request->cmd = WINBINDD_LIST_TRUSTDOM;
251 async_domain_request(mem_ctx, domain, request, response,
252 trustdom_recv, state);
255 static void trustdom_recv(void *private_data, BOOL success)
257 struct trustdom_state *state =
258 talloc_get_type_abort(private_data, struct trustdom_state);
259 struct winbindd_response *response = state->response;
262 if ((!success) || (response->result != WINBINDD_OK)) {
263 DEBUG(1, ("Could not receive trustdoms\n"));
264 talloc_destroy(state->mem_ctx);
268 p = (char *)response->extra_data.data;
270 while ((p != NULL) && (*p != '\0')) {
271 char *q, *sidstr, *alt_name;
273 struct winbindd_domain *domain;
274 char *alternate_name = NULL;
276 alt_name = strchr(p, '\\');
277 if (alt_name == NULL) {
278 DEBUG(0, ("Got invalid trustdom response\n"));
285 sidstr = strchr(alt_name, '\\');
286 if (sidstr == NULL) {
287 DEBUG(0, ("Got invalid trustdom response\n"));
294 q = strchr(sidstr, '\n');
298 if (!string_to_sid(&sid, sidstr)) {
299 /* Allow NULL sid for sibling domains */
300 if ( strcmp(sidstr,"S-0-0") == 0) {
301 sid_copy( &sid, &global_sid_NULL);
303 DEBUG(0, ("Got invalid trustdom response\n"));
308 /* use the real alt_name if we have one, else pass in NULL */
310 if ( !strequal( alt_name, "(null)" ) )
311 alternate_name = alt_name;
313 /* If we have an existing domain structure, calling
314 add_trusted_domain() will update the SID if
315 necessary. This is important because we need the
316 SID for sibling domains */
318 if ( find_domain_from_name_noinit(p) != NULL ) {
319 domain = add_trusted_domain(p, alternate_name,
323 domain = add_trusted_domain(p, alternate_name,
327 setup_domain_child(domain,
329 domain_dispatch_table,
338 SAFE_FREE(response->extra_data.data);
341 Cases to consider when scanning trusts:
342 (a) we are calling from a child domain (primary && !forest_root)
343 (b) we are calling from the root of the forest (primary && forest_root)
344 (c) we are calling from a trusted forest domain (!primary
348 if ( state->primary ) {
349 /* If this is our primary domain and we are not the in the
350 forest root, we have to scan the root trusts first */
352 if ( !state->forest_root )
353 rescan_forest_root_trusts();
355 rescan_forest_trusts();
357 } else if ( state->forest_root ) {
358 /* Once we have done root forest trust search, we can
359 go on to search thing trusted forests */
361 rescan_forest_trusts();
364 talloc_destroy(state->mem_ctx);
369 /********************************************************************
370 Scan the trusts of our forest root
371 ********************************************************************/
373 static void rescan_forest_root_trusts( void )
375 struct winbindd_tdc_domain *dom_list = NULL;
376 size_t num_trusts = 0;
379 /* The only transitive trusts supported by Windows 2003 AD are
380 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
381 first two are handled in forest and listed by
382 DsEnumerateDomainTrusts(). Forest trusts are not so we
383 have to do that ourselves. */
385 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
388 for ( i=0; i<num_trusts; i++ ) {
389 struct winbindd_domain *d = NULL;
391 /* Find the forest root. Don't necessarily trust
392 the domain_list() as our primary domain may not
393 have been initialized. */
395 if ( !(dom_list[i].trust_flags & DS_DOMAIN_TREE_ROOT) ) {
399 /* Here's the forest root */
401 d = find_domain_from_name_noinit( dom_list[i].domain_name );
404 d = add_trusted_domain( dom_list[i].domain_name,
405 dom_list[i].dns_name,
410 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
411 "for domain tree root %s (%s)\n",
412 d->name, d->alt_name ));
414 d->domain_flags = dom_list[i].trust_flags;
415 d->domain_type = dom_list[i].trust_type;
416 d->domain_trust_attribs = dom_list[i].trust_attribs;
418 add_trusted_domains( d );
423 TALLOC_FREE( dom_list );
428 /********************************************************************
429 scan the transitive forest trists (not our own)
430 ********************************************************************/
433 static void rescan_forest_trusts( void )
435 struct winbindd_domain *d = NULL;
436 struct winbindd_tdc_domain *dom_list = NULL;
437 size_t num_trusts = 0;
440 /* The only transitive trusts supported by Windows 2003 AD are
441 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
442 first two are handled in forest and listed by
443 DsEnumerateDomainTrusts(). Forest trusts are not so we
444 have to do that ourselves. */
446 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
449 for ( i=0; i<num_trusts; i++ ) {
450 uint32 flags = dom_list[i].trust_flags;
451 uint32 type = dom_list[i].trust_type;
452 uint32 attribs = dom_list[i].trust_attribs;
454 d = find_domain_from_name_noinit( dom_list[i].domain_name );
456 /* ignore our primary and internal domains */
458 if ( d && (d->internal || d->primary ) )
461 if ( (flags & DS_DOMAIN_DIRECT_INBOUND) &&
462 (type == DS_DOMAIN_TRUST_TYPE_UPLEVEL) &&
463 (attribs == DS_DOMAIN_TRUST_ATTRIB_FOREST_TRANSITIVE) )
465 /* add the trusted domain if we don't know
469 d = add_trusted_domain( dom_list[i].domain_name,
470 dom_list[i].dns_name,
475 DEBUG(10,("Following trust path for domain %s (%s)\n",
476 d->name, d->alt_name ));
477 add_trusted_domains( d );
481 TALLOC_FREE( dom_list );
486 /*********************************************************************
487 The process of updating the trusted domain list is a three step
490 (b) ask the root domain in our forest
491 (c) ask the a DC in any Win2003 trusted forests
492 *********************************************************************/
494 void rescan_trusted_domains( void )
496 time_t now = time(NULL);
498 /* see if the time has come... */
500 if ((now >= last_trustdom_scan) &&
501 ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
504 /* clear the TRUSTDOM cache first */
508 /* this will only add new domains we didn't already know about
509 in the domain_list()*/
511 add_trusted_domains( find_our_domain() );
513 last_trustdom_scan = now;
518 struct init_child_state {
520 struct winbindd_domain *domain;
521 struct winbindd_request *request;
522 struct winbindd_response *response;
523 void (*continuation)(void *private_data, BOOL success);
527 static void init_child_recv(void *private_data, BOOL success);
528 static void init_child_getdc_recv(void *private_data, BOOL success);
530 enum winbindd_result init_child_connection(struct winbindd_domain *domain,
531 void (*continuation)(void *private_data,
536 struct winbindd_request *request;
537 struct winbindd_response *response;
538 struct init_child_state *state;
539 struct winbindd_domain *request_domain;
541 mem_ctx = talloc_init("init_child_connection");
542 if (mem_ctx == NULL) {
543 DEBUG(0, ("talloc_init failed\n"));
544 return WINBINDD_ERROR;
547 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
548 response = TALLOC_P(mem_ctx, struct winbindd_response);
549 state = TALLOC_P(mem_ctx, struct init_child_state);
551 if ((request == NULL) || (response == NULL) || (state == NULL)) {
552 DEBUG(0, ("talloc failed\n"));
553 TALLOC_FREE(mem_ctx);
554 continuation(private_data, False);
555 return WINBINDD_ERROR;
558 request->length = sizeof(*request);
560 state->mem_ctx = mem_ctx;
561 state->domain = domain;
562 state->request = request;
563 state->response = response;
564 state->continuation = continuation;
565 state->private_data = private_data;
567 if (IS_DC || domain->primary || domain->internal ) {
568 /* The primary domain has to find the DC name itself */
569 request->cmd = WINBINDD_INIT_CONNECTION;
570 fstrcpy(request->domain_name, domain->name);
571 request->data.init_conn.is_primary = domain->internal ? False : True;
572 fstrcpy(request->data.init_conn.dcname, "");
573 async_request(mem_ctx, &domain->child, request, response,
574 init_child_recv, state);
575 return WINBINDD_PENDING;
578 /* This is *not* the primary domain, let's ask our DC about a DC
581 request->cmd = WINBINDD_GETDCNAME;
582 fstrcpy(request->domain_name, domain->name);
584 request_domain = find_our_domain();
585 async_domain_request(mem_ctx, request_domain, request, response,
586 init_child_getdc_recv, state);
587 return WINBINDD_PENDING;
590 static void init_child_getdc_recv(void *private_data, BOOL success)
592 struct init_child_state *state =
593 talloc_get_type_abort(private_data, struct init_child_state);
594 const char *dcname = "";
596 DEBUG(10, ("Received getdcname response\n"));
598 if (success && (state->response->result == WINBINDD_OK)) {
599 dcname = state->response->data.dc_name;
602 state->request->cmd = WINBINDD_INIT_CONNECTION;
603 fstrcpy(state->request->domain_name, state->domain->name);
604 state->request->data.init_conn.is_primary = False;
605 fstrcpy(state->request->data.init_conn.dcname, dcname);
607 async_request(state->mem_ctx, &state->domain->child,
608 state->request, state->response,
609 init_child_recv, state);
612 static void init_child_recv(void *private_data, BOOL success)
614 struct init_child_state *state =
615 talloc_get_type_abort(private_data, struct init_child_state);
617 DEBUG(5, ("Received child initialization response for domain %s\n",
618 state->domain->name));
620 if ((!success) || (state->response->result != WINBINDD_OK)) {
621 DEBUG(3, ("Could not init child\n"));
622 state->continuation(state->private_data, False);
623 talloc_destroy(state->mem_ctx);
627 fstrcpy(state->domain->name,
628 state->response->data.domain_info.name);
629 fstrcpy(state->domain->alt_name,
630 state->response->data.domain_info.alt_name);
631 string_to_sid(&state->domain->sid,
632 state->response->data.domain_info.sid);
633 state->domain->native_mode =
634 state->response->data.domain_info.native_mode;
635 state->domain->active_directory =
636 state->response->data.domain_info.active_directory;
638 init_dc_connection(state->domain);
640 if (state->continuation != NULL)
641 state->continuation(state->private_data, True);
642 talloc_destroy(state->mem_ctx);
645 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
646 struct winbindd_cli_state *state)
648 /* Ensure null termination */
649 state->request.domain_name
650 [sizeof(state->request.domain_name)-1]='\0';
651 state->request.data.init_conn.dcname
652 [sizeof(state->request.data.init_conn.dcname)-1]='\0';
654 if (strlen(state->request.data.init_conn.dcname) > 0) {
655 fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
658 init_dc_connection(domain);
660 if (!domain->initialized) {
661 /* If we return error here we can't do any cached authentication,
662 but we may be in disconnected mode and can't initialize correctly.
663 Do what the previous code did and just return without initialization,
664 once we go online we'll re-initialize.
666 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
667 "online = %d\n", domain->name, (int)domain->online ));
670 fstrcpy(state->response.data.domain_info.name, domain->name);
671 fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
672 fstrcpy(state->response.data.domain_info.sid,
673 sid_string_static(&domain->sid));
675 state->response.data.domain_info.native_mode
676 = domain->native_mode;
677 state->response.data.domain_info.active_directory
678 = domain->active_directory;
679 state->response.data.domain_info.primary
685 /* Look up global info for the winbind daemon */
686 BOOL init_domain_list(void)
688 struct winbindd_domain *domain;
689 int role = lp_server_role();
691 /* Free existing list */
696 domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
697 &global_sid_Builtin);
699 setup_domain_child(domain,
701 domain_dispatch_table,
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,
715 domain_dispatch_table,
719 /* Add ourselves as the first entry. */
721 if ( role == ROLE_DOMAIN_MEMBER ) {
724 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
725 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
729 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
730 &cache_methods, &our_sid);
732 domain->primary = True;
733 setup_domain_child(domain,
735 domain_dispatch_table,
738 /* Even in the parent winbindd we'll need to
739 talk to the DC, so try and see if we can
740 contact it. Theoretically this isn't neccessary
741 as the init_dc_connection() in init_child_recv()
742 will do this, but we can start detecting the DC
744 set_domain_online_request(domain);
751 void check_domain_trusted( const char *name, const DOM_SID *user_sid )
753 struct winbindd_domain *domain;
757 domain = find_domain_from_name_noinit( name );
761 sid_copy( &dom_sid, user_sid );
762 if ( !sid_split_rid( &dom_sid, &rid ) )
765 /* add the newly discovered trusted domain */
767 domain = add_trusted_domain( name, NULL, &cache_methods,
773 /* assume this is a trust from a one-way transitive
776 domain->active_directory = True;
777 domain->domain_flags = DS_DOMAIN_DIRECT_OUTBOUND;
778 domain->domain_type = DS_DOMAIN_TRUST_TYPE_UPLEVEL;
779 domain->internal = False;
780 domain->online = True;
782 setup_domain_child(domain,
784 domain_dispatch_table,
787 wcache_tdc_add_domain( domain );
793 * Given a domain name, return the struct winbindd domain info for it
795 * @note Do *not* pass lp_workgroup() to this function. domain_list
796 * may modify it's value, and free that pointer. Instead, our local
797 * domain may be found by calling find_our_domain().
801 * @return The domain structure for the named domain, if it is working.
804 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
806 struct winbindd_domain *domain;
808 /* Search through list */
810 for (domain = domain_list(); domain != NULL; domain = domain->next) {
811 if (strequal(domain_name, domain->name) ||
812 (domain->alt_name[0] &&
813 strequal(domain_name, domain->alt_name))) {
823 struct winbindd_domain *find_domain_from_name(const char *domain_name)
825 struct winbindd_domain *domain;
827 domain = find_domain_from_name_noinit(domain_name);
832 if (!domain->initialized)
833 init_dc_connection(domain);
838 /* Given a domain sid, return the struct winbindd domain info for it */
840 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
842 struct winbindd_domain *domain;
844 /* Search through list */
846 for (domain = domain_list(); domain != NULL; domain = domain->next) {
847 if (sid_compare_domain(sid, &domain->sid) == 0)
856 /* Given a domain sid, return the struct winbindd domain info for it */
858 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
860 struct winbindd_domain *domain;
862 domain = find_domain_from_sid_noinit(sid);
867 if (!domain->initialized)
868 init_dc_connection(domain);
873 struct winbindd_domain *find_our_domain(void)
875 struct winbindd_domain *domain;
877 /* Search through list */
879 for (domain = domain_list(); domain != NULL; domain = domain->next) {
884 smb_panic("Could not find our domain");
888 struct winbindd_domain *find_root_domain(void)
890 struct winbindd_domain *ours = find_our_domain();
895 if ( strlen(ours->forest_name) == 0 )
898 return find_domain_from_name( ours->forest_name );
901 struct winbindd_domain *find_builtin_domain(void)
904 struct winbindd_domain *domain;
906 string_to_sid(&sid, "S-1-5-32");
907 domain = find_domain_from_sid(&sid);
909 if (domain == NULL) {
910 smb_panic("Could not find BUILTIN domain");
916 /* Find the appropriate domain to lookup a name or SID */
918 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
920 /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
922 if ( sid_check_is_in_unix_groups(sid) ||
923 sid_check_is_unix_groups(sid) ||
924 sid_check_is_in_unix_users(sid) ||
925 sid_check_is_unix_users(sid) )
927 return find_domain_from_sid(get_global_sam_sid());
930 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
931 * one to contact the external DC's. On member servers the internal
932 * domains are different: These are part of the local SAM. */
934 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n",
935 sid_string_static(sid)));
937 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
938 DEBUG(10, ("calling find_domain_from_sid\n"));
939 return find_domain_from_sid(sid);
942 /* On a member server a query for SID or name can always go to our
945 DEBUG(10, ("calling find_our_domain\n"));
946 return find_our_domain();
949 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
951 if ( strequal(domain_name, unix_users_domain_name() ) ||
952 strequal(domain_name, unix_groups_domain_name() ) )
954 return find_domain_from_name_noinit( get_global_sam_name() );
957 if (IS_DC || strequal(domain_name, "BUILTIN") ||
958 strequal(domain_name, get_global_sam_name()))
959 return find_domain_from_name_noinit(domain_name);
961 /* The "Unix User" and "Unix Group" domain our handled by passdb */
963 return find_our_domain();
966 /* Lookup a sid in a domain from a name */
968 BOOL winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
969 enum winbindd_cmd orig_cmd,
970 struct winbindd_domain *domain,
971 const char *domain_name,
972 const char *name, DOM_SID *sid,
973 enum lsa_SidType *type)
978 result = domain->methods->name_to_sid(domain, mem_ctx, orig_cmd,
979 domain_name, name, sid, type);
981 /* Return sid and type if lookup successful */
982 if (!NT_STATUS_IS_OK(result)) {
983 *type = SID_NAME_UNKNOWN;
986 return NT_STATUS_IS_OK(result);
990 * @brief Lookup a name in a domain from a sid.
992 * @param sid Security ID you want to look up.
993 * @param name On success, set to the name corresponding to @p sid.
994 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
995 * @param type On success, contains the type of name: alias, group or
997 * @retval True if the name exists, in which case @p name and @p type
998 * are set, otherwise False.
1000 BOOL winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
1001 struct winbindd_domain *domain,
1005 enum lsa_SidType *type)
1014 result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
1016 /* Return name and type if successful */
1018 if (NT_STATUS_IS_OK(result)) {
1022 *type = SID_NAME_UNKNOWN;
1027 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
1029 void free_getent_state(struct getent_state *state)
1031 struct getent_state *temp;
1033 /* Iterate over state list */
1037 while(temp != NULL) {
1038 struct getent_state *next;
1040 /* Free sam entries then list entry */
1042 SAFE_FREE(state->sam_entries);
1043 DLIST_REMOVE(state, state);
1051 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1053 static BOOL assume_domain(const char *domain)
1055 /* never assume the domain on a standalone server */
1057 if ( lp_server_role() == ROLE_STANDALONE )
1060 /* domain member servers may possibly assume for the domain name */
1062 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1063 if ( !strequal(lp_workgroup(), domain) )
1066 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1070 /* only left with a domain controller */
1072 if ( strequal(get_global_sam_name(), domain) ) {
1079 /* Parse a string of the form DOMAIN\user into a domain and a user */
1081 BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
1083 char *p = strchr(domuser,*lp_winbind_separator());
1086 fstrcpy(user, domuser);
1088 if ( assume_domain(lp_workgroup())) {
1089 fstrcpy(domain, lp_workgroup());
1090 } else if ((p = strchr(domuser, '@')) != NULL) {
1091 fstrcpy(domain, "");
1097 fstrcpy(domain, domuser);
1098 domain[PTR_DIFF(p, domuser)] = 0;
1106 BOOL parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1107 char **domain, char **user)
1109 fstring fstr_domain, fstr_user;
1110 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1113 *domain = talloc_strdup(mem_ctx, fstr_domain);
1114 *user = talloc_strdup(mem_ctx, fstr_user);
1115 return ((*domain != NULL) && (*user != NULL));
1118 /* Ensure an incoming username from NSS is fully qualified. Replace the
1119 incoming fstring with DOMAIN <separator> user. Returns the same
1120 values as parse_domain_user() but also replaces the incoming username.
1121 Used to ensure all names are fully qualified within winbindd.
1122 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1123 The protocol definitions of auth_crap, chng_pswd_auth_crap
1124 really should be changed to use this instead of doing things
1127 BOOL canonicalize_username(fstring username_inout, fstring domain, fstring user)
1129 if (!parse_domain_user(username_inout, domain, user)) {
1132 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1133 domain, *lp_winbind_separator(),
1139 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1140 'winbind separator' options.
1142 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1145 If we are a PDC or BDC, and this is for our domain, do likewise.
1147 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
1148 username is then unqualified in unix
1150 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1152 void fill_domain_username(fstring name, const char *domain, const char *user, BOOL can_assume)
1156 fstrcpy(tmp_user, user);
1157 strlower_m(tmp_user);
1159 if (can_assume && assume_domain(domain)) {
1160 strlcpy(name, tmp_user, sizeof(fstring));
1162 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1163 domain, *lp_winbind_separator(),
1169 * Winbindd socket accessor functions
1172 const char *get_winbind_pipe_dir(void)
1174 return lp_parm_const_string(-1, "winbindd", "socket dir", WINBINDD_SOCKET_DIR);
1177 char *get_winbind_priv_pipe_dir(void)
1179 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
1183 * Client list accessor functions
1186 static struct winbindd_cli_state *_client_list;
1187 static int _num_clients;
1189 /* Return list of all connected clients */
1191 struct winbindd_cli_state *winbindd_client_list(void)
1193 return _client_list;
1196 /* Add a connection to the list */
1198 void winbindd_add_client(struct winbindd_cli_state *cli)
1200 DLIST_ADD(_client_list, cli);
1204 /* Remove a client from the list */
1206 void winbindd_remove_client(struct winbindd_cli_state *cli)
1208 DLIST_REMOVE(_client_list, cli);
1212 /* Close all open clients */
1214 void winbindd_kill_all_clients(void)
1216 struct winbindd_cli_state *cl = winbindd_client_list();
1218 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1221 struct winbindd_cli_state *next;
1224 winbindd_remove_client(cl);
1229 /* Return number of open clients */
1231 int winbindd_num_clients(void)
1233 return _num_clients;
1236 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1237 TALLOC_CTX *mem_ctx,
1238 const DOM_SID *user_sid,
1239 uint32 *p_num_groups, DOM_SID **user_sids)
1241 NET_USER_INFO_3 *info3 = NULL;
1242 NTSTATUS status = NT_STATUS_NO_MEMORY;
1244 size_t num_groups = 0;
1245 DOM_SID group_sid, primary_group;
1247 DEBUG(3,(": lookup_usergroups_cached\n"));
1253 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1255 if (info3 == NULL) {
1256 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1259 if (info3->num_groups == 0) {
1261 return NT_STATUS_UNSUCCESSFUL;
1264 /* always add the primary group to the sid array */
1265 sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
1267 if (!add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups)) {
1269 return NT_STATUS_NO_MEMORY;
1272 for (i=0; i<info3->num_groups; i++) {
1273 sid_copy(&group_sid, &info3->dom_sid.sid);
1274 sid_append_rid(&group_sid, info3->gids[i].g_rid);
1276 if (!add_sid_to_array(mem_ctx, &group_sid, user_sids,
1279 return NT_STATUS_NO_MEMORY;
1283 /* Add any Universal groups in the other_sids list */
1285 for (i=0; i<info3->num_other_sids; i++) {
1286 /* Skip Domain local groups outside our domain.
1287 We'll get these from the getsidaliases() RPC call. */
1288 if (info3->other_sids_attrib[i] & SE_GROUP_RESOURCE)
1291 if (!add_sid_to_array(mem_ctx, &info3->other_sids[i].sid,
1292 user_sids, &num_groups))
1295 return NT_STATUS_NO_MEMORY;
1301 *p_num_groups = num_groups;
1302 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1304 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1309 /*********************************************************************
1310 We use this to remove spaces from user and group names
1311 ********************************************************************/
1313 void ws_name_replace( char *name, char replace )
1315 char replace_char[2] = { 0x0, 0x0 };
1317 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1320 replace_char[0] = replace;
1321 all_string_sub( name, " ", replace_char, 0 );
1326 /*********************************************************************
1327 We use this to do the inverse of ws_name_replace()
1328 ********************************************************************/
1330 void ws_name_return( char *name, char replace )
1332 char replace_char[2] = { 0x0, 0x0 };
1334 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1337 replace_char[0] = replace;
1338 all_string_sub( name, replace_char, " ", 0 );
1343 /*********************************************************************
1344 ********************************************************************/
1346 BOOL winbindd_can_contact_domain( struct winbindd_domain *domain )
1348 /* We can contact the domain if it is our primary domain */
1350 if ( domain->primary )
1353 /* Can always contact a domain that is in out forest */
1355 if ( domain->domain_flags & DS_DOMAIN_IN_FOREST )
1358 /* We cannot contact the domain if it is running AD and
1359 we have no inbound trust */
1361 if ( domain->active_directory &&
1362 ((domain->domain_flags&DS_DOMAIN_DIRECT_INBOUND) != DS_DOMAIN_DIRECT_INBOUND) )
1367 /* Assume everything else is ok (probably not true but what
1373 /*********************************************************************
1374 ********************************************************************/
1376 BOOL winbindd_internal_child(struct winbindd_child *child)
1378 if ((child == idmap_child()) || (child == locator_child())) {
1385 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1387 /*********************************************************************
1388 ********************************************************************/
1390 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1393 const char *kdc = NULL;
1396 if (!domain || !domain->alt_name || !*domain->alt_name) {
1400 if (domain->initialized && !domain->active_directory) {
1401 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1406 kdc = inet_ntoa(domain->dcaddr.sin_addr);
1408 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1410 kdc = domain->dcname;
1413 if (!kdc || !*kdc) {
1414 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1419 if (asprintf(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1420 strupper_static(domain->alt_name)) == -1) {
1424 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1427 setenv(var, kdc, 1);
1431 /*********************************************************************
1432 ********************************************************************/
1434 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1436 struct winbindd_domain *our_dom = find_our_domain();
1438 winbindd_set_locator_kdc_env(domain);
1440 if (domain != our_dom) {
1441 winbindd_set_locator_kdc_env(our_dom);
1445 /*********************************************************************
1446 ********************************************************************/
1448 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1452 if (!domain || !domain->alt_name || !*domain->alt_name) {
1456 if (asprintf(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1457 strupper_static(domain->alt_name)) == -1) {
1466 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1471 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1476 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */