winbindd: remember the secure_channel_type in winbindd_domain
[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 "lib/util_unixsids.h"
26 #include "secrets.h"
27 #include "../libcli/security/security.h"
28 #include "../libcli/auth/pam_errors.h"
29 #include "passdb/machine_sid.h"
30 #include "passdb.h"
31 #include "source4/lib/messaging/messaging.h"
32 #include "librpc/gen_ndr/ndr_lsa.h"
33 #include "auth/credentials/credentials.h"
34 #include "libsmb/samlogon_cache.h"
35
36 #undef DBGC_CLASS
37 #define DBGC_CLASS DBGC_WINBIND
38
39 /**
40  * @file winbindd_util.c
41  *
42  * Winbind daemon for NT domain authentication nss module.
43  **/
44
45
46 /* The list of trusted domains.  Note that the list can be deleted and
47    recreated using the init_domain_list() function so pointers to
48    individual winbindd_domain structures cannot be made.  Keep a copy of
49    the domain name instead. */
50
51 static struct winbindd_domain *_domain_list = NULL;
52
53 struct winbindd_domain *domain_list(void)
54 {
55         /* Initialise list */
56
57         if ((!_domain_list) && (!init_domain_list())) {
58                 smb_panic("Init_domain_list failed");
59         }
60
61         return _domain_list;
62 }
63
64 /* Free all entries in the trusted domain list */
65
66 static void free_domain_list(void)
67 {
68         struct winbindd_domain *domain = _domain_list;
69
70         while(domain) {
71                 struct winbindd_domain *next = domain->next;
72
73                 DLIST_REMOVE(_domain_list, domain);
74                 TALLOC_FREE(domain);
75                 domain = next;
76         }
77 }
78
79 /**
80  * Iterator for winbindd's domain list.
81  * To be used (e.g.) in tevent based loops.
82  */
83 struct winbindd_domain *wb_next_domain(struct winbindd_domain *domain)
84 {
85         if (domain == NULL) {
86                 domain = domain_list();
87         } else {
88                 domain = domain->next;
89         }
90
91         if ((domain != NULL) &&
92             (lp_server_role() != ROLE_ACTIVE_DIRECTORY_DC) &&
93             sid_check_is_our_sam(&domain->sid))
94         {
95                 domain = domain->next;
96         }
97
98         return domain;
99 }
100
101 static bool is_internal_domain(const struct dom_sid *sid)
102 {
103         if (sid == NULL)
104                 return False;
105
106         return (sid_check_is_our_sam(sid) || sid_check_is_builtin(sid));
107 }
108
109 static bool is_in_internal_domain(const struct dom_sid *sid)
110 {
111         if (sid == NULL)
112                 return False;
113
114         return (sid_check_is_in_our_sam(sid) || sid_check_is_in_builtin(sid));
115 }
116
117
118 /* Add a trusted domain to our list of domains.
119    If the domain already exists in the list,
120    return it and don't re-initialize.  */
121
122 static NTSTATUS add_trusted_domain(const char *domain_name,
123                                    const char *dns_name,
124                                    const struct dom_sid *sid,
125                                    uint32_t trust_type,
126                                    uint32_t trust_flags,
127                                    uint32_t trust_attribs,
128                                    enum netr_SchannelType secure_channel_type,
129                                    struct winbindd_domain **_d)
130 {
131         struct winbindd_domain *domain = NULL;
132         const char **ignored_domains = NULL;
133         const char **dom = NULL;
134         int role = lp_server_role();
135
136         if (is_null_sid(sid)) {
137                 DBG_ERR("Got null SID for domain [%s]\n", domain_name);
138                 return NT_STATUS_INVALID_PARAMETER;
139         }
140
141         ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
142         for (dom=ignored_domains; dom && *dom; dom++) {
143                 if (gen_fnmatch(*dom, domain_name) == 0) {
144                         DEBUG(2,("Ignoring domain '%s'\n", domain_name));
145                         return NT_STATUS_NO_SUCH_DOMAIN;
146                 }
147         }
148
149         /*
150          * We can't call domain_list() as this function is called from
151          * init_domain_list() and we'll get stuck in a loop.
152          */
153         for (domain = _domain_list; domain; domain = domain->next) {
154                 if (strequal(domain_name, domain->name)) {
155                         break;
156                 }
157         }
158
159         if (domain != NULL) {
160                 struct winbindd_domain *check_domain = NULL;
161
162                 for (check_domain = _domain_list;
163                      check_domain != NULL;
164                      check_domain = check_domain->next)
165                 {
166                         if (check_domain == domain) {
167                                 continue;
168                         }
169
170                         if (dom_sid_equal(&check_domain->sid, sid)) {
171                                 break;
172                         }
173                 }
174
175                 if (check_domain != NULL) {
176                         DBG_ERR("SID [%s] already used by domain [%s], "
177                                 "expected [%s]\n",
178                                 sid_string_dbg(sid), check_domain->name,
179                                 domain->name);
180                         return NT_STATUS_INVALID_PARAMETER;
181                 }
182         }
183
184         if ((domain != NULL) && (dns_name != NULL)) {
185                 struct winbindd_domain *check_domain = NULL;
186
187                 for (check_domain = _domain_list;
188                      check_domain != NULL;
189                      check_domain = check_domain->next)
190                 {
191                         if (check_domain == domain) {
192                                 continue;
193                         }
194
195                         if (strequal(check_domain->alt_name, dns_name)) {
196                                 break;
197                         }
198                 }
199
200                 if (check_domain != NULL) {
201                         DBG_ERR("DNS name [%s] used by domain [%s], "
202                                 "expected [%s]\n",
203                                 dns_name, check_domain->name,
204                                 domain->name);
205                         return NT_STATUS_INVALID_PARAMETER;
206                 }
207         }
208
209         if (domain != NULL) {
210                 *_d = domain;
211                 return NT_STATUS_OK;
212         }
213
214         /* Create new domain entry */
215         domain = talloc_zero(NULL, struct winbindd_domain);
216         if (domain == NULL) {
217                 return NT_STATUS_NO_MEMORY;
218         }
219
220         domain->children = talloc_zero_array(domain,
221                                              struct winbindd_child,
222                                              lp_winbind_max_domain_connections());
223         if (domain->children == NULL) {
224                 TALLOC_FREE(domain);
225                 return NT_STATUS_NO_MEMORY;
226         }
227
228         domain->name = talloc_strdup(domain, domain_name);
229         if (domain->name == NULL) {
230                 TALLOC_FREE(domain);
231                 return NT_STATUS_NO_MEMORY;
232         }
233
234         if (dns_name != NULL) {
235                 domain->alt_name = talloc_strdup(domain, dns_name);
236                 if (domain->alt_name == NULL) {
237                         TALLOC_FREE(domain);
238                         return NT_STATUS_NO_MEMORY;
239                 }
240         }
241
242         domain->backend = NULL;
243         domain->internal = is_internal_domain(sid);
244         domain->secure_channel_type = secure_channel_type;
245         domain->sequence_number = DOM_SEQUENCE_NONE;
246         domain->last_seq_check = 0;
247         domain->initialized = false;
248         domain->online = is_internal_domain(sid);
249         domain->check_online_timeout = 0;
250         domain->dc_probe_pid = (pid_t)-1;
251         domain->domain_flags = trust_flags;
252         domain->domain_type = trust_type;
253         domain->domain_trust_attribs = trust_attribs;
254         domain->secure_channel_type = secure_channel_type;
255         sid_copy(&domain->sid, sid);
256
257         /* Is this our primary domain ? */
258         if (role == ROLE_DOMAIN_MEMBER) {
259                 domain->primary = strequal(domain_name, lp_workgroup());
260         } else {
261                 domain->primary = strequal(domain_name, get_global_sam_name());
262         }
263
264         if (domain->primary) {
265                 if (role == ROLE_ACTIVE_DIRECTORY_DC) {
266                         domain->active_directory = true;
267                 }
268                 if (lp_security() == SEC_ADS) {
269                         domain->active_directory = true;
270                 }
271         } else if (!domain->internal) {
272                 if (domain->domain_type == LSA_TRUST_TYPE_UPLEVEL) {
273                         domain->active_directory = true;
274                 }
275         }
276
277         /* Link to domain list */
278         DLIST_ADD_END(_domain_list, domain);
279
280         wcache_tdc_add_domain( domain );
281
282         setup_domain_child(domain);
283
284         DBG_NOTICE("Added domain [%s] [%s] [%s]\n",
285                    domain->name, domain->alt_name,
286                    sid_string_dbg(&domain->sid));
287
288         *_d = domain;
289         return NT_STATUS_OK;
290 }
291
292 bool domain_is_forest_root(const struct winbindd_domain *domain)
293 {
294         const uint32_t fr_flags =
295                 (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
296
297         return ((domain->domain_flags & fr_flags) == fr_flags);
298 }
299
300 /********************************************************************
301   rescan our domains looking for new trusted domains
302 ********************************************************************/
303
304 struct trustdom_state {
305         struct winbindd_domain *domain;
306         struct winbindd_request request;
307 };
308
309 static void trustdom_list_done(struct tevent_req *req);
310 static void rescan_forest_root_trusts( void );
311 static void rescan_forest_trusts( void );
312
313 static void add_trusted_domains( struct winbindd_domain *domain )
314 {
315         struct trustdom_state *state;
316         struct tevent_req *req;
317
318         state = talloc_zero(NULL, struct trustdom_state);
319         if (state == NULL) {
320                 DEBUG(0, ("talloc failed\n"));
321                 return;
322         }
323         state->domain = domain;
324
325         state->request.length = sizeof(state->request);
326         state->request.cmd = WINBINDD_LIST_TRUSTDOM;
327
328         req = wb_domain_request_send(state, server_event_context(),
329                                      domain, &state->request);
330         if (req == NULL) {
331                 DEBUG(1, ("wb_domain_request_send failed\n"));
332                 TALLOC_FREE(state);
333                 return;
334         }
335         tevent_req_set_callback(req, trustdom_list_done, state);
336 }
337
338 static void trustdom_list_done(struct tevent_req *req)
339 {
340         struct trustdom_state *state = tevent_req_callback_data(
341                 req, struct trustdom_state);
342         struct winbindd_response *response;
343         int res, err;
344         char *p;
345         ptrdiff_t extra_len;
346         bool within_forest = false;
347         NTSTATUS status;
348
349         /*
350          * Only when we enumerate our primary domain
351          * or our forest root domain, we should keep
352          * the NETR_TRUST_FLAG_IN_FOREST flag, in
353          * all other cases we need to clear it as the domain
354          * is not part of our forest.
355          */
356         if (state->domain->primary) {
357                 within_forest = true;
358         } else if (domain_is_forest_root(state->domain)) {
359                 within_forest = true;
360         }
361
362         res = wb_domain_request_recv(req, state, &response, &err);
363         if ((res == -1) || (response->result != WINBINDD_OK)) {
364                 DBG_WARNING("Could not receive trusts for domain %s\n",
365                             state->domain->name);
366                 TALLOC_FREE(state);
367                 return;
368         }
369
370         if (response->length < sizeof(struct winbindd_response)) {
371                 DBG_ERR("ill-formed trustdom response - short length\n");
372                 TALLOC_FREE(state);
373                 return;
374         }
375
376         extra_len = response->length - sizeof(struct winbindd_response);
377
378         p = (char *)response->extra_data.data;
379
380         while ((p - (char *)response->extra_data.data) < extra_len) {
381                 struct winbindd_domain *domain = NULL;
382                 char *name, *q, *sidstr, *alt_name;
383                 struct dom_sid sid;
384                 uint32_t trust_type;
385                 uint32_t trust_attribs;
386                 uint32_t trust_flags;
387
388                 DBG_DEBUG("parsing response line '%s'\n", p);
389
390                 name = p;
391
392                 alt_name = strchr(p, '\\');
393                 if (alt_name == NULL) {
394                         DBG_ERR("Got invalid trustdom response\n");
395                         break;
396                 }
397
398                 *alt_name = '\0';
399                 alt_name += 1;
400
401                 sidstr = strchr(alt_name, '\\');
402                 if (sidstr == NULL) {
403                         DBG_ERR("Got invalid trustdom response\n");
404                         break;
405                 }
406
407                 *sidstr = '\0';
408                 sidstr += 1;
409
410                 /* use the real alt_name if we have one, else pass in NULL */
411                 if (strequal(alt_name, "(null)")) {
412                         alt_name = NULL;
413                 }
414
415                 q = strtok(sidstr, "\\");
416                 if (q == NULL) {
417                         DBG_ERR("Got invalid trustdom response\n");
418                         break;
419                 }
420
421                 if (!string_to_sid(&sid, sidstr)) {
422                         DEBUG(0, ("Got invalid trustdom response\n"));
423                         break;
424                 }
425
426                 q = strtok(NULL, "\\");
427                 if (q == NULL) {
428                         DBG_ERR("Got invalid trustdom response\n");
429                         break;
430                 }
431
432                 trust_flags = (uint32_t)strtoul(q, NULL, 10);
433
434                 q = strtok(NULL, "\\");
435                 if (q == NULL) {
436                         DBG_ERR("Got invalid trustdom response\n");
437                         break;
438                 }
439
440                 trust_type = (uint32_t)strtoul(q, NULL, 10);
441
442                 q = strtok(NULL, "\n");
443                 if (q == NULL) {
444                         DBG_ERR("Got invalid trustdom response\n");
445                         break;
446                 }
447
448                 trust_attribs = (uint32_t)strtoul(q, NULL, 10);
449
450                 if (!within_forest) {
451                         trust_flags &= ~NETR_TRUST_FLAG_IN_FOREST;
452                 }
453
454                 if (!state->domain->primary) {
455                         trust_flags &= ~NETR_TRUST_FLAG_PRIMARY;
456                 }
457
458                 /*
459                  * We always call add_trusted_domain() cause on an existing
460                  * domain structure, it will update the SID if necessary.
461                  * This is important because we need the SID for sibling
462                  * domains.
463                  */
464                 status = add_trusted_domain(name,
465                                             alt_name,
466                                             &sid,
467                                             trust_type,
468                                             trust_flags,
469                                             trust_attribs,
470                                             SEC_CHAN_NULL,
471                                             &domain);
472                 if (!NT_STATUS_IS_OK(status) &&
473                     !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
474                 {
475                         DBG_NOTICE("add_trusted_domain returned %s\n",
476                                    nt_errstr(status));
477                         return;
478                 }
479
480                 p = q + strlen(q) + 1;
481         }
482
483         /*
484            Cases to consider when scanning trusts:
485            (a) we are calling from a child domain (primary && !forest_root)
486            (b) we are calling from the root of the forest (primary && forest_root)
487            (c) we are calling from a trusted forest domain (!primary
488                && !forest_root)
489         */
490
491         if (state->domain->primary) {
492                 /* If this is our primary domain and we are not in the
493                    forest root, we have to scan the root trusts first */
494
495                 if (!domain_is_forest_root(state->domain))
496                         rescan_forest_root_trusts();
497                 else
498                         rescan_forest_trusts();
499
500         } else if (domain_is_forest_root(state->domain)) {
501                 /* Once we have done root forest trust search, we can
502                    go on to search the trusted forests */
503
504                 rescan_forest_trusts();
505         }
506
507         TALLOC_FREE(state);
508
509         return;
510 }
511
512 /********************************************************************
513  Scan the trusts of our forest root
514 ********************************************************************/
515
516 static void rescan_forest_root_trusts( void )
517 {
518         struct winbindd_tdc_domain *dom_list = NULL;
519         size_t num_trusts = 0;
520         int i;
521         NTSTATUS status;
522
523         /* The only transitive trusts supported by Windows 2003 AD are
524            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
525            first two are handled in forest and listed by
526            DsEnumerateDomainTrusts().  Forest trusts are not so we
527            have to do that ourselves. */
528
529         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
530                 return;
531
532         for ( i=0; i<num_trusts; i++ ) {
533                 struct winbindd_domain *d = NULL;
534
535                 /* Find the forest root.  Don't necessarily trust
536                    the domain_list() as our primary domain may not
537                    have been initialized. */
538
539                 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
540                         continue;
541                 }
542
543                 /* Here's the forest root */
544
545                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
546                 if (d == NULL) {
547                         status = add_trusted_domain(dom_list[i].domain_name,
548                                                     dom_list[i].dns_name,
549                                                     &dom_list[i].sid,
550                                                     dom_list[i].trust_type,
551                                                     dom_list[i].trust_flags,
552                                                     dom_list[i].trust_attribs,
553                                                     SEC_CHAN_NULL,
554                                                     &d);
555
556                         if (!NT_STATUS_IS_OK(status) &&
557                             NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
558                         {
559                                 DBG_ERR("add_trusted_domain returned %s\n",
560                                         nt_errstr(status));
561                                 return;
562                         }
563                 }
564                 if (d == NULL) {
565                         continue;
566                 }
567
568                 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
569                           "for domain tree root %s (%s)\n",
570                           d->name, d->alt_name ));
571
572                 d->domain_flags = dom_list[i].trust_flags;
573                 d->domain_type  = dom_list[i].trust_type;
574                 d->domain_trust_attribs = dom_list[i].trust_attribs;
575
576                 add_trusted_domains( d );
577
578                 break;
579         }
580
581         TALLOC_FREE( dom_list );
582
583         return;
584 }
585
586 /********************************************************************
587  scan the transitive forest trusts (not our own)
588 ********************************************************************/
589
590
591 static void rescan_forest_trusts( void )
592 {
593         struct winbindd_domain *d = NULL;
594         struct winbindd_tdc_domain *dom_list = NULL;
595         size_t num_trusts = 0;
596         int i;
597         NTSTATUS status;
598
599         /* The only transitive trusts supported by Windows 2003 AD are
600            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
601            first two are handled in forest and listed by
602            DsEnumerateDomainTrusts().  Forest trusts are not so we
603            have to do that ourselves. */
604
605         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
606                 return;
607
608         for ( i=0; i<num_trusts; i++ ) {
609                 uint32_t flags   = dom_list[i].trust_flags;
610                 uint32_t type    = dom_list[i].trust_type;
611                 uint32_t attribs = dom_list[i].trust_attribs;
612
613                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
614
615                 /* ignore our primary and internal domains */
616
617                 if ( d && (d->internal || d->primary ) )
618                         continue;
619
620                 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
621                      (type == LSA_TRUST_TYPE_UPLEVEL) &&
622                      (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
623                 {
624                         /* add the trusted domain if we don't know
625                            about it */
626
627                         if (d == NULL) {
628                                 status = add_trusted_domain(
629                                         dom_list[i].domain_name,
630                                         dom_list[i].dns_name,
631                                         &dom_list[i].sid,
632                                         type,
633                                         flags,
634                                         attribs,
635                                         SEC_CHAN_NULL,
636                                         &d);
637                                 if (!NT_STATUS_IS_OK(status) &&
638                                     NT_STATUS_EQUAL(status,
639                                                     NT_STATUS_NO_SUCH_DOMAIN))
640                                 {
641                                         DBG_ERR("add_trusted_domain: %s\n",
642                                                 nt_errstr(status));
643                                         return;
644                                 }
645                         }
646
647                         if (d == NULL) {
648                                 continue;
649                         }
650
651                         DEBUG(10,("Following trust path for domain %s (%s)\n",
652                                   d->name, d->alt_name ));
653                         add_trusted_domains( d );
654                 }
655         }
656
657         TALLOC_FREE( dom_list );
658
659         return;
660 }
661
662 /*********************************************************************
663  The process of updating the trusted domain list is a three step
664  async process:
665  (a) ask our domain
666  (b) ask the root domain in our forest
667  (c) ask the a DC in any Win2003 trusted forests
668 *********************************************************************/
669
670 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
671                             struct timeval now, void *private_data)
672 {
673         TALLOC_FREE(te);
674
675         /* I use to clear the cache here and start over but that
676            caused problems in child processes that needed the
677            trust dom list early on.  Removing it means we
678            could have some trusted domains listed that have been
679            removed from our primary domain's DC until a full
680            restart.  This should be ok since I think this is what
681            Windows does as well. */
682
683         /* this will only add new domains we didn't already know about
684            in the domain_list()*/
685
686         add_trusted_domains( find_our_domain() );
687
688         te = tevent_add_timer(
689                 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
690                 rescan_trusted_domains, NULL);
691         /*
692          * If te == NULL, there's not much we can do here. Don't fail, the
693          * only thing we miss is new trusted domains.
694          */
695
696         return;
697 }
698
699 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
700                                                    struct winbindd_cli_state *state)
701 {
702         /* Ensure null termination */
703         state->request->domain_name
704                 [sizeof(state->request->domain_name)-1]='\0';
705         state->request->data.init_conn.dcname
706                 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
707
708         if (strlen(state->request->data.init_conn.dcname) > 0) {
709                 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
710         }
711
712         init_dc_connection(domain, false);
713
714         if (!domain->initialized) {
715                 /* If we return error here we can't do any cached authentication,
716                    but we may be in disconnected mode and can't initialize correctly.
717                    Do what the previous code did and just return without initialization,
718                    once we go online we'll re-initialize.
719                 */
720                 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
721                         "online = %d\n", domain->name, (int)domain->online ));
722         }
723
724         fstrcpy(state->response->data.domain_info.name, domain->name);
725         fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
726         sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
727
728         state->response->data.domain_info.native_mode
729                 = domain->native_mode;
730         state->response->data.domain_info.active_directory
731                 = domain->active_directory;
732         state->response->data.domain_info.primary
733                 = domain->primary;
734
735         return WINBINDD_OK;
736 }
737
738 static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
739                                        void *private_data,
740                                        uint32_t msg_type,
741                                        struct server_id server_id,
742                                        DATA_BLOB *data)
743 {
744         TALLOC_CTX *frame = talloc_stackframe();
745         enum netr_SchannelType secure_channel_type = SEC_CHAN_DOMAIN;
746         struct lsa_TrustDomainInfoInfoEx info;
747         enum ndr_err_code ndr_err;
748         struct winbindd_domain *d = NULL;
749         uint32_t trust_flags = 0;
750         NTSTATUS status;
751
752         DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
753
754         if (data == NULL) {
755                 TALLOC_FREE(frame);
756                 return;
757         }
758
759         ndr_err = ndr_pull_struct_blob_all(data, frame, &info,
760                         (ndr_pull_flags_fn_t)ndr_pull_lsa_TrustDomainInfoInfoEx);
761         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
762                 TALLOC_FREE(frame);
763                 return;
764         }
765
766         d = find_domain_from_name_noinit(info.netbios_name.string);
767         if (d != NULL) {
768                 TALLOC_FREE(frame);
769                 return;
770         }
771
772         if (info.trust_type == LSA_TRUST_TYPE_UPLEVEL) {
773                 secure_channel_type = SEC_CHAN_DNS_DOMAIN;
774         }
775         if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
776                 trust_flags |= NETR_TRUST_FLAG_INBOUND;
777         }
778         if (info.trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
779                 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
780         }
781         if (info.trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
782                 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
783         }
784
785         status = add_trusted_domain(info.netbios_name.string,
786                                     info.domain_name.string,
787                                     info.sid,
788                                     info.trust_type,
789                                     trust_flags,
790                                     info.trust_attributes,
791                                     secure_channel_type,
792                                     &d);
793         if (!NT_STATUS_IS_OK(status) &&
794             !NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN))
795         {
796                 DBG_NOTICE("add_trusted_domain returned %s\n",
797                            nt_errstr(status));
798                 TALLOC_FREE(frame);
799                 return;
800         }
801         TALLOC_FREE(frame);
802 }
803
804 /*
805  * We did not get the secret when we queried secrets.tdb, so read it
806  * from secrets.tdb and re-sync the databases
807  */
808 static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
809 {
810         bool ok;
811         struct cli_credentials *creds;
812         NTSTATUS can_migrate = pdb_get_trust_credentials(domain->name,
813                                                          NULL, domain, &creds);
814         if (!NT_STATUS_IS_OK(can_migrate)) {
815                 DEBUG(0, ("Failed to fetch our own, local AD domain join "
816                         "password for winbindd's internal use, both from "
817                         "secrets.tdb and secrets.ldb: %s\n",
818                         nt_errstr(can_migrate)));
819                 return false;
820         }
821
822         /*
823          * NOTE: It is very unlikely we end up here if there is an
824          * oldpass, because a new password is created at
825          * classicupgrade, so this is not a concern.
826          */
827         ok = secrets_store_machine_pw_sync(cli_credentials_get_password(creds),
828                    NULL /* oldpass */,
829                    cli_credentials_get_domain(creds),
830                    cli_credentials_get_realm(creds),
831                    cli_credentials_get_salt_principal(creds),
832                    0, /* Supported enc types, unused */
833                    &domain->sid,
834                    cli_credentials_get_password_last_changed_time(creds),
835                    cli_credentials_get_secure_channel_type(creds),
836                    false /* do_delete: Do not delete */);
837         TALLOC_FREE(creds);
838         if (ok == false) {
839                 DEBUG(0, ("Failed to write our our own, "
840                           "local AD domain join password for "
841                           "winbindd's internal use into secrets.tdb\n"));
842                 return false;
843         }
844         return true;
845 }
846
847 /* Look up global info for the winbind daemon */
848 bool init_domain_list(void)
849 {
850         int role = lp_server_role();
851         struct pdb_domain_info *pdb_domain_info = NULL;
852         struct winbindd_domain *domain =  NULL;
853         NTSTATUS status;
854
855         /* Free existing list */
856         free_domain_list();
857
858         /* BUILTIN domain */
859
860         status = add_trusted_domain("BUILTIN",
861                                     NULL,
862                                     &global_sid_Builtin,
863                                     LSA_TRUST_TYPE_DOWNLEVEL,
864                                     0, /* trust_flags */
865                                     0, /* trust_attribs */
866                                     SEC_CHAN_LOCAL,
867                                     &domain);
868         if (!NT_STATUS_IS_OK(status)) {
869                 DBG_ERR("add_trusted_domain BUILTIN returned %s\n",
870                         nt_errstr(status));
871                 return false;
872         }
873
874         /* Local SAM */
875
876         /*
877          * In case the passdb backend is passdb_dsdb the domain SID comes from
878          * dsdb, not from secrets.tdb. As we use the domain SID in various
879          * places, we must ensure the domain SID is migrated from dsdb to
880          * secrets.tdb before get_global_sam_sid() is called the first time.
881          *
882          * The migration is done as part of the passdb_dsdb initialisation,
883          * calling pdb_get_domain_info() triggers it.
884          */
885         pdb_domain_info = pdb_get_domain_info(talloc_tos());
886
887         if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
888                 uint32_t trust_flags;
889                 bool is_root;
890                 enum netr_SchannelType sec_chan_type;
891                 const char *account_name;
892                 struct samr_Password current_nt_hash;
893                 bool ok;
894
895                 if (pdb_domain_info == NULL) {
896                         DEBUG(0, ("Failed to fetch our own, local AD "
897                                 "domain info from sam.ldb\n"));
898                         return false;
899                 }
900
901                 trust_flags = NETR_TRUST_FLAG_PRIMARY;
902                 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
903                 trust_flags |= NETR_TRUST_FLAG_NATIVE;
904                 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
905
906                 is_root = strequal(pdb_domain_info->dns_domain,
907                                    pdb_domain_info->dns_forest);
908                 if (is_root) {
909                         trust_flags |= NETR_TRUST_FLAG_TREEROOT;
910                 }
911
912                 status = add_trusted_domain(pdb_domain_info->name,
913                                             pdb_domain_info->dns_domain,
914                                             &pdb_domain_info->sid,
915                                             LSA_TRUST_TYPE_UPLEVEL,
916                                             trust_flags,
917                                             LSA_TRUST_ATTRIBUTE_WITHIN_FOREST,
918                                             SEC_CHAN_BDC,
919                                             &domain);
920                 TALLOC_FREE(pdb_domain_info);
921                 if (!NT_STATUS_IS_OK(status)) {
922                         DBG_ERR("Failed to add our own, local AD "
923                                 "domain to winbindd's internal list\n");
924                         return false;
925                 }
926
927                 /*
928                  * We need to call this to find out if we are an RODC
929                  */
930                 ok = get_trust_pw_hash(domain->name,
931                                        current_nt_hash.hash,
932                                        &account_name,
933                                        &sec_chan_type);
934                 if (!ok) {
935                         /*
936                          * If get_trust_pw_hash() fails, then try and
937                          * fetch the password from the more recent of
938                          * secrets.{ldb,tdb} using the
939                          * pdb_get_trust_credentials()
940                          */
941                         ok = migrate_secrets_tdb_to_ldb(domain);
942
943                         if (!ok) {
944                                 DEBUG(0, ("Failed to migrate our own, "
945                                           "local AD domain join password for "
946                                           "winbindd's internal use into "
947                                           "secrets.tdb\n"));
948                                 return false;
949                         }
950                         ok = get_trust_pw_hash(domain->name,
951                                                current_nt_hash.hash,
952                                                &account_name,
953                                                &sec_chan_type);
954                         if (!ok) {
955                                 DEBUG(0, ("Failed to find our our own, just "
956                                           "written local AD domain join "
957                                           "password for winbindd's internal "
958                                           "use in secrets.tdb\n"));
959                                 return false;
960                         }
961                 }
962
963                 domain->secure_channel_type = sec_chan_type;
964                 if (sec_chan_type == SEC_CHAN_RODC) {
965                         domain->rodc = true;
966                 }
967
968         } else {
969                 uint32_t trust_flags;
970                 enum netr_SchannelType secure_channel_type;
971
972                 trust_flags = NETR_TRUST_FLAG_OUTBOUND;
973                 if (role != ROLE_DOMAIN_MEMBER) {
974                         trust_flags |= NETR_TRUST_FLAG_PRIMARY;
975                 }
976
977                 if (role > ROLE_DOMAIN_MEMBER) {
978                         secure_channel_type = SEC_CHAN_BDC;
979                 } else {
980                         secure_channel_type = SEC_CHAN_LOCAL;
981                 }
982
983                 status = add_trusted_domain(get_global_sam_name(),
984                                             NULL,
985                                             get_global_sam_sid(),
986                                             LSA_TRUST_TYPE_DOWNLEVEL,
987                                             trust_flags,
988                                             0, /* trust_attribs */
989                                             secure_channel_type,
990                                             &domain);
991                 if (!NT_STATUS_IS_OK(status)) {
992                         DBG_ERR("Failed to add local SAM to "
993                                 "domain to winbindd's internal list\n");
994                         return false;
995                 }
996         }
997         /* Add ourselves as the first entry. */
998
999         if ( role == ROLE_DOMAIN_MEMBER ) {
1000                 struct dom_sid our_sid;
1001                 uint32_t trust_type;
1002
1003                 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
1004                         DEBUG(0, ("Could not fetch our SID - did we join?\n"));
1005                         return False;
1006                 }
1007
1008                 if (lp_realm() != NULL) {
1009                         trust_type = LSA_TRUST_TYPE_UPLEVEL;
1010                 } else {
1011                         trust_type = LSA_TRUST_TYPE_DOWNLEVEL;
1012                 }
1013
1014                 status = add_trusted_domain(lp_workgroup(),
1015                                             lp_realm(),
1016                                             &our_sid,
1017                                             trust_type,
1018                                             NETR_TRUST_FLAG_PRIMARY|
1019                                             NETR_TRUST_FLAG_OUTBOUND,
1020                                             0, /* trust_attribs */
1021                                             SEC_CHAN_WKSTA,
1022                                             &domain);
1023                 if (!NT_STATUS_IS_OK(status)) {
1024                         DBG_ERR("Failed to add local SAM to "
1025                                 "domain to winbindd's internal list\n");
1026                         return false;
1027                 }
1028                 /* Even in the parent winbindd we'll need to
1029                    talk to the DC, so try and see if we can
1030                    contact it. Theoretically this isn't neccessary
1031                    as the init_dc_connection() in init_child_recv()
1032                    will do this, but we can start detecting the DC
1033                    early here. */
1034                 set_domain_online_request(domain);
1035
1036         }
1037
1038         status = imessaging_register(winbind_imessaging_context(), NULL,
1039                                      MSG_WINBIND_NEW_TRUSTED_DOMAIN,
1040                                      wb_imsg_new_trusted_domain);
1041         if (!NT_STATUS_IS_OK(status)) {
1042                 DEBUG(0, ("imessaging_register(MSG_WINBIND_NEW_TRUSTED_DOMAIN) - %s\n",
1043                           nt_errstr(status)));
1044                 return false;
1045         }
1046
1047         return True;
1048 }
1049
1050 /**
1051  * Given a domain name, return the struct winbindd domain info for it
1052  *
1053  * @note Do *not* pass lp_workgroup() to this function.  domain_list
1054  *       may modify it's value, and free that pointer.  Instead, our local
1055  *       domain may be found by calling find_our_domain().
1056  *       directly.
1057  *
1058  *
1059  * @return The domain structure for the named domain, if it is working.
1060  */
1061
1062 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
1063 {
1064         struct winbindd_domain *domain;
1065
1066         /* Search through list */
1067
1068         for (domain = domain_list(); domain != NULL; domain = domain->next) {
1069                 if (strequal(domain_name, domain->name)) {
1070                         return domain;
1071                 }
1072                 if (domain->alt_name == NULL) {
1073                         continue;
1074                 }
1075                 if (strequal(domain_name, domain->alt_name)) {
1076                         return domain;
1077                 }
1078         }
1079
1080         /* Not found */
1081
1082         return NULL;
1083 }
1084
1085 struct winbindd_domain *find_domain_from_name(const char *domain_name)
1086 {
1087         struct winbindd_domain *domain;
1088
1089         domain = find_domain_from_name_noinit(domain_name);
1090
1091         if (domain == NULL)
1092                 return NULL;
1093
1094         if (!domain->initialized)
1095                 init_dc_connection(domain, false);
1096
1097         return domain;
1098 }
1099
1100 /* Given a domain sid, return the struct winbindd domain info for it */
1101
1102 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
1103 {
1104         struct winbindd_domain *domain;
1105
1106         /* Search through list */
1107
1108         for (domain = domain_list(); domain != NULL; domain = domain->next) {
1109                 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
1110                         return domain;
1111         }
1112
1113         /* Not found */
1114
1115         return NULL;
1116 }
1117
1118 /* Given a domain sid, return the struct winbindd domain info for it */
1119
1120 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
1121 {
1122         struct winbindd_domain *domain;
1123
1124         domain = find_domain_from_sid_noinit(sid);
1125
1126         if (domain == NULL)
1127                 return NULL;
1128
1129         if (!domain->initialized)
1130                 init_dc_connection(domain, false);
1131
1132         return domain;
1133 }
1134
1135 struct winbindd_domain *find_our_domain(void)
1136 {
1137         struct winbindd_domain *domain;
1138
1139         /* Search through list */
1140
1141         for (domain = domain_list(); domain != NULL; domain = domain->next) {
1142                 if (domain->primary)
1143                         return domain;
1144         }
1145
1146         smb_panic("Could not find our domain");
1147         return NULL;
1148 }
1149
1150 /* Find the appropriate domain to lookup a name or SID */
1151
1152 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
1153 {
1154         DBG_DEBUG("SID [%s]\n", sid_string_dbg(sid));
1155
1156         /*
1157          * SIDs in the S-1-22-{1,2} domain and well-known SIDs should be handled
1158          * by our passdb.
1159          */
1160
1161         if ( sid_check_is_in_unix_groups(sid) ||
1162              sid_check_is_unix_groups(sid) ||
1163              sid_check_is_in_unix_users(sid) ||
1164              sid_check_is_unix_users(sid) ||
1165              sid_check_is_wellknown_domain(sid, NULL) ||
1166              sid_check_is_in_wellknown_domain(sid) )
1167         {
1168                 return find_domain_from_sid(get_global_sam_sid());
1169         }
1170
1171         /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
1172          * one to contact the external DC's. On member servers the internal
1173          * domains are different: These are part of the local SAM. */
1174
1175         if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
1176                 DEBUG(10, ("calling find_domain_from_sid\n"));
1177                 return find_domain_from_sid(sid);
1178         }
1179
1180         /* On a member server a query for SID or name can always go to our
1181          * primary DC. */
1182
1183         DEBUG(10, ("calling find_our_domain\n"));
1184         return find_our_domain();
1185 }
1186
1187 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1188 {
1189         if ( strequal(domain_name, unix_users_domain_name() ) ||
1190              strequal(domain_name, unix_groups_domain_name() ) )
1191         {
1192                 /*
1193                  * The "Unix User" and "Unix Group" domain our handled by
1194                  * passdb
1195                  */
1196                 return find_domain_from_name_noinit( get_global_sam_name() );
1197         }
1198
1199         if (IS_DC || strequal(domain_name, "BUILTIN") ||
1200             strequal(domain_name, get_global_sam_name()))
1201                 return find_domain_from_name_noinit(domain_name);
1202
1203
1204         return find_our_domain();
1205 }
1206
1207 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1208
1209 static bool assume_domain(const char *domain)
1210 {
1211         /* never assume the domain on a standalone server */
1212
1213         if ( lp_server_role() == ROLE_STANDALONE )
1214                 return False;
1215
1216         /* domain member servers may possibly assume for the domain name */
1217
1218         if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1219                 if ( !strequal(lp_workgroup(), domain) )
1220                         return False;
1221
1222                 if ( lp_winbind_use_default_domain() )
1223                         return True;
1224         }
1225
1226         /* only left with a domain controller */
1227
1228         if ( strequal(get_global_sam_name(), domain) )  {
1229                 return True;
1230         }
1231
1232         return False;
1233 }
1234
1235 /* Parse a string of the form DOMAIN\user into a domain and a user */
1236
1237 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1238 {
1239         char *p = strchr(domuser,*lp_winbind_separator());
1240
1241         if ( !p ) {
1242                 fstrcpy(user, domuser);
1243                 p = strchr(domuser, '@');
1244
1245                 if ( assume_domain(lp_workgroup()) && p == NULL) {
1246                         fstrcpy(domain, lp_workgroup());
1247                 } else if (p != NULL) {
1248                         fstrcpy(domain, p + 1);
1249                         user[PTR_DIFF(p, domuser)] = 0;
1250                 } else {
1251                         return False;
1252                 }
1253         } else {
1254                 fstrcpy(user, p+1);
1255                 fstrcpy(domain, domuser);
1256                 domain[PTR_DIFF(p, domuser)] = 0;
1257         }
1258
1259         return strupper_m(domain);
1260 }
1261
1262 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1263                               char **domain, char **user)
1264 {
1265         fstring fstr_domain, fstr_user;
1266         if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1267                 return False;
1268         }
1269         *domain = talloc_strdup(mem_ctx, fstr_domain);
1270         *user = talloc_strdup(mem_ctx, fstr_user);
1271         return ((*domain != NULL) && (*user != NULL));
1272 }
1273
1274 /* Ensure an incoming username from NSS is fully qualified. Replace the
1275    incoming fstring with DOMAIN <separator> user. Returns the same
1276    values as parse_domain_user() but also replaces the incoming username.
1277    Used to ensure all names are fully qualified within winbindd.
1278    Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1279    The protocol definitions of auth_crap, chng_pswd_auth_crap
1280    really should be changed to use this instead of doing things
1281    by hand. JRA. */
1282
1283 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1284 {
1285         if (!parse_domain_user(username_inout, domain, user)) {
1286                 return False;
1287         }
1288         slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1289                  domain, *lp_winbind_separator(),
1290                  user);
1291         return True;
1292 }
1293
1294 /*
1295     Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1296     'winbind separator' options.
1297     This means:
1298         - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1299         lp_workgroup()
1300
1301     If we are a PDC or BDC, and this is for our domain, do likewise.
1302
1303     On an AD DC we always fill DOMAIN\\USERNAME.
1304
1305     We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1306 */
1307 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1308 {
1309         fstring tmp_user;
1310
1311         if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1312                 can_assume = false;
1313         }
1314
1315         fstrcpy(tmp_user, user);
1316         (void)strlower_m(tmp_user);
1317
1318         if (can_assume && assume_domain(domain)) {
1319                 strlcpy(name, tmp_user, sizeof(fstring));
1320         } else {
1321                 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1322                          domain, *lp_winbind_separator(),
1323                          tmp_user);
1324         }
1325 }
1326
1327 /**
1328  * talloc version of fill_domain_username()
1329  * return NULL on talloc failure.
1330  */
1331 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1332                                   const char *domain,
1333                                   const char *user,
1334                                   bool can_assume)
1335 {
1336         char *tmp_user, *name;
1337
1338         if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1339                 can_assume = false;
1340         }
1341
1342         tmp_user = talloc_strdup(mem_ctx, user);
1343         if (!strlower_m(tmp_user)) {
1344                 TALLOC_FREE(tmp_user);
1345                 return NULL;
1346         }
1347
1348         if (can_assume && assume_domain(domain)) {
1349                 name = tmp_user;
1350         } else {
1351                 name = talloc_asprintf(mem_ctx, "%s%c%s",
1352                                        domain,
1353                                        *lp_winbind_separator(),
1354                                        tmp_user);
1355                 TALLOC_FREE(tmp_user);
1356         }
1357
1358         return name;
1359 }
1360
1361 /*
1362  * Client list accessor functions
1363  */
1364
1365 static struct winbindd_cli_state *_client_list;
1366 static int _num_clients;
1367
1368 /* Return list of all connected clients */
1369
1370 struct winbindd_cli_state *winbindd_client_list(void)
1371 {
1372         return _client_list;
1373 }
1374
1375 /* Return list-tail of all connected clients */
1376
1377 struct winbindd_cli_state *winbindd_client_list_tail(void)
1378 {
1379         return DLIST_TAIL(_client_list);
1380 }
1381
1382 /* Return previous (read:newer) client in list */
1383
1384 struct winbindd_cli_state *
1385 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1386 {
1387         return DLIST_PREV(cli);
1388 }
1389
1390 /* Add a connection to the list */
1391
1392 void winbindd_add_client(struct winbindd_cli_state *cli)
1393 {
1394         cli->last_access = time(NULL);
1395         DLIST_ADD(_client_list, cli);
1396         _num_clients++;
1397 }
1398
1399 /* Remove a client from the list */
1400
1401 void winbindd_remove_client(struct winbindd_cli_state *cli)
1402 {
1403         DLIST_REMOVE(_client_list, cli);
1404         _num_clients--;
1405 }
1406
1407 /* Move a client to head or list */
1408
1409 void winbindd_promote_client(struct winbindd_cli_state *cli)
1410 {
1411         cli->last_access = time(NULL);
1412         DLIST_PROMOTE(_client_list, cli);
1413 }
1414
1415 /* Return number of open clients */
1416
1417 int winbindd_num_clients(void)
1418 {
1419         return _num_clients;
1420 }
1421
1422 NTSTATUS lookup_usergroups_cached(TALLOC_CTX *mem_ctx,
1423                                   const struct dom_sid *user_sid,
1424                                   uint32_t *p_num_groups, struct dom_sid **user_sids)
1425 {
1426         struct netr_SamInfo3 *info3 = NULL;
1427         NTSTATUS status = NT_STATUS_NO_MEMORY;
1428         uint32_t num_groups = 0;
1429
1430         DEBUG(3,(": lookup_usergroups_cached\n"));
1431
1432         *user_sids = NULL;
1433         *p_num_groups = 0;
1434
1435         info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1436
1437         if (info3 == NULL) {
1438                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1439         }
1440
1441         /*
1442          * Before bug #7843 the "Domain Local" groups were added with a
1443          * lookupuseraliases call, but this isn't done anymore for our domain
1444          * so we need to resolve resource groups here.
1445          *
1446          * When to use Resource Groups:
1447          * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1448          */
1449         status = sid_array_from_info3(mem_ctx, info3,
1450                                       user_sids,
1451                                       &num_groups,
1452                                       false);
1453
1454         if (!NT_STATUS_IS_OK(status)) {
1455                 TALLOC_FREE(info3);
1456                 return status;
1457         }
1458
1459         TALLOC_FREE(info3);
1460         *p_num_groups = num_groups;
1461         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1462
1463         DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1464
1465         return status;
1466 }
1467
1468 /*********************************************************************
1469  We use this to remove spaces from user and group names
1470 ********************************************************************/
1471
1472 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1473                              const char *domain_name,
1474                              const char *name,
1475                              char **normalized)
1476 {
1477         struct winbindd_domain *domain = NULL;
1478         NTSTATUS nt_status;
1479
1480         if (!name || !normalized) {
1481                 return NT_STATUS_INVALID_PARAMETER;
1482         }
1483
1484         if (!lp_winbind_normalize_names()) {
1485                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1486         }
1487
1488         domain = find_domain_from_name_noinit(domain_name);
1489         if (domain == NULL) {
1490                 DBG_ERR("Failed to find domain '%s'\n", domain_name);
1491                 return NT_STATUS_NO_SUCH_DOMAIN;
1492         }
1493
1494         /* Alias support and whitespace replacement are mutually
1495            exclusive */
1496
1497         nt_status = resolve_username_to_alias(mem_ctx, domain,
1498                                               name, normalized );
1499         if (NT_STATUS_IS_OK(nt_status)) {
1500                 /* special return code to let the caller know we
1501                    mapped to an alias */
1502                 return NT_STATUS_FILE_RENAMED;
1503         }
1504
1505         /* check for an unreachable domain */
1506
1507         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1508                 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1509                          domain->name));
1510                 set_domain_offline(domain);
1511                 return nt_status;
1512         }
1513
1514         /* deal with whitespace */
1515
1516         *normalized = talloc_strdup(mem_ctx, name);
1517         if (!(*normalized)) {
1518                 return NT_STATUS_NO_MEMORY;
1519         }
1520
1521         all_string_sub( *normalized, " ", "_", 0 );
1522
1523         return NT_STATUS_OK;
1524 }
1525
1526 /*********************************************************************
1527  We use this to do the inverse of normalize_name_map()
1528 ********************************************************************/
1529
1530 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1531                               char *name,
1532                               char **normalized)
1533 {
1534         NTSTATUS nt_status;
1535         struct winbindd_domain *domain = find_our_domain();
1536
1537         if (!name || !normalized) {
1538                 return NT_STATUS_INVALID_PARAMETER;
1539         }
1540
1541         if (!lp_winbind_normalize_names()) {
1542                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1543         }
1544
1545         /* Alias support and whitespace replacement are mutally
1546            exclusive */
1547
1548         /* When mapping from an alias to a username, we don't know the
1549            domain.  But we only need a domain structure to cache
1550            a successful lookup , so just our own domain structure for
1551            the seqnum. */
1552
1553         nt_status = resolve_alias_to_username(mem_ctx, domain,
1554                                               name, normalized);
1555         if (NT_STATUS_IS_OK(nt_status)) {
1556                 /* Special return code to let the caller know we mapped
1557                    from an alias */
1558                 return NT_STATUS_FILE_RENAMED;
1559         }
1560
1561         /* check for an unreachable domain */
1562
1563         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1564                 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1565                          domain->name));
1566                 set_domain_offline(domain);
1567                 return nt_status;
1568         }
1569
1570         /* deal with whitespace */
1571
1572         *normalized = talloc_strdup(mem_ctx, name);
1573         if (!(*normalized)) {
1574                 return NT_STATUS_NO_MEMORY;
1575         }
1576
1577         all_string_sub(*normalized, "_", " ", 0);
1578
1579         return NT_STATUS_OK;
1580 }
1581
1582 /*********************************************************************
1583  ********************************************************************/
1584
1585 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1586 {
1587         struct winbindd_tdc_domain *tdc = NULL;
1588         TALLOC_CTX *frame = talloc_stackframe();
1589         bool ret = false;
1590
1591         /* We can contact the domain if it is our primary domain */
1592
1593         if (domain->primary) {
1594                 ret = true;
1595                 goto done;
1596         }
1597
1598         /* Trust the TDC cache and not the winbindd_domain flags */
1599
1600         if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1601                 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1602                           domain->name));
1603                 ret = false;
1604                 goto done;
1605         }
1606
1607         /* Can always contact a domain that is in out forest */
1608
1609         if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1610                 ret = true;
1611                 goto done;
1612         }
1613
1614         /*
1615          * On a _member_ server, we cannot contact the domain if it
1616          * is running AD and we have no inbound trust.
1617          */
1618
1619         if (!IS_DC &&
1620              domain->active_directory &&
1621             ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1622         {
1623                 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1624                            "and we have no inbound trust.\n", domain->name));
1625                 goto done;
1626         }
1627
1628         /* Assume everything else is ok (probably not true but what
1629            can you do?) */
1630
1631         ret = true;
1632
1633 done:
1634         talloc_destroy(frame);
1635
1636         return ret;
1637 }
1638
1639 /*********************************************************************
1640  ********************************************************************/
1641
1642 bool winbindd_internal_child(struct winbindd_child *child)
1643 {
1644         if ((child == idmap_child()) || (child == locator_child())) {
1645                 return True;
1646         }
1647
1648         return False;
1649 }
1650
1651 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1652
1653 /*********************************************************************
1654  ********************************************************************/
1655
1656 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1657 {
1658         char *var = NULL;
1659         char addr[INET6_ADDRSTRLEN];
1660         const char *kdc = NULL;
1661         int lvl = 11;
1662
1663         if (!domain || !domain->alt_name || !*domain->alt_name) {
1664                 return;
1665         }
1666
1667         if (domain->initialized && !domain->active_directory) {
1668                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1669                         domain->alt_name));
1670                 return;
1671         }
1672
1673         print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1674         kdc = addr;
1675         if (!*kdc) {
1676                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1677                         domain->alt_name));
1678                 kdc = domain->dcname;
1679         }
1680
1681         if (!kdc || !*kdc) {
1682                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1683                         domain->alt_name));
1684                 return;
1685         }
1686
1687         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1688                                 domain->alt_name) == -1) {
1689                 return;
1690         }
1691
1692         DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1693                 var, kdc));
1694
1695         setenv(var, kdc, 1);
1696         free(var);
1697 }
1698
1699 /*********************************************************************
1700  ********************************************************************/
1701
1702 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1703 {
1704         struct winbindd_domain *our_dom = find_our_domain();
1705
1706         winbindd_set_locator_kdc_env(domain);
1707
1708         if (domain != our_dom) {
1709                 winbindd_set_locator_kdc_env(our_dom);
1710         }
1711 }
1712
1713 /*********************************************************************
1714  ********************************************************************/
1715
1716 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1717 {
1718         char *var = NULL;
1719
1720         if (!domain || !domain->alt_name || !*domain->alt_name) {
1721                 return;
1722         }
1723
1724         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1725                                 domain->alt_name) == -1) {
1726                 return;
1727         }
1728
1729         unsetenv(var);
1730         free(var);
1731 }
1732 #else
1733
1734 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1735 {
1736         return;
1737 }
1738
1739 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1740 {
1741         return;
1742 }
1743
1744 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1745
1746 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1747 {
1748         resp->data.auth.nt_status = NT_STATUS_V(result);
1749         fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1750
1751         /* we might have given a more useful error above */
1752         if (*resp->data.auth.error_string == '\0')
1753                 fstrcpy(resp->data.auth.error_string,
1754                         get_friendly_nt_error_msg(result));
1755         resp->data.auth.pam_error = nt_status_to_pam(result);
1756 }
1757
1758 bool is_domain_offline(const struct winbindd_domain *domain)
1759 {
1760         if (get_global_winbindd_state_offline()) {
1761                 return true;
1762         }
1763         return !domain->online;
1764 }
1765
1766 bool is_domain_online(const struct winbindd_domain *domain)
1767 {
1768         return !is_domain_offline(domain);
1769 }
1770
1771 /**
1772  * Parse an char array into a list of sids.
1773  *
1774  * The input sidstr should consist of 0-terminated strings
1775  * representing sids, separated by newline characters '\n'.
1776  * The list is terminated by an empty string, i.e.
1777  * character '\0' directly following a character '\n'
1778  * (or '\0' right at the start of sidstr).
1779  */
1780 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
1781                    struct dom_sid **sids, uint32_t *num_sids)
1782 {
1783         const char *p;
1784
1785         p = sidstr;
1786         if (p == NULL)
1787                 return False;
1788
1789         while (p[0] != '\0') {
1790                 struct dom_sid sid;
1791                 const char *q = NULL;
1792
1793                 if (!dom_sid_parse_endp(p, &sid, &q)) {
1794                         DEBUG(1, ("Could not parse sid %s\n", p));
1795                         return false;
1796                 }
1797                 if (q[0] != '\n') {
1798                         DEBUG(1, ("Got invalid sidstr: %s\n", p));
1799                         return false;
1800                 }
1801                 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
1802                                                       num_sids)))
1803                 {
1804                         return False;
1805                 }
1806                 p = q+1;
1807         }
1808         return True;
1809 }
1810
1811 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
1812                    struct unixid **pxids, uint32_t *pnum_xids)
1813 {
1814         const char *p;
1815         struct unixid *xids = NULL;
1816         uint32_t num_xids = 0;
1817
1818         p = xidstr;
1819         if (p == NULL) {
1820                 return false;
1821         }
1822
1823         while (p[0] != '\0') {
1824                 struct unixid *tmp;
1825                 struct unixid xid;
1826                 unsigned long long id;
1827                 char *endp;
1828
1829                 switch (p[0]) {
1830                 case 'U':
1831                         xid = (struct unixid) { .type = ID_TYPE_UID };
1832                         break;
1833                 case 'G':
1834                         xid = (struct unixid) { .type = ID_TYPE_GID };
1835                         break;
1836                 default:
1837                         return false;
1838                 }
1839
1840                 p += 1;
1841
1842                 id = strtoull(p, &endp, 10);
1843                 if ((id == ULLONG_MAX) && (errno == ERANGE)) {
1844                         goto fail;
1845                 }
1846                 if (*endp != '\n') {
1847                         goto fail;
1848                 }
1849                 p = endp+1;
1850
1851                 xid.id = id;
1852                 if ((unsigned long long)xid.id != id) {
1853                         goto fail;
1854                 }
1855
1856                 tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
1857                 if (tmp == NULL) {
1858                         return 0;
1859                 }
1860                 xids = tmp;
1861
1862                 xids[num_xids] = xid;
1863                 num_xids += 1;
1864         }
1865
1866         *pxids = xids;
1867         *pnum_xids = num_xids;
1868         return true;
1869
1870 fail:
1871         TALLOC_FREE(xids);
1872         return false;
1873 }