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