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