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