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