Make rescan_trusted_domains a timed event
[samba.git] / source3 / winbindd / winbindd_util.c
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
29 extern struct winbindd_methods cache_methods;
30 extern struct winbindd_methods builtin_passdb_methods;
31 extern 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
46 static struct winbindd_domain *_domain_list = NULL;
47
48 struct winbindd_domain *domain_list(void)
49 {
50         /* Initialise list */
51
52         if ((!_domain_list) && (!init_domain_list())) {
53                 smb_panic("Init_domain_list failed");
54         }
55
56         return _domain_list;
57 }
58
59 /* Free all entries in the trusted domain list */
60
61 void free_domain_list(void)
62 {
63         struct winbindd_domain *domain = _domain_list;
64
65         while(domain) {
66                 struct winbindd_domain *next = domain->next;
67
68                 DLIST_REMOVE(_domain_list, domain);
69                 SAFE_FREE(domain);
70                 domain = next;
71         }
72 }
73
74 static bool is_internal_domain(const DOM_SID *sid)
75 {
76         if (sid == NULL)
77                 return False;
78
79         if ( IS_DC )
80                 return sid_check_is_builtin(sid);
81
82         return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
83 }
84
85 static bool is_in_internal_domain(const DOM_SID *sid)
86 {
87         if (sid == NULL)
88                 return False;
89
90         if ( IS_DC )
91                 return sid_check_is_in_builtin(sid);
92
93         return (sid_check_is_in_our_domain(sid) || sid_check_is_in_builtin(sid));
94 }
95
96
97 /* Add a trusted domain to our list of domains */
98 static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
99                                                   struct winbindd_methods *methods,
100                                                   const DOM_SID *sid)
101 {
102         struct winbindd_domain *domain;
103         const char *alternative_name = NULL;
104         char *idmap_config_option;
105         const char *param;
106         const char **ignored_domains, **dom;
107
108         ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
109         for (dom=ignored_domains; dom && *dom; dom++) {
110                 if (gen_fnmatch(*dom, domain_name) == 0) {
111                         DEBUG(2,("Ignoring domain '%s'\n", domain_name));
112                         return NULL;
113                 }
114         }
115
116         /* ignore alt_name if we are not in an AD domain */
117
118         if ( (lp_security() == SEC_ADS) && alt_name && *alt_name) {
119                 alternative_name = alt_name;
120         }
121
122         /* We can't call domain_list() as this function is called from
123            init_domain_list() and we'll get stuck in a loop. */
124         for (domain = _domain_list; domain; domain = domain->next) {
125                 if (strequal(domain_name, domain->name) ||
126                     strequal(domain_name, domain->alt_name))
127                 {
128                         break;
129                 }
130
131                 if (alternative_name && *alternative_name)
132                 {
133                         if (strequal(alternative_name, domain->name) ||
134                             strequal(alternative_name, domain->alt_name))
135                         {
136                                 break;
137                         }
138                 }
139
140                 if (sid)
141                 {
142                         if (is_null_sid(sid)) {
143                                 continue;
144                         }
145
146                         if (sid_equal(sid, &domain->sid)) {
147                                 break;
148                         }
149                 }
150         }
151
152         /* See if we found a match.  Check if we need to update the
153            SID. */
154
155         if ( domain && sid) {
156                 if ( sid_equal( &domain->sid, &global_sid_NULL ) )
157                         sid_copy( &domain->sid, sid );
158
159                 return domain;
160         }
161
162         /* Create new domain entry */
163
164         if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
165                 return NULL;
166
167         /* Fill in fields */
168
169         ZERO_STRUCTP(domain);
170
171         fstrcpy(domain->name, domain_name);
172         if (alternative_name) {
173                 fstrcpy(domain->alt_name, alternative_name);
174         }
175
176         domain->methods = methods;
177         domain->backend = NULL;
178         domain->internal = is_internal_domain(sid);
179         domain->sequence_number = DOM_SEQUENCE_NONE;
180         domain->last_seq_check = 0;
181         domain->initialized = False;
182         domain->online = is_internal_domain(sid);
183         domain->check_online_timeout = 0;
184         domain->dc_probe_pid = (pid_t)-1;
185         if (sid) {
186                 sid_copy(&domain->sid, sid);
187         }
188
189         /* Link to domain list */
190         DLIST_ADD_END(_domain_list, domain, struct winbindd_domain *);
191
192         wcache_tdc_add_domain( domain );
193
194         idmap_config_option = talloc_asprintf(talloc_tos(), "idmap config %s",
195                                               domain->name);
196         if (idmap_config_option == NULL) {
197                 DEBUG(0, ("talloc failed, not looking for idmap config\n"));
198                 goto done;
199         }
200
201         param = lp_parm_const_string(-1, idmap_config_option, "range", NULL);
202
203         DEBUG(10, ("%s : range = %s\n", idmap_config_option,
204                    param ? param : "not defined"));
205
206         if (param != NULL) {
207                 unsigned low_id, high_id;
208                 if (sscanf(param, "%u - %u", &low_id, &high_id) != 2) {
209                         DEBUG(1, ("invalid range syntax in %s: %s\n",
210                                   idmap_config_option, param));
211                         goto done;
212                 }
213                 if (low_id > high_id) {
214                         DEBUG(1, ("invalid range in %s: %s\n",
215                                   idmap_config_option, param));
216                         goto done;
217                 }
218                 domain->have_idmap_config = true;
219                 domain->id_range_low = low_id;
220                 domain->id_range_high = high_id;
221         }
222
223 done:
224
225         DEBUG(2,("Added domain %s %s %s\n",
226                  domain->name, domain->alt_name,
227                  &domain->sid?sid_string_dbg(&domain->sid):""));
228
229         return domain;
230 }
231
232 /********************************************************************
233   rescan our domains looking for new trusted domains
234 ********************************************************************/
235
236 struct trustdom_state {
237         TALLOC_CTX *mem_ctx;
238         bool primary;
239         bool forest_root;
240         struct winbindd_response *response;
241 };
242
243 static void trustdom_recv(void *private_data, bool success);
244 static void rescan_forest_root_trusts( void );
245 static void rescan_forest_trusts( void );
246
247 static void add_trusted_domains( struct winbindd_domain *domain )
248 {
249         TALLOC_CTX *mem_ctx;
250         struct winbindd_request *request;
251         struct winbindd_response *response;
252         uint32 fr_flags = (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
253
254         struct trustdom_state *state;
255
256         mem_ctx = talloc_init("add_trusted_domains");
257         if (mem_ctx == NULL) {
258                 DEBUG(0, ("talloc_init failed\n"));
259                 return;
260         }
261
262         request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
263         response = TALLOC_P(mem_ctx, struct winbindd_response);
264         state = TALLOC_P(mem_ctx, struct trustdom_state);
265
266         if ((request == NULL) || (response == NULL) || (state == NULL)) {
267                 DEBUG(0, ("talloc failed\n"));
268                 talloc_destroy(mem_ctx);
269                 return;
270         }
271
272         state->mem_ctx = mem_ctx;
273         state->response = response;
274
275         /* Flags used to know how to continue the forest trust search */
276
277         state->primary = domain->primary;
278         state->forest_root = ((domain->domain_flags & fr_flags) == fr_flags );
279
280         request->length = sizeof(*request);
281         request->cmd = WINBINDD_LIST_TRUSTDOM;
282
283         async_domain_request(mem_ctx, domain, request, response,
284                              trustdom_recv, state);
285 }
286
287 static void trustdom_recv(void *private_data, bool success)
288 {
289         struct trustdom_state *state =
290                 talloc_get_type_abort(private_data, struct trustdom_state);
291         struct winbindd_response *response = state->response;
292         char *p;
293
294         if ((!success) || (response->result != WINBINDD_OK)) {
295                 DEBUG(1, ("Could not receive trustdoms\n"));
296                 talloc_destroy(state->mem_ctx);
297                 return;
298         }
299
300         p = (char *)response->extra_data.data;
301
302         while ((p != NULL) && (*p != '\0')) {
303                 char *q, *sidstr, *alt_name;
304                 DOM_SID sid;
305                 struct winbindd_domain *domain;
306                 char *alternate_name = NULL;
307
308                 alt_name = strchr(p, '\\');
309                 if (alt_name == NULL) {
310                         DEBUG(0, ("Got invalid trustdom response\n"));
311                         break;
312                 }
313
314                 *alt_name = '\0';
315                 alt_name += 1;
316
317                 sidstr = strchr(alt_name, '\\');
318                 if (sidstr == NULL) {
319                         DEBUG(0, ("Got invalid trustdom response\n"));
320                         break;
321                 }
322
323                 *sidstr = '\0';
324                 sidstr += 1;
325
326                 q = strchr(sidstr, '\n');
327                 if (q != NULL)
328                         *q = '\0';
329
330                 if (!string_to_sid(&sid, sidstr)) {
331                         /* Allow NULL sid for sibling domains */
332                         if ( strcmp(sidstr,"S-0-0") == 0) {
333                                 sid_copy( &sid, &global_sid_NULL);
334                         } else {
335                                 DEBUG(0, ("Got invalid trustdom response\n"));
336                                 break;
337                         }
338                 }
339
340                 /* use the real alt_name if we have one, else pass in NULL */
341
342                 if ( !strequal( alt_name, "(null)" ) )
343                         alternate_name = alt_name;
344
345                 /* If we have an existing domain structure, calling
346                    add_trusted_domain() will update the SID if
347                    necessary.  This is important because we need the
348                    SID for sibling domains */
349
350                 if ( find_domain_from_name_noinit(p) != NULL ) {
351                         domain = add_trusted_domain(p, alternate_name,
352                                                     &cache_methods,
353                                                     &sid);
354                 } else {
355                         domain = add_trusted_domain(p, alternate_name,
356                                                     &cache_methods,
357                                                     &sid);
358                         if (domain) {
359                                 setup_domain_child(domain,
360                                                    &domain->child);
361                         }
362                 }
363                 p=q;
364                 if (p != NULL)
365                         p += 1;
366         }
367
368         /*
369            Cases to consider when scanning trusts:
370            (a) we are calling from a child domain (primary && !forest_root)
371            (b) we are calling from the root of the forest (primary && forest_root)
372            (c) we are calling from a trusted forest domain (!primary
373                && !forest_root)
374         */
375
376         if ( state->primary ) {
377                 /* If this is our primary domain and we are not in the
378                    forest root, we have to scan the root trusts first */
379
380                 if ( !state->forest_root )
381                         rescan_forest_root_trusts();
382                 else
383                         rescan_forest_trusts();
384
385         } else if ( state->forest_root ) {
386                 /* Once we have done root forest trust search, we can
387                    go on to search the trusted forests */
388
389                 rescan_forest_trusts();
390         }
391
392         talloc_destroy(state->mem_ctx);
393
394         return;
395 }
396
397 /********************************************************************
398  Scan the trusts of our forest root
399 ********************************************************************/
400
401 static void rescan_forest_root_trusts( void )
402 {
403         struct winbindd_tdc_domain *dom_list = NULL;
404         size_t num_trusts = 0;
405         int i;
406
407         /* The only transitive trusts supported by Windows 2003 AD are
408            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
409            first two are handled in forest and listed by
410            DsEnumerateDomainTrusts().  Forest trusts are not so we
411            have to do that ourselves. */
412
413         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
414                 return;
415
416         for ( i=0; i<num_trusts; i++ ) {
417                 struct winbindd_domain *d = NULL;
418
419                 /* Find the forest root.  Don't necessarily trust
420                    the domain_list() as our primary domain may not
421                    have been initialized. */
422
423                 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
424                         continue;
425                 }
426
427                 /* Here's the forest root */
428
429                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
430
431                 if ( !d ) {
432                         d = add_trusted_domain( dom_list[i].domain_name,
433                                                 dom_list[i].dns_name,
434                                                 &cache_methods,
435                                                 &dom_list[i].sid );
436                 }
437
438                 if (d == NULL) {
439                         continue;
440                 }
441
442                 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
443                           "for domain tree root %s (%s)\n",
444                           d->name, d->alt_name ));
445
446                 d->domain_flags = dom_list[i].trust_flags;
447                 d->domain_type  = dom_list[i].trust_type;
448                 d->domain_trust_attribs = dom_list[i].trust_attribs;
449
450                 add_trusted_domains( d );
451
452                 break;
453         }
454
455         TALLOC_FREE( dom_list );
456
457         return;
458 }
459
460 /********************************************************************
461  scan the transitive forest trusts (not our own)
462 ********************************************************************/
463
464
465 static void rescan_forest_trusts( void )
466 {
467         struct winbindd_domain *d = NULL;
468         struct winbindd_tdc_domain *dom_list = NULL;
469         size_t num_trusts = 0;
470         int i;
471
472         /* The only transitive trusts supported by Windows 2003 AD are
473            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
474            first two are handled in forest and listed by
475            DsEnumerateDomainTrusts().  Forest trusts are not so we
476            have to do that ourselves. */
477
478         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
479                 return;
480
481         for ( i=0; i<num_trusts; i++ ) {
482                 uint32 flags   = dom_list[i].trust_flags;
483                 uint32 type    = dom_list[i].trust_type;
484                 uint32 attribs = dom_list[i].trust_attribs;
485
486                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
487
488                 /* ignore our primary and internal domains */
489
490                 if ( d && (d->internal || d->primary ) )
491                         continue;
492
493                 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
494                      (type == NETR_TRUST_TYPE_UPLEVEL) &&
495                      (attribs == NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
496                 {
497                         /* add the trusted domain if we don't know
498                            about it */
499
500                         if ( !d ) {
501                                 d = add_trusted_domain( dom_list[i].domain_name,
502                                                         dom_list[i].dns_name,
503                                                         &cache_methods,
504                                                         &dom_list[i].sid );
505                         }
506
507                         if (d == NULL) {
508                                 continue;
509                         }
510
511                         DEBUG(10,("Following trust path for domain %s (%s)\n",
512                                   d->name, d->alt_name ));
513                         add_trusted_domains( d );
514                 }
515         }
516
517         TALLOC_FREE( dom_list );
518
519         return;
520 }
521
522 /*********************************************************************
523  The process of updating the trusted domain list is a three step
524  async process:
525  (a) ask our domain
526  (b) ask the root domain in our forest
527  (c) ask the a DC in any Win2003 trusted forests
528 *********************************************************************/
529
530 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
531                             struct timeval now, void *private_data)
532 {
533         TALLOC_FREE(te);
534
535         /* I use to clear the cache here and start over but that
536            caused problems in child processes that needed the
537            trust dom list early on.  Removing it means we
538            could have some trusted domains listed that have been
539            removed from our primary domain's DC until a full
540            restart.  This should be ok since I think this is what
541            Windows does as well. */
542
543         /* this will only add new domains we didn't already know about
544            in the domain_list()*/
545
546         add_trusted_domains( find_our_domain() );
547
548         te = tevent_add_timer(
549                 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
550                 rescan_trusted_domains, NULL);
551         /*
552          * If te == NULL, there's not much we can do here. Don't fail, the
553          * only thing we miss is new trusted domains.
554          */
555
556         return;
557 }
558
559 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
560                                                    struct winbindd_cli_state *state)
561 {
562         /* Ensure null termination */
563         state->request->domain_name
564                 [sizeof(state->request->domain_name)-1]='\0';
565         state->request->data.init_conn.dcname
566                 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
567
568         if (strlen(state->request->data.init_conn.dcname) > 0) {
569                 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
570         }
571
572         init_dc_connection(domain);
573
574         if (!domain->initialized) {
575                 /* If we return error here we can't do any cached authentication,
576                    but we may be in disconnected mode and can't initialize correctly.
577                    Do what the previous code did and just return without initialization,
578                    once we go online we'll re-initialize.
579                 */
580                 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
581                         "online = %d\n", domain->name, (int)domain->online ));
582         }
583
584         fstrcpy(state->response.data.domain_info.name, domain->name);
585         fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
586         sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
587
588         state->response.data.domain_info.native_mode
589                 = domain->native_mode;
590         state->response.data.domain_info.active_directory
591                 = domain->active_directory;
592         state->response.data.domain_info.primary
593                 = domain->primary;
594
595         return WINBINDD_OK;
596 }
597
598 /* Look up global info for the winbind daemon */
599 bool init_domain_list(void)
600 {
601         struct winbindd_domain *domain;
602         int role = lp_server_role();
603
604         /* Free existing list */
605         free_domain_list();
606
607         /* BUILTIN domain */
608
609         domain = add_trusted_domain("BUILTIN", NULL, &builtin_passdb_methods,
610                                     &global_sid_Builtin);
611         if (domain) {
612                 setup_domain_child(domain,
613                                    &domain->child);
614         }
615
616         /* Local SAM */
617
618         domain = add_trusted_domain(get_global_sam_name(), NULL,
619                                     &sam_passdb_methods, get_global_sam_sid());
620         if (domain) {
621                 if ( role != ROLE_DOMAIN_MEMBER ) {
622                         domain->primary = True;
623                 }
624                 setup_domain_child(domain,
625                                    &domain->child);
626         }
627
628         /* Add ourselves as the first entry. */
629
630         if ( role == ROLE_DOMAIN_MEMBER ) {
631                 DOM_SID our_sid;
632
633                 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
634                         DEBUG(0, ("Could not fetch our SID - did we join?\n"));
635                         return False;
636                 }
637
638                 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
639                                              &cache_methods, &our_sid);
640                 if (domain) {
641                         domain->primary = True;
642                         setup_domain_child(domain,
643                                            &domain->child);
644
645                         /* Even in the parent winbindd we'll need to
646                            talk to the DC, so try and see if we can
647                            contact it. Theoretically this isn't neccessary
648                            as the init_dc_connection() in init_child_recv()
649                            will do this, but we can start detecting the DC
650                            early here. */
651                         set_domain_online_request(domain);
652                 }
653         }
654
655         return True;
656 }
657
658 void check_domain_trusted( const char *name, const DOM_SID *user_sid )
659 {
660         struct winbindd_domain *domain;
661         DOM_SID dom_sid;
662         uint32 rid;
663
664         /* Check if we even care */
665
666         if (!lp_allow_trusted_domains())
667                 return;
668
669         domain = find_domain_from_name_noinit( name );
670         if ( domain )
671                 return;
672
673         sid_copy( &dom_sid, user_sid );
674         if ( !sid_split_rid( &dom_sid, &rid ) )
675                 return;
676
677         /* add the newly discovered trusted domain */
678
679         domain = add_trusted_domain( name, NULL, &cache_methods,
680                                      &dom_sid);
681
682         if ( !domain )
683                 return;
684
685         /* assume this is a trust from a one-way transitive
686            forest trust */
687
688         domain->active_directory = True;
689         domain->domain_flags = NETR_TRUST_FLAG_OUTBOUND;
690         domain->domain_type  = NETR_TRUST_TYPE_UPLEVEL;
691         domain->internal = False;
692         domain->online = True;
693
694         setup_domain_child(domain,
695                            &domain->child);
696
697         wcache_tdc_add_domain( domain );
698
699         return;
700 }
701
702 /**
703  * Given a domain name, return the struct winbindd domain info for it
704  *
705  * @note Do *not* pass lp_workgroup() to this function.  domain_list
706  *       may modify it's value, and free that pointer.  Instead, our local
707  *       domain may be found by calling find_our_domain().
708  *       directly.
709  *
710  *
711  * @return The domain structure for the named domain, if it is working.
712  */
713
714 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
715 {
716         struct winbindd_domain *domain;
717
718         /* Search through list */
719
720         for (domain = domain_list(); domain != NULL; domain = domain->next) {
721                 if (strequal(domain_name, domain->name) ||
722                     (domain->alt_name[0] &&
723                      strequal(domain_name, domain->alt_name))) {
724                         return domain;
725                 }
726         }
727
728         /* Not found */
729
730         return NULL;
731 }
732
733 struct winbindd_domain *find_domain_from_name(const char *domain_name)
734 {
735         struct winbindd_domain *domain;
736
737         domain = find_domain_from_name_noinit(domain_name);
738
739         if (domain == NULL)
740                 return NULL;
741
742         if (!domain->initialized)
743                 init_dc_connection(domain);
744
745         return domain;
746 }
747
748 /* Given a domain sid, return the struct winbindd domain info for it */
749
750 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
751 {
752         struct winbindd_domain *domain;
753
754         /* Search through list */
755
756         for (domain = domain_list(); domain != NULL; domain = domain->next) {
757                 if (sid_compare_domain(sid, &domain->sid) == 0)
758                         return domain;
759         }
760
761         /* Not found */
762
763         return NULL;
764 }
765
766 /* Given a domain sid, return the struct winbindd domain info for it */
767
768 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
769 {
770         struct winbindd_domain *domain;
771
772         domain = find_domain_from_sid_noinit(sid);
773
774         if (domain == NULL)
775                 return NULL;
776
777         if (!domain->initialized)
778                 init_dc_connection(domain);
779
780         return domain;
781 }
782
783 struct winbindd_domain *find_our_domain(void)
784 {
785         struct winbindd_domain *domain;
786
787         /* Search through list */
788
789         for (domain = domain_list(); domain != NULL; domain = domain->next) {
790                 if (domain->primary)
791                         return domain;
792         }
793
794         smb_panic("Could not find our domain");
795         return NULL;
796 }
797
798 struct winbindd_domain *find_root_domain(void)
799 {
800         struct winbindd_domain *ours = find_our_domain();
801
802         if ( !ours )
803                 return NULL;
804
805         if ( strlen(ours->forest_name) == 0 )
806                 return NULL;
807
808         return find_domain_from_name( ours->forest_name );
809 }
810
811 struct winbindd_domain *find_builtin_domain(void)
812 {
813         DOM_SID sid;
814         struct winbindd_domain *domain;
815
816         string_to_sid(&sid, "S-1-5-32");
817         domain = find_domain_from_sid(&sid);
818
819         if (domain == NULL) {
820                 smb_panic("Could not find BUILTIN domain");
821         }
822
823         return domain;
824 }
825
826 /* Find the appropriate domain to lookup a name or SID */
827
828 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
829 {
830         /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
831
832         if ( sid_check_is_in_unix_groups(sid) ||
833              sid_check_is_unix_groups(sid) ||
834              sid_check_is_in_unix_users(sid) ||
835              sid_check_is_unix_users(sid) )
836         {
837                 return find_domain_from_sid(get_global_sam_sid());
838         }
839
840         /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
841          * one to contact the external DC's. On member servers the internal
842          * domains are different: These are part of the local SAM. */
843
844         DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid)));
845
846         if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
847                 DEBUG(10, ("calling find_domain_from_sid\n"));
848                 return find_domain_from_sid(sid);
849         }
850
851         /* On a member server a query for SID or name can always go to our
852          * primary DC. */
853
854         DEBUG(10, ("calling find_our_domain\n"));
855         return find_our_domain();
856 }
857
858 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
859 {
860         if ( strequal(domain_name, unix_users_domain_name() ) ||
861              strequal(domain_name, unix_groups_domain_name() ) )
862         {
863                 return find_domain_from_name_noinit( get_global_sam_name() );
864         }
865
866         if (IS_DC || strequal(domain_name, "BUILTIN") ||
867             strequal(domain_name, get_global_sam_name()))
868                 return find_domain_from_name_noinit(domain_name);
869
870         /* The "Unix User" and "Unix Group" domain our handled by passdb */
871
872         return find_our_domain();
873 }
874
875 /* Lookup a sid in a domain from a name */
876
877 bool winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
878                                  enum winbindd_cmd orig_cmd,
879                                  struct winbindd_domain *domain,
880                                  const char *domain_name,
881                                  const char *name, DOM_SID *sid,
882                                  enum lsa_SidType *type)
883 {
884         NTSTATUS result;
885
886         /* Lookup name */
887         result = domain->methods->name_to_sid(domain, mem_ctx, orig_cmd,
888                                               domain_name, name, sid, type);
889
890         /* Return sid and type if lookup successful */
891         if (!NT_STATUS_IS_OK(result)) {
892                 *type = SID_NAME_UNKNOWN;
893         }
894
895         return NT_STATUS_IS_OK(result);
896 }
897
898 /**
899  * @brief Lookup a name in a domain from a sid.
900  *
901  * @param sid Security ID you want to look up.
902  * @param name On success, set to the name corresponding to @p sid.
903  * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
904  * @param type On success, contains the type of name: alias, group or
905  * user.
906  * @retval True if the name exists, in which case @p name and @p type
907  * are set, otherwise False.
908  **/
909 bool winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
910                                  struct winbindd_domain *domain,
911                                  DOM_SID *sid,
912                                  char **dom_name,
913                                  char **name,
914                                  enum lsa_SidType *type)
915 {
916         NTSTATUS result;
917
918         *dom_name = NULL;
919         *name = NULL;
920
921         /* Lookup name */
922
923         result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
924
925         /* Return name and type if successful */
926
927         if (NT_STATUS_IS_OK(result)) {
928                 return True;
929         }
930
931         *type = SID_NAME_UNKNOWN;
932
933         return False;
934 }
935
936 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
937
938 void free_getent_state(struct getent_state *state)
939 {
940         struct getent_state *temp;
941
942         /* Iterate over state list */
943
944         temp = state;
945
946         while(temp != NULL) {
947                 struct getent_state *next = temp->next;
948
949                 /* Free sam entries then list entry */
950
951                 SAFE_FREE(state->sam_entries);
952                 DLIST_REMOVE(state, state);
953
954                 SAFE_FREE(temp);
955                 temp = next;
956         }
957 }
958
959 /* Is this a domain which we may assume no DOMAIN\ prefix? */
960
961 static bool assume_domain(const char *domain)
962 {
963         /* never assume the domain on a standalone server */
964
965         if ( lp_server_role() == ROLE_STANDALONE )
966                 return False;
967
968         /* domain member servers may possibly assume for the domain name */
969
970         if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
971                 if ( !strequal(lp_workgroup(), domain) )
972                         return False;
973
974                 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
975                         return True;
976         }
977
978         /* only left with a domain controller */
979
980         if ( strequal(get_global_sam_name(), domain) )  {
981                 return True;
982         }
983
984         return False;
985 }
986
987 /* Parse a string of the form DOMAIN\user into a domain and a user */
988
989 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
990 {
991         char *p = strchr(domuser,*lp_winbind_separator());
992
993         if ( !p ) {
994                 fstrcpy(user, domuser);
995
996                 if ( assume_domain(lp_workgroup())) {
997                         fstrcpy(domain, lp_workgroup());
998                 } else if ((p = strchr(domuser, '@')) != NULL) {
999                         fstrcpy(domain, "");
1000                 } else {
1001                         return False;
1002                 }
1003         } else {
1004                 fstrcpy(user, p+1);
1005                 fstrcpy(domain, domuser);
1006                 domain[PTR_DIFF(p, domuser)] = 0;
1007         }
1008
1009         strupper_m(domain);
1010
1011         return True;
1012 }
1013
1014 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1015                               char **domain, char **user)
1016 {
1017         fstring fstr_domain, fstr_user;
1018         if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1019                 return False;
1020         }
1021         *domain = talloc_strdup(mem_ctx, fstr_domain);
1022         *user = talloc_strdup(mem_ctx, fstr_user);
1023         return ((*domain != NULL) && (*user != NULL));
1024 }
1025
1026 /* add a domain user name to a buffer */
1027 void parse_add_domuser(void *buf, char *domuser, int *len)
1028 {
1029         fstring domain;
1030         char *p, *user;
1031
1032         user = domuser;
1033         p = strchr(domuser, *lp_winbind_separator());
1034
1035         if (p) {
1036
1037                 fstrcpy(domain, domuser);
1038                 domain[PTR_DIFF(p, domuser)] = 0;
1039                 p++;
1040
1041                 if (assume_domain(domain)) {
1042
1043                         user = p;
1044                         *len -= (PTR_DIFF(p, domuser));
1045                 }
1046         }
1047
1048         safe_strcpy((char *)buf, user, *len);
1049 }
1050
1051 /* Ensure an incoming username from NSS is fully qualified. Replace the
1052    incoming fstring with DOMAIN <separator> user. Returns the same
1053    values as parse_domain_user() but also replaces the incoming username.
1054    Used to ensure all names are fully qualified within winbindd.
1055    Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1056    The protocol definitions of auth_crap, chng_pswd_auth_crap
1057    really should be changed to use this instead of doing things
1058    by hand. JRA. */
1059
1060 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1061 {
1062         if (!parse_domain_user(username_inout, domain, user)) {
1063                 return False;
1064         }
1065         slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1066                  domain, *lp_winbind_separator(),
1067                  user);
1068         return True;
1069 }
1070
1071 /*
1072     Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1073     'winbind separator' options.
1074     This means:
1075         - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1076         lp_workgroup()
1077
1078     If we are a PDC or BDC, and this is for our domain, do likewise.
1079
1080     Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
1081     username is then unqualified in unix
1082
1083     We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1084 */
1085 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1086 {
1087         fstring tmp_user;
1088
1089         fstrcpy(tmp_user, user);
1090         strlower_m(tmp_user);
1091
1092         if (can_assume && assume_domain(domain)) {
1093                 strlcpy(name, tmp_user, sizeof(fstring));
1094         } else {
1095                 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1096                          domain, *lp_winbind_separator(),
1097                          tmp_user);
1098         }
1099 }
1100
1101 /**
1102  * talloc version of fill_domain_username()
1103  * return NULL on talloc failure.
1104  */
1105 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1106                                   const char *domain,
1107                                   const char *user,
1108                                   bool can_assume)
1109 {
1110         char *tmp_user, *name;
1111
1112         tmp_user = talloc_strdup(mem_ctx, user);
1113         strlower_m(tmp_user);
1114
1115         if (can_assume && assume_domain(domain)) {
1116                 name = tmp_user;
1117         } else {
1118                 name = talloc_asprintf(mem_ctx, "%s%c%s",
1119                                        domain,
1120                                        *lp_winbind_separator(),
1121                                        tmp_user);
1122                 TALLOC_FREE(tmp_user);
1123         }
1124
1125         return name;
1126 }
1127
1128 /*
1129  * Winbindd socket accessor functions
1130  */
1131
1132 const char *get_winbind_pipe_dir(void)
1133 {
1134         return lp_parm_const_string(-1, "winbindd", "socket dir", WINBINDD_SOCKET_DIR);
1135 }
1136
1137 char *get_winbind_priv_pipe_dir(void)
1138 {
1139         return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
1140 }
1141
1142 /* Open the winbindd socket */
1143
1144 static int _winbindd_socket = -1;
1145 static int _winbindd_priv_socket = -1;
1146
1147 int open_winbindd_socket(void)
1148 {
1149         if (_winbindd_socket == -1) {
1150                 _winbindd_socket = create_pipe_sock(
1151                         get_winbind_pipe_dir(), WINBINDD_SOCKET_NAME, 0755);
1152                 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
1153                            _winbindd_socket));
1154         }
1155
1156         return _winbindd_socket;
1157 }
1158
1159 int open_winbindd_priv_socket(void)
1160 {
1161         if (_winbindd_priv_socket == -1) {
1162                 _winbindd_priv_socket = create_pipe_sock(
1163                         get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
1164                 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
1165                            _winbindd_priv_socket));
1166         }
1167
1168         return _winbindd_priv_socket;
1169 }
1170
1171 /*
1172  * Client list accessor functions
1173  */
1174
1175 static struct winbindd_cli_state *_client_list;
1176 static int _num_clients;
1177
1178 /* Return list of all connected clients */
1179
1180 struct winbindd_cli_state *winbindd_client_list(void)
1181 {
1182         return _client_list;
1183 }
1184
1185 /* Add a connection to the list */
1186
1187 void winbindd_add_client(struct winbindd_cli_state *cli)
1188 {
1189         DLIST_ADD(_client_list, cli);
1190         _num_clients++;
1191 }
1192
1193 /* Remove a client from the list */
1194
1195 void winbindd_remove_client(struct winbindd_cli_state *cli)
1196 {
1197         DLIST_REMOVE(_client_list, cli);
1198         _num_clients--;
1199 }
1200
1201 /* Close all open clients */
1202
1203 void winbindd_kill_all_clients(void)
1204 {
1205         struct winbindd_cli_state *cl = winbindd_client_list();
1206
1207         DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1208
1209         while (cl) {
1210                 struct winbindd_cli_state *next;
1211
1212                 next = cl->next;
1213                 winbindd_remove_client(cl);
1214                 cl = next;
1215         }
1216 }
1217
1218 /* Return number of open clients */
1219
1220 int winbindd_num_clients(void)
1221 {
1222         return _num_clients;
1223 }
1224
1225 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1226                                   TALLOC_CTX *mem_ctx,
1227                                   const DOM_SID *user_sid,
1228                                   uint32 *p_num_groups, DOM_SID **user_sids)
1229 {
1230         struct netr_SamInfo3 *info3 = NULL;
1231         NTSTATUS status = NT_STATUS_NO_MEMORY;
1232         size_t num_groups = 0;
1233
1234         DEBUG(3,(": lookup_usergroups_cached\n"));
1235
1236         *user_sids = NULL;
1237         *p_num_groups = 0;
1238
1239         info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1240
1241         if (info3 == NULL) {
1242                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1243         }
1244
1245         if (info3->base.groups.count == 0) {
1246                 TALLOC_FREE(info3);
1247                 return NT_STATUS_UNSUCCESSFUL;
1248         }
1249
1250         /* Skip Domain local groups outside our domain.
1251            We'll get these from the getsidaliases() RPC call. */
1252         status = sid_array_from_info3(mem_ctx, info3,
1253                                       user_sids,
1254                                       &num_groups,
1255                                       false, true);
1256
1257         if (!NT_STATUS_IS_OK(status)) {
1258                 TALLOC_FREE(info3);
1259                 return status;
1260         }
1261
1262         TALLOC_FREE(info3);
1263         *p_num_groups = num_groups;
1264         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1265
1266         DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1267
1268         return status;
1269 }
1270
1271 /*********************************************************************
1272  We use this to remove spaces from user and group names
1273 ********************************************************************/
1274
1275 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1276                              struct winbindd_domain *domain,
1277                              char *name,
1278                              char **normalized)
1279 {
1280         NTSTATUS nt_status;
1281
1282         if (!name || !normalized) {
1283                 return NT_STATUS_INVALID_PARAMETER;
1284         }
1285
1286         if (!lp_winbind_normalize_names()) {
1287                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1288         }
1289
1290         /* Alias support and whitespace replacement are mutually
1291            exclusive */
1292
1293         nt_status = resolve_username_to_alias(mem_ctx, domain,
1294                                               name, normalized );
1295         if (NT_STATUS_IS_OK(nt_status)) {
1296                 /* special return code to let the caller know we
1297                    mapped to an alias */
1298                 return NT_STATUS_FILE_RENAMED;
1299         }
1300
1301         /* check for an unreachable domain */
1302
1303         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1304                 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1305                          domain->name));
1306                 set_domain_offline(domain);
1307                 return nt_status;
1308         }
1309
1310         /* deal with whitespace */
1311
1312         *normalized = talloc_strdup(mem_ctx, name);
1313         if (!(*normalized)) {
1314                 return NT_STATUS_NO_MEMORY;
1315         }
1316
1317         all_string_sub( *normalized, " ", "_", 0 );
1318
1319         return NT_STATUS_OK;
1320 }
1321
1322 /*********************************************************************
1323  We use this to do the inverse of normalize_name_map()
1324 ********************************************************************/
1325
1326 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1327                               char *name,
1328                               char **normalized)
1329 {
1330         NTSTATUS nt_status;
1331         struct winbindd_domain *domain = find_our_domain();
1332
1333         if (!name || !normalized) {
1334                 return NT_STATUS_INVALID_PARAMETER;
1335         }
1336
1337         if (!lp_winbind_normalize_names()) {
1338                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1339         }
1340
1341         /* Alias support and whitespace replacement are mutally
1342            exclusive */
1343
1344         /* When mapping from an alias to a username, we don't know the
1345            domain.  But we only need a domain structure to cache
1346            a successful lookup , so just our own domain structure for
1347            the seqnum. */
1348
1349         nt_status = resolve_alias_to_username(mem_ctx, domain,
1350                                               name, normalized);
1351         if (NT_STATUS_IS_OK(nt_status)) {
1352                 /* Special return code to let the caller know we mapped
1353                    from an alias */
1354                 return NT_STATUS_FILE_RENAMED;
1355         }
1356
1357         /* check for an unreachable domain */
1358
1359         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1360                 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1361                          domain->name));
1362                 set_domain_offline(domain);
1363                 return nt_status;
1364         }
1365
1366         /* deal with whitespace */
1367
1368         *normalized = talloc_strdup(mem_ctx, name);
1369         if (!(*normalized)) {
1370                 return NT_STATUS_NO_MEMORY;
1371         }
1372
1373         all_string_sub(*normalized, "_", " ", 0);
1374
1375         return NT_STATUS_OK;
1376 }
1377
1378 /*********************************************************************
1379  ********************************************************************/
1380
1381 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1382 {
1383         struct winbindd_tdc_domain *tdc = NULL;
1384         TALLOC_CTX *frame = talloc_stackframe();
1385         bool ret = false;
1386
1387         /* We can contact the domain if it is our primary domain */
1388
1389         if (domain->primary) {
1390                 return true;
1391         }
1392
1393         /* Trust the TDC cache and not the winbindd_domain flags */
1394
1395         if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1396                 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1397                           domain->name));
1398                 return false;
1399         }
1400
1401         /* Can always contact a domain that is in out forest */
1402
1403         if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1404                 ret = true;
1405                 goto done;
1406         }
1407
1408         /*
1409          * On a _member_ server, we cannot contact the domain if it
1410          * is running AD and we have no inbound trust.
1411          */
1412
1413         if (!IS_DC &&
1414              domain->active_directory &&
1415             ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1416         {
1417                 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1418                            "and we have no inbound trust.\n", domain->name));
1419                 goto done;
1420         }
1421
1422         /* Assume everything else is ok (probably not true but what
1423            can you do?) */
1424
1425         ret = true;
1426
1427 done:
1428         talloc_destroy(frame);
1429
1430         return ret;
1431 }
1432
1433 /*********************************************************************
1434  ********************************************************************/
1435
1436 bool winbindd_internal_child(struct winbindd_child *child)
1437 {
1438         if ((child == idmap_child()) || (child == locator_child())) {
1439                 return True;
1440         }
1441
1442         return False;
1443 }
1444
1445 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1446
1447 /*********************************************************************
1448  ********************************************************************/
1449
1450 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1451 {
1452         char *var = NULL;
1453         char addr[INET6_ADDRSTRLEN];
1454         const char *kdc = NULL;
1455         int lvl = 11;
1456
1457         if (!domain || !domain->alt_name || !*domain->alt_name) {
1458                 return;
1459         }
1460
1461         if (domain->initialized && !domain->active_directory) {
1462                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1463                         domain->alt_name));
1464                 return;
1465         }
1466
1467         print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1468         kdc = addr;
1469         if (!*kdc) {
1470                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1471                         domain->alt_name));
1472                 kdc = domain->dcname;
1473         }
1474
1475         if (!kdc || !*kdc) {
1476                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1477                         domain->alt_name));
1478                 return;
1479         }
1480
1481         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1482                                 domain->alt_name) == -1) {
1483                 return;
1484         }
1485
1486         DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1487                 var, kdc));
1488
1489         setenv(var, kdc, 1);
1490         free(var);
1491 }
1492
1493 /*********************************************************************
1494  ********************************************************************/
1495
1496 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1497 {
1498         struct winbindd_domain *our_dom = find_our_domain();
1499
1500         winbindd_set_locator_kdc_env(domain);
1501
1502         if (domain != our_dom) {
1503                 winbindd_set_locator_kdc_env(our_dom);
1504         }
1505 }
1506
1507 /*********************************************************************
1508  ********************************************************************/
1509
1510 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1511 {
1512         char *var = NULL;
1513
1514         if (!domain || !domain->alt_name || !*domain->alt_name) {
1515                 return;
1516         }
1517
1518         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1519                                 domain->alt_name) == -1) {
1520                 return;
1521         }
1522
1523         unsetenv(var);
1524         free(var);
1525 }
1526 #else
1527
1528 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1529 {
1530         return;
1531 }
1532
1533 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1534 {
1535         return;
1536 }
1537
1538 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1539
1540 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1541 {
1542         resp->data.auth.nt_status = NT_STATUS_V(result);
1543         fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1544
1545         /* we might have given a more useful error above */
1546         if (*resp->data.auth.error_string == '\0')
1547                 fstrcpy(resp->data.auth.error_string,
1548                         get_friendly_nt_error_msg(result));
1549         resp->data.auth.pam_error = nt_status_to_pam(result);
1550 }