source: branches/samba-3.3.x/source/winbindd/winbindd_util.c

Last change on this file was 309, checked in by Herwig Bauernfeind, 16 years ago

Update 3.3 to 3.3.7

File size: 43.7 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 Winbind daemon for ntdom nss module
5
6 Copyright (C) Tim Potter 2000-2001
7 Copyright (C) 2001 by Martin Pool <mbp@samba.org>
8
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.
13
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.
18
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/>.
21*/
22
23#include "includes.h"
24#include "winbindd.h"
25
26#undef DBGC_CLASS
27#define DBGC_CLASS DBGC_WINBIND
28
29extern struct winbindd_methods cache_methods;
30extern struct winbindd_methods builtin_passdb_methods;
31extern struct winbindd_methods sam_passdb_methods;
32
33
34/**
35 * @file winbindd_util.c
36 *
37 * Winbind daemon for NT domain authentication nss module.
38 **/
39
40
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. */
45
46static struct winbindd_domain *_domain_list = NULL;
47
48/**
49 When was the last scan of trusted domains done?
50
51 0 == not ever
52*/
53
54static time_t last_trustdom_scan;
55
56struct winbindd_domain *domain_list(void)
57{
58 /* Initialise list */
59
60 if ((!_domain_list) && (!init_domain_list())) {
61 smb_panic("Init_domain_list failed");
62 }
63
64 return _domain_list;
65}
66
67/* Free all entries in the trusted domain list */
68
69void free_domain_list(void)
70{
71 struct winbindd_domain *domain = _domain_list;
72
73 while(domain) {
74 struct winbindd_domain *next = domain->next;
75
76 DLIST_REMOVE(_domain_list, domain);
77 SAFE_FREE(domain);
78 domain = next;
79 }
80}
81
82static bool is_internal_domain(const DOM_SID *sid)
83{
84 if (sid == NULL)
85 return False;
86
87 if ( IS_DC )
88 return sid_check_is_builtin(sid);
89
90 return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
91}
92
93static bool is_in_internal_domain(const DOM_SID *sid)
94{
95 if (sid == NULL)
96 return False;
97
98 if ( IS_DC )
99 return sid_check_is_in_builtin(sid);
100
101 return (sid_check_is_in_our_domain(sid) || sid_check_is_in_builtin(sid));
102}
103
104
105/* Add a trusted domain to our list of domains */
106static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
107 struct winbindd_methods *methods,
108 const DOM_SID *sid)
109{
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;
115
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;
121 }
122 }
123
124 /* ignore alt_name if we are not in an AD domain */
125
126 if ( (lp_security() == SEC_ADS) && alt_name && *alt_name) {
127 alternative_name = alt_name;
128 }
129
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))
135 {
136 break;
137 }
138
139 if (alternative_name && *alternative_name)
140 {
141 if (strequal(alternative_name, domain->name) ||
142 strequal(alternative_name, domain->alt_name))
143 {
144 break;
145 }
146 }
147
148 if (sid)
149 {
150 if (is_null_sid(sid)) {
151 continue;
152 }
153
154 if (sid_equal(sid, &domain->sid)) {
155 break;
156 }
157 }
158 }
159
160 /* See if we found a match. Check if we need to update the
161 SID. */
162
163 if ( domain && sid) {
164 if ( sid_equal( &domain->sid, &global_sid_NULL ) )
165 sid_copy( &domain->sid, sid );
166
167 return domain;
168 }
169
170 /* Create new domain entry */
171
172 if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
173 return NULL;
174
175 /* Fill in fields */
176
177 ZERO_STRUCTP(domain);
178
179 fstrcpy(domain->name, domain_name);
180 if (alternative_name) {
181 fstrcpy(domain->alt_name, alternative_name);
182 }
183
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);
195 }
196
197 /* Link to domain list */
198 DLIST_ADD_END(_domain_list, domain, struct winbindd_domain *);
199
200 wcache_tdc_add_domain( domain );
201
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;
207 }
208
209 param = lp_parm_const_string(-1, idmap_config_option, "range", NULL);
210
211 DEBUG(10, ("%s : range = %s\n", idmap_config_option,
212 param ? param : "not defined"));
213
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;
220 }
221 if (low_id > high_id) {
222 DEBUG(1, ("invalid range in %s: %s\n",
223 idmap_config_option, param));
224 goto done;
225 }
226 domain->have_idmap_config = true;
227 domain->id_range_low = low_id;
228 domain->id_range_high = high_id;
229 }
230
231done:
232
233 DEBUG(2,("Added domain %s %s %s\n",
234 domain->name, domain->alt_name,
235 &domain->sid?sid_string_dbg(&domain->sid):""));
236
237 return domain;
238}
239
240/********************************************************************
241 rescan our domains looking for new trusted domains
242********************************************************************/
243
244struct trustdom_state {
245 TALLOC_CTX *mem_ctx;
246 bool primary;
247 bool forest_root;
248 struct winbindd_response *response;
249};
250
251static void trustdom_recv(void *private_data, bool success);
252static void rescan_forest_root_trusts( void );
253static void rescan_forest_trusts( void );
254
255static void add_trusted_domains( struct winbindd_domain *domain )
256{
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);
261
262 struct trustdom_state *state;
263
264 mem_ctx = talloc_init("add_trusted_domains");
265 if (mem_ctx == NULL) {
266 DEBUG(0, ("talloc_init failed\n"));
267 return;
268 }
269
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);
273
274 if ((request == NULL) || (response == NULL) || (state == NULL)) {
275 DEBUG(0, ("talloc failed\n"));
276 talloc_destroy(mem_ctx);
277 return;
278 }
279
280 state->mem_ctx = mem_ctx;
281 state->response = response;
282
283 /* Flags used to know how to continue the forest trust search */
284
285 state->primary = domain->primary;
286 state->forest_root = ((domain->domain_flags & fr_flags) == fr_flags );
287
288 request->length = sizeof(*request);
289 request->cmd = WINBINDD_LIST_TRUSTDOM;
290
291 async_domain_request(mem_ctx, domain, request, response,
292 trustdom_recv, state);
293}
294
295static void trustdom_recv(void *private_data, bool success)
296{
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;
301
302 if ((!success) || (response->result != WINBINDD_OK)) {
303 DEBUG(1, ("Could not receive trustdoms\n"));
304 talloc_destroy(state->mem_ctx);
305 return;
306 }
307
308 p = (char *)response->extra_data.data;
309
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;
315
316 alt_name = strchr(p, '\\');
317 if (alt_name == NULL) {
318 DEBUG(0, ("Got invalid trustdom response\n"));
319 break;
320 }
321
322 *alt_name = '\0';
323 alt_name += 1;
324
325 sidstr = strchr(alt_name, '\\');
326 if (sidstr == NULL) {
327 DEBUG(0, ("Got invalid trustdom response\n"));
328 break;
329 }
330
331 *sidstr = '\0';
332 sidstr += 1;
333
334 q = strchr(sidstr, '\n');
335 if (q != NULL)
336 *q = '\0';
337
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;
345 }
346 }
347
348 /* use the real alt_name if we have one, else pass in NULL */
349
350 if ( !strequal( alt_name, "(null)" ) )
351 alternate_name = alt_name;
352
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 */
357
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);
369 }
370 }
371 p=q;
372 if (p != NULL)
373 p += 1;
374 }
375
376 SAFE_FREE(response->extra_data.data);
377
378 /*
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)
384 */
385
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 */
389
390 if ( !state->forest_root )
391 rescan_forest_root_trusts();
392 else
393 rescan_forest_trusts();
394
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 */
398
399 rescan_forest_trusts();
400 }
401
402 talloc_destroy(state->mem_ctx);
403
404 return;
405}
406
407/********************************************************************
408 Scan the trusts of our forest root
409********************************************************************/
410
411static void rescan_forest_root_trusts( void )
412{
413 struct winbindd_tdc_domain *dom_list = NULL;
414 size_t num_trusts = 0;
415 int i;
416
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. */
422
423 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
424 return;
425
426 for ( i=0; i<num_trusts; i++ ) {
427 struct winbindd_domain *d = NULL;
428
429 /* Find the forest root. Don't necessarily trust
430 the domain_list() as our primary domain may not
431 have been initialized. */
432
433 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
434 continue;
435 }
436
437 /* Here's the forest root */
438
439 d = find_domain_from_name_noinit( dom_list[i].domain_name );
440
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 );
446 }
447
448 if (d == NULL) {
449 continue;
450 }
451
452 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
453 "for domain tree root %s (%s)\n",
454 d->name, d->alt_name ));
455
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;
459
460 add_trusted_domains( d );
461
462 break;
463 }
464
465 TALLOC_FREE( dom_list );
466
467 return;
468}
469
470/********************************************************************
471 scan the transitive forest trusts (not our own)
472********************************************************************/
473
474
475static void rescan_forest_trusts( void )
476{
477 struct winbindd_domain *d = NULL;
478 struct winbindd_tdc_domain *dom_list = NULL;
479 size_t num_trusts = 0;
480 int i;
481
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. */
487
488 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
489 return;
490
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;
495
496 d = find_domain_from_name_noinit( dom_list[i].domain_name );
497
498 /* ignore our primary and internal domains */
499
500 if ( d && (d->internal || d->primary ) )
501 continue;
502
503 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
504 (type == NETR_TRUST_TYPE_UPLEVEL) &&
505 (attribs == NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
506 {
507 /* add the trusted domain if we don't know
508 about it */
509
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 );
515 }
516
517 if (d == NULL) {
518 continue;
519 }
520
521 DEBUG(10,("Following trust path for domain %s (%s)\n",
522 d->name, d->alt_name ));
523 add_trusted_domains( d );
524 }
525 }
526
527 TALLOC_FREE( dom_list );
528
529 return;
530}
531
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*********************************************************************/
539
540void rescan_trusted_domains( void )
541{
542 time_t now = time(NULL);
543
544 /* Check that we allow trusted domains at all */
545 if (!lp_allow_trusted_domains())
546 return;
547
548 /* see if the time has come... */
549
550 if ((now >= last_trustdom_scan) &&
551 ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
552 return;
553
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. */
561
562 /* this will only add new domains we didn't already know about
563 in the domain_list()*/
564
565 add_trusted_domains( find_our_domain() );
566
567 last_trustdom_scan = now;
568
569 return;
570}
571
572struct 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;
579};
580
581static void init_child_recv(void *private_data, bool success);
582static void init_child_getdc_recv(void *private_data, bool success);
583
584enum winbindd_result init_child_connection(struct winbindd_domain *domain,
585 void (*continuation)(void *private_data,
586 bool success),
587 void *private_data)
588{
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;
594
595 mem_ctx = talloc_init("init_child_connection");
596 if (mem_ctx == NULL) {
597 DEBUG(0, ("talloc_init failed\n"));
598 return WINBINDD_ERROR;
599 }
600
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);
604
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;
610 }
611
612 request->length = sizeof(*request);
613
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;
620
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;
630 }
631
632 /* This is *not* the primary domain, let's ask our DC about a DC
633 * name */
634
635 request->cmd = WINBINDD_GETDCNAME;
636 fstrcpy(request->domain_name, domain->name);
637
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;
642}
643
644static void init_child_getdc_recv(void *private_data, bool success)
645{
646 struct init_child_state *state =
647 talloc_get_type_abort(private_data, struct init_child_state);
648 const char *dcname = "";
649
650 DEBUG(10, ("Received getdcname response\n"));
651
652 if (success && (state->response->result == WINBINDD_OK)) {
653 dcname = state->response->data.dc_name;
654 }
655
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);
660
661 async_request(state->mem_ctx, &state->domain->child,
662 state->request, state->response,
663 init_child_recv, state);
664}
665
666static void init_child_recv(void *private_data, bool success)
667{
668 struct init_child_state *state =
669 talloc_get_type_abort(private_data, struct init_child_state);
670
671 DEBUG(5, ("Received child initialization response for domain %s\n",
672 state->domain->name));
673
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;
679 }
680
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 if (!string_to_sid(&state->domain->sid,
686 state->response->data.domain_info.sid)) {
687 DEBUG(1,("init_child_recv: Could not convert sid %s "
688 "from string\n",
689 state->response->data.domain_info.sid));
690 state->continuation(state->private_data, False);
691 talloc_destroy(state->mem_ctx);
692 return;
693 }
694
695 state->domain->native_mode =
696 state->response->data.domain_info.native_mode;
697 state->domain->active_directory =
698 state->response->data.domain_info.active_directory;
699
700 init_dc_connection(state->domain);
701
702 if (state->continuation != NULL)
703 state->continuation(state->private_data, True);
704 talloc_destroy(state->mem_ctx);
705}
706
707enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
708 struct winbindd_cli_state *state)
709{
710 /* Ensure null termination */
711 state->request.domain_name
712 [sizeof(state->request.domain_name)-1]='\0';
713 state->request.data.init_conn.dcname
714 [sizeof(state->request.data.init_conn.dcname)-1]='\0';
715
716 if (strlen(state->request.data.init_conn.dcname) > 0) {
717 fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
718 }
719
720 init_dc_connection(domain);
721
722 if (!domain->initialized) {
723 /* If we return error here we can't do any cached authentication,
724 but we may be in disconnected mode and can't initialize correctly.
725 Do what the previous code did and just return without initialization,
726 once we go online we'll re-initialize.
727 */
728 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
729 "online = %d\n", domain->name, (int)domain->online ));
730 }
731
732 fstrcpy(state->response.data.domain_info.name, domain->name);
733 fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
734 sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
735
736 state->response.data.domain_info.native_mode
737 = domain->native_mode;
738 state->response.data.domain_info.active_directory
739 = domain->active_directory;
740 state->response.data.domain_info.primary
741 = domain->primary;
742
743 return WINBINDD_OK;
744}
745
746/* Look up global info for the winbind daemon */
747bool init_domain_list(void)
748{
749 struct winbindd_domain *domain;
750 int role = lp_server_role();
751
752 /* Free existing list */
753 free_domain_list();
754
755 /* BUILTIN domain */
756
757 domain = add_trusted_domain("BUILTIN", NULL, &builtin_passdb_methods,
758 &global_sid_Builtin);
759 if (domain) {
760 setup_domain_child(domain,
761 &domain->child);
762 }
763
764 /* Local SAM */
765
766 domain = add_trusted_domain(get_global_sam_name(), NULL,
767 &sam_passdb_methods, get_global_sam_sid());
768 if (domain) {
769 if ( role != ROLE_DOMAIN_MEMBER ) {
770 domain->primary = True;
771 }
772 setup_domain_child(domain,
773 &domain->child);
774 }
775
776 /* Add ourselves as the first entry. */
777
778 if ( role == ROLE_DOMAIN_MEMBER ) {
779 DOM_SID our_sid;
780
781 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
782 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
783 return False;
784 }
785
786 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
787 &cache_methods, &our_sid);
788 if (domain) {
789 domain->primary = True;
790 setup_domain_child(domain,
791 &domain->child);
792
793 /* Even in the parent winbindd we'll need to
794 talk to the DC, so try and see if we can
795 contact it. Theoretically this isn't neccessary
796 as the init_dc_connection() in init_child_recv()
797 will do this, but we can start detecting the DC
798 early here. */
799 set_domain_online_request(domain);
800 }
801 }
802
803 return True;
804}
805
806void check_domain_trusted( const char *name, const DOM_SID *user_sid )
807{
808 struct winbindd_domain *domain;
809 DOM_SID dom_sid;
810 uint32 rid;
811
812 /* Check if we even care */
813
814 if (!lp_allow_trusted_domains())
815 return;
816
817 domain = find_domain_from_name_noinit( name );
818 if ( domain )
819 return;
820
821 sid_copy( &dom_sid, user_sid );
822 if ( !sid_split_rid( &dom_sid, &rid ) )
823 return;
824
825 /* add the newly discovered trusted domain */
826
827 domain = add_trusted_domain( name, NULL, &cache_methods,
828 &dom_sid);
829
830 if ( !domain )
831 return;
832
833 /* assume this is a trust from a one-way transitive
834 forest trust */
835
836 domain->active_directory = True;
837 domain->domain_flags = NETR_TRUST_FLAG_OUTBOUND;
838 domain->domain_type = NETR_TRUST_TYPE_UPLEVEL;
839 domain->internal = False;
840 domain->online = True;
841
842 setup_domain_child(domain,
843 &domain->child);
844
845 wcache_tdc_add_domain( domain );
846
847 return;
848}
849
850/**
851 * Given a domain name, return the struct winbindd domain info for it
852 *
853 * @note Do *not* pass lp_workgroup() to this function. domain_list
854 * may modify it's value, and free that pointer. Instead, our local
855 * domain may be found by calling find_our_domain().
856 * directly.
857 *
858 *
859 * @return The domain structure for the named domain, if it is working.
860 */
861
862struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
863{
864 struct winbindd_domain *domain;
865
866 /* Search through list */
867
868 for (domain = domain_list(); domain != NULL; domain = domain->next) {
869 if (strequal(domain_name, domain->name) ||
870 (domain->alt_name[0] &&
871 strequal(domain_name, domain->alt_name))) {
872 return domain;
873 }
874 }
875
876 /* Not found */
877
878 return NULL;
879}
880
881struct winbindd_domain *find_domain_from_name(const char *domain_name)
882{
883 struct winbindd_domain *domain;
884
885 domain = find_domain_from_name_noinit(domain_name);
886
887 if (domain == NULL)
888 return NULL;
889
890 if (!domain->initialized)
891 init_dc_connection(domain);
892
893 return domain;
894}
895
896/* Given a domain sid, return the struct winbindd domain info for it */
897
898struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
899{
900 struct winbindd_domain *domain;
901
902 /* Search through list */
903
904 for (domain = domain_list(); domain != NULL; domain = domain->next) {
905 if (sid_compare_domain(sid, &domain->sid) == 0)
906 return domain;
907 }
908
909 /* Not found */
910
911 return NULL;
912}
913
914/* Given a domain sid, return the struct winbindd domain info for it */
915
916struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
917{
918 struct winbindd_domain *domain;
919
920 domain = find_domain_from_sid_noinit(sid);
921
922 if (domain == NULL)
923 return NULL;
924
925 if (!domain->initialized)
926 init_dc_connection(domain);
927
928 return domain;
929}
930
931struct winbindd_domain *find_our_domain(void)
932{
933 struct winbindd_domain *domain;
934
935 /* Search through list */
936
937 for (domain = domain_list(); domain != NULL; domain = domain->next) {
938 if (domain->primary)
939 return domain;
940 }
941
942 smb_panic("Could not find our domain");
943 return NULL;
944}
945
946struct winbindd_domain *find_root_domain(void)
947{
948 struct winbindd_domain *ours = find_our_domain();
949
950 if ( !ours )
951 return NULL;
952
953 if ( strlen(ours->forest_name) == 0 )
954 return NULL;
955
956 return find_domain_from_name( ours->forest_name );
957}
958
959struct winbindd_domain *find_builtin_domain(void)
960{
961 DOM_SID sid;
962 struct winbindd_domain *domain;
963
964 string_to_sid(&sid, "S-1-5-32");
965 domain = find_domain_from_sid(&sid);
966
967 if (domain == NULL) {
968 smb_panic("Could not find BUILTIN domain");
969 }
970
971 return domain;
972}
973
974/* Find the appropriate domain to lookup a name or SID */
975
976struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
977{
978 /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
979
980 if ( sid_check_is_in_unix_groups(sid) ||
981 sid_check_is_unix_groups(sid) ||
982 sid_check_is_in_unix_users(sid) ||
983 sid_check_is_unix_users(sid) )
984 {
985 return find_domain_from_sid(get_global_sam_sid());
986 }
987
988 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
989 * one to contact the external DC's. On member servers the internal
990 * domains are different: These are part of the local SAM. */
991
992 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid)));
993
994 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
995 DEBUG(10, ("calling find_domain_from_sid\n"));
996 return find_domain_from_sid(sid);
997 }
998
999 /* On a member server a query for SID or name can always go to our
1000 * primary DC. */
1001
1002 DEBUG(10, ("calling find_our_domain\n"));
1003 return find_our_domain();
1004}
1005
1006struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1007{
1008 if ( strequal(domain_name, unix_users_domain_name() ) ||
1009 strequal(domain_name, unix_groups_domain_name() ) )
1010 {
1011 return find_domain_from_name_noinit( get_global_sam_name() );
1012 }
1013
1014 if (IS_DC || strequal(domain_name, "BUILTIN") ||
1015 strequal(domain_name, get_global_sam_name()))
1016 return find_domain_from_name_noinit(domain_name);
1017
1018 /* The "Unix User" and "Unix Group" domain our handled by passdb */
1019
1020 return find_our_domain();
1021}
1022
1023/* Lookup a sid in a domain from a name */
1024
1025bool winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
1026 enum winbindd_cmd orig_cmd,
1027 struct winbindd_domain *domain,
1028 const char *domain_name,
1029 const char *name, DOM_SID *sid,
1030 enum lsa_SidType *type)
1031{
1032 NTSTATUS result;
1033
1034 /* Lookup name */
1035 result = domain->methods->name_to_sid(domain, mem_ctx, orig_cmd,
1036 domain_name, name, sid, type);
1037
1038 /* Return sid and type if lookup successful */
1039 if (!NT_STATUS_IS_OK(result)) {
1040 *type = SID_NAME_UNKNOWN;
1041 }
1042
1043 return NT_STATUS_IS_OK(result);
1044}
1045
1046/**
1047 * @brief Lookup a name in a domain from a sid.
1048 *
1049 * @param sid Security ID you want to look up.
1050 * @param name On success, set to the name corresponding to @p sid.
1051 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
1052 * @param type On success, contains the type of name: alias, group or
1053 * user.
1054 * @retval True if the name exists, in which case @p name and @p type
1055 * are set, otherwise False.
1056 **/
1057bool winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
1058 struct winbindd_domain *domain,
1059 DOM_SID *sid,
1060 char **dom_name,
1061 char **name,
1062 enum lsa_SidType *type)
1063{
1064 NTSTATUS result;
1065
1066 *dom_name = NULL;
1067 *name = NULL;
1068
1069 /* Lookup name */
1070
1071 result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
1072
1073 /* Return name and type if successful */
1074
1075 if (NT_STATUS_IS_OK(result)) {
1076 return True;
1077 }
1078
1079 *type = SID_NAME_UNKNOWN;
1080
1081 return False;
1082}
1083
1084/* Free state information held for {set,get,end}{pw,gr}ent() functions */
1085
1086void free_getent_state(struct getent_state *state)
1087{
1088 struct getent_state *temp;
1089
1090 /* Iterate over state list */
1091
1092 temp = state;
1093
1094 while(temp != NULL) {
1095 struct getent_state *next = temp->next;
1096
1097 /* Free sam entries then list entry */
1098
1099 SAFE_FREE(state->sam_entries);
1100 DLIST_REMOVE(state, state);
1101
1102 SAFE_FREE(temp);
1103 temp = next;
1104 }
1105}
1106
1107/* Is this a domain which we may assume no DOMAIN\ prefix? */
1108
1109static bool assume_domain(const char *domain)
1110{
1111 /* never assume the domain on a standalone server */
1112
1113 if ( lp_server_role() == ROLE_STANDALONE )
1114 return False;
1115
1116 /* domain member servers may possibly assume for the domain name */
1117
1118 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1119 if ( !strequal(lp_workgroup(), domain) )
1120 return False;
1121
1122 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1123 return True;
1124 }
1125
1126 /* only left with a domain controller */
1127
1128 if ( strequal(get_global_sam_name(), domain) ) {
1129 return True;
1130 }
1131
1132 return False;
1133}
1134
1135/* Parse a string of the form DOMAIN\user into a domain and a user */
1136
1137bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1138{
1139 char *p = strchr(domuser,*lp_winbind_separator());
1140
1141 if ( !p ) {
1142 fstrcpy(user, domuser);
1143
1144 if ( assume_domain(lp_workgroup())) {
1145 fstrcpy(domain, lp_workgroup());
1146 } else if ((p = strchr(domuser, '@')) != NULL) {
1147 fstrcpy(domain, p + 1);
1148 user[PTR_DIFF(p, domuser)] = 0;
1149 } else {
1150 return False;
1151 }
1152 } else {
1153 fstrcpy(user, p+1);
1154 fstrcpy(domain, domuser);
1155 domain[PTR_DIFF(p, domuser)] = 0;
1156 }
1157
1158 strupper_m(domain);
1159
1160 return True;
1161}
1162
1163bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1164 char **domain, char **user)
1165{
1166 fstring fstr_domain, fstr_user;
1167 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1168 return False;
1169 }
1170 *domain = talloc_strdup(mem_ctx, fstr_domain);
1171 *user = talloc_strdup(mem_ctx, fstr_user);
1172 return ((*domain != NULL) && (*user != NULL));
1173}
1174
1175/* add a domain user name to a buffer */
1176void parse_add_domuser(void *buf, char *domuser, int *len)
1177{
1178 fstring domain;
1179 char *p, *user;
1180
1181 user = domuser;
1182 p = strchr(domuser, *lp_winbind_separator());
1183
1184 if (p) {
1185
1186 fstrcpy(domain, domuser);
1187 domain[PTR_DIFF(p, domuser)] = 0;
1188 p++;
1189
1190 if (assume_domain(domain)) {
1191
1192 user = p;
1193 *len -= (PTR_DIFF(p, domuser));
1194 }
1195 }
1196
1197 safe_strcpy((char *)buf, user, *len);
1198}
1199
1200/* Ensure an incoming username from NSS is fully qualified. Replace the
1201 incoming fstring with DOMAIN <separator> user. Returns the same
1202 values as parse_domain_user() but also replaces the incoming username.
1203 Used to ensure all names are fully qualified within winbindd.
1204 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1205 The protocol definitions of auth_crap, chng_pswd_auth_crap
1206 really should be changed to use this instead of doing things
1207 by hand. JRA. */
1208
1209bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1210{
1211 if (!parse_domain_user(username_inout, domain, user)) {
1212 return False;
1213 }
1214 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1215 domain, *lp_winbind_separator(),
1216 user);
1217 return True;
1218}
1219
1220/*
1221 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1222 'winbind separator' options.
1223 This means:
1224 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1225 lp_workgroup()
1226
1227 If we are a PDC or BDC, and this is for our domain, do likewise.
1228
1229 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
1230 username is then unqualified in unix
1231
1232 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1233*/
1234void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1235{
1236 fstring tmp_user;
1237
1238 fstrcpy(tmp_user, user);
1239 strlower_m(tmp_user);
1240
1241 if (can_assume && assume_domain(domain)) {
1242 strlcpy(name, tmp_user, sizeof(fstring));
1243 } else {
1244 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1245 domain, *lp_winbind_separator(),
1246 tmp_user);
1247 }
1248}
1249
1250/**
1251 * talloc version of fill_domain_username()
1252 * return NULL on talloc failure.
1253 */
1254char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1255 const char *domain,
1256 const char *user,
1257 bool can_assume)
1258{
1259 char *tmp_user, *name;
1260
1261 tmp_user = talloc_strdup(mem_ctx, user);
1262 strlower_m(tmp_user);
1263
1264 if (can_assume && assume_domain(domain)) {
1265 name = tmp_user;
1266 } else {
1267 name = talloc_asprintf(mem_ctx, "%s%c%s",
1268 domain,
1269 *lp_winbind_separator(),
1270 tmp_user);
1271 TALLOC_FREE(tmp_user);
1272 }
1273
1274 return name;
1275}
1276
1277/*
1278 * Winbindd socket accessor functions
1279 */
1280
1281const char *get_winbind_pipe_dir(void)
1282{
1283 return lp_parm_const_string(-1, "winbindd", "socket dir", WINBINDD_SOCKET_DIR);
1284}
1285
1286char *get_winbind_priv_pipe_dir(void)
1287{
1288 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
1289}
1290
1291/* Open the winbindd socket */
1292
1293static int _winbindd_socket = -1;
1294static int _winbindd_priv_socket = -1;
1295
1296int open_winbindd_socket(void)
1297{
1298 if (_winbindd_socket == -1) {
1299 _winbindd_socket = create_pipe_sock(
1300 get_winbind_pipe_dir(), WINBINDD_SOCKET_NAME, 0755);
1301 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
1302 _winbindd_socket));
1303 }
1304
1305 return _winbindd_socket;
1306}
1307
1308int open_winbindd_priv_socket(void)
1309{
1310 if (_winbindd_priv_socket == -1) {
1311 _winbindd_priv_socket = create_pipe_sock(
1312 get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
1313 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
1314 _winbindd_priv_socket));
1315 }
1316
1317 return _winbindd_priv_socket;
1318}
1319
1320/* Close the winbindd socket */
1321
1322void close_winbindd_socket(void)
1323{
1324 if (_winbindd_socket != -1) {
1325 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
1326 _winbindd_socket));
1327 close(_winbindd_socket);
1328 _winbindd_socket = -1;
1329 }
1330 if (_winbindd_priv_socket != -1) {
1331 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
1332 _winbindd_priv_socket));
1333 close(_winbindd_priv_socket);
1334 _winbindd_priv_socket = -1;
1335 }
1336}
1337
1338/*
1339 * Client list accessor functions
1340 */
1341
1342static struct winbindd_cli_state *_client_list;
1343static int _num_clients;
1344
1345/* Return list of all connected clients */
1346
1347struct winbindd_cli_state *winbindd_client_list(void)
1348{
1349 return _client_list;
1350}
1351
1352/* Add a connection to the list */
1353
1354void winbindd_add_client(struct winbindd_cli_state *cli)
1355{
1356 DLIST_ADD(_client_list, cli);
1357 _num_clients++;
1358}
1359
1360/* Remove a client from the list */
1361
1362void winbindd_remove_client(struct winbindd_cli_state *cli)
1363{
1364 DLIST_REMOVE(_client_list, cli);
1365 _num_clients--;
1366}
1367
1368/* Close all open clients */
1369
1370void winbindd_kill_all_clients(void)
1371{
1372 struct winbindd_cli_state *cl = winbindd_client_list();
1373
1374 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1375
1376 while (cl) {
1377 struct winbindd_cli_state *next;
1378
1379 next = cl->next;
1380 winbindd_remove_client(cl);
1381 cl = next;
1382 }
1383}
1384
1385/* Return number of open clients */
1386
1387int winbindd_num_clients(void)
1388{
1389 return _num_clients;
1390}
1391
1392NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1393 TALLOC_CTX *mem_ctx,
1394 const DOM_SID *user_sid,
1395 uint32 *p_num_groups, DOM_SID **user_sids)
1396{
1397 struct netr_SamInfo3 *info3 = NULL;
1398 NTSTATUS status = NT_STATUS_NO_MEMORY;
1399 size_t num_groups = 0;
1400
1401 DEBUG(3,(": lookup_usergroups_cached\n"));
1402
1403 *user_sids = NULL;
1404 *p_num_groups = 0;
1405
1406 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1407
1408 if (info3 == NULL) {
1409 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1410 }
1411
1412 if (info3->base.groups.count == 0) {
1413 TALLOC_FREE(info3);
1414 return NT_STATUS_UNSUCCESSFUL;
1415 }
1416
1417 /* Skip Domain local groups outside our domain.
1418 We'll get these from the getsidaliases() RPC call. */
1419 status = sid_array_from_info3(mem_ctx, info3,
1420 user_sids,
1421 &num_groups,
1422 false, true);
1423
1424 if (!NT_STATUS_IS_OK(status)) {
1425 TALLOC_FREE(info3);
1426 return status;
1427 }
1428
1429 TALLOC_FREE(info3);
1430 *p_num_groups = num_groups;
1431 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1432
1433 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1434
1435 return status;
1436}
1437
1438/*********************************************************************
1439 We use this to remove spaces from user and group names
1440********************************************************************/
1441
1442NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1443 struct winbindd_domain *domain,
1444 char *name,
1445 char **normalized)
1446{
1447 NTSTATUS nt_status;
1448
1449 if (!name || !normalized) {
1450 return NT_STATUS_INVALID_PARAMETER;
1451 }
1452
1453 if (!lp_winbind_normalize_names()) {
1454 return NT_STATUS_PROCEDURE_NOT_FOUND;
1455 }
1456
1457 /* Alias support and whitespace replacement are mutually
1458 exclusive */
1459
1460 nt_status = resolve_username_to_alias(mem_ctx, domain,
1461 name, normalized );
1462 if (NT_STATUS_IS_OK(nt_status)) {
1463 /* special return code to let the caller know we
1464 mapped to an alias */
1465 return NT_STATUS_FILE_RENAMED;
1466 }
1467
1468 /* check for an unreachable domain */
1469
1470 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1471 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1472 domain->name));
1473 set_domain_offline(domain);
1474 return nt_status;
1475 }
1476
1477 /* deal with whitespace */
1478
1479 *normalized = talloc_strdup(mem_ctx, name);
1480 if (!(*normalized)) {
1481 return NT_STATUS_NO_MEMORY;
1482 }
1483
1484 all_string_sub( *normalized, " ", "_", 0 );
1485
1486 return NT_STATUS_OK;
1487}
1488
1489/*********************************************************************
1490 We use this to do the inverse of normalize_name_map()
1491********************************************************************/
1492
1493NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1494 char *name,
1495 char **normalized)
1496{
1497 NTSTATUS nt_status;
1498 struct winbindd_domain *domain = find_our_domain();
1499
1500 if (!name || !normalized) {
1501 return NT_STATUS_INVALID_PARAMETER;
1502 }
1503
1504 if (!lp_winbind_normalize_names()) {
1505 return NT_STATUS_PROCEDURE_NOT_FOUND;
1506 }
1507
1508 /* Alias support and whitespace replacement are mutally
1509 exclusive */
1510
1511 /* When mapping from an alias to a username, we don't know the
1512 domain. But we only need a domain structure to cache
1513 a successful lookup , so just our own domain structure for
1514 the seqnum. */
1515
1516 nt_status = resolve_alias_to_username(mem_ctx, domain,
1517 name, normalized);
1518 if (NT_STATUS_IS_OK(nt_status)) {
1519 /* Special return code to let the caller know we mapped
1520 from an alias */
1521 return NT_STATUS_FILE_RENAMED;
1522 }
1523
1524 /* check for an unreachable domain */
1525
1526 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1527 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1528 domain->name));
1529 set_domain_offline(domain);
1530 return nt_status;
1531 }
1532
1533 /* deal with whitespace */
1534
1535 *normalized = talloc_strdup(mem_ctx, name);
1536 if (!(*normalized)) {
1537 return NT_STATUS_NO_MEMORY;
1538 }
1539
1540 all_string_sub(*normalized, "_", " ", 0);
1541
1542 return NT_STATUS_OK;
1543}
1544
1545/*********************************************************************
1546 ********************************************************************/
1547
1548bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1549{
1550 struct winbindd_tdc_domain *tdc = NULL;
1551 TALLOC_CTX *frame = talloc_stackframe();
1552 bool ret = false;
1553
1554 /* We can contact the domain if it is our primary domain */
1555
1556 if (domain->primary) {
1557 return true;
1558 }
1559
1560 /* Trust the TDC cache and not the winbindd_domain flags */
1561
1562 if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1563 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1564 domain->name));
1565 return false;
1566 }
1567
1568 /* Can always contact a domain that is in out forest */
1569
1570 if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1571 ret = true;
1572 goto done;
1573 }
1574
1575 /*
1576 * On a _member_ server, we cannot contact the domain if it
1577 * is running AD and we have no inbound trust.
1578 */
1579
1580 if (!IS_DC &&
1581 domain->active_directory &&
1582 ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1583 {
1584 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1585 "and we have no inbound trust.\n", domain->name));
1586 goto done;
1587 }
1588
1589 /* Assume everything else is ok (probably not true but what
1590 can you do?) */
1591
1592 ret = true;
1593
1594done:
1595 talloc_destroy(frame);
1596
1597 return ret;
1598}
1599
1600/*********************************************************************
1601 ********************************************************************/
1602
1603bool winbindd_internal_child(struct winbindd_child *child)
1604{
1605 if ((child == idmap_child()) || (child == locator_child())) {
1606 return True;
1607 }
1608
1609 return False;
1610}
1611
1612#ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1613
1614/*********************************************************************
1615 ********************************************************************/
1616
1617static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1618{
1619 char *var = NULL;
1620 char addr[INET6_ADDRSTRLEN];
1621 const char *kdc = NULL;
1622 int lvl = 11;
1623
1624 if (!domain || !domain->alt_name || !*domain->alt_name) {
1625 return;
1626 }
1627
1628 if (domain->initialized && !domain->active_directory) {
1629 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1630 domain->alt_name));
1631 return;
1632 }
1633
1634 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1635 kdc = addr;
1636 if (!*kdc) {
1637 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1638 domain->alt_name));
1639 kdc = domain->dcname;
1640 }
1641
1642 if (!kdc || !*kdc) {
1643 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1644 domain->alt_name));
1645 return;
1646 }
1647
1648 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1649 domain->alt_name) == -1) {
1650 return;
1651 }
1652
1653 DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1654 var, kdc));
1655
1656 setenv(var, kdc, 1);
1657 free(var);
1658}
1659
1660/*********************************************************************
1661 ********************************************************************/
1662
1663void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1664{
1665 struct winbindd_domain *our_dom = find_our_domain();
1666
1667 winbindd_set_locator_kdc_env(domain);
1668
1669 if (domain != our_dom) {
1670 winbindd_set_locator_kdc_env(our_dom);
1671 }
1672}
1673
1674/*********************************************************************
1675 ********************************************************************/
1676
1677void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1678{
1679 char *var = NULL;
1680
1681 if (!domain || !domain->alt_name || !*domain->alt_name) {
1682 return;
1683 }
1684
1685 if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1686 domain->alt_name) == -1) {
1687 return;
1688 }
1689
1690 unsetenv(var);
1691 free(var);
1692}
1693#else
1694
1695void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1696{
1697 return;
1698}
1699
1700void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1701{
1702 return;
1703}
1704
1705#endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1706
1707void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1708{
1709 resp->data.auth.nt_status = NT_STATUS_V(result);
1710 fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1711
1712 /* we might have given a more useful error above */
1713 if (*resp->data.auth.error_string == '\0')
1714 fstrcpy(resp->data.auth.error_string,
1715 get_friendly_nt_error_msg(result));
1716 resp->data.auth.pam_error = nt_status_to_pam(result);
1717}
Note: See TracBrowser for help on using the repository browser.