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