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