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, &domain->child, NULL);
336 SAFE_FREE(response->extra_data.data);
339 Cases to consider when scanning trusts:
340 (a) we are calling from a child domain (primary && !forest_root)
341 (b) we are calling from the root of the forest (primary && forest_root)
342 (c) we are calling from a trusted forest domain (!primary
346 if ( state->primary ) {
347 /* If this is our primary domain and we are not the in the
348 forest root, we have to scan the root trusts first */
350 if ( !state->forest_root )
351 rescan_forest_root_trusts();
353 rescan_forest_trusts();
355 } else if ( state->forest_root ) {
356 /* Once we have done root forest trust search, we can
357 go on to search thing trusted forests */
359 rescan_forest_trusts();
362 talloc_destroy(state->mem_ctx);
367 /********************************************************************
368 Scan the trusts of our forest root
369 ********************************************************************/
371 static void rescan_forest_root_trusts( void )
373 struct winbindd_tdc_domain *dom_list = NULL;
374 size_t num_trusts = 0;
377 /* The only transitive trusts supported by Windows 2003 AD are
378 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
379 first two are handled in forest and listed by
380 DsEnumerateDomainTrusts(). Forest trusts are not so we
381 have to do that ourselves. */
383 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
386 for ( i=0; i<num_trusts; i++ ) {
387 struct winbindd_domain *d = NULL;
389 /* Find the forest root. Don't necessarily trust
390 the domain_list() as our primary domain may not
391 have been initialized. */
393 if ( !(dom_list[i].trust_flags & DS_DOMAIN_TREE_ROOT) ) {
397 /* Here's the forest root */
399 d = find_domain_from_name_noinit( dom_list[i].domain_name );
402 d = add_trusted_domain( dom_list[i].domain_name,
403 dom_list[i].dns_name,
408 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
409 "for domain tree root %s (%s)\n",
410 d->name, d->alt_name ));
412 d->domain_flags = dom_list[i].trust_flags;
413 d->domain_type = dom_list[i].trust_type;
414 d->domain_trust_attribs = dom_list[i].trust_attribs;
416 add_trusted_domains( d );
421 TALLOC_FREE( dom_list );
426 /********************************************************************
427 scan the transitive forest trists (not our own)
428 ********************************************************************/
431 static void rescan_forest_trusts( void )
433 struct winbindd_domain *d = NULL;
434 struct winbindd_tdc_domain *dom_list = NULL;
435 size_t num_trusts = 0;
438 /* The only transitive trusts supported by Windows 2003 AD are
439 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
440 first two are handled in forest and listed by
441 DsEnumerateDomainTrusts(). Forest trusts are not so we
442 have to do that ourselves. */
444 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
447 for ( i=0; i<num_trusts; i++ ) {
448 uint32 flags = dom_list[i].trust_flags;
449 uint32 type = dom_list[i].trust_type;
450 uint32 attribs = dom_list[i].trust_attribs;
452 d = find_domain_from_name_noinit( dom_list[i].domain_name );
454 /* ignore our primary and internal domains */
456 if ( d && (d->internal || d->primary ) )
459 if ( (flags & DS_DOMAIN_DIRECT_INBOUND) &&
460 (type == DS_DOMAIN_TRUST_TYPE_UPLEVEL) &&
461 (attribs == DS_DOMAIN_TRUST_ATTRIB_FOREST_TRANSITIVE) )
463 /* add the trusted domain if we don't know
467 d = add_trusted_domain( dom_list[i].domain_name,
468 dom_list[i].dns_name,
473 DEBUG(10,("Following trust path for domain %s (%s)\n",
474 d->name, d->alt_name ));
475 add_trusted_domains( d );
479 TALLOC_FREE( dom_list );
484 /*********************************************************************
485 The process of updating the trusted domain list is a three step
488 (b) ask the root domain in our forest
489 (c) ask the a DC in any Win2003 trusted forests
490 *********************************************************************/
492 void rescan_trusted_domains( void )
494 time_t now = time(NULL);
496 /* see if the time has come... */
498 if ((now >= last_trustdom_scan) &&
499 ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
502 /* clear the TRUSTDOM cache first */
506 /* this will only add new domains we didn't already know about
507 in the domain_list()*/
509 add_trusted_domains( find_our_domain() );
511 last_trustdom_scan = now;
516 struct init_child_state {
518 struct winbindd_domain *domain;
519 struct winbindd_request *request;
520 struct winbindd_response *response;
521 void (*continuation)(void *private_data, bool success);
525 static void init_child_recv(void *private_data, bool success);
526 static void init_child_getdc_recv(void *private_data, bool success);
528 enum winbindd_result init_child_connection(struct winbindd_domain *domain,
529 void (*continuation)(void *private_data,
534 struct winbindd_request *request;
535 struct winbindd_response *response;
536 struct init_child_state *state;
537 struct winbindd_domain *request_domain;
539 mem_ctx = talloc_init("init_child_connection");
540 if (mem_ctx == NULL) {
541 DEBUG(0, ("talloc_init failed\n"));
542 return WINBINDD_ERROR;
545 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
546 response = TALLOC_P(mem_ctx, struct winbindd_response);
547 state = TALLOC_P(mem_ctx, struct init_child_state);
549 if ((request == NULL) || (response == NULL) || (state == NULL)) {
550 DEBUG(0, ("talloc failed\n"));
551 TALLOC_FREE(mem_ctx);
552 continuation(private_data, False);
553 return WINBINDD_ERROR;
556 request->length = sizeof(*request);
558 state->mem_ctx = mem_ctx;
559 state->domain = domain;
560 state->request = request;
561 state->response = response;
562 state->continuation = continuation;
563 state->private_data = private_data;
565 if (IS_DC || domain->primary || domain->internal ) {
566 /* The primary domain has to find the DC name itself */
567 request->cmd = WINBINDD_INIT_CONNECTION;
568 fstrcpy(request->domain_name, domain->name);
569 request->data.init_conn.is_primary = domain->internal ? False : True;
570 fstrcpy(request->data.init_conn.dcname, "");
571 async_request(mem_ctx, &domain->child, request, response,
572 init_child_recv, state);
573 return WINBINDD_PENDING;
576 /* This is *not* the primary domain, let's ask our DC about a DC
579 request->cmd = WINBINDD_GETDCNAME;
580 fstrcpy(request->domain_name, domain->name);
582 request_domain = find_our_domain();
583 async_domain_request(mem_ctx, request_domain, request, response,
584 init_child_getdc_recv, state);
585 return WINBINDD_PENDING;
588 static void init_child_getdc_recv(void *private_data, bool success)
590 struct init_child_state *state =
591 talloc_get_type_abort(private_data, struct init_child_state);
592 const char *dcname = "";
594 DEBUG(10, ("Received getdcname response\n"));
596 if (success && (state->response->result == WINBINDD_OK)) {
597 dcname = state->response->data.dc_name;
600 state->request->cmd = WINBINDD_INIT_CONNECTION;
601 fstrcpy(state->request->domain_name, state->domain->name);
602 state->request->data.init_conn.is_primary = False;
603 fstrcpy(state->request->data.init_conn.dcname, dcname);
605 async_request(state->mem_ctx, &state->domain->child,
606 state->request, state->response,
607 init_child_recv, state);
610 static void init_child_recv(void *private_data, bool success)
612 struct init_child_state *state =
613 talloc_get_type_abort(private_data, struct init_child_state);
615 DEBUG(5, ("Received child initialization response for domain %s\n",
616 state->domain->name));
618 if ((!success) || (state->response->result != WINBINDD_OK)) {
619 DEBUG(3, ("Could not init child\n"));
620 state->continuation(state->private_data, False);
621 talloc_destroy(state->mem_ctx);
625 fstrcpy(state->domain->name,
626 state->response->data.domain_info.name);
627 fstrcpy(state->domain->alt_name,
628 state->response->data.domain_info.alt_name);
629 string_to_sid(&state->domain->sid,
630 state->response->data.domain_info.sid);
631 state->domain->native_mode =
632 state->response->data.domain_info.native_mode;
633 state->domain->active_directory =
634 state->response->data.domain_info.active_directory;
636 init_dc_connection(state->domain);
638 if (state->continuation != NULL)
639 state->continuation(state->private_data, True);
640 talloc_destroy(state->mem_ctx);
643 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
644 struct winbindd_cli_state *state)
646 /* Ensure null termination */
647 state->request.domain_name
648 [sizeof(state->request.domain_name)-1]='\0';
649 state->request.data.init_conn.dcname
650 [sizeof(state->request.data.init_conn.dcname)-1]='\0';
652 if (strlen(state->request.data.init_conn.dcname) > 0) {
653 fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
656 init_dc_connection(domain);
658 if (!domain->initialized) {
659 /* If we return error here we can't do any cached authentication,
660 but we may be in disconnected mode and can't initialize correctly.
661 Do what the previous code did and just return without initialization,
662 once we go online we'll re-initialize.
664 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
665 "online = %d\n", domain->name, (int)domain->online ));
668 fstrcpy(state->response.data.domain_info.name, domain->name);
669 fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
670 fstrcpy(state->response.data.domain_info.sid,
671 sid_string_static(&domain->sid));
673 state->response.data.domain_info.native_mode
674 = domain->native_mode;
675 state->response.data.domain_info.active_directory
676 = domain->active_directory;
677 state->response.data.domain_info.primary
683 /* Look up global info for the winbind daemon */
684 bool init_domain_list(void)
686 struct winbindd_domain *domain;
687 int role = lp_server_role();
689 /* Free existing list */
694 domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
695 &global_sid_Builtin);
697 setup_domain_child(domain, &domain->child, NULL);
702 domain = add_trusted_domain(get_global_sam_name(), NULL,
703 &passdb_methods, get_global_sam_sid());
705 if ( role != ROLE_DOMAIN_MEMBER ) {
706 domain->primary = True;
708 setup_domain_child(domain, &domain->child, NULL);
711 /* Add ourselves as the first entry. */
713 if ( role == ROLE_DOMAIN_MEMBER ) {
716 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
717 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
721 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
722 &cache_methods, &our_sid);
724 domain->primary = True;
725 setup_domain_child(domain, &domain->child, NULL);
727 /* Even in the parent winbindd we'll need to
728 talk to the DC, so try and see if we can
729 contact it. Theoretically this isn't neccessary
730 as the init_dc_connection() in init_child_recv()
731 will do this, but we can start detecting the DC
733 set_domain_online_request(domain);
740 void check_domain_trusted( const char *name, const DOM_SID *user_sid )
742 struct winbindd_domain *domain;
746 domain = find_domain_from_name_noinit( name );
750 sid_copy( &dom_sid, user_sid );
751 if ( !sid_split_rid( &dom_sid, &rid ) )
754 /* add the newly discovered trusted domain */
756 domain = add_trusted_domain( name, NULL, &cache_methods,
762 /* assume this is a trust from a one-way transitive
765 domain->active_directory = True;
766 domain->domain_flags = DS_DOMAIN_DIRECT_OUTBOUND;
767 domain->domain_type = DS_DOMAIN_TRUST_TYPE_UPLEVEL;
768 domain->internal = False;
769 domain->online = True;
771 setup_domain_child(domain, &domain->child, NULL);
773 wcache_tdc_add_domain( domain );
779 * Given a domain name, return the struct winbindd domain info for it
781 * @note Do *not* pass lp_workgroup() to this function. domain_list
782 * may modify it's value, and free that pointer. Instead, our local
783 * domain may be found by calling find_our_domain().
787 * @return The domain structure for the named domain, if it is working.
790 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
792 struct winbindd_domain *domain;
794 /* Search through list */
796 for (domain = domain_list(); domain != NULL; domain = domain->next) {
797 if (strequal(domain_name, domain->name) ||
798 (domain->alt_name[0] &&
799 strequal(domain_name, domain->alt_name))) {
809 struct winbindd_domain *find_domain_from_name(const char *domain_name)
811 struct winbindd_domain *domain;
813 domain = find_domain_from_name_noinit(domain_name);
818 if (!domain->initialized)
819 init_dc_connection(domain);
824 /* Given a domain sid, return the struct winbindd domain info for it */
826 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
828 struct winbindd_domain *domain;
830 /* Search through list */
832 for (domain = domain_list(); domain != NULL; domain = domain->next) {
833 if (sid_compare_domain(sid, &domain->sid) == 0)
842 /* Given a domain sid, return the struct winbindd domain info for it */
844 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
846 struct winbindd_domain *domain;
848 domain = find_domain_from_sid_noinit(sid);
853 if (!domain->initialized)
854 init_dc_connection(domain);
859 struct winbindd_domain *find_our_domain(void)
861 struct winbindd_domain *domain;
863 /* Search through list */
865 for (domain = domain_list(); domain != NULL; domain = domain->next) {
870 smb_panic("Could not find our domain");
874 struct winbindd_domain *find_root_domain(void)
876 struct winbindd_domain *ours = find_our_domain();
881 if ( strlen(ours->forest_name) == 0 )
884 return find_domain_from_name( ours->forest_name );
887 struct winbindd_domain *find_builtin_domain(void)
890 struct winbindd_domain *domain;
892 string_to_sid(&sid, "S-1-5-32");
893 domain = find_domain_from_sid(&sid);
895 if (domain == NULL) {
896 smb_panic("Could not find BUILTIN domain");
902 /* Find the appropriate domain to lookup a name or SID */
904 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
906 /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
908 if ( sid_check_is_in_unix_groups(sid) ||
909 sid_check_is_unix_groups(sid) ||
910 sid_check_is_in_unix_users(sid) ||
911 sid_check_is_unix_users(sid) )
913 return find_domain_from_sid(get_global_sam_sid());
916 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
917 * one to contact the external DC's. On member servers the internal
918 * domains are different: These are part of the local SAM. */
920 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n",
921 sid_string_static(sid)));
923 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
924 DEBUG(10, ("calling find_domain_from_sid\n"));
925 return find_domain_from_sid(sid);
928 /* On a member server a query for SID or name can always go to our
931 DEBUG(10, ("calling find_our_domain\n"));
932 return find_our_domain();
935 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
937 if ( strequal(domain_name, unix_users_domain_name() ) ||
938 strequal(domain_name, unix_groups_domain_name() ) )
940 return find_domain_from_name_noinit( get_global_sam_name() );
943 if (IS_DC || strequal(domain_name, "BUILTIN") ||
944 strequal(domain_name, get_global_sam_name()))
945 return find_domain_from_name_noinit(domain_name);
947 /* The "Unix User" and "Unix Group" domain our handled by passdb */
949 return find_our_domain();
952 /* Lookup a sid in a domain from a name */
954 bool winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
955 enum winbindd_cmd orig_cmd,
956 struct winbindd_domain *domain,
957 const char *domain_name,
958 const char *name, DOM_SID *sid,
959 enum lsa_SidType *type)
964 result = domain->methods->name_to_sid(domain, mem_ctx, orig_cmd,
965 domain_name, name, sid, type);
967 /* Return sid and type if lookup successful */
968 if (!NT_STATUS_IS_OK(result)) {
969 *type = SID_NAME_UNKNOWN;
972 return NT_STATUS_IS_OK(result);
976 * @brief Lookup a name in a domain from a sid.
978 * @param sid Security ID you want to look up.
979 * @param name On success, set to the name corresponding to @p sid.
980 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
981 * @param type On success, contains the type of name: alias, group or
983 * @retval True if the name exists, in which case @p name and @p type
984 * are set, otherwise False.
986 bool winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
987 struct winbindd_domain *domain,
991 enum lsa_SidType *type)
1000 result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
1002 /* Return name and type if successful */
1004 if (NT_STATUS_IS_OK(result)) {
1008 *type = SID_NAME_UNKNOWN;
1013 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
1015 void free_getent_state(struct getent_state *state)
1017 struct getent_state *temp;
1019 /* Iterate over state list */
1023 while(temp != NULL) {
1024 struct getent_state *next;
1026 /* Free sam entries then list entry */
1028 SAFE_FREE(state->sam_entries);
1029 DLIST_REMOVE(state, state);
1037 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1039 static bool assume_domain(const char *domain)
1041 /* never assume the domain on a standalone server */
1043 if ( lp_server_role() == ROLE_STANDALONE )
1046 /* domain member servers may possibly assume for the domain name */
1048 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1049 if ( !strequal(lp_workgroup(), domain) )
1052 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1056 /* only left with a domain controller */
1058 if ( strequal(get_global_sam_name(), domain) ) {
1065 /* Parse a string of the form DOMAIN\user into a domain and a user */
1067 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1069 char *p = strchr(domuser,*lp_winbind_separator());
1072 fstrcpy(user, domuser);
1074 if ( assume_domain(lp_workgroup())) {
1075 fstrcpy(domain, lp_workgroup());
1076 } else if ((p = strchr(domuser, '@')) != NULL) {
1077 fstrcpy(domain, "");
1083 fstrcpy(domain, domuser);
1084 domain[PTR_DIFF(p, domuser)] = 0;
1092 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1093 char **domain, char **user)
1095 fstring fstr_domain, fstr_user;
1096 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1099 *domain = talloc_strdup(mem_ctx, fstr_domain);
1100 *user = talloc_strdup(mem_ctx, fstr_user);
1101 return ((*domain != NULL) && (*user != NULL));
1104 /* Ensure an incoming username from NSS is fully qualified. Replace the
1105 incoming fstring with DOMAIN <separator> user. Returns the same
1106 values as parse_domain_user() but also replaces the incoming username.
1107 Used to ensure all names are fully qualified within winbindd.
1108 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1109 The protocol definitions of auth_crap, chng_pswd_auth_crap
1110 really should be changed to use this instead of doing things
1113 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1115 if (!parse_domain_user(username_inout, domain, user)) {
1118 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1119 domain, *lp_winbind_separator(),
1125 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1126 'winbind separator' options.
1128 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1131 If we are a PDC or BDC, and this is for our domain, do likewise.
1133 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
1134 username is then unqualified in unix
1136 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1138 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1142 fstrcpy(tmp_user, user);
1143 strlower_m(tmp_user);
1145 if (can_assume && assume_domain(domain)) {
1146 strlcpy(name, tmp_user, sizeof(fstring));
1148 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1149 domain, *lp_winbind_separator(),
1155 * Winbindd socket accessor functions
1158 const char *get_winbind_pipe_dir(void)
1160 return lp_parm_const_string(-1, "winbindd", "socket dir", WINBINDD_SOCKET_DIR);
1163 char *get_winbind_priv_pipe_dir(void)
1165 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
1168 /* Open the winbindd socket */
1170 static int _winbindd_socket = -1;
1171 static int _winbindd_priv_socket = -1;
1173 int open_winbindd_socket(void)
1175 if (_winbindd_socket == -1) {
1176 _winbindd_socket = create_pipe_sock(
1177 get_winbind_pipe_dir(), WINBINDD_SOCKET_NAME, 0755);
1178 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
1182 return _winbindd_socket;
1185 int open_winbindd_priv_socket(void)
1187 if (_winbindd_priv_socket == -1) {
1188 _winbindd_priv_socket = create_pipe_sock(
1189 get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
1190 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
1191 _winbindd_priv_socket));
1194 return _winbindd_priv_socket;
1197 /* Close the winbindd socket */
1199 void close_winbindd_socket(void)
1201 if (_winbindd_socket != -1) {
1202 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
1204 close(_winbindd_socket);
1205 _winbindd_socket = -1;
1207 if (_winbindd_priv_socket != -1) {
1208 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
1209 _winbindd_priv_socket));
1210 close(_winbindd_priv_socket);
1211 _winbindd_priv_socket = -1;
1216 * Client list accessor functions
1219 static struct winbindd_cli_state *_client_list;
1220 static int _num_clients;
1222 /* Return list of all connected clients */
1224 struct winbindd_cli_state *winbindd_client_list(void)
1226 return _client_list;
1229 /* Add a connection to the list */
1231 void winbindd_add_client(struct winbindd_cli_state *cli)
1233 DLIST_ADD(_client_list, cli);
1237 /* Remove a client from the list */
1239 void winbindd_remove_client(struct winbindd_cli_state *cli)
1241 DLIST_REMOVE(_client_list, cli);
1245 /* Close all open clients */
1247 void winbindd_kill_all_clients(void)
1249 struct winbindd_cli_state *cl = winbindd_client_list();
1251 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1254 struct winbindd_cli_state *next;
1257 winbindd_remove_client(cl);
1262 /* Return number of open clients */
1264 int winbindd_num_clients(void)
1266 return _num_clients;
1269 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1270 TALLOC_CTX *mem_ctx,
1271 const DOM_SID *user_sid,
1272 uint32 *p_num_groups, DOM_SID **user_sids)
1274 NET_USER_INFO_3 *info3 = NULL;
1275 NTSTATUS status = NT_STATUS_NO_MEMORY;
1277 size_t num_groups = 0;
1278 DOM_SID group_sid, primary_group;
1280 DEBUG(3,(": lookup_usergroups_cached\n"));
1286 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1288 if (info3 == NULL) {
1289 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1292 if (info3->num_groups == 0) {
1294 return NT_STATUS_UNSUCCESSFUL;
1297 /* always add the primary group to the sid array */
1298 sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
1300 if (!add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups)) {
1302 return NT_STATUS_NO_MEMORY;
1305 for (i=0; i<info3->num_groups; i++) {
1306 sid_copy(&group_sid, &info3->dom_sid.sid);
1307 sid_append_rid(&group_sid, info3->gids[i].g_rid);
1309 if (!add_sid_to_array(mem_ctx, &group_sid, user_sids,
1312 return NT_STATUS_NO_MEMORY;
1316 /* Add any Universal groups in the other_sids list */
1318 for (i=0; i<info3->num_other_sids; i++) {
1319 /* Skip Domain local groups outside our domain.
1320 We'll get these from the getsidaliases() RPC call. */
1321 if (info3->other_sids_attrib[i] & SE_GROUP_RESOURCE)
1324 if (!add_sid_to_array(mem_ctx, &info3->other_sids[i].sid,
1325 user_sids, &num_groups))
1328 return NT_STATUS_NO_MEMORY;
1334 *p_num_groups = num_groups;
1335 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1337 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1342 /*********************************************************************
1343 We use this to remove spaces from user and group names
1344 ********************************************************************/
1346 void ws_name_replace( char *name, char replace )
1348 char replace_char[2] = { 0x0, 0x0 };
1350 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1353 replace_char[0] = replace;
1354 all_string_sub( name, " ", replace_char, 0 );
1359 /*********************************************************************
1360 We use this to do the inverse of ws_name_replace()
1361 ********************************************************************/
1363 void ws_name_return( char *name, char replace )
1365 char replace_char[2] = { 0x0, 0x0 };
1367 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1370 replace_char[0] = replace;
1371 all_string_sub( name, replace_char, " ", 0 );
1376 /*********************************************************************
1377 ********************************************************************/
1379 bool winbindd_can_contact_domain( struct winbindd_domain *domain )
1381 /* We can contact the domain if it is our primary domain */
1383 if ( domain->primary )
1386 /* Can always contact a domain that is in out forest */
1388 if ( domain->domain_flags & DS_DOMAIN_IN_FOREST )
1391 /* We cannot contact the domain if it is running AD and
1392 we have no inbound trust */
1394 if ( domain->active_directory &&
1395 ((domain->domain_flags&DS_DOMAIN_DIRECT_INBOUND) != DS_DOMAIN_DIRECT_INBOUND) )
1400 /* Assume everything else is ok (probably not true but what
1406 /*********************************************************************
1407 ********************************************************************/
1409 bool winbindd_internal_child(struct winbindd_child *child)
1411 if ((child == idmap_child()) || (child == locator_child())) {
1418 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1420 /*********************************************************************
1421 ********************************************************************/
1423 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1426 const char *kdc = NULL;
1429 if (!domain || !domain->alt_name || !*domain->alt_name) {
1433 if (domain->initialized && !domain->active_directory) {
1434 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1439 kdc = inet_ntoa(domain->dcaddr.sin_addr);
1441 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1443 kdc = domain->dcname;
1446 if (!kdc || !*kdc) {
1447 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1452 if (asprintf(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1453 strupper_static(domain->alt_name)) == -1) {
1457 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1460 setenv(var, kdc, 1);
1464 /*********************************************************************
1465 ********************************************************************/
1467 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1469 struct winbindd_domain *our_dom = find_our_domain();
1471 winbindd_set_locator_kdc_env(domain);
1473 if (domain != our_dom) {
1474 winbindd_set_locator_kdc_env(our_dom);
1478 /*********************************************************************
1479 ********************************************************************/
1481 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1485 if (!domain || !domain->alt_name || !*domain->alt_name) {
1489 if (asprintf(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1490 strupper_static(domain->alt_name)) == -1) {
1499 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1504 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1509 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */