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