winbindd: add find_trust_from_{name,sid}_noinit()
[amitay/samba.git] / source3 / winbindd / winbindd_util.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Winbind daemon for ntdom nss module
5
6    Copyright (C) Tim Potter 2000-2001
7    Copyright (C) 2001 by Martin Pool <mbp@samba.org>
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "winbindd.h"
25 #include "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 /**
1086  * Given a domain name, return the struct winbindd domain if it's a direct
1087  * outgoing trust
1088  *
1089  * @return The domain structure for the named domain, if it is a direct outgoing trust
1090  */
1091 struct winbindd_domain *find_trust_from_name_noinit(const char *domain_name)
1092 {
1093         struct winbindd_domain *domain = NULL;
1094
1095         domain = find_domain_from_name_noinit(domain_name);
1096         if (domain == NULL) {
1097                 return NULL;
1098         }
1099
1100         if (domain->secure_channel_type != SEC_CHAN_NULL) {
1101                 return domain;
1102         }
1103
1104         return NULL;
1105 }
1106
1107 struct winbindd_domain *find_domain_from_name(const char *domain_name)
1108 {
1109         struct winbindd_domain *domain;
1110
1111         domain = find_domain_from_name_noinit(domain_name);
1112
1113         if (domain == NULL)
1114                 return NULL;
1115
1116         if (!domain->initialized)
1117                 init_dc_connection(domain, false);
1118
1119         return domain;
1120 }
1121
1122 /* Given a domain sid, return the struct winbindd domain info for it */
1123
1124 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
1125 {
1126         struct winbindd_domain *domain;
1127
1128         /* Search through list */
1129
1130         for (domain = domain_list(); domain != NULL; domain = domain->next) {
1131                 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
1132                         return domain;
1133         }
1134
1135         /* Not found */
1136
1137         return NULL;
1138 }
1139
1140 /**
1141  * Given a domain sid, return the struct winbindd domain if it's a direct
1142  * outgoing trust
1143  *
1144  * @return The domain structure for the specified domain, if it is a direct outgoing trust
1145  */
1146 struct winbindd_domain *find_trust_from_sid_noinit(const struct dom_sid *sid)
1147 {
1148         struct winbindd_domain *domain = NULL;
1149
1150         domain = find_domain_from_sid_noinit(sid);
1151         if (domain == NULL) {
1152                 return NULL;
1153         }
1154
1155         if (domain->secure_channel_type != SEC_CHAN_NULL) {
1156                 return domain;
1157         }
1158
1159         return NULL;
1160 }
1161
1162 /* Given a domain sid, return the struct winbindd domain info for it */
1163
1164 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
1165 {
1166         struct winbindd_domain *domain;
1167
1168         domain = find_domain_from_sid_noinit(sid);
1169
1170         if (domain == NULL)
1171                 return NULL;
1172
1173         if (!domain->initialized)
1174                 init_dc_connection(domain, false);
1175
1176         return domain;
1177 }
1178
1179 struct winbindd_domain *find_our_domain(void)
1180 {
1181         struct winbindd_domain *domain;
1182
1183         /* Search through list */
1184
1185         for (domain = domain_list(); domain != NULL; domain = domain->next) {
1186                 if (domain->primary)
1187                         return domain;
1188         }
1189
1190         smb_panic("Could not find our domain");
1191         return NULL;
1192 }
1193
1194 /* Find the appropriate domain to lookup a name or SID */
1195
1196 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
1197 {
1198         DBG_DEBUG("SID [%s]\n", sid_string_dbg(sid));
1199
1200         /*
1201          * SIDs in the S-1-22-{1,2} domain and well-known SIDs should be handled
1202          * by our passdb.
1203          */
1204
1205         if ( sid_check_is_in_unix_groups(sid) ||
1206              sid_check_is_unix_groups(sid) ||
1207              sid_check_is_in_unix_users(sid) ||
1208              sid_check_is_unix_users(sid) ||
1209              sid_check_is_wellknown_domain(sid, NULL) ||
1210              sid_check_is_in_wellknown_domain(sid) )
1211         {
1212                 return find_domain_from_sid(get_global_sam_sid());
1213         }
1214
1215         /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
1216          * one to contact the external DC's. On member servers the internal
1217          * domains are different: These are part of the local SAM. */
1218
1219         if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
1220                 DEBUG(10, ("calling find_domain_from_sid\n"));
1221                 return find_domain_from_sid(sid);
1222         }
1223
1224         /* On a member server a query for SID or name can always go to our
1225          * primary DC. */
1226
1227         DEBUG(10, ("calling find_our_domain\n"));
1228         return find_our_domain();
1229 }
1230
1231 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1232 {
1233         if ( strequal(domain_name, unix_users_domain_name() ) ||
1234              strequal(domain_name, unix_groups_domain_name() ) )
1235         {
1236                 /*
1237                  * The "Unix User" and "Unix Group" domain our handled by
1238                  * passdb
1239                  */
1240                 return find_domain_from_name_noinit( get_global_sam_name() );
1241         }
1242
1243         if (IS_DC || strequal(domain_name, "BUILTIN") ||
1244             strequal(domain_name, get_global_sam_name()))
1245                 return find_domain_from_name_noinit(domain_name);
1246
1247
1248         return find_our_domain();
1249 }
1250
1251 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1252
1253 static bool assume_domain(const char *domain)
1254 {
1255         /* never assume the domain on a standalone server */
1256
1257         if ( lp_server_role() == ROLE_STANDALONE )
1258                 return False;
1259
1260         /* domain member servers may possibly assume for the domain name */
1261
1262         if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1263                 if ( !strequal(lp_workgroup(), domain) )
1264                         return False;
1265
1266                 if ( lp_winbind_use_default_domain() )
1267                         return True;
1268         }
1269
1270         /* only left with a domain controller */
1271
1272         if ( strequal(get_global_sam_name(), domain) )  {
1273                 return True;
1274         }
1275
1276         return False;
1277 }
1278
1279 /* Parse a string of the form DOMAIN\user into a domain and a user */
1280
1281 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1282 {
1283         char *p = strchr(domuser,*lp_winbind_separator());
1284
1285         if ( !p ) {
1286                 fstrcpy(user, domuser);
1287                 p = strchr(domuser, '@');
1288
1289                 if ( assume_domain(lp_workgroup()) && p == NULL) {
1290                         fstrcpy(domain, lp_workgroup());
1291                 } else if (p != NULL) {
1292                         fstrcpy(domain, p + 1);
1293                         user[PTR_DIFF(p, domuser)] = 0;
1294                 } else {
1295                         return False;
1296                 }
1297         } else {
1298                 fstrcpy(user, p+1);
1299                 fstrcpy(domain, domuser);
1300                 domain[PTR_DIFF(p, domuser)] = 0;
1301         }
1302
1303         return strupper_m(domain);
1304 }
1305
1306 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1307                               char **domain, char **user)
1308 {
1309         fstring fstr_domain, fstr_user;
1310         if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1311                 return False;
1312         }
1313         *domain = talloc_strdup(mem_ctx, fstr_domain);
1314         *user = talloc_strdup(mem_ctx, fstr_user);
1315         return ((*domain != NULL) && (*user != NULL));
1316 }
1317
1318 /* Ensure an incoming username from NSS is fully qualified. Replace the
1319    incoming fstring with DOMAIN <separator> user. Returns the same
1320    values as parse_domain_user() but also replaces the incoming username.
1321    Used to ensure all names are fully qualified within winbindd.
1322    Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1323    The protocol definitions of auth_crap, chng_pswd_auth_crap
1324    really should be changed to use this instead of doing things
1325    by hand. JRA. */
1326
1327 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1328 {
1329         if (!parse_domain_user(username_inout, domain, user)) {
1330                 return False;
1331         }
1332         slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1333                  domain, *lp_winbind_separator(),
1334                  user);
1335         return True;
1336 }
1337
1338 /*
1339     Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1340     'winbind separator' options.
1341     This means:
1342         - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1343         lp_workgroup()
1344
1345     If we are a PDC or BDC, and this is for our domain, do likewise.
1346
1347     On an AD DC we always fill DOMAIN\\USERNAME.
1348
1349     We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1350 */
1351 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1352 {
1353         fstring tmp_user;
1354
1355         if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1356                 can_assume = false;
1357         }
1358
1359         fstrcpy(tmp_user, user);
1360         (void)strlower_m(tmp_user);
1361
1362         if (can_assume && assume_domain(domain)) {
1363                 strlcpy(name, tmp_user, sizeof(fstring));
1364         } else {
1365                 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1366                          domain, *lp_winbind_separator(),
1367                          tmp_user);
1368         }
1369 }
1370
1371 /**
1372  * talloc version of fill_domain_username()
1373  * return NULL on talloc failure.
1374  */
1375 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1376                                   const char *domain,
1377                                   const char *user,
1378                                   bool can_assume)
1379 {
1380         char *tmp_user, *name;
1381
1382         if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1383                 can_assume = false;
1384         }
1385
1386         tmp_user = talloc_strdup(mem_ctx, user);
1387         if (!strlower_m(tmp_user)) {
1388                 TALLOC_FREE(tmp_user);
1389                 return NULL;
1390         }
1391
1392         if (can_assume && assume_domain(domain)) {
1393                 name = tmp_user;
1394         } else {
1395                 name = talloc_asprintf(mem_ctx, "%s%c%s",
1396                                        domain,
1397                                        *lp_winbind_separator(),
1398                                        tmp_user);
1399                 TALLOC_FREE(tmp_user);
1400         }
1401
1402         return name;
1403 }
1404
1405 /*
1406  * Client list accessor functions
1407  */
1408
1409 static struct winbindd_cli_state *_client_list;
1410 static int _num_clients;
1411
1412 /* Return list of all connected clients */
1413
1414 struct winbindd_cli_state *winbindd_client_list(void)
1415 {
1416         return _client_list;
1417 }
1418
1419 /* Return list-tail of all connected clients */
1420
1421 struct winbindd_cli_state *winbindd_client_list_tail(void)
1422 {
1423         return DLIST_TAIL(_client_list);
1424 }
1425
1426 /* Return previous (read:newer) client in list */
1427
1428 struct winbindd_cli_state *
1429 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1430 {
1431         return DLIST_PREV(cli);
1432 }
1433
1434 /* Add a connection to the list */
1435
1436 void winbindd_add_client(struct winbindd_cli_state *cli)
1437 {
1438         cli->last_access = time(NULL);
1439         DLIST_ADD(_client_list, cli);
1440         _num_clients++;
1441 }
1442
1443 /* Remove a client from the list */
1444
1445 void winbindd_remove_client(struct winbindd_cli_state *cli)
1446 {
1447         DLIST_REMOVE(_client_list, cli);
1448         _num_clients--;
1449 }
1450
1451 /* Move a client to head or list */
1452
1453 void winbindd_promote_client(struct winbindd_cli_state *cli)
1454 {
1455         cli->last_access = time(NULL);
1456         DLIST_PROMOTE(_client_list, cli);
1457 }
1458
1459 /* Return number of open clients */
1460
1461 int winbindd_num_clients(void)
1462 {
1463         return _num_clients;
1464 }
1465
1466 NTSTATUS lookup_usergroups_cached(TALLOC_CTX *mem_ctx,
1467                                   const struct dom_sid *user_sid,
1468                                   uint32_t *p_num_groups, struct dom_sid **user_sids)
1469 {
1470         struct netr_SamInfo3 *info3 = NULL;
1471         NTSTATUS status = NT_STATUS_NO_MEMORY;
1472         uint32_t num_groups = 0;
1473
1474         DEBUG(3,(": lookup_usergroups_cached\n"));
1475
1476         *user_sids = NULL;
1477         *p_num_groups = 0;
1478
1479         info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1480
1481         if (info3 == NULL) {
1482                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1483         }
1484
1485         /*
1486          * Before bug #7843 the "Domain Local" groups were added with a
1487          * lookupuseraliases call, but this isn't done anymore for our domain
1488          * so we need to resolve resource groups here.
1489          *
1490          * When to use Resource Groups:
1491          * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1492          */
1493         status = sid_array_from_info3(mem_ctx, info3,
1494                                       user_sids,
1495                                       &num_groups,
1496                                       false);
1497
1498         if (!NT_STATUS_IS_OK(status)) {
1499                 TALLOC_FREE(info3);
1500                 return status;
1501         }
1502
1503         TALLOC_FREE(info3);
1504         *p_num_groups = num_groups;
1505         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1506
1507         DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1508
1509         return status;
1510 }
1511
1512 /*********************************************************************
1513  We use this to remove spaces from user and group names
1514 ********************************************************************/
1515
1516 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1517                              const char *domain_name,
1518                              const char *name,
1519                              char **normalized)
1520 {
1521         struct winbindd_domain *domain = NULL;
1522         NTSTATUS nt_status;
1523
1524         if (!name || !normalized) {
1525                 return NT_STATUS_INVALID_PARAMETER;
1526         }
1527
1528         if (!lp_winbind_normalize_names()) {
1529                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1530         }
1531
1532         domain = find_domain_from_name_noinit(domain_name);
1533         if (domain == NULL) {
1534                 DBG_ERR("Failed to find domain '%s'\n", domain_name);
1535                 return NT_STATUS_NO_SUCH_DOMAIN;
1536         }
1537
1538         /* Alias support and whitespace replacement are mutually
1539            exclusive */
1540
1541         nt_status = resolve_username_to_alias(mem_ctx, domain,
1542                                               name, normalized );
1543         if (NT_STATUS_IS_OK(nt_status)) {
1544                 /* special return code to let the caller know we
1545                    mapped to an alias */
1546                 return NT_STATUS_FILE_RENAMED;
1547         }
1548
1549         /* check for an unreachable domain */
1550
1551         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1552                 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1553                          domain->name));
1554                 set_domain_offline(domain);
1555                 return nt_status;
1556         }
1557
1558         /* deal with whitespace */
1559
1560         *normalized = talloc_strdup(mem_ctx, name);
1561         if (!(*normalized)) {
1562                 return NT_STATUS_NO_MEMORY;
1563         }
1564
1565         all_string_sub( *normalized, " ", "_", 0 );
1566
1567         return NT_STATUS_OK;
1568 }
1569
1570 /*********************************************************************
1571  We use this to do the inverse of normalize_name_map()
1572 ********************************************************************/
1573
1574 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1575                               char *name,
1576                               char **normalized)
1577 {
1578         NTSTATUS nt_status;
1579         struct winbindd_domain *domain = find_our_domain();
1580
1581         if (!name || !normalized) {
1582                 return NT_STATUS_INVALID_PARAMETER;
1583         }
1584
1585         if (!lp_winbind_normalize_names()) {
1586                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1587         }
1588
1589         /* Alias support and whitespace replacement are mutally
1590            exclusive */
1591
1592         /* When mapping from an alias to a username, we don't know the
1593            domain.  But we only need a domain structure to cache
1594            a successful lookup , so just our own domain structure for
1595            the seqnum. */
1596
1597         nt_status = resolve_alias_to_username(mem_ctx, domain,
1598                                               name, normalized);
1599         if (NT_STATUS_IS_OK(nt_status)) {
1600                 /* Special return code to let the caller know we mapped
1601                    from an alias */
1602                 return NT_STATUS_FILE_RENAMED;
1603         }
1604
1605         /* check for an unreachable domain */
1606
1607         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1608                 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1609                          domain->name));
1610                 set_domain_offline(domain);
1611                 return nt_status;
1612         }
1613
1614         /* deal with whitespace */
1615
1616         *normalized = talloc_strdup(mem_ctx, name);
1617         if (!(*normalized)) {
1618                 return NT_STATUS_NO_MEMORY;
1619         }
1620
1621         all_string_sub(*normalized, "_", " ", 0);
1622
1623         return NT_STATUS_OK;
1624 }
1625
1626 /*********************************************************************
1627  ********************************************************************/
1628
1629 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1630 {
1631         struct winbindd_tdc_domain *tdc = NULL;
1632         TALLOC_CTX *frame = talloc_stackframe();
1633         bool ret = false;
1634
1635         /* We can contact the domain if it is our primary domain */
1636
1637         if (domain->primary) {
1638                 ret = true;
1639                 goto done;
1640         }
1641
1642         /* Trust the TDC cache and not the winbindd_domain flags */
1643
1644         if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1645                 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1646                           domain->name));
1647                 ret = false;
1648                 goto done;
1649         }
1650
1651         /* Can always contact a domain that is in out forest */
1652
1653         if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1654                 ret = true;
1655                 goto done;
1656         }
1657
1658         /*
1659          * On a _member_ server, we cannot contact the domain if it
1660          * is running AD and we have no inbound trust.
1661          */
1662
1663         if (!IS_DC &&
1664              domain->active_directory &&
1665             ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1666         {
1667                 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1668                            "and we have no inbound trust.\n", domain->name));
1669                 goto done;
1670         }
1671
1672         /* Assume everything else is ok (probably not true but what
1673            can you do?) */
1674
1675         ret = true;
1676
1677 done:
1678         talloc_destroy(frame);
1679
1680         return ret;
1681 }
1682
1683 /*********************************************************************
1684  ********************************************************************/
1685
1686 bool winbindd_internal_child(struct winbindd_child *child)
1687 {
1688         if ((child == idmap_child()) || (child == locator_child())) {
1689                 return True;
1690         }
1691
1692         return False;
1693 }
1694
1695 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1696
1697 /*********************************************************************
1698  ********************************************************************/
1699
1700 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1701 {
1702         char *var = NULL;
1703         char addr[INET6_ADDRSTRLEN];
1704         const char *kdc = NULL;
1705         int lvl = 11;
1706
1707         if (!domain || !domain->alt_name || !*domain->alt_name) {
1708                 return;
1709         }
1710
1711         if (domain->initialized && !domain->active_directory) {
1712                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1713                         domain->alt_name));
1714                 return;
1715         }
1716
1717         print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1718         kdc = addr;
1719         if (!*kdc) {
1720                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1721                         domain->alt_name));
1722                 kdc = domain->dcname;
1723         }
1724
1725         if (!kdc || !*kdc) {
1726                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1727                         domain->alt_name));
1728                 return;
1729         }
1730
1731         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1732                                 domain->alt_name) == -1) {
1733                 return;
1734         }
1735
1736         DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1737                 var, kdc));
1738
1739         setenv(var, kdc, 1);
1740         free(var);
1741 }
1742
1743 /*********************************************************************
1744  ********************************************************************/
1745
1746 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1747 {
1748         struct winbindd_domain *our_dom = find_our_domain();
1749
1750         winbindd_set_locator_kdc_env(domain);
1751
1752         if (domain != our_dom) {
1753                 winbindd_set_locator_kdc_env(our_dom);
1754         }
1755 }
1756
1757 /*********************************************************************
1758  ********************************************************************/
1759
1760 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1761 {
1762         char *var = NULL;
1763
1764         if (!domain || !domain->alt_name || !*domain->alt_name) {
1765                 return;
1766         }
1767
1768         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1769                                 domain->alt_name) == -1) {
1770                 return;
1771         }
1772
1773         unsetenv(var);
1774         free(var);
1775 }
1776 #else
1777
1778 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1779 {
1780         return;
1781 }
1782
1783 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1784 {
1785         return;
1786 }
1787
1788 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1789
1790 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1791 {
1792         resp->data.auth.nt_status = NT_STATUS_V(result);
1793         fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1794
1795         /* we might have given a more useful error above */
1796         if (*resp->data.auth.error_string == '\0')
1797                 fstrcpy(resp->data.auth.error_string,
1798                         get_friendly_nt_error_msg(result));
1799         resp->data.auth.pam_error = nt_status_to_pam(result);
1800 }
1801
1802 bool is_domain_offline(const struct winbindd_domain *domain)
1803 {
1804         if (get_global_winbindd_state_offline()) {
1805                 return true;
1806         }
1807         return !domain->online;
1808 }
1809
1810 bool is_domain_online(const struct winbindd_domain *domain)
1811 {
1812         return !is_domain_offline(domain);
1813 }
1814
1815 /**
1816  * Parse an char array into a list of sids.
1817  *
1818  * The input sidstr should consist of 0-terminated strings
1819  * representing sids, separated by newline characters '\n'.
1820  * The list is terminated by an empty string, i.e.
1821  * character '\0' directly following a character '\n'
1822  * (or '\0' right at the start of sidstr).
1823  */
1824 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
1825                    struct dom_sid **sids, uint32_t *num_sids)
1826 {
1827         const char *p;
1828
1829         p = sidstr;
1830         if (p == NULL)
1831                 return False;
1832
1833         while (p[0] != '\0') {
1834                 struct dom_sid sid;
1835                 const char *q = NULL;
1836
1837                 if (!dom_sid_parse_endp(p, &sid, &q)) {
1838                         DEBUG(1, ("Could not parse sid %s\n", p));
1839                         return false;
1840                 }
1841                 if (q[0] != '\n') {
1842                         DEBUG(1, ("Got invalid sidstr: %s\n", p));
1843                         return false;
1844                 }
1845                 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
1846                                                       num_sids)))
1847                 {
1848                         return False;
1849                 }
1850                 p = q+1;
1851         }
1852         return True;
1853 }
1854
1855 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
1856                    struct unixid **pxids, uint32_t *pnum_xids)
1857 {
1858         const char *p;
1859         struct unixid *xids = NULL;
1860         uint32_t num_xids = 0;
1861
1862         p = xidstr;
1863         if (p == NULL) {
1864                 return false;
1865         }
1866
1867         while (p[0] != '\0') {
1868                 struct unixid *tmp;
1869                 struct unixid xid;
1870                 unsigned long long id;
1871                 char *endp;
1872
1873                 switch (p[0]) {
1874                 case 'U':
1875                         xid = (struct unixid) { .type = ID_TYPE_UID };
1876                         break;
1877                 case 'G':
1878                         xid = (struct unixid) { .type = ID_TYPE_GID };
1879                         break;
1880                 default:
1881                         return false;
1882                 }
1883
1884                 p += 1;
1885
1886                 id = strtoull(p, &endp, 10);
1887                 if ((id == ULLONG_MAX) && (errno == ERANGE)) {
1888                         goto fail;
1889                 }
1890                 if (*endp != '\n') {
1891                         goto fail;
1892                 }
1893                 p = endp+1;
1894
1895                 xid.id = id;
1896                 if ((unsigned long long)xid.id != id) {
1897                         goto fail;
1898                 }
1899
1900                 tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
1901                 if (tmp == NULL) {
1902                         return 0;
1903                 }
1904                 xids = tmp;
1905
1906                 xids[num_xids] = xid;
1907                 num_xids += 1;
1908         }
1909
1910         *pxids = xids;
1911         *pnum_xids = num_xids;
1912         return true;
1913
1914 fail:
1915         TALLOC_FREE(xids);
1916         return false;
1917 }