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