217c049874264601573a7788786821f32dfcd7f9
[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
34 #undef DBGC_CLASS
35 #define DBGC_CLASS DBGC_WINBIND
36
37 static struct winbindd_domain *
38 add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc);
39
40 /**
41  * @file winbindd_util.c
42  *
43  * Winbind daemon for NT domain authentication nss module.
44  **/
45
46
47 /* The list of trusted domains.  Note that the list can be deleted and
48    recreated using the init_domain_list() function so pointers to
49    individual winbindd_domain structures cannot be made.  Keep a copy of
50    the domain name instead. */
51
52 static struct winbindd_domain *_domain_list = NULL;
53
54 struct winbindd_domain *domain_list(void)
55 {
56         /* Initialise list */
57
58         if ((!_domain_list) && (!init_domain_list())) {
59                 smb_panic("Init_domain_list failed");
60         }
61
62         return _domain_list;
63 }
64
65 /* Free all entries in the trusted domain list */
66
67 static void free_domain_list(void)
68 {
69         struct winbindd_domain *domain = _domain_list;
70
71         while(domain) {
72                 struct winbindd_domain *next = domain->next;
73
74                 DLIST_REMOVE(_domain_list, domain);
75                 TALLOC_FREE(domain);
76                 domain = next;
77         }
78 }
79
80 /**
81  * Iterator for winbindd's domain list.
82  * To be used (e.g.) in tevent based loops.
83  */
84 struct winbindd_domain *wb_next_domain(struct winbindd_domain *domain)
85 {
86         if (domain == NULL) {
87                 domain = domain_list();
88         } else {
89                 domain = domain->next;
90         }
91
92         if ((domain != NULL) &&
93             (lp_server_role() != ROLE_ACTIVE_DIRECTORY_DC) &&
94             sid_check_is_our_sam(&domain->sid))
95         {
96                 domain = domain->next;
97         }
98
99         return domain;
100 }
101
102 static bool is_internal_domain(const struct dom_sid *sid)
103 {
104         if (sid == NULL)
105                 return False;
106
107         return (sid_check_is_our_sam(sid) || sid_check_is_builtin(sid));
108 }
109
110 static bool is_in_internal_domain(const struct dom_sid *sid)
111 {
112         if (sid == NULL)
113                 return False;
114
115         return (sid_check_is_in_our_sam(sid) || sid_check_is_in_builtin(sid));
116 }
117
118
119 /* Add a trusted domain to our list of domains.
120    If the domain already exists in the list,
121    return it and don't re-initialize.  */
122
123 static struct winbindd_domain *
124 add_trusted_domain(const char *domain_name, const char *alt_name,
125                    const struct dom_sid *sid)
126 {
127         struct winbindd_tdc_domain tdc;
128
129         ZERO_STRUCT(tdc);
130
131         tdc.domain_name = domain_name;
132         tdc.dns_name = alt_name;
133         if (sid) {
134                 sid_copy(&tdc.sid, sid);
135         }
136
137         return add_trusted_domain_from_tdc(&tdc);
138 }
139
140 /* Add a trusted domain out of a trusted domain cache
141    entry
142 */
143 static struct winbindd_domain *
144 add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
145 {
146         struct winbindd_domain *domain;
147         const char *alternative_name = NULL;
148         const char **ignored_domains, **dom;
149         int role = lp_server_role();
150         const char *domain_name = tdc->domain_name;
151         const struct dom_sid *sid = &tdc->sid;
152
153         if (is_null_sid(sid)) {
154                 sid = NULL;
155         }
156
157         ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
158         for (dom=ignored_domains; dom && *dom; dom++) {
159                 if (gen_fnmatch(*dom, domain_name) == 0) {
160                         DEBUG(2,("Ignoring domain '%s'\n", domain_name));
161                         return NULL;
162                 }
163         }
164
165         /* use alt_name if available to allow DNS lookups */
166
167         if (tdc->dns_name && *tdc->dns_name) {
168                 alternative_name = tdc->dns_name;
169         }
170
171         /* We can't call domain_list() as this function is called from
172            init_domain_list() and we'll get stuck in a loop. */
173         for (domain = _domain_list; domain; domain = domain->next) {
174                 if (strequal(domain_name, domain->name) ||
175                     strequal(domain_name, domain->alt_name))
176                 {
177                         break;
178                 }
179
180                 if (alternative_name) {
181                         if (strequal(alternative_name, domain->name) ||
182                             strequal(alternative_name, domain->alt_name))
183                         {
184                                 break;
185                         }
186                 }
187
188                 if (sid != NULL) {
189                         if (dom_sid_equal(sid, &domain->sid)) {
190                                 break;
191                         }
192                 }
193         }
194
195         if (domain != NULL) {
196                 /*
197                  * We found a match on domain->name or
198                  * domain->alt_name. Possibly update the SID
199                  * if the stored SID was the NULL SID
200                  * and return the matching entry.
201                  */
202                 if ((sid != NULL)
203                     && dom_sid_equal(&domain->sid, &global_sid_NULL)) {
204                         sid_copy( &domain->sid, sid );
205                 }
206                 return domain;
207         }
208
209         /* Create new domain entry */
210         domain = talloc_zero(NULL, struct winbindd_domain);
211         if (domain == NULL) {
212                 return NULL;
213         }
214
215         domain->children = talloc_zero_array(domain,
216                                              struct winbindd_child,
217                                              lp_winbind_max_domain_connections());
218         if (domain->children == NULL) {
219                 TALLOC_FREE(domain);
220                 return NULL;
221         }
222
223         domain->name = talloc_strdup(domain, domain_name);
224         if (domain->name == NULL) {
225                 TALLOC_FREE(domain);
226                 return NULL;
227         }
228
229         if (alternative_name) {
230                 domain->alt_name = talloc_strdup(domain, alternative_name);
231                 if (domain->alt_name == NULL) {
232                         TALLOC_FREE(domain);
233                         return NULL;
234                 }
235         }
236
237         domain->backend = NULL;
238         domain->internal = is_internal_domain(sid);
239         domain->sequence_number = DOM_SEQUENCE_NONE;
240         domain->last_seq_check = 0;
241         domain->initialized = false;
242         domain->online = is_internal_domain(sid);
243         domain->check_online_timeout = 0;
244         domain->dc_probe_pid = (pid_t)-1;
245         if (sid != NULL) {
246                 sid_copy(&domain->sid, sid);
247         }
248         domain->domain_flags = tdc->trust_flags;
249         domain->domain_type = tdc->trust_type;
250         domain->domain_trust_attribs = tdc->trust_attribs;
251
252         /* Is this our primary domain ? */
253         if (strequal(domain_name, get_global_sam_name()) &&
254                         (role != ROLE_DOMAIN_MEMBER)) {
255                 domain->primary = true;
256         } else if (strequal(domain_name, lp_workgroup()) &&
257                         (role == ROLE_DOMAIN_MEMBER)) {
258                 domain->primary = true;
259         }
260
261         if (domain->primary) {
262                 if (role == ROLE_ACTIVE_DIRECTORY_DC) {
263                         domain->active_directory = true;
264                 }
265                 if (lp_security() == SEC_ADS) {
266                         domain->active_directory = true;
267                 }
268         } else if (!domain->internal) {
269                 if (domain->domain_type == LSA_TRUST_TYPE_UPLEVEL) {
270                         domain->active_directory = true;
271                 }
272         }
273
274         /* Link to domain list */
275         DLIST_ADD_END(_domain_list, domain);
276
277         wcache_tdc_add_domain( domain );
278
279         setup_domain_child(domain);
280
281         DEBUG(2,
282               ("Added domain %s %s %s\n", domain->name, domain->alt_name,
283                !is_null_sid(&domain->sid) ? sid_string_dbg(&domain->sid) : ""));
284
285         return domain;
286 }
287
288 bool domain_is_forest_root(const struct winbindd_domain *domain)
289 {
290         const uint32_t fr_flags =
291                 (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
292
293         return ((domain->domain_flags & fr_flags) == fr_flags);
294 }
295
296 /********************************************************************
297   rescan our domains looking for new trusted domains
298 ********************************************************************/
299
300 struct trustdom_state {
301         struct winbindd_domain *domain;
302         struct winbindd_request request;
303 };
304
305 static void trustdom_list_done(struct tevent_req *req);
306 static void rescan_forest_root_trusts( void );
307 static void rescan_forest_trusts( void );
308
309 static void add_trusted_domains( struct winbindd_domain *domain )
310 {
311         struct trustdom_state *state;
312         struct tevent_req *req;
313
314         state = talloc_zero(NULL, struct trustdom_state);
315         if (state == NULL) {
316                 DEBUG(0, ("talloc failed\n"));
317                 return;
318         }
319         state->domain = domain;
320
321         state->request.length = sizeof(state->request);
322         state->request.cmd = WINBINDD_LIST_TRUSTDOM;
323
324         req = wb_domain_request_send(state, winbind_event_context(),
325                                      domain, &state->request);
326         if (req == NULL) {
327                 DEBUG(1, ("wb_domain_request_send failed\n"));
328                 TALLOC_FREE(state);
329                 return;
330         }
331         tevent_req_set_callback(req, trustdom_list_done, state);
332 }
333
334 static void trustdom_list_done(struct tevent_req *req)
335 {
336         struct trustdom_state *state = tevent_req_callback_data(
337                 req, struct trustdom_state);
338         struct winbindd_response *response;
339         int res, err;
340         char *p;
341         struct winbindd_tdc_domain trust_params = {0};
342         ptrdiff_t extra_len;
343
344         res = wb_domain_request_recv(req, state, &response, &err);
345         if ((res == -1) || (response->result != WINBINDD_OK)) {
346                 DBG_WARNING("Could not receive trusts for domain %s\n",
347                             state->domain->name);
348                 TALLOC_FREE(state);
349                 return;
350         }
351
352         if (response->length < sizeof(struct winbindd_response)) {
353                 DBG_ERR("ill-formed trustdom response - short length\n");
354                 TALLOC_FREE(state);
355                 return;
356         }
357
358         extra_len = response->length - sizeof(struct winbindd_response);
359
360         p = (char *)response->extra_data.data;
361
362         while ((p - (char *)response->extra_data.data) < extra_len) {
363                 char *q, *sidstr, *alt_name;
364
365                 DBG_DEBUG("parsing response line '%s'\n", p);
366
367                 ZERO_STRUCT(trust_params);
368                 trust_params.domain_name = p;
369
370                 alt_name = strchr(p, '\\');
371                 if (alt_name == NULL) {
372                         DBG_ERR("Got invalid trustdom response\n");
373                         break;
374                 }
375
376                 *alt_name = '\0';
377                 alt_name += 1;
378
379                 sidstr = strchr(alt_name, '\\');
380                 if (sidstr == NULL) {
381                         DBG_ERR("Got invalid trustdom response\n");
382                         break;
383                 }
384
385                 *sidstr = '\0';
386                 sidstr += 1;
387
388                 /* use the real alt_name if we have one, else pass in NULL */
389                 if (!strequal(alt_name, "(null)")) {
390                         trust_params.dns_name = alt_name;
391                 }
392
393                 q = strtok(sidstr, "\\");
394                 if (q == NULL) {
395                         DBG_ERR("Got invalid trustdom response\n");
396                         break;
397                 }
398
399                 if (!string_to_sid(&trust_params.sid, sidstr)) {
400                         DEBUG(0, ("Got invalid trustdom response\n"));
401                         break;
402                 }
403
404                 q = strtok(NULL, "\\");
405                 if (q == NULL) {
406                         DBG_ERR("Got invalid trustdom response\n");
407                         break;
408                 }
409
410                 trust_params.trust_flags = (uint32_t)strtoul(q, NULL, 10);
411
412                 q = strtok(NULL, "\\");
413                 if (q == NULL) {
414                         DBG_ERR("Got invalid trustdom response\n");
415                         break;
416                 }
417
418                 trust_params.trust_type = (uint32_t)strtoul(q, NULL, 10);
419
420                 q = strtok(NULL, "\n");
421                 if (q == NULL) {
422                         DBG_ERR("Got invalid trustdom response\n");
423                         break;
424                 }
425
426                 trust_params.trust_attribs = (uint32_t)strtoul(q, NULL, 10);
427
428                 /*
429                  * We always call add_trusted_domain() cause on an existing
430                  * domain structure, it will update the SID if necessary.
431                  * This is important because we need the SID for sibling
432                  * domains.
433                  */
434                 (void)add_trusted_domain_from_tdc(&trust_params);
435
436                 p = q + strlen(q) + 1;
437         }
438
439         /*
440            Cases to consider when scanning trusts:
441            (a) we are calling from a child domain (primary && !forest_root)
442            (b) we are calling from the root of the forest (primary && forest_root)
443            (c) we are calling from a trusted forest domain (!primary
444                && !forest_root)
445         */
446
447         if (state->domain->primary) {
448                 /* If this is our primary domain and we are not in the
449                    forest root, we have to scan the root trusts first */
450
451                 if (!domain_is_forest_root(state->domain))
452                         rescan_forest_root_trusts();
453                 else
454                         rescan_forest_trusts();
455
456         } else if (domain_is_forest_root(state->domain)) {
457                 /* Once we have done root forest trust search, we can
458                    go on to search the trusted forests */
459
460                 rescan_forest_trusts();
461         }
462
463         TALLOC_FREE(state);
464
465         return;
466 }
467
468 /********************************************************************
469  Scan the trusts of our forest root
470 ********************************************************************/
471
472 static void rescan_forest_root_trusts( void )
473 {
474         struct winbindd_tdc_domain *dom_list = NULL;
475         size_t num_trusts = 0;
476         int i;
477
478         /* The only transitive trusts supported by Windows 2003 AD are
479            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
480            first two are handled in forest and listed by
481            DsEnumerateDomainTrusts().  Forest trusts are not so we
482            have to do that ourselves. */
483
484         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
485                 return;
486
487         for ( i=0; i<num_trusts; i++ ) {
488                 struct winbindd_domain *d = NULL;
489
490                 /* Find the forest root.  Don't necessarily trust
491                    the domain_list() as our primary domain may not
492                    have been initialized. */
493
494                 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
495                         continue;
496                 }
497
498                 /* Here's the forest root */
499
500                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
501
502                 if ( !d ) {
503                         d = add_trusted_domain_from_tdc(&dom_list[i]);
504                 }
505
506                 if (d == NULL) {
507                         continue;
508                 }
509
510                 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
511                           "for domain tree root %s (%s)\n",
512                           d->name, d->alt_name ));
513
514                 d->domain_flags = dom_list[i].trust_flags;
515                 d->domain_type  = dom_list[i].trust_type;
516                 d->domain_trust_attribs = dom_list[i].trust_attribs;
517
518                 add_trusted_domains( d );
519
520                 break;
521         }
522
523         TALLOC_FREE( dom_list );
524
525         return;
526 }
527
528 /********************************************************************
529  scan the transitive forest trusts (not our own)
530 ********************************************************************/
531
532
533 static void rescan_forest_trusts( void )
534 {
535         struct winbindd_domain *d = NULL;
536         struct winbindd_tdc_domain *dom_list = NULL;
537         size_t num_trusts = 0;
538         int i;
539
540         /* The only transitive trusts supported by Windows 2003 AD are
541            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
542            first two are handled in forest and listed by
543            DsEnumerateDomainTrusts().  Forest trusts are not so we
544            have to do that ourselves. */
545
546         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
547                 return;
548
549         for ( i=0; i<num_trusts; i++ ) {
550                 uint32_t flags   = dom_list[i].trust_flags;
551                 uint32_t type    = dom_list[i].trust_type;
552                 uint32_t attribs = dom_list[i].trust_attribs;
553
554                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
555
556                 /* ignore our primary and internal domains */
557
558                 if ( d && (d->internal || d->primary ) )
559                         continue;
560
561                 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
562                      (type == LSA_TRUST_TYPE_UPLEVEL) &&
563                      (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
564                 {
565                         /* add the trusted domain if we don't know
566                            about it */
567
568                         if ( !d ) {
569                                 d = add_trusted_domain_from_tdc(&dom_list[i]);
570                         }
571
572                         if (d == NULL) {
573                                 continue;
574                         }
575
576                         DEBUG(10,("Following trust path for domain %s (%s)\n",
577                                   d->name, d->alt_name ));
578                         add_trusted_domains( d );
579                 }
580         }
581
582         TALLOC_FREE( dom_list );
583
584         return;
585 }
586
587 /*********************************************************************
588  The process of updating the trusted domain list is a three step
589  async process:
590  (a) ask our domain
591  (b) ask the root domain in our forest
592  (c) ask the a DC in any Win2003 trusted forests
593 *********************************************************************/
594
595 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
596                             struct timeval now, void *private_data)
597 {
598         TALLOC_FREE(te);
599
600         /* I use to clear the cache here and start over but that
601            caused problems in child processes that needed the
602            trust dom list early on.  Removing it means we
603            could have some trusted domains listed that have been
604            removed from our primary domain's DC until a full
605            restart.  This should be ok since I think this is what
606            Windows does as well. */
607
608         /* this will only add new domains we didn't already know about
609            in the domain_list()*/
610
611         add_trusted_domains( find_our_domain() );
612
613         te = tevent_add_timer(
614                 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
615                 rescan_trusted_domains, NULL);
616         /*
617          * If te == NULL, there's not much we can do here. Don't fail, the
618          * only thing we miss is new trusted domains.
619          */
620
621         return;
622 }
623
624 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
625                                                    struct winbindd_cli_state *state)
626 {
627         /* Ensure null termination */
628         state->request->domain_name
629                 [sizeof(state->request->domain_name)-1]='\0';
630         state->request->data.init_conn.dcname
631                 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
632
633         if (strlen(state->request->data.init_conn.dcname) > 0) {
634                 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
635         }
636
637         init_dc_connection(domain, false);
638
639         if (!domain->initialized) {
640                 /* If we return error here we can't do any cached authentication,
641                    but we may be in disconnected mode and can't initialize correctly.
642                    Do what the previous code did and just return without initialization,
643                    once we go online we'll re-initialize.
644                 */
645                 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
646                         "online = %d\n", domain->name, (int)domain->online ));
647         }
648
649         fstrcpy(state->response->data.domain_info.name, domain->name);
650         fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
651         sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
652
653         state->response->data.domain_info.native_mode
654                 = domain->native_mode;
655         state->response->data.domain_info.active_directory
656                 = domain->active_directory;
657         state->response->data.domain_info.primary
658                 = domain->primary;
659
660         return WINBINDD_OK;
661 }
662
663 static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
664                                        void *private_data,
665                                        uint32_t msg_type,
666                                        struct server_id server_id,
667                                        DATA_BLOB *data)
668 {
669         TALLOC_CTX *frame = talloc_stackframe();
670         struct lsa_TrustDomainInfoInfoEx info;
671         enum ndr_err_code ndr_err;
672         struct winbindd_domain *d = NULL;
673
674         DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
675
676         if (data == NULL) {
677                 TALLOC_FREE(frame);
678                 return;
679         }
680
681         ndr_err = ndr_pull_struct_blob_all(data, frame, &info,
682                         (ndr_pull_flags_fn_t)ndr_pull_lsa_TrustDomainInfoInfoEx);
683         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
684                 TALLOC_FREE(frame);
685                 return;
686         }
687
688         d = find_domain_from_name_noinit(info.netbios_name.string);
689         if (d != NULL) {
690                 TALLOC_FREE(frame);
691                 return;
692         }
693
694         d = add_trusted_domain(info.netbios_name.string,
695                                info.domain_name.string,
696                                info.sid);
697         if (d == NULL) {
698                 TALLOC_FREE(frame);
699                 return;
700         }
701
702         if (d->internal) {
703                 TALLOC_FREE(frame);
704                 return;
705         }
706
707         if (d->primary) {
708                 TALLOC_FREE(frame);
709                 return;
710         }
711
712         if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
713                 d->domain_flags |= NETR_TRUST_FLAG_INBOUND;
714         }
715         if (info.trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
716                 d->domain_flags |= NETR_TRUST_FLAG_OUTBOUND;
717         }
718         if (info.trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
719                 d->domain_flags |= NETR_TRUST_FLAG_IN_FOREST;
720         }
721         d->domain_type = info.trust_type;
722         d->domain_trust_attribs = info.trust_attributes;
723
724         TALLOC_FREE(frame);
725 }
726
727 /*
728  * We did not get the secret when we queried secrets.tdb, so read it
729  * from secrets.tdb and re-sync the databases
730  */
731 static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
732 {
733         bool ok;
734         struct cli_credentials *creds;
735         NTSTATUS can_migrate = pdb_get_trust_credentials(domain->name,
736                                                          NULL, domain, &creds);
737         if (!NT_STATUS_IS_OK(can_migrate)) {
738                 DEBUG(0, ("Failed to fetch our own, local AD domain join "
739                         "password for winbindd's internal use, both from "
740                         "secrets.tdb and secrets.ldb: %s\n",
741                         nt_errstr(can_migrate)));
742                 return false;
743         }
744
745         /*
746          * NOTE: It is very unlikely we end up here if there is an
747          * oldpass, because a new password is created at
748          * classicupgrade, so this is not a concern.
749          */
750         ok = secrets_store_machine_pw_sync(cli_credentials_get_password(creds),
751                    NULL /* oldpass */,
752                    cli_credentials_get_domain(creds),
753                    cli_credentials_get_realm(creds),
754                    cli_credentials_get_salt_principal(creds),
755                    0, /* Supported enc types, unused */
756                    &domain->sid,
757                    cli_credentials_get_password_last_changed_time(creds),
758                    cli_credentials_get_secure_channel_type(creds),
759                    false /* do_delete: Do not delete */);
760         TALLOC_FREE(creds);
761         if (ok == false) {
762                 DEBUG(0, ("Failed to write our our own, "
763                           "local AD domain join password for "
764                           "winbindd's internal use into secrets.tdb\n"));
765                 return false;
766         }
767         return true;
768 }
769
770 /* Look up global info for the winbind daemon */
771 bool init_domain_list(void)
772 {
773         int role = lp_server_role();
774         NTSTATUS status;
775
776         /* Free existing list */
777         free_domain_list();
778
779         /* BUILTIN domain */
780
781         (void)add_trusted_domain("BUILTIN", NULL, &global_sid_Builtin);
782
783         /* Local SAM */
784
785         if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
786                 struct winbindd_domain *domain;
787                 enum netr_SchannelType sec_chan_type;
788                 const char *account_name;
789                 struct samr_Password current_nt_hash;
790                 struct pdb_domain_info *pdb_domain_info;
791                 bool ok;
792
793                 pdb_domain_info = pdb_get_domain_info(talloc_tos());
794                 if (pdb_domain_info == NULL) {
795                         DEBUG(0, ("Failed to fetch our own, local AD "
796                                 "domain info from sam.ldb\n"));
797                         return false;
798                 }
799                 domain = add_trusted_domain(pdb_domain_info->name,
800                                         pdb_domain_info->dns_domain,
801                                         &pdb_domain_info->sid);
802                 TALLOC_FREE(pdb_domain_info);
803                 if (domain == NULL) {
804                         DEBUG(0, ("Failed to add our own, local AD "
805                                 "domain to winbindd's internal list\n"));
806                         return false;
807                 }
808
809                 /*
810                  * We need to call this to find out if we are an RODC
811                  */
812                 ok = get_trust_pw_hash(domain->name,
813                                        current_nt_hash.hash,
814                                        &account_name,
815                                        &sec_chan_type);
816                 if (!ok) {
817                         /*
818                          * If get_trust_pw_hash() fails, then try and
819                          * fetch the password from the more recent of
820                          * secrets.{ldb,tdb} using the
821                          * pdb_get_trust_credentials()
822                          */
823                         ok = migrate_secrets_tdb_to_ldb(domain);
824
825                         if (ok == false) {
826                                 DEBUG(0, ("Failed to migrate our own, "
827                                           "local AD domain join password for "
828                                           "winbindd's internal use into "
829                                           "secrets.tdb\n"));
830                                 return false;
831                         }
832                         ok = get_trust_pw_hash(domain->name,
833                                                current_nt_hash.hash,
834                                                &account_name,
835                                                &sec_chan_type);
836                         if (ok == false) {
837                                 DEBUG(0, ("Failed to find our our own, just "
838                                           "written local AD domain join "
839                                           "password for winbindd's internal "
840                                           "use in secrets.tdb\n"));
841                                 return false;
842                         }
843                 }
844                 if (sec_chan_type == SEC_CHAN_RODC) {
845                         domain->rodc = true;
846                 }
847
848         } else {
849                 (void)add_trusted_domain(get_global_sam_name(), NULL,
850                                          get_global_sam_sid());
851         }
852         /* Add ourselves as the first entry. */
853
854         if ( role == ROLE_DOMAIN_MEMBER ) {
855                 struct winbindd_domain *domain;
856                 struct dom_sid our_sid;
857
858                 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
859                         DEBUG(0, ("Could not fetch our SID - did we join?\n"));
860                         return False;
861                 }
862
863                 domain = add_trusted_domain(lp_workgroup(), lp_realm(),
864                                             &our_sid);
865                 if (domain) {
866                         /* Even in the parent winbindd we'll need to
867                            talk to the DC, so try and see if we can
868                            contact it. Theoretically this isn't neccessary
869                            as the init_dc_connection() in init_child_recv()
870                            will do this, but we can start detecting the DC
871                            early here. */
872                         set_domain_online_request(domain);
873                 }
874         }
875
876         status = imessaging_register(winbind_imessaging_context(), NULL,
877                                      MSG_WINBIND_NEW_TRUSTED_DOMAIN,
878                                      wb_imsg_new_trusted_domain);
879         if (!NT_STATUS_IS_OK(status)) {
880                 DEBUG(0, ("imessaging_register(MSG_WINBIND_NEW_TRUSTED_DOMAIN) - %s\n",
881                           nt_errstr(status)));
882                 return false;
883         }
884
885         return True;
886 }
887
888 /**
889  * Given a domain name, return the struct winbindd domain info for it
890  *
891  * @note Do *not* pass lp_workgroup() to this function.  domain_list
892  *       may modify it's value, and free that pointer.  Instead, our local
893  *       domain may be found by calling find_our_domain().
894  *       directly.
895  *
896  *
897  * @return The domain structure for the named domain, if it is working.
898  */
899
900 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
901 {
902         struct winbindd_domain *domain;
903
904         /* Search through list */
905
906         for (domain = domain_list(); domain != NULL; domain = domain->next) {
907                 if (strequal(domain_name, domain->name) ||
908                     (domain->alt_name != NULL &&
909                      strequal(domain_name, domain->alt_name))) {
910                         return domain;
911                 }
912         }
913
914         /* Not found */
915
916         return NULL;
917 }
918
919 struct winbindd_domain *find_domain_from_name(const char *domain_name)
920 {
921         struct winbindd_domain *domain;
922
923         domain = find_domain_from_name_noinit(domain_name);
924
925         if (domain == NULL)
926                 return NULL;
927
928         if (!domain->initialized)
929                 init_dc_connection(domain, false);
930
931         return domain;
932 }
933
934 /* Given a domain sid, return the struct winbindd domain info for it */
935
936 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
937 {
938         struct winbindd_domain *domain;
939
940         /* Search through list */
941
942         for (domain = domain_list(); domain != NULL; domain = domain->next) {
943                 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
944                         return domain;
945         }
946
947         /* Not found */
948
949         return NULL;
950 }
951
952 /* Given a domain sid, return the struct winbindd domain info for it */
953
954 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
955 {
956         struct winbindd_domain *domain;
957
958         domain = find_domain_from_sid_noinit(sid);
959
960         if (domain == NULL)
961                 return NULL;
962
963         if (!domain->initialized)
964                 init_dc_connection(domain, false);
965
966         return domain;
967 }
968
969 struct winbindd_domain *find_our_domain(void)
970 {
971         struct winbindd_domain *domain;
972
973         /* Search through list */
974
975         for (domain = domain_list(); domain != NULL; domain = domain->next) {
976                 if (domain->primary)
977                         return domain;
978         }
979
980         smb_panic("Could not find our domain");
981         return NULL;
982 }
983
984 struct winbindd_domain *find_root_domain(void)
985 {
986         struct winbindd_domain *ours = find_our_domain();
987
988         if (ours->forest_name == NULL) {
989                 return NULL;
990         }
991
992         return find_domain_from_name( ours->forest_name );
993 }
994
995 struct winbindd_domain *find_builtin_domain(void)
996 {
997         struct winbindd_domain *domain;
998
999         domain = find_domain_from_sid(&global_sid_Builtin);
1000         if (domain == NULL) {
1001                 smb_panic("Could not find BUILTIN domain");
1002         }
1003
1004         return domain;
1005 }
1006
1007 /* Find the appropriate domain to lookup a name or SID */
1008
1009 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
1010 {
1011         /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
1012
1013         if ( sid_check_is_in_unix_groups(sid) ||
1014              sid_check_is_unix_groups(sid) ||
1015              sid_check_is_in_unix_users(sid) ||
1016              sid_check_is_unix_users(sid) )
1017         {
1018                 return find_domain_from_sid(get_global_sam_sid());
1019         }
1020
1021         /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
1022          * one to contact the external DC's. On member servers the internal
1023          * domains are different: These are part of the local SAM. */
1024
1025         DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid)));
1026
1027         if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
1028                 DEBUG(10, ("calling find_domain_from_sid\n"));
1029                 return find_domain_from_sid(sid);
1030         }
1031
1032         /* On a member server a query for SID or name can always go to our
1033          * primary DC. */
1034
1035         DEBUG(10, ("calling find_our_domain\n"));
1036         return find_our_domain();
1037 }
1038
1039 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1040 {
1041         if ( strequal(domain_name, unix_users_domain_name() ) ||
1042              strequal(domain_name, unix_groups_domain_name() ) )
1043         {
1044                 /*
1045                  * The "Unix User" and "Unix Group" domain our handled by
1046                  * passdb
1047                  */
1048                 return find_domain_from_name_noinit( get_global_sam_name() );
1049         }
1050
1051         if (IS_DC || strequal(domain_name, "BUILTIN") ||
1052             strequal(domain_name, get_global_sam_name()))
1053                 return find_domain_from_name_noinit(domain_name);
1054
1055
1056         return find_our_domain();
1057 }
1058
1059 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1060
1061 static bool assume_domain(const char *domain)
1062 {
1063         /* never assume the domain on a standalone server */
1064
1065         if ( lp_server_role() == ROLE_STANDALONE )
1066                 return False;
1067
1068         /* domain member servers may possibly assume for the domain name */
1069
1070         if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1071                 if ( !strequal(lp_workgroup(), domain) )
1072                         return False;
1073
1074                 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1075                         return True;
1076         }
1077
1078         /* only left with a domain controller */
1079
1080         if ( strequal(get_global_sam_name(), domain) )  {
1081                 return True;
1082         }
1083
1084         return False;
1085 }
1086
1087 /* Parse a string of the form DOMAIN\user into a domain and a user */
1088
1089 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1090 {
1091         char *p = strchr(domuser,*lp_winbind_separator());
1092
1093         if ( !p ) {
1094                 fstrcpy(user, domuser);
1095                 p = strchr(domuser, '@');
1096
1097                 if ( assume_domain(lp_workgroup()) && p == NULL) {
1098                         fstrcpy(domain, lp_workgroup());
1099                 } else if (p != NULL) {
1100                         fstrcpy(domain, p + 1);
1101                         user[PTR_DIFF(p, domuser)] = 0;
1102                 } else {
1103                         return False;
1104                 }
1105         } else {
1106                 fstrcpy(user, p+1);
1107                 fstrcpy(domain, domuser);
1108                 domain[PTR_DIFF(p, domuser)] = 0;
1109         }
1110
1111         return strupper_m(domain);
1112 }
1113
1114 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1115                               char **domain, char **user)
1116 {
1117         fstring fstr_domain, fstr_user;
1118         if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1119                 return False;
1120         }
1121         *domain = talloc_strdup(mem_ctx, fstr_domain);
1122         *user = talloc_strdup(mem_ctx, fstr_user);
1123         return ((*domain != NULL) && (*user != NULL));
1124 }
1125
1126 /* Ensure an incoming username from NSS is fully qualified. Replace the
1127    incoming fstring with DOMAIN <separator> user. Returns the same
1128    values as parse_domain_user() but also replaces the incoming username.
1129    Used to ensure all names are fully qualified within winbindd.
1130    Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1131    The protocol definitions of auth_crap, chng_pswd_auth_crap
1132    really should be changed to use this instead of doing things
1133    by hand. JRA. */
1134
1135 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1136 {
1137         if (!parse_domain_user(username_inout, domain, user)) {
1138                 return False;
1139         }
1140         slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1141                  domain, *lp_winbind_separator(),
1142                  user);
1143         return True;
1144 }
1145
1146 /*
1147     Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1148     'winbind separator' options.
1149     This means:
1150         - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1151         lp_workgroup()
1152
1153     If we are a PDC or BDC, and this is for our domain, do likewise.
1154
1155     Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
1156     username is then unqualified in unix
1157
1158     On an AD DC we always fill DOMAIN\\USERNAME.
1159
1160     We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1161 */
1162 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1163 {
1164         fstring tmp_user;
1165
1166         if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1167                 can_assume = false;
1168         }
1169
1170         fstrcpy(tmp_user, user);
1171         (void)strlower_m(tmp_user);
1172
1173         if (can_assume && assume_domain(domain)) {
1174                 strlcpy(name, tmp_user, sizeof(fstring));
1175         } else {
1176                 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1177                          domain, *lp_winbind_separator(),
1178                          tmp_user);
1179         }
1180 }
1181
1182 /**
1183  * talloc version of fill_domain_username()
1184  * return NULL on talloc failure.
1185  */
1186 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1187                                   const char *domain,
1188                                   const char *user,
1189                                   bool can_assume)
1190 {
1191         char *tmp_user, *name;
1192
1193         if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1194                 can_assume = false;
1195         }
1196
1197         tmp_user = talloc_strdup(mem_ctx, user);
1198         if (!strlower_m(tmp_user)) {
1199                 TALLOC_FREE(tmp_user);
1200                 return NULL;
1201         }
1202
1203         if (can_assume && assume_domain(domain)) {
1204                 name = tmp_user;
1205         } else {
1206                 name = talloc_asprintf(mem_ctx, "%s%c%s",
1207                                        domain,
1208                                        *lp_winbind_separator(),
1209                                        tmp_user);
1210                 TALLOC_FREE(tmp_user);
1211         }
1212
1213         return name;
1214 }
1215
1216 /*
1217  * Client list accessor functions
1218  */
1219
1220 static struct winbindd_cli_state *_client_list;
1221 static int _num_clients;
1222
1223 /* Return list of all connected clients */
1224
1225 struct winbindd_cli_state *winbindd_client_list(void)
1226 {
1227         return _client_list;
1228 }
1229
1230 /* Return list-tail of all connected clients */
1231
1232 struct winbindd_cli_state *winbindd_client_list_tail(void)
1233 {
1234         return DLIST_TAIL(_client_list);
1235 }
1236
1237 /* Return previous (read:newer) client in list */
1238
1239 struct winbindd_cli_state *
1240 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1241 {
1242         return DLIST_PREV(cli);
1243 }
1244
1245 /* Add a connection to the list */
1246
1247 void winbindd_add_client(struct winbindd_cli_state *cli)
1248 {
1249         cli->last_access = time(NULL);
1250         DLIST_ADD(_client_list, cli);
1251         _num_clients++;
1252 }
1253
1254 /* Remove a client from the list */
1255
1256 void winbindd_remove_client(struct winbindd_cli_state *cli)
1257 {
1258         DLIST_REMOVE(_client_list, cli);
1259         _num_clients--;
1260 }
1261
1262 /* Move a client to head or list */
1263
1264 void winbindd_promote_client(struct winbindd_cli_state *cli)
1265 {
1266         cli->last_access = time(NULL);
1267         DLIST_PROMOTE(_client_list, cli);
1268 }
1269
1270 /* Return number of open clients */
1271
1272 int winbindd_num_clients(void)
1273 {
1274         return _num_clients;
1275 }
1276
1277 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1278                                   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 == NULL) || (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 }