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