winbind: dom_sid_parse_endp always initializes "endp" when ok
[samba.git] / source3 / winbindd / winbindd_util.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Winbind daemon for ntdom nss module
5
6    Copyright (C) Tim Potter 2000-2001
7    Copyright (C) 2001 by Martin Pool <mbp@samba.org>
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "winbindd.h"
25 #include "secrets.h"
26 #include "../libcli/security/security.h"
27 #include "../libcli/auth/pam_errors.h"
28 #include "passdb/machine_sid.h"
29 #include "passdb.h"
30 #include "source4/lib/messaging/messaging.h"
31 #include "librpc/gen_ndr/ndr_lsa.h"
32 #include "auth/credentials/credentials.h"
33 #include "libsmb/samlogon_cache.h"
34
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_WINBIND
37
38 static struct winbindd_domain *
39 add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc);
40
41 /**
42  * @file winbindd_util.c
43  *
44  * Winbind daemon for NT domain authentication nss module.
45  **/
46
47
48 /* The list of trusted domains.  Note that the list can be deleted and
49    recreated using the init_domain_list() function so pointers to
50    individual winbindd_domain structures cannot be made.  Keep a copy of
51    the domain name instead. */
52
53 static struct winbindd_domain *_domain_list = NULL;
54
55 struct winbindd_domain *domain_list(void)
56 {
57         /* Initialise list */
58
59         if ((!_domain_list) && (!init_domain_list())) {
60                 smb_panic("Init_domain_list failed");
61         }
62
63         return _domain_list;
64 }
65
66 /* Free all entries in the trusted domain list */
67
68 static void free_domain_list(void)
69 {
70         struct winbindd_domain *domain = _domain_list;
71
72         while(domain) {
73                 struct winbindd_domain *next = domain->next;
74
75                 DLIST_REMOVE(_domain_list, domain);
76                 TALLOC_FREE(domain);
77                 domain = next;
78         }
79 }
80
81 /**
82  * Iterator for winbindd's domain list.
83  * To be used (e.g.) in tevent based loops.
84  */
85 struct winbindd_domain *wb_next_domain(struct winbindd_domain *domain)
86 {
87         if (domain == NULL) {
88                 domain = domain_list();
89         } else {
90                 domain = domain->next;
91         }
92
93         if ((domain != NULL) &&
94             (lp_server_role() != ROLE_ACTIVE_DIRECTORY_DC) &&
95             sid_check_is_our_sam(&domain->sid))
96         {
97                 domain = domain->next;
98         }
99
100         return domain;
101 }
102
103 static bool is_internal_domain(const struct dom_sid *sid)
104 {
105         if (sid == NULL)
106                 return False;
107
108         return (sid_check_is_our_sam(sid) || sid_check_is_builtin(sid));
109 }
110
111 static bool is_in_internal_domain(const struct dom_sid *sid)
112 {
113         if (sid == NULL)
114                 return False;
115
116         return (sid_check_is_in_our_sam(sid) || sid_check_is_in_builtin(sid));
117 }
118
119
120 /* Add a trusted domain to our list of domains.
121    If the domain already exists in the list,
122    return it and don't re-initialize.  */
123
124 static struct winbindd_domain *
125 add_trusted_domain(const char *domain_name, const char *alt_name,
126                    const struct dom_sid *sid)
127 {
128         struct winbindd_tdc_domain tdc;
129
130         ZERO_STRUCT(tdc);
131
132         tdc.domain_name = domain_name;
133         tdc.dns_name = alt_name;
134         if (sid) {
135                 sid_copy(&tdc.sid, sid);
136         }
137
138         return add_trusted_domain_from_tdc(&tdc);
139 }
140
141 /* Add a trusted domain out of a trusted domain cache
142    entry
143 */
144 static struct winbindd_domain *
145 add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
146 {
147         struct winbindd_domain *domain;
148         const char *alternative_name = NULL;
149         const char **ignored_domains, **dom;
150         int role = lp_server_role();
151         const char *domain_name = tdc->domain_name;
152         const struct dom_sid *sid = &tdc->sid;
153
154         if (is_null_sid(sid)) {
155                 sid = NULL;
156         }
157
158         ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
159         for (dom=ignored_domains; dom && *dom; dom++) {
160                 if (gen_fnmatch(*dom, domain_name) == 0) {
161                         DEBUG(2,("Ignoring domain '%s'\n", domain_name));
162                         return NULL;
163                 }
164         }
165
166         /* use alt_name if available to allow DNS lookups */
167
168         if (tdc->dns_name && *tdc->dns_name) {
169                 alternative_name = tdc->dns_name;
170         }
171
172         /* We can't call domain_list() as this function is called from
173            init_domain_list() and we'll get stuck in a loop. */
174         for (domain = _domain_list; domain; domain = domain->next) {
175                 if (strequal(domain_name, domain->name) ||
176                     strequal(domain_name, domain->alt_name))
177                 {
178                         break;
179                 }
180
181                 if (alternative_name) {
182                         if (strequal(alternative_name, domain->name) ||
183                             strequal(alternative_name, domain->alt_name))
184                         {
185                                 break;
186                         }
187                 }
188
189                 if (sid != NULL) {
190                         if (dom_sid_equal(sid, &domain->sid)) {
191                                 break;
192                         }
193                 }
194         }
195
196         if (domain != NULL) {
197                 /*
198                  * We found a match on domain->name or
199                  * domain->alt_name. Possibly update the SID
200                  * if the stored SID was the NULL SID
201                  * and return the matching entry.
202                  */
203                 if ((sid != NULL)
204                     && dom_sid_equal(&domain->sid, &global_sid_NULL)) {
205                         sid_copy( &domain->sid, sid );
206                 }
207                 return domain;
208         }
209
210         /* Create new domain entry */
211         domain = talloc_zero(NULL, struct winbindd_domain);
212         if (domain == NULL) {
213                 return NULL;
214         }
215
216         domain->children = talloc_zero_array(domain,
217                                              struct winbindd_child,
218                                              lp_winbind_max_domain_connections());
219         if (domain->children == NULL) {
220                 TALLOC_FREE(domain);
221                 return NULL;
222         }
223
224         domain->name = talloc_strdup(domain, domain_name);
225         if (domain->name == NULL) {
226                 TALLOC_FREE(domain);
227                 return NULL;
228         }
229
230         if (alternative_name) {
231                 domain->alt_name = talloc_strdup(domain, alternative_name);
232                 if (domain->alt_name == NULL) {
233                         TALLOC_FREE(domain);
234                         return NULL;
235                 }
236         }
237
238         domain->backend = NULL;
239         domain->internal = is_internal_domain(sid);
240         domain->sequence_number = DOM_SEQUENCE_NONE;
241         domain->last_seq_check = 0;
242         domain->initialized = false;
243         domain->online = is_internal_domain(sid);
244         domain->check_online_timeout = 0;
245         domain->dc_probe_pid = (pid_t)-1;
246         if (sid != NULL) {
247                 sid_copy(&domain->sid, sid);
248         }
249         domain->domain_flags = tdc->trust_flags;
250         domain->domain_type = tdc->trust_type;
251         domain->domain_trust_attribs = tdc->trust_attribs;
252
253         /* Is this our primary domain ? */
254         if (strequal(domain_name, get_global_sam_name()) &&
255                         (role != ROLE_DOMAIN_MEMBER)) {
256                 domain->primary = true;
257         } else if (strequal(domain_name, lp_workgroup()) &&
258                         (role == ROLE_DOMAIN_MEMBER)) {
259                 domain->primary = true;
260         }
261
262         if (domain->primary) {
263                 if (role == ROLE_ACTIVE_DIRECTORY_DC) {
264                         domain->active_directory = true;
265                 }
266                 if (lp_security() == SEC_ADS) {
267                         domain->active_directory = true;
268                 }
269         } else if (!domain->internal) {
270                 if (domain->domain_type == LSA_TRUST_TYPE_UPLEVEL) {
271                         domain->active_directory = true;
272                 }
273         }
274
275         /* Link to domain list */
276         DLIST_ADD_END(_domain_list, domain);
277
278         wcache_tdc_add_domain( domain );
279
280         setup_domain_child(domain);
281
282         DEBUG(2,
283               ("Added domain %s %s %s\n", domain->name, domain->alt_name,
284                !is_null_sid(&domain->sid) ? sid_string_dbg(&domain->sid) : ""));
285
286         return domain;
287 }
288
289 bool domain_is_forest_root(const struct winbindd_domain *domain)
290 {
291         const uint32_t fr_flags =
292                 (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
293
294         return ((domain->domain_flags & fr_flags) == fr_flags);
295 }
296
297 /********************************************************************
298   rescan our domains looking for new trusted domains
299 ********************************************************************/
300
301 struct trustdom_state {
302         struct winbindd_domain *domain;
303         struct winbindd_request request;
304 };
305
306 static void trustdom_list_done(struct tevent_req *req);
307 static void rescan_forest_root_trusts( void );
308 static void rescan_forest_trusts( void );
309
310 static void add_trusted_domains( struct winbindd_domain *domain )
311 {
312         struct trustdom_state *state;
313         struct tevent_req *req;
314
315         state = talloc_zero(NULL, struct trustdom_state);
316         if (state == NULL) {
317                 DEBUG(0, ("talloc failed\n"));
318                 return;
319         }
320         state->domain = domain;
321
322         state->request.length = sizeof(state->request);
323         state->request.cmd = WINBINDD_LIST_TRUSTDOM;
324
325         req = wb_domain_request_send(state, winbind_event_context(),
326                                      domain, &state->request);
327         if (req == NULL) {
328                 DEBUG(1, ("wb_domain_request_send failed\n"));
329                 TALLOC_FREE(state);
330                 return;
331         }
332         tevent_req_set_callback(req, trustdom_list_done, state);
333 }
334
335 static void trustdom_list_done(struct tevent_req *req)
336 {
337         struct trustdom_state *state = tevent_req_callback_data(
338                 req, struct trustdom_state);
339         struct winbindd_response *response;
340         int res, err;
341         char *p;
342         struct winbindd_tdc_domain trust_params = {0};
343         ptrdiff_t extra_len;
344
345         res = wb_domain_request_recv(req, state, &response, &err);
346         if ((res == -1) || (response->result != WINBINDD_OK)) {
347                 DBG_WARNING("Could not receive trusts for domain %s\n",
348                             state->domain->name);
349                 TALLOC_FREE(state);
350                 return;
351         }
352
353         if (response->length < sizeof(struct winbindd_response)) {
354                 DBG_ERR("ill-formed trustdom response - short length\n");
355                 TALLOC_FREE(state);
356                 return;
357         }
358
359         extra_len = response->length - sizeof(struct winbindd_response);
360
361         p = (char *)response->extra_data.data;
362
363         while ((p - (char *)response->extra_data.data) < extra_len) {
364                 char *q, *sidstr, *alt_name;
365
366                 DBG_DEBUG("parsing response line '%s'\n", p);
367
368                 ZERO_STRUCT(trust_params);
369                 trust_params.domain_name = p;
370
371                 alt_name = strchr(p, '\\');
372                 if (alt_name == NULL) {
373                         DBG_ERR("Got invalid trustdom response\n");
374                         break;
375                 }
376
377                 *alt_name = '\0';
378                 alt_name += 1;
379
380                 sidstr = strchr(alt_name, '\\');
381                 if (sidstr == NULL) {
382                         DBG_ERR("Got invalid trustdom response\n");
383                         break;
384                 }
385
386                 *sidstr = '\0';
387                 sidstr += 1;
388
389                 /* use the real alt_name if we have one, else pass in NULL */
390                 if (!strequal(alt_name, "(null)")) {
391                         trust_params.dns_name = alt_name;
392                 }
393
394                 q = strtok(sidstr, "\\");
395                 if (q == NULL) {
396                         DBG_ERR("Got invalid trustdom response\n");
397                         break;
398                 }
399
400                 if (!string_to_sid(&trust_params.sid, sidstr)) {
401                         DEBUG(0, ("Got invalid trustdom response\n"));
402                         break;
403                 }
404
405                 q = strtok(NULL, "\\");
406                 if (q == NULL) {
407                         DBG_ERR("Got invalid trustdom response\n");
408                         break;
409                 }
410
411                 trust_params.trust_flags = (uint32_t)strtoul(q, NULL, 10);
412
413                 q = strtok(NULL, "\\");
414                 if (q == NULL) {
415                         DBG_ERR("Got invalid trustdom response\n");
416                         break;
417                 }
418
419                 trust_params.trust_type = (uint32_t)strtoul(q, NULL, 10);
420
421                 q = strtok(NULL, "\n");
422                 if (q == NULL) {
423                         DBG_ERR("Got invalid trustdom response\n");
424                         break;
425                 }
426
427                 trust_params.trust_attribs = (uint32_t)strtoul(q, NULL, 10);
428
429                 /*
430                  * We always call add_trusted_domain() cause on an existing
431                  * domain structure, it will update the SID if necessary.
432                  * This is important because we need the SID for sibling
433                  * domains.
434                  */
435                 (void)add_trusted_domain_from_tdc(&trust_params);
436
437                 p = q + strlen(q) + 1;
438         }
439
440         /*
441            Cases to consider when scanning trusts:
442            (a) we are calling from a child domain (primary && !forest_root)
443            (b) we are calling from the root of the forest (primary && forest_root)
444            (c) we are calling from a trusted forest domain (!primary
445                && !forest_root)
446         */
447
448         if (state->domain->primary) {
449                 /* If this is our primary domain and we are not in the
450                    forest root, we have to scan the root trusts first */
451
452                 if (!domain_is_forest_root(state->domain))
453                         rescan_forest_root_trusts();
454                 else
455                         rescan_forest_trusts();
456
457         } else if (domain_is_forest_root(state->domain)) {
458                 /* Once we have done root forest trust search, we can
459                    go on to search the trusted forests */
460
461                 rescan_forest_trusts();
462         }
463
464         TALLOC_FREE(state);
465
466         return;
467 }
468
469 /********************************************************************
470  Scan the trusts of our forest root
471 ********************************************************************/
472
473 static void rescan_forest_root_trusts( void )
474 {
475         struct winbindd_tdc_domain *dom_list = NULL;
476         size_t num_trusts = 0;
477         int i;
478
479         /* The only transitive trusts supported by Windows 2003 AD are
480            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
481            first two are handled in forest and listed by
482            DsEnumerateDomainTrusts().  Forest trusts are not so we
483            have to do that ourselves. */
484
485         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
486                 return;
487
488         for ( i=0; i<num_trusts; i++ ) {
489                 struct winbindd_domain *d = NULL;
490
491                 /* Find the forest root.  Don't necessarily trust
492                    the domain_list() as our primary domain may not
493                    have been initialized. */
494
495                 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
496                         continue;
497                 }
498
499                 /* Here's the forest root */
500
501                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
502
503                 if ( !d ) {
504                         d = add_trusted_domain_from_tdc(&dom_list[i]);
505                 }
506
507                 if (d == NULL) {
508                         continue;
509                 }
510
511                 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
512                           "for domain tree root %s (%s)\n",
513                           d->name, d->alt_name ));
514
515                 d->domain_flags = dom_list[i].trust_flags;
516                 d->domain_type  = dom_list[i].trust_type;
517                 d->domain_trust_attribs = dom_list[i].trust_attribs;
518
519                 add_trusted_domains( d );
520
521                 break;
522         }
523
524         TALLOC_FREE( dom_list );
525
526         return;
527 }
528
529 /********************************************************************
530  scan the transitive forest trusts (not our own)
531 ********************************************************************/
532
533
534 static void rescan_forest_trusts( void )
535 {
536         struct winbindd_domain *d = NULL;
537         struct winbindd_tdc_domain *dom_list = NULL;
538         size_t num_trusts = 0;
539         int i;
540
541         /* The only transitive trusts supported by Windows 2003 AD are
542            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
543            first two are handled in forest and listed by
544            DsEnumerateDomainTrusts().  Forest trusts are not so we
545            have to do that ourselves. */
546
547         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
548                 return;
549
550         for ( i=0; i<num_trusts; i++ ) {
551                 uint32_t flags   = dom_list[i].trust_flags;
552                 uint32_t type    = dom_list[i].trust_type;
553                 uint32_t attribs = dom_list[i].trust_attribs;
554
555                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
556
557                 /* ignore our primary and internal domains */
558
559                 if ( d && (d->internal || d->primary ) )
560                         continue;
561
562                 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
563                      (type == LSA_TRUST_TYPE_UPLEVEL) &&
564                      (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
565                 {
566                         /* add the trusted domain if we don't know
567                            about it */
568
569                         if ( !d ) {
570                                 d = add_trusted_domain_from_tdc(&dom_list[i]);
571                         }
572
573                         if (d == NULL) {
574                                 continue;
575                         }
576
577                         DEBUG(10,("Following trust path for domain %s (%s)\n",
578                                   d->name, d->alt_name ));
579                         add_trusted_domains( d );
580                 }
581         }
582
583         TALLOC_FREE( dom_list );
584
585         return;
586 }
587
588 /*********************************************************************
589  The process of updating the trusted domain list is a three step
590  async process:
591  (a) ask our domain
592  (b) ask the root domain in our forest
593  (c) ask the a DC in any Win2003 trusted forests
594 *********************************************************************/
595
596 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
597                             struct timeval now, void *private_data)
598 {
599         TALLOC_FREE(te);
600
601         /* I use to clear the cache here and start over but that
602            caused problems in child processes that needed the
603            trust dom list early on.  Removing it means we
604            could have some trusted domains listed that have been
605            removed from our primary domain's DC until a full
606            restart.  This should be ok since I think this is what
607            Windows does as well. */
608
609         /* this will only add new domains we didn't already know about
610            in the domain_list()*/
611
612         add_trusted_domains( find_our_domain() );
613
614         te = tevent_add_timer(
615                 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
616                 rescan_trusted_domains, NULL);
617         /*
618          * If te == NULL, there's not much we can do here. Don't fail, the
619          * only thing we miss is new trusted domains.
620          */
621
622         return;
623 }
624
625 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
626                                                    struct winbindd_cli_state *state)
627 {
628         /* Ensure null termination */
629         state->request->domain_name
630                 [sizeof(state->request->domain_name)-1]='\0';
631         state->request->data.init_conn.dcname
632                 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
633
634         if (strlen(state->request->data.init_conn.dcname) > 0) {
635                 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
636         }
637
638         init_dc_connection(domain, false);
639
640         if (!domain->initialized) {
641                 /* If we return error here we can't do any cached authentication,
642                    but we may be in disconnected mode and can't initialize correctly.
643                    Do what the previous code did and just return without initialization,
644                    once we go online we'll re-initialize.
645                 */
646                 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
647                         "online = %d\n", domain->name, (int)domain->online ));
648         }
649
650         fstrcpy(state->response->data.domain_info.name, domain->name);
651         fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
652         sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
653
654         state->response->data.domain_info.native_mode
655                 = domain->native_mode;
656         state->response->data.domain_info.active_directory
657                 = domain->active_directory;
658         state->response->data.domain_info.primary
659                 = domain->primary;
660
661         return WINBINDD_OK;
662 }
663
664 static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
665                                        void *private_data,
666                                        uint32_t msg_type,
667                                        struct server_id server_id,
668                                        DATA_BLOB *data)
669 {
670         TALLOC_CTX *frame = talloc_stackframe();
671         struct lsa_TrustDomainInfoInfoEx info;
672         enum ndr_err_code ndr_err;
673         struct winbindd_domain *d = NULL;
674
675         DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
676
677         if (data == NULL) {
678                 TALLOC_FREE(frame);
679                 return;
680         }
681
682         ndr_err = ndr_pull_struct_blob_all(data, frame, &info,
683                         (ndr_pull_flags_fn_t)ndr_pull_lsa_TrustDomainInfoInfoEx);
684         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
685                 TALLOC_FREE(frame);
686                 return;
687         }
688
689         d = find_domain_from_name_noinit(info.netbios_name.string);
690         if (d != NULL) {
691                 TALLOC_FREE(frame);
692                 return;
693         }
694
695         d = add_trusted_domain(info.netbios_name.string,
696                                info.domain_name.string,
697                                info.sid);
698         if (d == NULL) {
699                 TALLOC_FREE(frame);
700                 return;
701         }
702
703         if (d->internal) {
704                 TALLOC_FREE(frame);
705                 return;
706         }
707
708         if (d->primary) {
709                 TALLOC_FREE(frame);
710                 return;
711         }
712
713         if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
714                 d->domain_flags |= NETR_TRUST_FLAG_INBOUND;
715         }
716         if (info.trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
717                 d->domain_flags |= NETR_TRUST_FLAG_OUTBOUND;
718         }
719         if (info.trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
720                 d->domain_flags |= NETR_TRUST_FLAG_IN_FOREST;
721         }
722         d->domain_type = info.trust_type;
723         d->domain_trust_attribs = info.trust_attributes;
724
725         TALLOC_FREE(frame);
726 }
727
728 /*
729  * We did not get the secret when we queried secrets.tdb, so read it
730  * from secrets.tdb and re-sync the databases
731  */
732 static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
733 {
734         bool ok;
735         struct cli_credentials *creds;
736         NTSTATUS can_migrate = pdb_get_trust_credentials(domain->name,
737                                                          NULL, domain, &creds);
738         if (!NT_STATUS_IS_OK(can_migrate)) {
739                 DEBUG(0, ("Failed to fetch our own, local AD domain join "
740                         "password for winbindd's internal use, both from "
741                         "secrets.tdb and secrets.ldb: %s\n",
742                         nt_errstr(can_migrate)));
743                 return false;
744         }
745
746         /*
747          * NOTE: It is very unlikely we end up here if there is an
748          * oldpass, because a new password is created at
749          * classicupgrade, so this is not a concern.
750          */
751         ok = secrets_store_machine_pw_sync(cli_credentials_get_password(creds),
752                    NULL /* oldpass */,
753                    cli_credentials_get_domain(creds),
754                    cli_credentials_get_realm(creds),
755                    cli_credentials_get_salt_principal(creds),
756                    0, /* Supported enc types, unused */
757                    &domain->sid,
758                    cli_credentials_get_password_last_changed_time(creds),
759                    cli_credentials_get_secure_channel_type(creds),
760                    false /* do_delete: Do not delete */);
761         TALLOC_FREE(creds);
762         if (ok == false) {
763                 DEBUG(0, ("Failed to write our our own, "
764                           "local AD domain join password for "
765                           "winbindd's internal use into secrets.tdb\n"));
766                 return false;
767         }
768         return true;
769 }
770
771 /* Look up global info for the winbind daemon */
772 bool init_domain_list(void)
773 {
774         int role = lp_server_role();
775         NTSTATUS status;
776
777         /* Free existing list */
778         free_domain_list();
779
780         /* BUILTIN domain */
781
782         (void)add_trusted_domain("BUILTIN", NULL, &global_sid_Builtin);
783
784         /* Local SAM */
785
786         if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
787                 struct winbindd_domain *domain;
788                 enum netr_SchannelType sec_chan_type;
789                 const char *account_name;
790                 struct samr_Password current_nt_hash;
791                 struct pdb_domain_info *pdb_domain_info;
792                 bool ok;
793
794                 pdb_domain_info = pdb_get_domain_info(talloc_tos());
795                 if (pdb_domain_info == NULL) {
796                         DEBUG(0, ("Failed to fetch our own, local AD "
797                                 "domain info from sam.ldb\n"));
798                         return false;
799                 }
800                 domain = add_trusted_domain(pdb_domain_info->name,
801                                         pdb_domain_info->dns_domain,
802                                         &pdb_domain_info->sid);
803                 TALLOC_FREE(pdb_domain_info);
804                 if (domain == NULL) {
805                         DEBUG(0, ("Failed to add our own, local AD "
806                                 "domain to winbindd's internal list\n"));
807                         return false;
808                 }
809
810                 /*
811                  * We need to call this to find out if we are an RODC
812                  */
813                 ok = get_trust_pw_hash(domain->name,
814                                        current_nt_hash.hash,
815                                        &account_name,
816                                        &sec_chan_type);
817                 if (!ok) {
818                         /*
819                          * If get_trust_pw_hash() fails, then try and
820                          * fetch the password from the more recent of
821                          * secrets.{ldb,tdb} using the
822                          * pdb_get_trust_credentials()
823                          */
824                         ok = migrate_secrets_tdb_to_ldb(domain);
825
826                         if (ok == false) {
827                                 DEBUG(0, ("Failed to migrate our own, "
828                                           "local AD domain join password for "
829                                           "winbindd's internal use into "
830                                           "secrets.tdb\n"));
831                                 return false;
832                         }
833                         ok = get_trust_pw_hash(domain->name,
834                                                current_nt_hash.hash,
835                                                &account_name,
836                                                &sec_chan_type);
837                         if (ok == false) {
838                                 DEBUG(0, ("Failed to find our our own, just "
839                                           "written local AD domain join "
840                                           "password for winbindd's internal "
841                                           "use in secrets.tdb\n"));
842                                 return false;
843                         }
844                 }
845                 if (sec_chan_type == SEC_CHAN_RODC) {
846                         domain->rodc = true;
847                 }
848
849         } else {
850                 (void)add_trusted_domain(get_global_sam_name(), NULL,
851                                          get_global_sam_sid());
852         }
853         /* Add ourselves as the first entry. */
854
855         if ( role == ROLE_DOMAIN_MEMBER ) {
856                 struct winbindd_domain *domain;
857                 struct dom_sid our_sid;
858
859                 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
860                         DEBUG(0, ("Could not fetch our SID - did we join?\n"));
861                         return False;
862                 }
863
864                 domain = add_trusted_domain(lp_workgroup(), lp_realm(),
865                                             &our_sid);
866                 if (domain) {
867                         /* Even in the parent winbindd we'll need to
868                            talk to the DC, so try and see if we can
869                            contact it. Theoretically this isn't neccessary
870                            as the init_dc_connection() in init_child_recv()
871                            will do this, but we can start detecting the DC
872                            early here. */
873                         set_domain_online_request(domain);
874                 }
875         }
876
877         status = imessaging_register(winbind_imessaging_context(), NULL,
878                                      MSG_WINBIND_NEW_TRUSTED_DOMAIN,
879                                      wb_imsg_new_trusted_domain);
880         if (!NT_STATUS_IS_OK(status)) {
881                 DEBUG(0, ("imessaging_register(MSG_WINBIND_NEW_TRUSTED_DOMAIN) - %s\n",
882                           nt_errstr(status)));
883                 return false;
884         }
885
886         return True;
887 }
888
889 /**
890  * Given a domain name, return the struct winbindd domain info for it
891  *
892  * @note Do *not* pass lp_workgroup() to this function.  domain_list
893  *       may modify it's value, and free that pointer.  Instead, our local
894  *       domain may be found by calling find_our_domain().
895  *       directly.
896  *
897  *
898  * @return The domain structure for the named domain, if it is working.
899  */
900
901 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
902 {
903         struct winbindd_domain *domain;
904
905         /* Search through list */
906
907         for (domain = domain_list(); domain != NULL; domain = domain->next) {
908                 if (strequal(domain_name, domain->name) ||
909                     (domain->alt_name != NULL &&
910                      strequal(domain_name, domain->alt_name))) {
911                         return domain;
912                 }
913         }
914
915         /* Not found */
916
917         return NULL;
918 }
919
920 struct winbindd_domain *find_domain_from_name(const char *domain_name)
921 {
922         struct winbindd_domain *domain;
923
924         domain = find_domain_from_name_noinit(domain_name);
925
926         if (domain == NULL)
927                 return NULL;
928
929         if (!domain->initialized)
930                 init_dc_connection(domain, false);
931
932         return domain;
933 }
934
935 /* Given a domain sid, return the struct winbindd domain info for it */
936
937 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
938 {
939         struct winbindd_domain *domain;
940
941         /* Search through list */
942
943         for (domain = domain_list(); domain != NULL; domain = domain->next) {
944                 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
945                         return domain;
946         }
947
948         /* Not found */
949
950         return NULL;
951 }
952
953 /* Given a domain sid, return the struct winbindd domain info for it */
954
955 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
956 {
957         struct winbindd_domain *domain;
958
959         domain = find_domain_from_sid_noinit(sid);
960
961         if (domain == NULL)
962                 return NULL;
963
964         if (!domain->initialized)
965                 init_dc_connection(domain, false);
966
967         return domain;
968 }
969
970 struct winbindd_domain *find_our_domain(void)
971 {
972         struct winbindd_domain *domain;
973
974         /* Search through list */
975
976         for (domain = domain_list(); domain != NULL; domain = domain->next) {
977                 if (domain->primary)
978                         return domain;
979         }
980
981         smb_panic("Could not find our domain");
982         return NULL;
983 }
984
985 struct winbindd_domain *find_root_domain(void)
986 {
987         struct winbindd_domain *ours = find_our_domain();
988
989         if (ours->forest_name == NULL) {
990                 return NULL;
991         }
992
993         return find_domain_from_name( ours->forest_name );
994 }
995
996 struct winbindd_domain *find_builtin_domain(void)
997 {
998         struct winbindd_domain *domain;
999
1000         domain = find_domain_from_sid(&global_sid_Builtin);
1001         if (domain == NULL) {
1002                 smb_panic("Could not find BUILTIN domain");
1003         }
1004
1005         return domain;
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         if (info3->base.groups.count == 0) {
1298                 TALLOC_FREE(info3);
1299                 return NT_STATUS_UNSUCCESSFUL;
1300         }
1301
1302         /*
1303          * Before bug #7843 the "Domain Local" groups were added with a
1304          * lookupuseraliases call, but this isn't done anymore for our domain
1305          * so we need to resolve resource groups here.
1306          *
1307          * When to use Resource Groups:
1308          * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1309          */
1310         status = sid_array_from_info3(mem_ctx, info3,
1311                                       user_sids,
1312                                       &num_groups,
1313                                       false);
1314
1315         if (!NT_STATUS_IS_OK(status)) {
1316                 TALLOC_FREE(info3);
1317                 return status;
1318         }
1319
1320         TALLOC_FREE(info3);
1321         *p_num_groups = num_groups;
1322         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1323
1324         DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1325
1326         return status;
1327 }
1328
1329 /*********************************************************************
1330  We use this to remove spaces from user and group names
1331 ********************************************************************/
1332
1333 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1334                              struct winbindd_domain *domain,
1335                              const char *name,
1336                              char **normalized)
1337 {
1338         NTSTATUS nt_status;
1339
1340         if (!name || !normalized) {
1341                 return NT_STATUS_INVALID_PARAMETER;
1342         }
1343
1344         if (!lp_winbind_normalize_names()) {
1345                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1346         }
1347
1348         /* Alias support and whitespace replacement are mutually
1349            exclusive */
1350
1351         nt_status = resolve_username_to_alias(mem_ctx, domain,
1352                                               name, normalized );
1353         if (NT_STATUS_IS_OK(nt_status)) {
1354                 /* special return code to let the caller know we
1355                    mapped to an alias */
1356                 return NT_STATUS_FILE_RENAMED;
1357         }
1358
1359         /* check for an unreachable domain */
1360
1361         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1362                 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1363                          domain->name));
1364                 set_domain_offline(domain);
1365                 return nt_status;
1366         }
1367
1368         /* deal with whitespace */
1369
1370         *normalized = talloc_strdup(mem_ctx, name);
1371         if (!(*normalized)) {
1372                 return NT_STATUS_NO_MEMORY;
1373         }
1374
1375         all_string_sub( *normalized, " ", "_", 0 );
1376
1377         return NT_STATUS_OK;
1378 }
1379
1380 /*********************************************************************
1381  We use this to do the inverse of normalize_name_map()
1382 ********************************************************************/
1383
1384 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1385                               char *name,
1386                               char **normalized)
1387 {
1388         NTSTATUS nt_status;
1389         struct winbindd_domain *domain = find_our_domain();
1390
1391         if (!name || !normalized) {
1392                 return NT_STATUS_INVALID_PARAMETER;
1393         }
1394
1395         if (!lp_winbind_normalize_names()) {
1396                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1397         }
1398
1399         /* Alias support and whitespace replacement are mutally
1400            exclusive */
1401
1402         /* When mapping from an alias to a username, we don't know the
1403            domain.  But we only need a domain structure to cache
1404            a successful lookup , so just our own domain structure for
1405            the seqnum. */
1406
1407         nt_status = resolve_alias_to_username(mem_ctx, domain,
1408                                               name, normalized);
1409         if (NT_STATUS_IS_OK(nt_status)) {
1410                 /* Special return code to let the caller know we mapped
1411                    from an alias */
1412                 return NT_STATUS_FILE_RENAMED;
1413         }
1414
1415         /* check for an unreachable domain */
1416
1417         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1418                 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1419                          domain->name));
1420                 set_domain_offline(domain);
1421                 return nt_status;
1422         }
1423
1424         /* deal with whitespace */
1425
1426         *normalized = talloc_strdup(mem_ctx, name);
1427         if (!(*normalized)) {
1428                 return NT_STATUS_NO_MEMORY;
1429         }
1430
1431         all_string_sub(*normalized, "_", " ", 0);
1432
1433         return NT_STATUS_OK;
1434 }
1435
1436 /*********************************************************************
1437  ********************************************************************/
1438
1439 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1440 {
1441         struct winbindd_tdc_domain *tdc = NULL;
1442         TALLOC_CTX *frame = talloc_stackframe();
1443         bool ret = false;
1444
1445         /* We can contact the domain if it is our primary domain */
1446
1447         if (domain->primary) {
1448                 ret = true;
1449                 goto done;
1450         }
1451
1452         /* Trust the TDC cache and not the winbindd_domain flags */
1453
1454         if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1455                 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1456                           domain->name));
1457                 ret = false;
1458                 goto done;
1459         }
1460
1461         /* Can always contact a domain that is in out forest */
1462
1463         if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1464                 ret = true;
1465                 goto done;
1466         }
1467
1468         /*
1469          * On a _member_ server, we cannot contact the domain if it
1470          * is running AD and we have no inbound trust.
1471          */
1472
1473         if (!IS_DC &&
1474              domain->active_directory &&
1475             ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1476         {
1477                 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1478                            "and we have no inbound trust.\n", domain->name));
1479                 goto done;
1480         }
1481
1482         /* Assume everything else is ok (probably not true but what
1483            can you do?) */
1484
1485         ret = true;
1486
1487 done:
1488         talloc_destroy(frame);
1489
1490         return ret;
1491 }
1492
1493 /*********************************************************************
1494  ********************************************************************/
1495
1496 bool winbindd_internal_child(struct winbindd_child *child)
1497 {
1498         if ((child == idmap_child()) || (child == locator_child())) {
1499                 return True;
1500         }
1501
1502         return False;
1503 }
1504
1505 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1506
1507 /*********************************************************************
1508  ********************************************************************/
1509
1510 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1511 {
1512         char *var = NULL;
1513         char addr[INET6_ADDRSTRLEN];
1514         const char *kdc = NULL;
1515         int lvl = 11;
1516
1517         if (!domain || !domain->alt_name || !*domain->alt_name) {
1518                 return;
1519         }
1520
1521         if (domain->initialized && !domain->active_directory) {
1522                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1523                         domain->alt_name));
1524                 return;
1525         }
1526
1527         print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1528         kdc = addr;
1529         if (!*kdc) {
1530                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1531                         domain->alt_name));
1532                 kdc = domain->dcname;
1533         }
1534
1535         if (!kdc || !*kdc) {
1536                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1537                         domain->alt_name));
1538                 return;
1539         }
1540
1541         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1542                                 domain->alt_name) == -1) {
1543                 return;
1544         }
1545
1546         DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1547                 var, kdc));
1548
1549         setenv(var, kdc, 1);
1550         free(var);
1551 }
1552
1553 /*********************************************************************
1554  ********************************************************************/
1555
1556 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1557 {
1558         struct winbindd_domain *our_dom = find_our_domain();
1559
1560         winbindd_set_locator_kdc_env(domain);
1561
1562         if (domain != our_dom) {
1563                 winbindd_set_locator_kdc_env(our_dom);
1564         }
1565 }
1566
1567 /*********************************************************************
1568  ********************************************************************/
1569
1570 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1571 {
1572         char *var = NULL;
1573
1574         if (!domain || !domain->alt_name || !*domain->alt_name) {
1575                 return;
1576         }
1577
1578         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1579                                 domain->alt_name) == -1) {
1580                 return;
1581         }
1582
1583         unsetenv(var);
1584         free(var);
1585 }
1586 #else
1587
1588 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1589 {
1590         return;
1591 }
1592
1593 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1594 {
1595         return;
1596 }
1597
1598 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1599
1600 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1601 {
1602         resp->data.auth.nt_status = NT_STATUS_V(result);
1603         fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1604
1605         /* we might have given a more useful error above */
1606         if (*resp->data.auth.error_string == '\0')
1607                 fstrcpy(resp->data.auth.error_string,
1608                         get_friendly_nt_error_msg(result));
1609         resp->data.auth.pam_error = nt_status_to_pam(result);
1610 }
1611
1612 bool is_domain_offline(const struct winbindd_domain *domain)
1613 {
1614         if (!lp_winbind_offline_logon()) {
1615                 return false;
1616         }
1617         if (get_global_winbindd_state_offline()) {
1618                 return true;
1619         }
1620         return !domain->online;
1621 }
1622
1623 bool is_domain_online(const struct winbindd_domain *domain)
1624 {
1625         return !is_domain_offline(domain);
1626 }
1627
1628 /**
1629  * Parse an char array into a list of sids.
1630  *
1631  * The input sidstr should consist of 0-terminated strings
1632  * representing sids, separated by newline characters '\n'.
1633  * The list is terminated by an empty string, i.e.
1634  * character '\0' directly following a character '\n'
1635  * (or '\0' right at the start of sidstr).
1636  */
1637 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
1638                    struct dom_sid **sids, uint32_t *num_sids)
1639 {
1640         const char *p;
1641
1642         p = sidstr;
1643         if (p == NULL)
1644                 return False;
1645
1646         while (p[0] != '\0') {
1647                 struct dom_sid sid;
1648                 const char *q = NULL;
1649
1650                 if (!dom_sid_parse_endp(p, &sid, &q)) {
1651                         DEBUG(1, ("Could not parse sid %s\n", p));
1652                         return false;
1653                 }
1654                 if (q[0] != '\n') {
1655                         DEBUG(1, ("Got invalid sidstr: %s\n", p));
1656                         return false;
1657                 }
1658                 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
1659                                                       num_sids)))
1660                 {
1661                         return False;
1662                 }
1663                 p = q+1;
1664         }
1665         return True;
1666 }
1667
1668 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
1669                    struct unixid **pxids, uint32_t *pnum_xids)
1670 {
1671         const char *p;
1672         struct unixid *xids = NULL;
1673         uint32_t num_xids = 0;
1674
1675         p = xidstr;
1676         if (p == NULL) {
1677                 return false;
1678         }
1679
1680         while (p[0] != '\0') {
1681                 struct unixid *tmp;
1682                 struct unixid xid;
1683                 unsigned long long id;
1684                 char *endp;
1685
1686                 switch (p[0]) {
1687                 case 'U':
1688                         xid = (struct unixid) { .type = ID_TYPE_UID };
1689                         break;
1690                 case 'G':
1691                         xid = (struct unixid) { .type = ID_TYPE_GID };
1692                         break;
1693                 default:
1694                         return false;
1695                 }
1696
1697                 p += 1;
1698
1699                 id = strtoull(p, &endp, 10);
1700                 if ((id == ULLONG_MAX) && (errno == ERANGE)) {
1701                         goto fail;
1702                 }
1703                 if (*endp != '\n') {
1704                         goto fail;
1705                 }
1706                 p = endp+1;
1707
1708                 xid.id = id;
1709                 if ((unsigned long long)xid.id != id) {
1710                         goto fail;
1711                 }
1712
1713                 tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
1714                 if (tmp == NULL) {
1715                         return 0;
1716                 }
1717                 xids = tmp;
1718
1719                 xids[num_xids] = xid;
1720                 num_xids += 1;
1721         }
1722
1723         *pxids = xids;
1724         *pnum_xids = num_xids;
1725         return true;
1726
1727 fail:
1728         TALLOC_FREE(xids);
1729         return false;
1730 }