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