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