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