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