s3:libsmbconf: use talloc_free instead of TALLOC_FREE in testsuite
[Samba.git] / source3 / winbindd / winbindd_util.c
blob748099a32e578d2b7e94605955d750dee9154b2d
1 /*
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/>.
23 #include "includes.h"
24 #include "winbindd.h"
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_WINBIND
29 extern struct winbindd_methods cache_methods;
30 extern struct winbindd_methods builtin_passdb_methods;
31 extern struct winbindd_methods sam_passdb_methods;
34 /**
35 * @file winbindd_util.c
37 * Winbind daemon for NT domain authentication nss module.
38 **/
41 /* The list of trusted domains. Note that the list can be deleted and
42 recreated using the init_domain_list() function so pointers to
43 individual winbindd_domain structures cannot be made. Keep a copy of
44 the domain name instead. */
46 static struct winbindd_domain *_domain_list = NULL;
48 /**
49 When was the last scan of trusted domains done?
51 0 == not ever
54 static time_t last_trustdom_scan;
56 struct winbindd_domain *domain_list(void)
58 /* Initialise list */
60 if ((!_domain_list) && (!init_domain_list())) {
61 smb_panic("Init_domain_list failed");
64 return _domain_list;
67 /* Free all entries in the trusted domain list */
69 void free_domain_list(void)
71 struct winbindd_domain *domain = _domain_list;
73 while(domain) {
74 struct winbindd_domain *next = domain->next;
76 DLIST_REMOVE(_domain_list, domain);
77 SAFE_FREE(domain);
78 domain = next;
82 static bool is_internal_domain(const DOM_SID *sid)
84 if (sid == NULL)
85 return False;
87 if ( IS_DC )
88 return sid_check_is_builtin(sid);
90 return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
93 static bool is_in_internal_domain(const DOM_SID *sid)
95 if (sid == NULL)
96 return False;
98 if ( IS_DC )
99 return sid_check_is_in_builtin(sid);
101 return (sid_check_is_in_our_domain(sid) || sid_check_is_in_builtin(sid));
105 /* Add a trusted domain to our list of domains */
106 static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
107 struct winbindd_methods *methods,
108 const DOM_SID *sid)
110 struct winbindd_domain *domain;
111 const char *alternative_name = NULL;
112 char *idmap_config_option;
113 const char *param;
114 const char **ignored_domains, **dom;
116 ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
117 for (dom=ignored_domains; dom && *dom; dom++) {
118 if (gen_fnmatch(*dom, domain_name) == 0) {
119 DEBUG(2,("Ignoring domain '%s'\n", domain_name));
120 return NULL;
124 /* ignore alt_name if we are not in an AD domain */
126 if ( (lp_security() == SEC_ADS) && alt_name && *alt_name) {
127 alternative_name = alt_name;
130 /* We can't call domain_list() as this function is called from
131 init_domain_list() and we'll get stuck in a loop. */
132 for (domain = _domain_list; domain; domain = domain->next) {
133 if (strequal(domain_name, domain->name) ||
134 strequal(domain_name, domain->alt_name))
136 break;
139 if (alternative_name && *alternative_name)
141 if (strequal(alternative_name, domain->name) ||
142 strequal(alternative_name, domain->alt_name))
144 break;
148 if (sid)
150 if (is_null_sid(sid)) {
151 continue;
154 if (sid_equal(sid, &domain->sid)) {
155 break;
160 /* See if we found a match. Check if we need to update the
161 SID. */
163 if ( domain && sid) {
164 if ( sid_equal( &domain->sid, &global_sid_NULL ) )
165 sid_copy( &domain->sid, sid );
167 return domain;
170 /* Create new domain entry */
172 if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
173 return NULL;
175 /* Fill in fields */
177 ZERO_STRUCTP(domain);
179 fstrcpy(domain->name, domain_name);
180 if (alternative_name) {
181 fstrcpy(domain->alt_name, alternative_name);
184 domain->methods = methods;
185 domain->backend = NULL;
186 domain->internal = is_internal_domain(sid);
187 domain->sequence_number = DOM_SEQUENCE_NONE;
188 domain->last_seq_check = 0;
189 domain->initialized = False;
190 domain->online = is_internal_domain(sid);
191 domain->check_online_timeout = 0;
192 domain->dc_probe_pid = (pid_t)-1;
193 if (sid) {
194 sid_copy(&domain->sid, sid);
197 /* Link to domain list */
198 DLIST_ADD_END(_domain_list, domain, struct winbindd_domain *);
200 wcache_tdc_add_domain( domain );
202 idmap_config_option = talloc_asprintf(talloc_tos(), "idmap config %s",
203 domain->name);
204 if (idmap_config_option == NULL) {
205 DEBUG(0, ("talloc failed, not looking for idmap config\n"));
206 goto done;
209 param = lp_parm_const_string(-1, idmap_config_option, "range", NULL);
211 DEBUG(10, ("%s : range = %s\n", idmap_config_option,
212 param ? param : "not defined"));
214 if (param != NULL) {
215 unsigned low_id, high_id;
216 if (sscanf(param, "%u - %u", &low_id, &high_id) != 2) {
217 DEBUG(1, ("invalid range syntax in %s: %s\n",
218 idmap_config_option, param));
219 goto done;
221 if (low_id > high_id) {
222 DEBUG(1, ("invalid range in %s: %s\n",
223 idmap_config_option, param));
224 goto done;
226 domain->have_idmap_config = true;
227 domain->id_range_low = low_id;
228 domain->id_range_high = high_id;
231 done:
233 DEBUG(2,("Added domain %s %s %s\n",
234 domain->name, domain->alt_name,
235 &domain->sid?sid_string_dbg(&domain->sid):""));
237 return domain;
240 /********************************************************************
241 rescan our domains looking for new trusted domains
242 ********************************************************************/
244 struct trustdom_state {
245 TALLOC_CTX *mem_ctx;
246 bool primary;
247 bool forest_root;
248 struct winbindd_response *response;
251 static void trustdom_recv(void *private_data, bool success);
252 static void rescan_forest_root_trusts( void );
253 static void rescan_forest_trusts( void );
255 static void add_trusted_domains( struct winbindd_domain *domain )
257 TALLOC_CTX *mem_ctx;
258 struct winbindd_request *request;
259 struct winbindd_response *response;
260 uint32 fr_flags = (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
262 struct trustdom_state *state;
264 mem_ctx = talloc_init("add_trusted_domains");
265 if (mem_ctx == NULL) {
266 DEBUG(0, ("talloc_init failed\n"));
267 return;
270 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
271 response = TALLOC_P(mem_ctx, struct winbindd_response);
272 state = TALLOC_P(mem_ctx, struct trustdom_state);
274 if ((request == NULL) || (response == NULL) || (state == NULL)) {
275 DEBUG(0, ("talloc failed\n"));
276 talloc_destroy(mem_ctx);
277 return;
280 state->mem_ctx = mem_ctx;
281 state->response = response;
283 /* Flags used to know how to continue the forest trust search */
285 state->primary = domain->primary;
286 state->forest_root = ((domain->domain_flags & fr_flags) == fr_flags );
288 request->length = sizeof(*request);
289 request->cmd = WINBINDD_LIST_TRUSTDOM;
291 async_domain_request(mem_ctx, domain, request, response,
292 trustdom_recv, state);
295 static void trustdom_recv(void *private_data, bool success)
297 struct trustdom_state *state =
298 talloc_get_type_abort(private_data, struct trustdom_state);
299 struct winbindd_response *response = state->response;
300 char *p;
302 if ((!success) || (response->result != WINBINDD_OK)) {
303 DEBUG(1, ("Could not receive trustdoms\n"));
304 talloc_destroy(state->mem_ctx);
305 return;
308 p = (char *)response->extra_data.data;
310 while ((p != NULL) && (*p != '\0')) {
311 char *q, *sidstr, *alt_name;
312 DOM_SID sid;
313 struct winbindd_domain *domain;
314 char *alternate_name = NULL;
316 alt_name = strchr(p, '\\');
317 if (alt_name == NULL) {
318 DEBUG(0, ("Got invalid trustdom response\n"));
319 break;
322 *alt_name = '\0';
323 alt_name += 1;
325 sidstr = strchr(alt_name, '\\');
326 if (sidstr == NULL) {
327 DEBUG(0, ("Got invalid trustdom response\n"));
328 break;
331 *sidstr = '\0';
332 sidstr += 1;
334 q = strchr(sidstr, '\n');
335 if (q != NULL)
336 *q = '\0';
338 if (!string_to_sid(&sid, sidstr)) {
339 /* Allow NULL sid for sibling domains */
340 if ( strcmp(sidstr,"S-0-0") == 0) {
341 sid_copy( &sid, &global_sid_NULL);
342 } else {
343 DEBUG(0, ("Got invalid trustdom response\n"));
344 break;
348 /* use the real alt_name if we have one, else pass in NULL */
350 if ( !strequal( alt_name, "(null)" ) )
351 alternate_name = alt_name;
353 /* If we have an existing domain structure, calling
354 add_trusted_domain() will update the SID if
355 necessary. This is important because we need the
356 SID for sibling domains */
358 if ( find_domain_from_name_noinit(p) != NULL ) {
359 domain = add_trusted_domain(p, alternate_name,
360 &cache_methods,
361 &sid);
362 } else {
363 domain = add_trusted_domain(p, alternate_name,
364 &cache_methods,
365 &sid);
366 if (domain) {
367 setup_domain_child(domain,
368 &domain->child);
371 p=q;
372 if (p != NULL)
373 p += 1;
376 SAFE_FREE(response->extra_data.data);
379 Cases to consider when scanning trusts:
380 (a) we are calling from a child domain (primary && !forest_root)
381 (b) we are calling from the root of the forest (primary && forest_root)
382 (c) we are calling from a trusted forest domain (!primary
383 && !forest_root)
386 if ( state->primary ) {
387 /* If this is our primary domain and we are not in the
388 forest root, we have to scan the root trusts first */
390 if ( !state->forest_root )
391 rescan_forest_root_trusts();
392 else
393 rescan_forest_trusts();
395 } else if ( state->forest_root ) {
396 /* Once we have done root forest trust search, we can
397 go on to search the trusted forests */
399 rescan_forest_trusts();
402 talloc_destroy(state->mem_ctx);
404 return;
407 /********************************************************************
408 Scan the trusts of our forest root
409 ********************************************************************/
411 static void rescan_forest_root_trusts( void )
413 struct winbindd_tdc_domain *dom_list = NULL;
414 size_t num_trusts = 0;
415 int i;
417 /* The only transitive trusts supported by Windows 2003 AD are
418 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
419 first two are handled in forest and listed by
420 DsEnumerateDomainTrusts(). Forest trusts are not so we
421 have to do that ourselves. */
423 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
424 return;
426 for ( i=0; i<num_trusts; i++ ) {
427 struct winbindd_domain *d = NULL;
429 /* Find the forest root. Don't necessarily trust
430 the domain_list() as our primary domain may not
431 have been initialized. */
433 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
434 continue;
437 /* Here's the forest root */
439 d = find_domain_from_name_noinit( dom_list[i].domain_name );
441 if ( !d ) {
442 d = add_trusted_domain( dom_list[i].domain_name,
443 dom_list[i].dns_name,
444 &cache_methods,
445 &dom_list[i].sid );
448 if (d == NULL) {
449 continue;
452 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
453 "for domain tree root %s (%s)\n",
454 d->name, d->alt_name ));
456 d->domain_flags = dom_list[i].trust_flags;
457 d->domain_type = dom_list[i].trust_type;
458 d->domain_trust_attribs = dom_list[i].trust_attribs;
460 add_trusted_domains( d );
462 break;
465 TALLOC_FREE( dom_list );
467 return;
470 /********************************************************************
471 scan the transitive forest trusts (not our own)
472 ********************************************************************/
475 static void rescan_forest_trusts( void )
477 struct winbindd_domain *d = NULL;
478 struct winbindd_tdc_domain *dom_list = NULL;
479 size_t num_trusts = 0;
480 int i;
482 /* The only transitive trusts supported by Windows 2003 AD are
483 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
484 first two are handled in forest and listed by
485 DsEnumerateDomainTrusts(). Forest trusts are not so we
486 have to do that ourselves. */
488 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
489 return;
491 for ( i=0; i<num_trusts; i++ ) {
492 uint32 flags = dom_list[i].trust_flags;
493 uint32 type = dom_list[i].trust_type;
494 uint32 attribs = dom_list[i].trust_attribs;
496 d = find_domain_from_name_noinit( dom_list[i].domain_name );
498 /* ignore our primary and internal domains */
500 if ( d && (d->internal || d->primary ) )
501 continue;
503 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
504 (type == NETR_TRUST_TYPE_UPLEVEL) &&
505 (attribs == NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
507 /* add the trusted domain if we don't know
508 about it */
510 if ( !d ) {
511 d = add_trusted_domain( dom_list[i].domain_name,
512 dom_list[i].dns_name,
513 &cache_methods,
514 &dom_list[i].sid );
517 if (d == NULL) {
518 continue;
521 DEBUG(10,("Following trust path for domain %s (%s)\n",
522 d->name, d->alt_name ));
523 add_trusted_domains( d );
527 TALLOC_FREE( dom_list );
529 return;
532 /*********************************************************************
533 The process of updating the trusted domain list is a three step
534 async process:
535 (a) ask our domain
536 (b) ask the root domain in our forest
537 (c) ask the a DC in any Win2003 trusted forests
538 *********************************************************************/
540 void rescan_trusted_domains( void )
542 time_t now = time(NULL);
544 /* Check that we allow trusted domains at all */
545 if (!lp_allow_trusted_domains())
546 return;
548 /* see if the time has come... */
550 if ((now >= last_trustdom_scan) &&
551 ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
552 return;
554 /* I use to clear the cache here and start over but that
555 caused problems in child processes that needed the
556 trust dom list early on. Removing it means we
557 could have some trusted domains listed that have been
558 removed from our primary domain's DC until a full
559 restart. This should be ok since I think this is what
560 Windows does as well. */
562 /* this will only add new domains we didn't already know about
563 in the domain_list()*/
565 add_trusted_domains( find_our_domain() );
567 last_trustdom_scan = now;
569 return;
572 struct init_child_state {
573 TALLOC_CTX *mem_ctx;
574 struct winbindd_domain *domain;
575 struct winbindd_request *request;
576 struct winbindd_response *response;
577 void (*continuation)(void *private_data, bool success);
578 void *private_data;
581 static void init_child_recv(void *private_data, bool success);
582 static void init_child_getdc_recv(void *private_data, bool success);
584 enum winbindd_result init_child_connection(struct winbindd_domain *domain,
585 void (*continuation)(void *private_data,
586 bool success),
587 void *private_data)
589 TALLOC_CTX *mem_ctx;
590 struct winbindd_request *request;
591 struct winbindd_response *response;
592 struct init_child_state *state;
593 struct winbindd_domain *request_domain;
595 mem_ctx = talloc_init("init_child_connection");
596 if (mem_ctx == NULL) {
597 DEBUG(0, ("talloc_init failed\n"));
598 return WINBINDD_ERROR;
601 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
602 response = TALLOC_P(mem_ctx, struct winbindd_response);
603 state = TALLOC_P(mem_ctx, struct init_child_state);
605 if ((request == NULL) || (response == NULL) || (state == NULL)) {
606 DEBUG(0, ("talloc failed\n"));
607 TALLOC_FREE(mem_ctx);
608 continuation(private_data, False);
609 return WINBINDD_ERROR;
612 request->length = sizeof(*request);
614 state->mem_ctx = mem_ctx;
615 state->domain = domain;
616 state->request = request;
617 state->response = response;
618 state->continuation = continuation;
619 state->private_data = private_data;
621 if (IS_DC || domain->primary || domain->internal ) {
622 /* The primary domain has to find the DC name itself */
623 request->cmd = WINBINDD_INIT_CONNECTION;
624 fstrcpy(request->domain_name, domain->name);
625 request->data.init_conn.is_primary = domain->primary ? true : false;
626 fstrcpy(request->data.init_conn.dcname, "");
627 async_request(mem_ctx, &domain->child, request, response,
628 init_child_recv, state);
629 return WINBINDD_PENDING;
632 /* This is *not* the primary domain, let's ask our DC about a DC
633 * name */
635 request->cmd = WINBINDD_GETDCNAME;
636 fstrcpy(request->domain_name, domain->name);
638 request_domain = find_our_domain();
639 async_domain_request(mem_ctx, request_domain, request, response,
640 init_child_getdc_recv, state);
641 return WINBINDD_PENDING;
644 static void init_child_getdc_recv(void *private_data, bool success)
646 struct init_child_state *state =
647 talloc_get_type_abort(private_data, struct init_child_state);
648 const char *dcname = "";
650 DEBUG(10, ("Received getdcname response\n"));
652 if (success && (state->response->result == WINBINDD_OK)) {
653 dcname = state->response->data.dc_name;
656 state->request->cmd = WINBINDD_INIT_CONNECTION;
657 fstrcpy(state->request->domain_name, state->domain->name);
658 state->request->data.init_conn.is_primary = False;
659 fstrcpy(state->request->data.init_conn.dcname, dcname);
661 async_request(state->mem_ctx, &state->domain->child,
662 state->request, state->response,
663 init_child_recv, state);
666 static void init_child_recv(void *private_data, bool success)
668 struct init_child_state *state =
669 talloc_get_type_abort(private_data, struct init_child_state);
671 DEBUG(5, ("Received child initialization response for domain %s\n",
672 state->domain->name));
674 if ((!success) || (state->response->result != WINBINDD_OK)) {
675 DEBUG(3, ("Could not init child\n"));
676 state->continuation(state->private_data, False);
677 talloc_destroy(state->mem_ctx);
678 return;
681 fstrcpy(state->domain->name,
682 state->response->data.domain_info.name);
683 fstrcpy(state->domain->alt_name,
684 state->response->data.domain_info.alt_name);
685 string_to_sid(&state->domain->sid,
686 state->response->data.domain_info.sid);
687 state->domain->native_mode =
688 state->response->data.domain_info.native_mode;
689 state->domain->active_directory =
690 state->response->data.domain_info.active_directory;
692 init_dc_connection(state->domain);
694 if (state->continuation != NULL)
695 state->continuation(state->private_data, True);
696 talloc_destroy(state->mem_ctx);
699 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
700 struct winbindd_cli_state *state)
702 /* Ensure null termination */
703 state->request.domain_name
704 [sizeof(state->request.domain_name)-1]='\0';
705 state->request.data.init_conn.dcname
706 [sizeof(state->request.data.init_conn.dcname)-1]='\0';
708 if (strlen(state->request.data.init_conn.dcname) > 0) {
709 fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
712 init_dc_connection(domain);
714 if (!domain->initialized) {
715 /* If we return error here we can't do any cached authentication,
716 but we may be in disconnected mode and can't initialize correctly.
717 Do what the previous code did and just return without initialization,
718 once we go online we'll re-initialize.
720 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
721 "online = %d\n", domain->name, (int)domain->online ));
724 fstrcpy(state->response.data.domain_info.name, domain->name);
725 fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
726 sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
728 state->response.data.domain_info.native_mode
729 = domain->native_mode;
730 state->response.data.domain_info.active_directory
731 = domain->active_directory;
732 state->response.data.domain_info.primary
733 = domain->primary;
735 return WINBINDD_OK;
738 /* Look up global info for the winbind daemon */
739 bool init_domain_list(void)
741 struct winbindd_domain *domain;
742 int role = lp_server_role();
744 /* Free existing list */
745 free_domain_list();
747 /* BUILTIN domain */
749 domain = add_trusted_domain("BUILTIN", NULL, &builtin_passdb_methods,
750 &global_sid_Builtin);
751 if (domain) {
752 setup_domain_child(domain,
753 &domain->child);
756 /* Local SAM */
758 domain = add_trusted_domain(get_global_sam_name(), NULL,
759 &sam_passdb_methods, get_global_sam_sid());
760 if (domain) {
761 if ( role != ROLE_DOMAIN_MEMBER ) {
762 domain->primary = True;
764 setup_domain_child(domain,
765 &domain->child);
768 /* Add ourselves as the first entry. */
770 if ( role == ROLE_DOMAIN_MEMBER ) {
771 DOM_SID our_sid;
773 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
774 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
775 return False;
778 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
779 &cache_methods, &our_sid);
780 if (domain) {
781 domain->primary = True;
782 setup_domain_child(domain,
783 &domain->child);
785 /* Even in the parent winbindd we'll need to
786 talk to the DC, so try and see if we can
787 contact it. Theoretically this isn't neccessary
788 as the init_dc_connection() in init_child_recv()
789 will do this, but we can start detecting the DC
790 early here. */
791 set_domain_online_request(domain);
795 return True;
798 void check_domain_trusted( const char *name, const DOM_SID *user_sid )
800 struct winbindd_domain *domain;
801 DOM_SID dom_sid;
802 uint32 rid;
804 /* Check if we even care */
806 if (!lp_allow_trusted_domains())
807 return;
809 domain = find_domain_from_name_noinit( name );
810 if ( domain )
811 return;
813 sid_copy( &dom_sid, user_sid );
814 if ( !sid_split_rid( &dom_sid, &rid ) )
815 return;
817 /* add the newly discovered trusted domain */
819 domain = add_trusted_domain( name, NULL, &cache_methods,
820 &dom_sid);
822 if ( !domain )
823 return;
825 /* assume this is a trust from a one-way transitive
826 forest trust */
828 domain->active_directory = True;
829 domain->domain_flags = NETR_TRUST_FLAG_OUTBOUND;
830 domain->domain_type = NETR_TRUST_TYPE_UPLEVEL;
831 domain->internal = False;
832 domain->online = True;
834 setup_domain_child(domain,
835 &domain->child);
837 wcache_tdc_add_domain( domain );
839 return;
842 /**
843 * Given a domain name, return the struct winbindd domain info for it
845 * @note Do *not* pass lp_workgroup() to this function. domain_list
846 * may modify it's value, and free that pointer. Instead, our local
847 * domain may be found by calling find_our_domain().
848 * directly.
851 * @return The domain structure for the named domain, if it is working.
854 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
856 struct winbindd_domain *domain;
858 /* Search through list */
860 for (domain = domain_list(); domain != NULL; domain = domain->next) {
861 if (strequal(domain_name, domain->name) ||
862 (domain->alt_name[0] &&
863 strequal(domain_name, domain->alt_name))) {
864 return domain;
868 /* Not found */
870 return NULL;
873 struct winbindd_domain *find_domain_from_name(const char *domain_name)
875 struct winbindd_domain *domain;
877 domain = find_domain_from_name_noinit(domain_name);
879 if (domain == NULL)
880 return NULL;
882 if (!domain->initialized)
883 init_dc_connection(domain);
885 return domain;
888 /* Given a domain sid, return the struct winbindd domain info for it */
890 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
892 struct winbindd_domain *domain;
894 /* Search through list */
896 for (domain = domain_list(); domain != NULL; domain = domain->next) {
897 if (sid_compare_domain(sid, &domain->sid) == 0)
898 return domain;
901 /* Not found */
903 return NULL;
906 /* Given a domain sid, return the struct winbindd domain info for it */
908 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
910 struct winbindd_domain *domain;
912 domain = find_domain_from_sid_noinit(sid);
914 if (domain == NULL)
915 return NULL;
917 if (!domain->initialized)
918 init_dc_connection(domain);
920 return domain;
923 struct winbindd_domain *find_our_domain(void)
925 struct winbindd_domain *domain;
927 /* Search through list */
929 for (domain = domain_list(); domain != NULL; domain = domain->next) {
930 if (domain->primary)
931 return domain;
934 smb_panic("Could not find our domain");
935 return NULL;
938 struct winbindd_domain *find_root_domain(void)
940 struct winbindd_domain *ours = find_our_domain();
942 if ( !ours )
943 return NULL;
945 if ( strlen(ours->forest_name) == 0 )
946 return NULL;
948 return find_domain_from_name( ours->forest_name );
951 struct winbindd_domain *find_builtin_domain(void)
953 DOM_SID sid;
954 struct winbindd_domain *domain;
956 string_to_sid(&sid, "S-1-5-32");
957 domain = find_domain_from_sid(&sid);
959 if (domain == NULL) {
960 smb_panic("Could not find BUILTIN domain");
963 return domain;
966 /* Find the appropriate domain to lookup a name or SID */
968 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
970 /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
972 if ( sid_check_is_in_unix_groups(sid) ||
973 sid_check_is_unix_groups(sid) ||
974 sid_check_is_in_unix_users(sid) ||
975 sid_check_is_unix_users(sid) )
977 return find_domain_from_sid(get_global_sam_sid());
980 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
981 * one to contact the external DC's. On member servers the internal
982 * domains are different: These are part of the local SAM. */
984 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid)));
986 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
987 DEBUG(10, ("calling find_domain_from_sid\n"));
988 return find_domain_from_sid(sid);
991 /* On a member server a query for SID or name can always go to our
992 * primary DC. */
994 DEBUG(10, ("calling find_our_domain\n"));
995 return find_our_domain();
998 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1000 if ( strequal(domain_name, unix_users_domain_name() ) ||
1001 strequal(domain_name, unix_groups_domain_name() ) )
1003 return find_domain_from_name_noinit( get_global_sam_name() );
1006 if (IS_DC || strequal(domain_name, "BUILTIN") ||
1007 strequal(domain_name, get_global_sam_name()))
1008 return find_domain_from_name_noinit(domain_name);
1010 /* The "Unix User" and "Unix Group" domain our handled by passdb */
1012 return find_our_domain();
1015 /* Lookup a sid in a domain from a name */
1017 bool winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
1018 enum winbindd_cmd orig_cmd,
1019 struct winbindd_domain *domain,
1020 const char *domain_name,
1021 const char *name, DOM_SID *sid,
1022 enum lsa_SidType *type)
1024 NTSTATUS result;
1026 /* Lookup name */
1027 result = domain->methods->name_to_sid(domain, mem_ctx, orig_cmd,
1028 domain_name, name, sid, type);
1030 /* Return sid and type if lookup successful */
1031 if (!NT_STATUS_IS_OK(result)) {
1032 *type = SID_NAME_UNKNOWN;
1035 return NT_STATUS_IS_OK(result);
1039 * @brief Lookup a name in a domain from a sid.
1041 * @param sid Security ID you want to look up.
1042 * @param name On success, set to the name corresponding to @p sid.
1043 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
1044 * @param type On success, contains the type of name: alias, group or
1045 * user.
1046 * @retval True if the name exists, in which case @p name and @p type
1047 * are set, otherwise False.
1049 bool winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
1050 struct winbindd_domain *domain,
1051 DOM_SID *sid,
1052 char **dom_name,
1053 char **name,
1054 enum lsa_SidType *type)
1056 NTSTATUS result;
1058 *dom_name = NULL;
1059 *name = NULL;
1061 /* Lookup name */
1063 result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
1065 /* Return name and type if successful */
1067 if (NT_STATUS_IS_OK(result)) {
1068 return True;
1071 *type = SID_NAME_UNKNOWN;
1073 return False;
1076 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
1078 void free_getent_state(struct getent_state *state)
1080 struct getent_state *temp;
1082 /* Iterate over state list */
1084 temp = state;
1086 while(temp != NULL) {
1087 struct getent_state *next = temp->next;
1089 /* Free sam entries then list entry */
1091 SAFE_FREE(state->sam_entries);
1092 DLIST_REMOVE(state, state);
1094 SAFE_FREE(temp);
1095 temp = next;
1099 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1101 static bool assume_domain(const char *domain)
1103 /* never assume the domain on a standalone server */
1105 if ( lp_server_role() == ROLE_STANDALONE )
1106 return False;
1108 /* domain member servers may possibly assume for the domain name */
1110 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1111 if ( !strequal(lp_workgroup(), domain) )
1112 return False;
1114 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1115 return True;
1118 /* only left with a domain controller */
1120 if ( strequal(get_global_sam_name(), domain) ) {
1121 return True;
1124 return False;
1127 /* Parse a string of the form DOMAIN\user into a domain and a user */
1129 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1131 char *p = strchr(domuser,*lp_winbind_separator());
1133 if ( !p ) {
1134 fstrcpy(user, domuser);
1136 if ( assume_domain(lp_workgroup())) {
1137 fstrcpy(domain, lp_workgroup());
1138 } else if ((p = strchr(domuser, '@')) != NULL) {
1139 fstrcpy(domain, "");
1140 } else {
1141 return False;
1143 } else {
1144 fstrcpy(user, p+1);
1145 fstrcpy(domain, domuser);
1146 domain[PTR_DIFF(p, domuser)] = 0;
1149 strupper_m(domain);
1151 return True;
1154 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1155 char **domain, char **user)
1157 fstring fstr_domain, fstr_user;
1158 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1159 return False;
1161 *domain = talloc_strdup(mem_ctx, fstr_domain);
1162 *user = talloc_strdup(mem_ctx, fstr_user);
1163 return ((*domain != NULL) && (*user != NULL));
1166 /* add a domain user name to a buffer */
1167 void parse_add_domuser(void *buf, char *domuser, int *len)
1169 fstring domain;
1170 char *p, *user;
1172 user = domuser;
1173 p = strchr(domuser, *lp_winbind_separator());
1175 if (p) {
1177 fstrcpy(domain, domuser);
1178 domain[PTR_DIFF(p, domuser)] = 0;
1179 p++;
1181 if (assume_domain(domain)) {
1183 user = p;
1184 *len -= (PTR_DIFF(p, domuser));
1188 safe_strcpy((char *)buf, user, *len);
1191 /* Ensure an incoming username from NSS is fully qualified. Replace the
1192 incoming fstring with DOMAIN <separator> user. Returns the same
1193 values as parse_domain_user() but also replaces the incoming username.
1194 Used to ensure all names are fully qualified within winbindd.
1195 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1196 The protocol definitions of auth_crap, chng_pswd_auth_crap
1197 really should be changed to use this instead of doing things
1198 by hand. JRA. */
1200 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1202 if (!parse_domain_user(username_inout, domain, user)) {
1203 return False;
1205 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1206 domain, *lp_winbind_separator(),
1207 user);
1208 return True;
1212 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1213 'winbind separator' options.
1214 This means:
1215 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1216 lp_workgroup()
1218 If we are a PDC or BDC, and this is for our domain, do likewise.
1220 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
1221 username is then unqualified in unix
1223 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1225 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1227 fstring tmp_user;
1229 fstrcpy(tmp_user, user);
1230 strlower_m(tmp_user);
1232 if (can_assume && assume_domain(domain)) {
1233 strlcpy(name, tmp_user, sizeof(fstring));
1234 } else {
1235 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1236 domain, *lp_winbind_separator(),
1237 tmp_user);
1242 * talloc version of fill_domain_username()
1243 * return NULL on talloc failure.
1245 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1246 const char *domain,
1247 const char *user,
1248 bool can_assume)
1250 char *tmp_user, *name;
1252 tmp_user = talloc_strdup(mem_ctx, user);
1253 strlower_m(tmp_user);
1255 if (can_assume && assume_domain(domain)) {
1256 name = tmp_user;
1257 } else {
1258 name = talloc_asprintf(mem_ctx, "%s%c%s",
1259 domain,
1260 *lp_winbind_separator(),
1261 tmp_user);
1262 TALLOC_FREE(tmp_user);
1265 return name;
1269 * Winbindd socket accessor functions
1272 const char *get_winbind_pipe_dir(void)
1274 return lp_parm_const_string(-1, "winbindd", "socket dir", WINBINDD_SOCKET_DIR);
1277 char *get_winbind_priv_pipe_dir(void)
1279 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
1282 /* Open the winbindd socket */
1284 static int _winbindd_socket = -1;
1285 static int _winbindd_priv_socket = -1;
1287 int open_winbindd_socket(void)
1289 if (_winbindd_socket == -1) {
1290 _winbindd_socket = create_pipe_sock(
1291 get_winbind_pipe_dir(), WINBINDD_SOCKET_NAME, 0755);
1292 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
1293 _winbindd_socket));
1296 return _winbindd_socket;
1299 int open_winbindd_priv_socket(void)
1301 if (_winbindd_priv_socket == -1) {
1302 _winbindd_priv_socket = create_pipe_sock(
1303 get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
1304 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
1305 _winbindd_priv_socket));
1308 return _winbindd_priv_socket;
1311 /* Close the winbindd socket */
1313 void close_winbindd_socket(void)
1315 if (_winbindd_socket != -1) {
1316 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
1317 _winbindd_socket));
1318 close(_winbindd_socket);
1319 _winbindd_socket = -1;
1321 if (_winbindd_priv_socket != -1) {
1322 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
1323 _winbindd_priv_socket));
1324 close(_winbindd_priv_socket);
1325 _winbindd_priv_socket = -1;
1330 * Client list accessor functions
1333 static struct winbindd_cli_state *_client_list;
1334 static int _num_clients;
1336 /* Return list of all connected clients */
1338 struct winbindd_cli_state *winbindd_client_list(void)
1340 return _client_list;
1343 /* Add a connection to the list */
1345 void winbindd_add_client(struct winbindd_cli_state *cli)
1347 DLIST_ADD(_client_list, cli);
1348 _num_clients++;
1351 /* Remove a client from the list */
1353 void winbindd_remove_client(struct winbindd_cli_state *cli)
1355 DLIST_REMOVE(_client_list, cli);
1356 _num_clients--;
1359 /* Close all open clients */
1361 void winbindd_kill_all_clients(void)
1363 struct winbindd_cli_state *cl = winbindd_client_list();
1365 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1367 while (cl) {
1368 struct winbindd_cli_state *next;
1370 next = cl->next;
1371 winbindd_remove_client(cl);
1372 cl = next;
1376 /* Return number of open clients */
1378 int winbindd_num_clients(void)
1380 return _num_clients;
1383 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1384 TALLOC_CTX *mem_ctx,
1385 const DOM_SID *user_sid,
1386 uint32 *p_num_groups, DOM_SID **user_sids)
1388 struct netr_SamInfo3 *info3 = NULL;
1389 NTSTATUS status = NT_STATUS_NO_MEMORY;
1390 size_t num_groups = 0;
1392 DEBUG(3,(": lookup_usergroups_cached\n"));
1394 *user_sids = NULL;
1395 *p_num_groups = 0;
1397 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1399 if (info3 == NULL) {
1400 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1403 if (info3->base.groups.count == 0) {
1404 TALLOC_FREE(info3);
1405 return NT_STATUS_UNSUCCESSFUL;
1408 /* Skip Domain local groups outside our domain.
1409 We'll get these from the getsidaliases() RPC call. */
1410 status = sid_array_from_info3(mem_ctx, info3,
1411 user_sids,
1412 &num_groups,
1413 false, true);
1415 if (!NT_STATUS_IS_OK(status)) {
1416 TALLOC_FREE(info3);
1417 return status;
1420 TALLOC_FREE(info3);
1421 *p_num_groups = num_groups;
1422 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1424 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1426 return status;
1429 /*********************************************************************
1430 We use this to remove spaces from user and group names
1431 ********************************************************************/
1433 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1434 struct winbindd_domain *domain,
1435 char *name,
1436 char **normalized)
1438 NTSTATUS nt_status;
1440 if (!name || !normalized) {
1441 return NT_STATUS_INVALID_PARAMETER;
1444 if (!lp_winbind_normalize_names()) {
1445 return NT_STATUS_PROCEDURE_NOT_FOUND;
1448 /* Alias support and whitespace replacement are mutually
1449 exclusive */
1451 nt_status = resolve_username_to_alias(mem_ctx, domain,
1452 name, normalized );
1453 if (NT_STATUS_IS_OK(nt_status)) {
1454 /* special return code to let the caller know we
1455 mapped to an alias */
1456 return NT_STATUS_FILE_RENAMED;
1459 /* check for an unreachable domain */
1461 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1462 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1463 domain->name));
1464 set_domain_offline(domain);
1465 return nt_status;
1468 /* deal with whitespace */
1470 *normalized = talloc_strdup(mem_ctx, name);
1471 if (!(*normalized)) {
1472 return NT_STATUS_NO_MEMORY;
1475 all_string_sub( *normalized, " ", "_", 0 );
1477 return NT_STATUS_OK;
1480 /*********************************************************************
1481 We use this to do the inverse of normalize_name_map()
1482 ********************************************************************/
1484 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1485 char *name,
1486 char **normalized)
1488 NTSTATUS nt_status;
1489 struct winbindd_domain *domain = find_our_domain();
1491 if (!name || !normalized) {
1492 return NT_STATUS_INVALID_PARAMETER;
1495 if (!lp_winbind_normalize_names()) {
1496 return NT_STATUS_PROCEDURE_NOT_FOUND;
1499 /* Alias support and whitespace replacement are mutally
1500 exclusive */
1502 /* When mapping from an alias to a username, we don't know the
1503 domain. But we only need a domain structure to cache
1504 a successful lookup , so just our own domain structure for
1505 the seqnum. */
1507 nt_status = resolve_alias_to_username(mem_ctx, domain,
1508 name, normalized);
1509 if (NT_STATUS_IS_OK(nt_status)) {
1510 /* Special return code to let the caller know we mapped
1511 from an alias */
1512 return NT_STATUS_FILE_RENAMED;
1515 /* check for an unreachable domain */
1517 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1518 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1519 domain->name));
1520 set_domain_offline(domain);
1521 return nt_status;
1524 /* deal with whitespace */
1526 *normalized = talloc_strdup(mem_ctx, name);
1527 if (!(*normalized)) {
1528 return NT_STATUS_NO_MEMORY;
1531 all_string_sub(*normalized, "_", " ", 0);
1533 return NT_STATUS_OK;
1536 /*********************************************************************
1537 ********************************************************************/
1539 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1541 struct winbindd_tdc_domain *tdc = NULL;
1542 TALLOC_CTX *frame = talloc_stackframe();
1543 bool ret = false;
1545 /* We can contact the domain if it is our primary domain */
1547 if (domain->primary) {
1548 return true;
1551 /* Trust the TDC cache and not the winbindd_domain flags */
1553 if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1554 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1555 domain->name));
1556 return false;
1559 /* Can always contact a domain that is in out forest */
1561 if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1562 ret = true;
1563 goto done;
1567 * On a _member_ server, we cannot contact the domain if it
1568 * is running AD and we have no inbound trust.
1571 if (!IS_DC &&
1572 domain->active_directory &&
1573 ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1575 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1576 "and we have no inbound trust.\n", domain->name));
1577 goto done;
1580 /* Assume everything else is ok (probably not true but what
1581 can you do?) */
1583 ret = true;
1585 done:
1586 talloc_destroy(frame);
1588 return ret;
1591 /*********************************************************************
1592 ********************************************************************/
1594 bool winbindd_internal_child(struct winbindd_child *child)
1596 if ((child == idmap_child()) || (child == locator_child())) {
1597 return True;
1600 return False;
1603 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1605 /*********************************************************************
1606 ********************************************************************/
1608 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1610 char *var = NULL;
1611 char addr[INET6_ADDRSTRLEN];
1612 const char *kdc = NULL;
1613 int lvl = 11;
1615 if (!domain || !domain->alt_name || !*domain->alt_name) {
1616 return;
1619 if (domain->initialized && !domain->active_directory) {
1620 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1621 domain->alt_name));
1622 return;
1625 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1626 kdc = addr;
1627 if (!*kdc) {
1628 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1629 domain->alt_name));
1630 kdc = domain->dcname;
1633 if (!kdc || !*kdc) {
1634 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1635 domain->alt_name));
1636 return;
1639 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1640 domain->alt_name) == -1) {
1641 return;
1644 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1645 var, kdc));
1647 setenv(var, kdc, 1);
1648 free(var);
1651 /*********************************************************************
1652 ********************************************************************/
1654 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1656 struct winbindd_domain *our_dom = find_our_domain();
1658 winbindd_set_locator_kdc_env(domain);
1660 if (domain != our_dom) {
1661 winbindd_set_locator_kdc_env(our_dom);
1665 /*********************************************************************
1666 ********************************************************************/
1668 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1670 char *var = NULL;
1672 if (!domain || !domain->alt_name || !*domain->alt_name) {
1673 return;
1676 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1677 domain->alt_name) == -1) {
1678 return;
1681 unsetenv(var);
1682 free(var);
1684 #else
1686 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1688 return;
1691 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1693 return;
1696 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1698 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1700 resp->data.auth.nt_status = NT_STATUS_V(result);
1701 fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1703 /* we might have given a more useful error above */
1704 if (*resp->data.auth.error_string == '\0')
1705 fstrcpy(resp->data.auth.error_string,
1706 get_friendly_nt_error_msg(result));
1707 resp->data.auth.pam_error = nt_status_to_pam(result);