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,
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 /* clear the TRUSTDOM cache first */
507 /* this will only add new domains we didn't already know about
508 in the domain_list()*/
510 add_trusted_domains( find_our_domain() );
512 last_trustdom_scan = now;
517 struct init_child_state {
519 struct winbindd_domain *domain;
520 struct winbindd_request *request;
521 struct winbindd_response *response;
522 void (*continuation)(void *private_data, bool success);
526 static void init_child_recv(void *private_data, bool success);
527 static void init_child_getdc_recv(void *private_data, bool success);
529 enum winbindd_result init_child_connection(struct winbindd_domain *domain,
530 void (*continuation)(void *private_data,
535 struct winbindd_request *request;
536 struct winbindd_response *response;
537 struct init_child_state *state;
538 struct winbindd_domain *request_domain;
540 mem_ctx = talloc_init("init_child_connection");
541 if (mem_ctx == NULL) {
542 DEBUG(0, ("talloc_init failed\n"));
543 return WINBINDD_ERROR;
546 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
547 response = TALLOC_P(mem_ctx, struct winbindd_response);
548 state = TALLOC_P(mem_ctx, struct init_child_state);
550 if ((request == NULL) || (response == NULL) || (state == NULL)) {
551 DEBUG(0, ("talloc failed\n"));
552 TALLOC_FREE(mem_ctx);
553 continuation(private_data, False);
554 return WINBINDD_ERROR;
557 request->length = sizeof(*request);
559 state->mem_ctx = mem_ctx;
560 state->domain = domain;
561 state->request = request;
562 state->response = response;
563 state->continuation = continuation;
564 state->private_data = private_data;
566 if (IS_DC || domain->primary || domain->internal ) {
567 /* The primary domain has to find the DC name itself */
568 request->cmd = WINBINDD_INIT_CONNECTION;
569 fstrcpy(request->domain_name, domain->name);
570 request->data.init_conn.is_primary = domain->internal ? False : True;
571 fstrcpy(request->data.init_conn.dcname, "");
572 async_request(mem_ctx, &domain->child, request, response,
573 init_child_recv, state);
574 return WINBINDD_PENDING;
577 /* This is *not* the primary domain, let's ask our DC about a DC
580 request->cmd = WINBINDD_GETDCNAME;
581 fstrcpy(request->domain_name, domain->name);
583 request_domain = find_our_domain();
584 async_domain_request(mem_ctx, request_domain, request, response,
585 init_child_getdc_recv, state);
586 return WINBINDD_PENDING;
589 static void init_child_getdc_recv(void *private_data, bool success)
591 struct init_child_state *state =
592 talloc_get_type_abort(private_data, struct init_child_state);
593 const char *dcname = "";
595 DEBUG(10, ("Received getdcname response\n"));
597 if (success && (state->response->result == WINBINDD_OK)) {
598 dcname = state->response->data.dc_name;
601 state->request->cmd = WINBINDD_INIT_CONNECTION;
602 fstrcpy(state->request->domain_name, state->domain->name);
603 state->request->data.init_conn.is_primary = False;
604 fstrcpy(state->request->data.init_conn.dcname, dcname);
606 async_request(state->mem_ctx, &state->domain->child,
607 state->request, state->response,
608 init_child_recv, state);
611 static void init_child_recv(void *private_data, bool success)
613 struct init_child_state *state =
614 talloc_get_type_abort(private_data, struct init_child_state);
616 DEBUG(5, ("Received child initialization response for domain %s\n",
617 state->domain->name));
619 if ((!success) || (state->response->result != WINBINDD_OK)) {
620 DEBUG(3, ("Could not init child\n"));
621 state->continuation(state->private_data, False);
622 talloc_destroy(state->mem_ctx);
626 fstrcpy(state->domain->name,
627 state->response->data.domain_info.name);
628 fstrcpy(state->domain->alt_name,
629 state->response->data.domain_info.alt_name);
630 string_to_sid(&state->domain->sid,
631 state->response->data.domain_info.sid);
632 state->domain->native_mode =
633 state->response->data.domain_info.native_mode;
634 state->domain->active_directory =
635 state->response->data.domain_info.active_directory;
637 init_dc_connection(state->domain);
639 if (state->continuation != NULL)
640 state->continuation(state->private_data, True);
641 talloc_destroy(state->mem_ctx);
644 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
645 struct winbindd_cli_state *state)
647 /* Ensure null termination */
648 state->request.domain_name
649 [sizeof(state->request.domain_name)-1]='\0';
650 state->request.data.init_conn.dcname
651 [sizeof(state->request.data.init_conn.dcname)-1]='\0';
653 if (strlen(state->request.data.init_conn.dcname) > 0) {
654 fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
657 init_dc_connection(domain);
659 if (!domain->initialized) {
660 /* If we return error here we can't do any cached authentication,
661 but we may be in disconnected mode and can't initialize correctly.
662 Do what the previous code did and just return without initialization,
663 once we go online we'll re-initialize.
665 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
666 "online = %d\n", domain->name, (int)domain->online ));
669 fstrcpy(state->response.data.domain_info.name, domain->name);
670 fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
671 fstrcpy(state->response.data.domain_info.sid,
672 sid_string_static(&domain->sid));
674 state->response.data.domain_info.native_mode
675 = domain->native_mode;
676 state->response.data.domain_info.active_directory
677 = domain->active_directory;
678 state->response.data.domain_info.primary
684 /* Look up global info for the winbind daemon */
685 bool init_domain_list(void)
687 struct winbindd_domain *domain;
688 int role = lp_server_role();
690 /* Free existing list */
695 domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
696 &global_sid_Builtin);
698 setup_domain_child(domain,
704 domain = add_trusted_domain(get_global_sam_name(), NULL,
705 &passdb_methods, get_global_sam_sid());
707 if ( role != ROLE_DOMAIN_MEMBER ) {
708 domain->primary = True;
710 setup_domain_child(domain,
714 /* Add ourselves as the first entry. */
716 if ( role == ROLE_DOMAIN_MEMBER ) {
719 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
720 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
724 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
725 &cache_methods, &our_sid);
727 domain->primary = True;
728 setup_domain_child(domain,
731 /* Even in the parent winbindd we'll need to
732 talk to the DC, so try and see if we can
733 contact it. Theoretically this isn't neccessary
734 as the init_dc_connection() in init_child_recv()
735 will do this, but we can start detecting the DC
737 set_domain_online_request(domain);
744 void check_domain_trusted( const char *name, const DOM_SID *user_sid )
746 struct winbindd_domain *domain;
750 domain = find_domain_from_name_noinit( name );
754 sid_copy( &dom_sid, user_sid );
755 if ( !sid_split_rid( &dom_sid, &rid ) )
758 /* add the newly discovered trusted domain */
760 domain = add_trusted_domain( name, NULL, &cache_methods,
766 /* assume this is a trust from a one-way transitive
769 domain->active_directory = True;
770 domain->domain_flags = DS_DOMAIN_DIRECT_OUTBOUND;
771 domain->domain_type = DS_DOMAIN_TRUST_TYPE_UPLEVEL;
772 domain->internal = False;
773 domain->online = True;
775 setup_domain_child(domain,
778 wcache_tdc_add_domain( domain );
784 * Given a domain name, return the struct winbindd domain info for it
786 * @note Do *not* pass lp_workgroup() to this function. domain_list
787 * may modify it's value, and free that pointer. Instead, our local
788 * domain may be found by calling find_our_domain().
792 * @return The domain structure for the named domain, if it is working.
795 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
797 struct winbindd_domain *domain;
799 /* Search through list */
801 for (domain = domain_list(); domain != NULL; domain = domain->next) {
802 if (strequal(domain_name, domain->name) ||
803 (domain->alt_name[0] &&
804 strequal(domain_name, domain->alt_name))) {
814 struct winbindd_domain *find_domain_from_name(const char *domain_name)
816 struct winbindd_domain *domain;
818 domain = find_domain_from_name_noinit(domain_name);
823 if (!domain->initialized)
824 init_dc_connection(domain);
829 /* Given a domain sid, return the struct winbindd domain info for it */
831 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
833 struct winbindd_domain *domain;
835 /* Search through list */
837 for (domain = domain_list(); domain != NULL; domain = domain->next) {
838 if (sid_compare_domain(sid, &domain->sid) == 0)
847 /* Given a domain sid, return the struct winbindd domain info for it */
849 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
851 struct winbindd_domain *domain;
853 domain = find_domain_from_sid_noinit(sid);
858 if (!domain->initialized)
859 init_dc_connection(domain);
864 struct winbindd_domain *find_our_domain(void)
866 struct winbindd_domain *domain;
868 /* Search through list */
870 for (domain = domain_list(); domain != NULL; domain = domain->next) {
875 smb_panic("Could not find our domain");
879 struct winbindd_domain *find_root_domain(void)
881 struct winbindd_domain *ours = find_our_domain();
886 if ( strlen(ours->forest_name) == 0 )
889 return find_domain_from_name( ours->forest_name );
892 struct winbindd_domain *find_builtin_domain(void)
895 struct winbindd_domain *domain;
897 string_to_sid(&sid, "S-1-5-32");
898 domain = find_domain_from_sid(&sid);
900 if (domain == NULL) {
901 smb_panic("Could not find BUILTIN domain");
907 /* Find the appropriate domain to lookup a name or SID */
909 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
911 /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
913 if ( sid_check_is_in_unix_groups(sid) ||
914 sid_check_is_unix_groups(sid) ||
915 sid_check_is_in_unix_users(sid) ||
916 sid_check_is_unix_users(sid) )
918 return find_domain_from_sid(get_global_sam_sid());
921 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
922 * one to contact the external DC's. On member servers the internal
923 * domains are different: These are part of the local SAM. */
925 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n",
926 sid_string_static(sid)));
928 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
929 DEBUG(10, ("calling find_domain_from_sid\n"));
930 return find_domain_from_sid(sid);
933 /* On a member server a query for SID or name can always go to our
936 DEBUG(10, ("calling find_our_domain\n"));
937 return find_our_domain();
940 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
942 if ( strequal(domain_name, unix_users_domain_name() ) ||
943 strequal(domain_name, unix_groups_domain_name() ) )
945 return find_domain_from_name_noinit( get_global_sam_name() );
948 if (IS_DC || strequal(domain_name, "BUILTIN") ||
949 strequal(domain_name, get_global_sam_name()))
950 return find_domain_from_name_noinit(domain_name);
952 /* The "Unix User" and "Unix Group" domain our handled by passdb */
954 return find_our_domain();
957 /* Lookup a sid in a domain from a name */
959 bool winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
960 enum winbindd_cmd orig_cmd,
961 struct winbindd_domain *domain,
962 const char *domain_name,
963 const char *name, DOM_SID *sid,
964 enum lsa_SidType *type)
969 result = domain->methods->name_to_sid(domain, mem_ctx, orig_cmd,
970 domain_name, name, sid, type);
972 /* Return sid and type if lookup successful */
973 if (!NT_STATUS_IS_OK(result)) {
974 *type = SID_NAME_UNKNOWN;
977 return NT_STATUS_IS_OK(result);
981 * @brief Lookup a name in a domain from a sid.
983 * @param sid Security ID you want to look up.
984 * @param name On success, set to the name corresponding to @p sid.
985 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
986 * @param type On success, contains the type of name: alias, group or
988 * @retval True if the name exists, in which case @p name and @p type
989 * are set, otherwise False.
991 bool winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
992 struct winbindd_domain *domain,
996 enum lsa_SidType *type)
1005 result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
1007 /* Return name and type if successful */
1009 if (NT_STATUS_IS_OK(result)) {
1013 *type = SID_NAME_UNKNOWN;
1018 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
1020 void free_getent_state(struct getent_state *state)
1022 struct getent_state *temp;
1024 /* Iterate over state list */
1028 while(temp != NULL) {
1029 struct getent_state *next;
1031 /* Free sam entries then list entry */
1033 SAFE_FREE(state->sam_entries);
1034 DLIST_REMOVE(state, state);
1042 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1044 static bool assume_domain(const char *domain)
1046 /* never assume the domain on a standalone server */
1048 if ( lp_server_role() == ROLE_STANDALONE )
1051 /* domain member servers may possibly assume for the domain name */
1053 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1054 if ( !strequal(lp_workgroup(), domain) )
1057 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1061 /* only left with a domain controller */
1063 if ( strequal(get_global_sam_name(), domain) ) {
1070 /* Parse a string of the form DOMAIN\user into a domain and a user */
1072 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1074 char *p = strchr(domuser,*lp_winbind_separator());
1077 fstrcpy(user, domuser);
1079 if ( assume_domain(lp_workgroup())) {
1080 fstrcpy(domain, lp_workgroup());
1081 } else if ((p = strchr(domuser, '@')) != NULL) {
1082 fstrcpy(domain, "");
1088 fstrcpy(domain, domuser);
1089 domain[PTR_DIFF(p, domuser)] = 0;
1097 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1098 char **domain, char **user)
1100 fstring fstr_domain, fstr_user;
1101 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1104 *domain = talloc_strdup(mem_ctx, fstr_domain);
1105 *user = talloc_strdup(mem_ctx, fstr_user);
1106 return ((*domain != NULL) && (*user != NULL));
1109 /* Ensure an incoming username from NSS is fully qualified. Replace the
1110 incoming fstring with DOMAIN <separator> user. Returns the same
1111 values as parse_domain_user() but also replaces the incoming username.
1112 Used to ensure all names are fully qualified within winbindd.
1113 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1114 The protocol definitions of auth_crap, chng_pswd_auth_crap
1115 really should be changed to use this instead of doing things
1118 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1120 if (!parse_domain_user(username_inout, domain, user)) {
1123 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1124 domain, *lp_winbind_separator(),
1130 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1131 'winbind separator' options.
1133 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1136 If we are a PDC or BDC, and this is for our domain, do likewise.
1138 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
1139 username is then unqualified in unix
1141 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1143 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1147 fstrcpy(tmp_user, user);
1148 strlower_m(tmp_user);
1150 if (can_assume && assume_domain(domain)) {
1151 strlcpy(name, tmp_user, sizeof(fstring));
1153 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1154 domain, *lp_winbind_separator(),
1160 * Winbindd socket accessor functions
1163 const char *get_winbind_pipe_dir(void)
1165 return lp_parm_const_string(-1, "winbindd", "socket dir", WINBINDD_SOCKET_DIR);
1168 char *get_winbind_priv_pipe_dir(void)
1170 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
1173 /* Open the winbindd socket */
1175 static int _winbindd_socket = -1;
1176 static int _winbindd_priv_socket = -1;
1178 int open_winbindd_socket(void)
1180 if (_winbindd_socket == -1) {
1181 _winbindd_socket = create_pipe_sock(
1182 get_winbind_pipe_dir(), WINBINDD_SOCKET_NAME, 0755);
1183 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
1187 return _winbindd_socket;
1190 int open_winbindd_priv_socket(void)
1192 if (_winbindd_priv_socket == -1) {
1193 _winbindd_priv_socket = create_pipe_sock(
1194 get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
1195 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
1196 _winbindd_priv_socket));
1199 return _winbindd_priv_socket;
1202 /* Close the winbindd socket */
1204 void close_winbindd_socket(void)
1206 if (_winbindd_socket != -1) {
1207 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
1209 close(_winbindd_socket);
1210 _winbindd_socket = -1;
1212 if (_winbindd_priv_socket != -1) {
1213 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
1214 _winbindd_priv_socket));
1215 close(_winbindd_priv_socket);
1216 _winbindd_priv_socket = -1;
1221 * Client list accessor functions
1224 static struct winbindd_cli_state *_client_list;
1225 static int _num_clients;
1227 /* Return list of all connected clients */
1229 struct winbindd_cli_state *winbindd_client_list(void)
1231 return _client_list;
1234 /* Add a connection to the list */
1236 void winbindd_add_client(struct winbindd_cli_state *cli)
1238 DLIST_ADD(_client_list, cli);
1242 /* Remove a client from the list */
1244 void winbindd_remove_client(struct winbindd_cli_state *cli)
1246 DLIST_REMOVE(_client_list, cli);
1250 /* Close all open clients */
1252 void winbindd_kill_all_clients(void)
1254 struct winbindd_cli_state *cl = winbindd_client_list();
1256 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1259 struct winbindd_cli_state *next;
1262 winbindd_remove_client(cl);
1267 /* Return number of open clients */
1269 int winbindd_num_clients(void)
1271 return _num_clients;
1274 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1275 TALLOC_CTX *mem_ctx,
1276 const DOM_SID *user_sid,
1277 uint32 *p_num_groups, DOM_SID **user_sids)
1279 NET_USER_INFO_3 *info3 = NULL;
1280 NTSTATUS status = NT_STATUS_NO_MEMORY;
1282 size_t num_groups = 0;
1283 DOM_SID group_sid, primary_group;
1285 DEBUG(3,(": lookup_usergroups_cached\n"));
1291 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1293 if (info3 == NULL) {
1294 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1297 if (info3->num_groups == 0) {
1299 return NT_STATUS_UNSUCCESSFUL;
1302 /* always add the primary group to the sid array */
1303 sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
1305 if (!add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups)) {
1307 return NT_STATUS_NO_MEMORY;
1310 for (i=0; i<info3->num_groups; i++) {
1311 sid_copy(&group_sid, &info3->dom_sid.sid);
1312 sid_append_rid(&group_sid, info3->gids[i].g_rid);
1314 if (!add_sid_to_array(mem_ctx, &group_sid, user_sids,
1317 return NT_STATUS_NO_MEMORY;
1321 /* Add any Universal groups in the other_sids list */
1323 for (i=0; i<info3->num_other_sids; i++) {
1324 /* Skip Domain local groups outside our domain.
1325 We'll get these from the getsidaliases() RPC call. */
1326 if (info3->other_sids_attrib[i] & SE_GROUP_RESOURCE)
1329 if (!add_sid_to_array(mem_ctx, &info3->other_sids[i].sid,
1330 user_sids, &num_groups))
1333 return NT_STATUS_NO_MEMORY;
1339 *p_num_groups = num_groups;
1340 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1342 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1347 /*********************************************************************
1348 We use this to remove spaces from user and group names
1349 ********************************************************************/
1351 void ws_name_replace( char *name, char replace )
1353 char replace_char[2] = { 0x0, 0x0 };
1355 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1358 replace_char[0] = replace;
1359 all_string_sub( name, " ", replace_char, 0 );
1364 /*********************************************************************
1365 We use this to do the inverse of ws_name_replace()
1366 ********************************************************************/
1368 void ws_name_return( char *name, char replace )
1370 char replace_char[2] = { 0x0, 0x0 };
1372 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1375 replace_char[0] = replace;
1376 all_string_sub( name, replace_char, " ", 0 );
1381 /*********************************************************************
1382 ********************************************************************/
1384 bool winbindd_can_contact_domain( struct winbindd_domain *domain )
1386 /* We can contact the domain if it is our primary domain */
1388 if ( domain->primary )
1391 /* Can always contact a domain that is in out forest */
1393 if ( domain->domain_flags & DS_DOMAIN_IN_FOREST )
1396 /* We cannot contact the domain if it is running AD and
1397 we have no inbound trust */
1399 if ( domain->active_directory &&
1400 ((domain->domain_flags&DS_DOMAIN_DIRECT_INBOUND) != DS_DOMAIN_DIRECT_INBOUND) )
1405 /* Assume everything else is ok (probably not true but what
1411 /*********************************************************************
1412 ********************************************************************/
1414 bool winbindd_internal_child(struct winbindd_child *child)
1416 if ((child == idmap_child()) || (child == locator_child())) {
1423 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1425 /*********************************************************************
1426 ********************************************************************/
1428 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1431 char addr[INET6_ADDRSTRLEN];
1432 const char *kdc = NULL;
1435 if (!domain || !domain->alt_name || !*domain->alt_name) {
1439 if (domain->initialized && !domain->active_directory) {
1440 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1445 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1448 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1450 kdc = domain->dcname;
1453 if (!kdc || !*kdc) {
1454 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1459 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1460 domain->alt_name) == -1) {
1464 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1467 setenv(var, kdc, 1);
1471 /*********************************************************************
1472 ********************************************************************/
1474 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1476 struct winbindd_domain *our_dom = find_our_domain();
1478 winbindd_set_locator_kdc_env(domain);
1480 if (domain != our_dom) {
1481 winbindd_set_locator_kdc_env(our_dom);
1485 /*********************************************************************
1486 ********************************************************************/
1488 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1492 if (!domain || !domain->alt_name || !*domain->alt_name) {
1496 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1497 domain->alt_name) == -1) {
1506 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1511 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1516 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */