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