s3/winbindd: Remove unnecessary check for NULL SID
[nivanova/samba-autobuild/.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
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_WINBIND
28
29 extern struct winbindd_methods cache_methods;
30 extern struct winbindd_methods builtin_passdb_methods;
31 extern struct winbindd_methods sam_passdb_methods;
32
33
34 /**
35  * @file winbindd_util.c
36  *
37  * Winbind daemon for NT domain authentication nss module.
38  **/
39
40
41 /* The list of trusted domains.  Note that the list can be deleted and
42    recreated using the init_domain_list() function so pointers to
43    individual winbindd_domain structures cannot be made.  Keep a copy of
44    the domain name instead. */
45
46 static struct winbindd_domain *_domain_list = NULL;
47
48 struct winbindd_domain *domain_list(void)
49 {
50         /* Initialise list */
51
52         if ((!_domain_list) && (!init_domain_list())) {
53                 smb_panic("Init_domain_list failed");
54         }
55
56         return _domain_list;
57 }
58
59 /* Free all entries in the trusted domain list */
60
61 void free_domain_list(void)
62 {
63         struct winbindd_domain *domain = _domain_list;
64
65         while(domain) {
66                 struct winbindd_domain *next = domain->next;
67
68                 DLIST_REMOVE(_domain_list, domain);
69                 SAFE_FREE(domain);
70                 domain = next;
71         }
72 }
73
74 static bool is_internal_domain(const DOM_SID *sid)
75 {
76         if (sid == NULL)
77                 return False;
78
79         return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
80 }
81
82 static bool is_in_internal_domain(const DOM_SID *sid)
83 {
84         if (sid == NULL)
85                 return False;
86
87         return (sid_check_is_in_our_domain(sid) || sid_check_is_in_builtin(sid));
88 }
89
90
91 /* Add a trusted domain to our list of domains */
92 static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
93                                                   struct winbindd_methods *methods,
94                                                   const DOM_SID *sid)
95 {
96         struct winbindd_domain *domain;
97         const char *alternative_name = NULL;
98         char *idmap_config_option;
99         const char *param;
100         const char **ignored_domains, **dom;
101
102         ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
103         for (dom=ignored_domains; dom && *dom; dom++) {
104                 if (gen_fnmatch(*dom, domain_name) == 0) {
105                         DEBUG(2,("Ignoring domain '%s'\n", domain_name));
106                         return NULL;
107                 }
108         }
109
110         /* ignore alt_name if we are not in an AD domain */
111
112         if ( (lp_security() == SEC_ADS) && alt_name && *alt_name) {
113                 alternative_name = alt_name;
114         }
115
116         /* We can't call domain_list() as this function is called from
117            init_domain_list() and we'll get stuck in a loop. */
118         for (domain = _domain_list; domain; domain = domain->next) {
119                 if (strequal(domain_name, domain->name) ||
120                     strequal(domain_name, domain->alt_name))
121                 {
122                         break;
123                 }
124
125                 if (alternative_name && *alternative_name)
126                 {
127                         if (strequal(alternative_name, domain->name) ||
128                             strequal(alternative_name, domain->alt_name))
129                         {
130                                 break;
131                         }
132                 }
133
134                 if (sid)
135                 {
136                         if (is_null_sid(sid)) {
137                                 continue;
138                         }
139
140                         if (sid_equal(sid, &domain->sid)) {
141                                 break;
142                         }
143                 }
144         }
145
146         /* See if we found a match.  Check if we need to update the
147            SID. */
148
149         if ( domain && sid) {
150                 if ( sid_equal( &domain->sid, &global_sid_NULL ) )
151                         sid_copy( &domain->sid, sid );
152
153                 return domain;
154         }
155
156         /* Create new domain entry */
157
158         if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
159                 return NULL;
160
161         /* Fill in fields */
162
163         ZERO_STRUCTP(domain);
164
165         fstrcpy(domain->name, domain_name);
166         if (alternative_name) {
167                 fstrcpy(domain->alt_name, alternative_name);
168         }
169
170         domain->methods = methods;
171         domain->backend = NULL;
172         domain->internal = is_internal_domain(sid);
173         domain->sequence_number = DOM_SEQUENCE_NONE;
174         domain->last_seq_check = 0;
175         domain->initialized = False;
176         domain->online = is_internal_domain(sid);
177         domain->check_online_timeout = 0;
178         domain->dc_probe_pid = (pid_t)-1;
179         if (sid) {
180                 sid_copy(&domain->sid, sid);
181         }
182
183         /* Link to domain list */
184         DLIST_ADD_END(_domain_list, domain, struct winbindd_domain *);
185
186         wcache_tdc_add_domain( domain );
187
188         idmap_config_option = talloc_asprintf(talloc_tos(), "idmap config %s",
189                                               domain->name);
190         if (idmap_config_option == NULL) {
191                 DEBUG(0, ("talloc failed, not looking for idmap config\n"));
192                 goto done;
193         }
194
195         param = lp_parm_const_string(-1, idmap_config_option, "range", NULL);
196
197         DEBUG(10, ("%s : range = %s\n", idmap_config_option,
198                    param ? param : "not defined"));
199
200         if (param != NULL) {
201                 unsigned low_id, high_id;
202                 if (sscanf(param, "%u - %u", &low_id, &high_id) != 2) {
203                         DEBUG(1, ("invalid range syntax in %s: %s\n",
204                                   idmap_config_option, param));
205                         goto done;
206                 }
207                 if (low_id > high_id) {
208                         DEBUG(1, ("invalid range in %s: %s\n",
209                                   idmap_config_option, param));
210                         goto done;
211                 }
212                 domain->have_idmap_config = true;
213                 domain->id_range_low = low_id;
214                 domain->id_range_high = high_id;
215         }
216
217 done:
218
219         DEBUG(2,("Added domain %s %s %s\n",
220                  domain->name, domain->alt_name,
221                  &domain->sid?sid_string_dbg(&domain->sid):""));
222
223         return domain;
224 }
225
226 /********************************************************************
227   rescan our domains looking for new trusted domains
228 ********************************************************************/
229
230 struct trustdom_state {
231         TALLOC_CTX *mem_ctx;
232         bool primary;
233         bool forest_root;
234         struct winbindd_response *response;
235 };
236
237 static void trustdom_recv(void *private_data, bool success);
238 static void rescan_forest_root_trusts( void );
239 static void rescan_forest_trusts( void );
240
241 static void add_trusted_domains( struct winbindd_domain *domain )
242 {
243         TALLOC_CTX *mem_ctx;
244         struct winbindd_request *request;
245         struct winbindd_response *response;
246         uint32 fr_flags = (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
247
248         struct trustdom_state *state;
249
250         mem_ctx = talloc_init("add_trusted_domains");
251         if (mem_ctx == NULL) {
252                 DEBUG(0, ("talloc_init failed\n"));
253                 return;
254         }
255
256         request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
257         response = TALLOC_P(mem_ctx, struct winbindd_response);
258         state = TALLOC_P(mem_ctx, struct trustdom_state);
259
260         if ((request == NULL) || (response == NULL) || (state == NULL)) {
261                 DEBUG(0, ("talloc failed\n"));
262                 talloc_destroy(mem_ctx);
263                 return;
264         }
265
266         state->mem_ctx = mem_ctx;
267         state->response = response;
268
269         /* Flags used to know how to continue the forest trust search */
270
271         state->primary = domain->primary;
272         state->forest_root = ((domain->domain_flags & fr_flags) == fr_flags );
273
274         request->length = sizeof(*request);
275         request->cmd = WINBINDD_LIST_TRUSTDOM;
276
277         async_domain_request(mem_ctx, domain, request, response,
278                              trustdom_recv, state);
279 }
280
281 static void trustdom_recv(void *private_data, bool success)
282 {
283         struct trustdom_state *state =
284                 talloc_get_type_abort(private_data, struct trustdom_state);
285         struct winbindd_response *response = state->response;
286         char *p;
287
288         if ((!success) || (response->result != WINBINDD_OK)) {
289                 DEBUG(1, ("Could not receive trustdoms\n"));
290                 talloc_destroy(state->mem_ctx);
291                 return;
292         }
293
294         p = (char *)response->extra_data.data;
295
296         while ((p != NULL) && (*p != '\0')) {
297                 char *q, *sidstr, *alt_name;
298                 DOM_SID sid;
299                 struct winbindd_domain *domain;
300                 char *alternate_name = NULL;
301
302                 alt_name = strchr(p, '\\');
303                 if (alt_name == NULL) {
304                         DEBUG(0, ("Got invalid trustdom response\n"));
305                         break;
306                 }
307
308                 *alt_name = '\0';
309                 alt_name += 1;
310
311                 sidstr = strchr(alt_name, '\\');
312                 if (sidstr == NULL) {
313                         DEBUG(0, ("Got invalid trustdom response\n"));
314                         break;
315                 }
316
317                 *sidstr = '\0';
318                 sidstr += 1;
319
320                 q = strchr(sidstr, '\n');
321                 if (q != NULL)
322                         *q = '\0';
323
324                 if (!string_to_sid(&sid, sidstr)) {
325                         DEBUG(0, ("Got invalid trustdom response\n"));
326                         break;
327                 }
328
329                 /* use the real alt_name if we have one, else pass in NULL */
330
331                 if ( !strequal( alt_name, "(null)" ) )
332                         alternate_name = alt_name;
333
334                 /* If we have an existing domain structure, calling
335                    add_trusted_domain() will update the SID if
336                    necessary.  This is important because we need the
337                    SID for sibling domains */
338
339                 if ( find_domain_from_name_noinit(p) != NULL ) {
340                         domain = add_trusted_domain(p, alternate_name,
341                                                     &cache_methods,
342                                                     &sid);
343                 } else {
344                         domain = add_trusted_domain(p, alternate_name,
345                                                     &cache_methods,
346                                                     &sid);
347                         if (domain) {
348                                 setup_domain_child(domain,
349                                                    &domain->child);
350                         }
351                 }
352                 p=q;
353                 if (p != NULL)
354                         p += 1;
355         }
356
357         /*
358            Cases to consider when scanning trusts:
359            (a) we are calling from a child domain (primary && !forest_root)
360            (b) we are calling from the root of the forest (primary && forest_root)
361            (c) we are calling from a trusted forest domain (!primary
362                && !forest_root)
363         */
364
365         if ( state->primary ) {
366                 /* If this is our primary domain and we are not in the
367                    forest root, we have to scan the root trusts first */
368
369                 if ( !state->forest_root )
370                         rescan_forest_root_trusts();
371                 else
372                         rescan_forest_trusts();
373
374         } else if ( state->forest_root ) {
375                 /* Once we have done root forest trust search, we can
376                    go on to search the trusted forests */
377
378                 rescan_forest_trusts();
379         }
380
381         talloc_destroy(state->mem_ctx);
382
383         return;
384 }
385
386 /********************************************************************
387  Scan the trusts of our forest root
388 ********************************************************************/
389
390 static void rescan_forest_root_trusts( void )
391 {
392         struct winbindd_tdc_domain *dom_list = NULL;
393         size_t num_trusts = 0;
394         int i;
395
396         /* The only transitive trusts supported by Windows 2003 AD are
397            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
398            first two are handled in forest and listed by
399            DsEnumerateDomainTrusts().  Forest trusts are not so we
400            have to do that ourselves. */
401
402         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
403                 return;
404
405         for ( i=0; i<num_trusts; i++ ) {
406                 struct winbindd_domain *d = NULL;
407
408                 /* Find the forest root.  Don't necessarily trust
409                    the domain_list() as our primary domain may not
410                    have been initialized. */
411
412                 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
413                         continue;
414                 }
415
416                 /* Here's the forest root */
417
418                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
419
420                 if ( !d ) {
421                         d = add_trusted_domain( dom_list[i].domain_name,
422                                                 dom_list[i].dns_name,
423                                                 &cache_methods,
424                                                 &dom_list[i].sid );
425                 }
426
427                 if (d == NULL) {
428                         continue;
429                 }
430
431                 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
432                           "for domain tree root %s (%s)\n",
433                           d->name, d->alt_name ));
434
435                 d->domain_flags = dom_list[i].trust_flags;
436                 d->domain_type  = dom_list[i].trust_type;
437                 d->domain_trust_attribs = dom_list[i].trust_attribs;
438
439                 add_trusted_domains( d );
440
441                 break;
442         }
443
444         TALLOC_FREE( dom_list );
445
446         return;
447 }
448
449 /********************************************************************
450  scan the transitive forest trusts (not our own)
451 ********************************************************************/
452
453
454 static void rescan_forest_trusts( void )
455 {
456         struct winbindd_domain *d = NULL;
457         struct winbindd_tdc_domain *dom_list = NULL;
458         size_t num_trusts = 0;
459         int i;
460
461         /* The only transitive trusts supported by Windows 2003 AD are
462            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
463            first two are handled in forest and listed by
464            DsEnumerateDomainTrusts().  Forest trusts are not so we
465            have to do that ourselves. */
466
467         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
468                 return;
469
470         for ( i=0; i<num_trusts; i++ ) {
471                 uint32 flags   = dom_list[i].trust_flags;
472                 uint32 type    = dom_list[i].trust_type;
473                 uint32 attribs = dom_list[i].trust_attribs;
474
475                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
476
477                 /* ignore our primary and internal domains */
478
479                 if ( d && (d->internal || d->primary ) )
480                         continue;
481
482                 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
483                      (type == NETR_TRUST_TYPE_UPLEVEL) &&
484                      (attribs == NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
485                 {
486                         /* add the trusted domain if we don't know
487                            about it */
488
489                         if ( !d ) {
490                                 d = add_trusted_domain( dom_list[i].domain_name,
491                                                         dom_list[i].dns_name,
492                                                         &cache_methods,
493                                                         &dom_list[i].sid );
494                         }
495
496                         if (d == NULL) {
497                                 continue;
498                         }
499
500                         DEBUG(10,("Following trust path for domain %s (%s)\n",
501                                   d->name, d->alt_name ));
502                         add_trusted_domains( d );
503                 }
504         }
505
506         TALLOC_FREE( dom_list );
507
508         return;
509 }
510
511 /*********************************************************************
512  The process of updating the trusted domain list is a three step
513  async process:
514  (a) ask our domain
515  (b) ask the root domain in our forest
516  (c) ask the a DC in any Win2003 trusted forests
517 *********************************************************************/
518
519 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
520                             struct timeval now, void *private_data)
521 {
522         TALLOC_FREE(te);
523
524         /* I use to clear the cache here and start over but that
525            caused problems in child processes that needed the
526            trust dom list early on.  Removing it means we
527            could have some trusted domains listed that have been
528            removed from our primary domain's DC until a full
529            restart.  This should be ok since I think this is what
530            Windows does as well. */
531
532         /* this will only add new domains we didn't already know about
533            in the domain_list()*/
534
535         add_trusted_domains( find_our_domain() );
536
537         te = tevent_add_timer(
538                 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
539                 rescan_trusted_domains, NULL);
540         /*
541          * If te == NULL, there's not much we can do here. Don't fail, the
542          * only thing we miss is new trusted domains.
543          */
544
545         return;
546 }
547
548 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
549                                                    struct winbindd_cli_state *state)
550 {
551         /* Ensure null termination */
552         state->request->domain_name
553                 [sizeof(state->request->domain_name)-1]='\0';
554         state->request->data.init_conn.dcname
555                 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
556
557         if (strlen(state->request->data.init_conn.dcname) > 0) {
558                 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
559         }
560
561         if (domain->internal) {
562                 domain->initialized = true;
563         } else {
564                 init_dc_connection(domain);
565         }
566
567         if (!domain->initialized) {
568                 /* If we return error here we can't do any cached authentication,
569                    but we may be in disconnected mode and can't initialize correctly.
570                    Do what the previous code did and just return without initialization,
571                    once we go online we'll re-initialize.
572                 */
573                 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
574                         "online = %d\n", domain->name, (int)domain->online ));
575         }
576
577         fstrcpy(state->response->data.domain_info.name, domain->name);
578         fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
579         sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
580
581         state->response->data.domain_info.native_mode
582                 = domain->native_mode;
583         state->response->data.domain_info.active_directory
584                 = domain->active_directory;
585         state->response->data.domain_info.primary
586                 = domain->primary;
587
588         return WINBINDD_OK;
589 }
590
591 /* Look up global info for the winbind daemon */
592 bool init_domain_list(void)
593 {
594         struct winbindd_domain *domain;
595         int role = lp_server_role();
596
597         /* Free existing list */
598         free_domain_list();
599
600         /* BUILTIN domain */
601
602         domain = add_trusted_domain("BUILTIN", NULL, &builtin_passdb_methods,
603                                     &global_sid_Builtin);
604         if (domain) {
605                 setup_domain_child(domain,
606                                    &domain->child);
607         }
608
609         /* Local SAM */
610
611         domain = add_trusted_domain(get_global_sam_name(), NULL,
612                                     &sam_passdb_methods, get_global_sam_sid());
613         if (domain) {
614                 if ( role != ROLE_DOMAIN_MEMBER ) {
615                         domain->primary = True;
616                 }
617                 setup_domain_child(domain,
618                                    &domain->child);
619         }
620
621         /* Add ourselves as the first entry. */
622
623         if ( role == ROLE_DOMAIN_MEMBER ) {
624                 DOM_SID our_sid;
625
626                 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
627                         DEBUG(0, ("Could not fetch our SID - did we join?\n"));
628                         return False;
629                 }
630
631                 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
632                                              &cache_methods, &our_sid);
633                 if (domain) {
634                         domain->primary = True;
635                         setup_domain_child(domain,
636                                            &domain->child);
637
638                         /* Even in the parent winbindd we'll need to
639                            talk to the DC, so try and see if we can
640                            contact it. Theoretically this isn't neccessary
641                            as the init_dc_connection() in init_child_recv()
642                            will do this, but we can start detecting the DC
643                            early here. */
644                         set_domain_online_request(domain);
645                 }
646         }
647
648         return True;
649 }
650
651 void check_domain_trusted( const char *name, const DOM_SID *user_sid )
652 {
653         struct winbindd_domain *domain;
654         DOM_SID dom_sid;
655         uint32 rid;
656
657         /* Check if we even care */
658
659         if (!lp_allow_trusted_domains())
660                 return;
661
662         domain = find_domain_from_name_noinit( name );
663         if ( domain )
664                 return;
665
666         sid_copy( &dom_sid, user_sid );
667         if ( !sid_split_rid( &dom_sid, &rid ) )
668                 return;
669
670         /* add the newly discovered trusted domain */
671
672         domain = add_trusted_domain( name, NULL, &cache_methods,
673                                      &dom_sid);
674
675         if ( !domain )
676                 return;
677
678         /* assume this is a trust from a one-way transitive
679            forest trust */
680
681         domain->active_directory = True;
682         domain->domain_flags = NETR_TRUST_FLAG_OUTBOUND;
683         domain->domain_type  = NETR_TRUST_TYPE_UPLEVEL;
684         domain->internal = False;
685         domain->online = True;
686
687         setup_domain_child(domain,
688                            &domain->child);
689
690         wcache_tdc_add_domain( domain );
691
692         return;
693 }
694
695 /**
696  * Given a domain name, return the struct winbindd domain info for it
697  *
698  * @note Do *not* pass lp_workgroup() to this function.  domain_list
699  *       may modify it's value, and free that pointer.  Instead, our local
700  *       domain may be found by calling find_our_domain().
701  *       directly.
702  *
703  *
704  * @return The domain structure for the named domain, if it is working.
705  */
706
707 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
708 {
709         struct winbindd_domain *domain;
710
711         /* Search through list */
712
713         for (domain = domain_list(); domain != NULL; domain = domain->next) {
714                 if (strequal(domain_name, domain->name) ||
715                     (domain->alt_name[0] &&
716                      strequal(domain_name, domain->alt_name))) {
717                         return domain;
718                 }
719         }
720
721         /* Not found */
722
723         return NULL;
724 }
725
726 struct winbindd_domain *find_domain_from_name(const char *domain_name)
727 {
728         struct winbindd_domain *domain;
729
730         domain = find_domain_from_name_noinit(domain_name);
731
732         if (domain == NULL)
733                 return NULL;
734
735         if (!domain->initialized)
736                 init_dc_connection(domain);
737
738         return domain;
739 }
740
741 /* Given a domain sid, return the struct winbindd domain info for it */
742
743 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
744 {
745         struct winbindd_domain *domain;
746
747         /* Search through list */
748
749         for (domain = domain_list(); domain != NULL; domain = domain->next) {
750                 if (sid_compare_domain(sid, &domain->sid) == 0)
751                         return domain;
752         }
753
754         /* Not found */
755
756         return NULL;
757 }
758
759 /* Given a domain sid, return the struct winbindd domain info for it */
760
761 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
762 {
763         struct winbindd_domain *domain;
764
765         domain = find_domain_from_sid_noinit(sid);
766
767         if (domain == NULL)
768                 return NULL;
769
770         if (!domain->initialized)
771                 init_dc_connection(domain);
772
773         return domain;
774 }
775
776 struct winbindd_domain *find_our_domain(void)
777 {
778         struct winbindd_domain *domain;
779
780         /* Search through list */
781
782         for (domain = domain_list(); domain != NULL; domain = domain->next) {
783                 if (domain->primary)
784                         return domain;
785         }
786
787         smb_panic("Could not find our domain");
788         return NULL;
789 }
790
791 struct winbindd_domain *find_root_domain(void)
792 {
793         struct winbindd_domain *ours = find_our_domain();
794
795         if ( !ours )
796                 return NULL;
797
798         if ( strlen(ours->forest_name) == 0 )
799                 return NULL;
800
801         return find_domain_from_name( ours->forest_name );
802 }
803
804 struct winbindd_domain *find_builtin_domain(void)
805 {
806         DOM_SID sid;
807         struct winbindd_domain *domain;
808
809         string_to_sid(&sid, "S-1-5-32");
810         domain = find_domain_from_sid(&sid);
811
812         if (domain == NULL) {
813                 smb_panic("Could not find BUILTIN domain");
814         }
815
816         return domain;
817 }
818
819 /* Find the appropriate domain to lookup a name or SID */
820
821 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
822 {
823         /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
824
825         if ( sid_check_is_in_unix_groups(sid) ||
826              sid_check_is_unix_groups(sid) ||
827              sid_check_is_in_unix_users(sid) ||
828              sid_check_is_unix_users(sid) )
829         {
830                 return find_domain_from_sid(get_global_sam_sid());
831         }
832
833         /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
834          * one to contact the external DC's. On member servers the internal
835          * domains are different: These are part of the local SAM. */
836
837         DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid)));
838
839         if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
840                 DEBUG(10, ("calling find_domain_from_sid\n"));
841                 return find_domain_from_sid(sid);
842         }
843
844         /* On a member server a query for SID or name can always go to our
845          * primary DC. */
846
847         DEBUG(10, ("calling find_our_domain\n"));
848         return find_our_domain();
849 }
850
851 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
852 {
853         if ( strequal(domain_name, unix_users_domain_name() ) ||
854              strequal(domain_name, unix_groups_domain_name() ) )
855         {
856                 /*
857                  * The "Unix User" and "Unix Group" domain our handled by
858                  * passdb
859                  */
860                 return find_domain_from_name_noinit( get_global_sam_name() );
861         }
862
863         if (IS_DC || strequal(domain_name, "BUILTIN") ||
864             strequal(domain_name, get_global_sam_name()))
865                 return find_domain_from_name_noinit(domain_name);
866
867
868         return find_our_domain();
869 }
870
871 /* Lookup a sid in a domain from a name */
872
873 bool winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
874                                  enum winbindd_cmd orig_cmd,
875                                  struct winbindd_domain *domain,
876                                  const char *domain_name,
877                                  const char *name, DOM_SID *sid,
878                                  enum lsa_SidType *type)
879 {
880         NTSTATUS result;
881
882         /*
883          * For all but LOOKUPNAME we have to avoid nss calls to avoid
884          * recursion
885          */
886         result = domain->methods->name_to_sid(
887                 domain, mem_ctx, domain_name, name,
888                 orig_cmd == WINBINDD_LOOKUPNAME ? 0 : LOOKUP_NAME_NO_NSS,
889                 sid, type);
890
891         /* Return sid and type if lookup successful */
892         if (!NT_STATUS_IS_OK(result)) {
893                 *type = SID_NAME_UNKNOWN;
894         }
895
896         return NT_STATUS_IS_OK(result);
897 }
898
899 /**
900  * @brief Lookup a name in a domain from a sid.
901  *
902  * @param sid Security ID you want to look up.
903  * @param name On success, set to the name corresponding to @p sid.
904  * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
905  * @param type On success, contains the type of name: alias, group or
906  * user.
907  * @retval True if the name exists, in which case @p name and @p type
908  * are set, otherwise False.
909  **/
910 bool winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
911                                  struct winbindd_domain *domain,
912                                  DOM_SID *sid,
913                                  char **dom_name,
914                                  char **name,
915                                  enum lsa_SidType *type)
916 {
917         NTSTATUS result;
918
919         *dom_name = NULL;
920         *name = NULL;
921
922         /* Lookup name */
923
924         result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
925
926         /* Return name and type if successful */
927
928         if (NT_STATUS_IS_OK(result)) {
929                 return True;
930         }
931
932         *type = SID_NAME_UNKNOWN;
933
934         return False;
935 }
936
937 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
938
939 void free_getent_state(struct getent_state *state)
940 {
941         struct getent_state *temp;
942
943         /* Iterate over state list */
944
945         temp = state;
946
947         while(temp != NULL) {
948                 struct getent_state *next = temp->next;
949
950                 /* Free sam entries then list entry */
951
952                 SAFE_FREE(state->sam_entries);
953                 DLIST_REMOVE(state, state);
954
955                 SAFE_FREE(temp);
956                 temp = next;
957         }
958 }
959
960 /* Is this a domain which we may assume no DOMAIN\ prefix? */
961
962 static bool assume_domain(const char *domain)
963 {
964         /* never assume the domain on a standalone server */
965
966         if ( lp_server_role() == ROLE_STANDALONE )
967                 return False;
968
969         /* domain member servers may possibly assume for the domain name */
970
971         if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
972                 if ( !strequal(lp_workgroup(), domain) )
973                         return False;
974
975                 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
976                         return True;
977         }
978
979         /* only left with a domain controller */
980
981         if ( strequal(get_global_sam_name(), domain) )  {
982                 return True;
983         }
984
985         return False;
986 }
987
988 /* Parse a string of the form DOMAIN\user into a domain and a user */
989
990 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
991 {
992         char *p = strchr(domuser,*lp_winbind_separator());
993
994         if ( !p ) {
995                 fstrcpy(user, domuser);
996
997                 if ( assume_domain(lp_workgroup())) {
998                         fstrcpy(domain, lp_workgroup());
999                 } else if ((p = strchr(domuser, '@')) != NULL) {
1000                         fstrcpy(domain, p + 1);
1001                         user[PTR_DIFF(p, domuser)] = 0;
1002                 } else {
1003                         return False;
1004                 }
1005         } else {
1006                 fstrcpy(user, p+1);
1007                 fstrcpy(domain, domuser);
1008                 domain[PTR_DIFF(p, domuser)] = 0;
1009         }
1010
1011         strupper_m(domain);
1012
1013         return True;
1014 }
1015
1016 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1017                               char **domain, char **user)
1018 {
1019         fstring fstr_domain, fstr_user;
1020         if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1021                 return False;
1022         }
1023         *domain = talloc_strdup(mem_ctx, fstr_domain);
1024         *user = talloc_strdup(mem_ctx, fstr_user);
1025         return ((*domain != NULL) && (*user != NULL));
1026 }
1027
1028 /* add a domain user name to a buffer */
1029 void parse_add_domuser(void *buf, char *domuser, int *len)
1030 {
1031         fstring domain;
1032         char *p, *user;
1033
1034         user = domuser;
1035         p = strchr(domuser, *lp_winbind_separator());
1036
1037         if (p) {
1038
1039                 fstrcpy(domain, domuser);
1040                 domain[PTR_DIFF(p, domuser)] = 0;
1041                 p++;
1042
1043                 if (assume_domain(domain)) {
1044
1045                         user = p;
1046                         *len -= (PTR_DIFF(p, domuser));
1047                 }
1048         }
1049
1050         safe_strcpy((char *)buf, user, *len);
1051 }
1052
1053 /* Ensure an incoming username from NSS is fully qualified. Replace the
1054    incoming fstring with DOMAIN <separator> user. Returns the same
1055    values as parse_domain_user() but also replaces the incoming username.
1056    Used to ensure all names are fully qualified within winbindd.
1057    Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1058    The protocol definitions of auth_crap, chng_pswd_auth_crap
1059    really should be changed to use this instead of doing things
1060    by hand. JRA. */
1061
1062 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1063 {
1064         if (!parse_domain_user(username_inout, domain, user)) {
1065                 return False;
1066         }
1067         slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1068                  domain, *lp_winbind_separator(),
1069                  user);
1070         return True;
1071 }
1072
1073 /*
1074     Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1075     'winbind separator' options.
1076     This means:
1077         - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1078         lp_workgroup()
1079
1080     If we are a PDC or BDC, and this is for our domain, do likewise.
1081
1082     Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
1083     username is then unqualified in unix
1084
1085     We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1086 */
1087 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1088 {
1089         fstring tmp_user;
1090
1091         fstrcpy(tmp_user, user);
1092         strlower_m(tmp_user);
1093
1094         if (can_assume && assume_domain(domain)) {
1095                 strlcpy(name, tmp_user, sizeof(fstring));
1096         } else {
1097                 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1098                          domain, *lp_winbind_separator(),
1099                          tmp_user);
1100         }
1101 }
1102
1103 /**
1104  * talloc version of fill_domain_username()
1105  * return NULL on talloc failure.
1106  */
1107 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1108                                   const char *domain,
1109                                   const char *user,
1110                                   bool can_assume)
1111 {
1112         char *tmp_user, *name;
1113
1114         tmp_user = talloc_strdup(mem_ctx, user);
1115         strlower_m(tmp_user);
1116
1117         if (can_assume && assume_domain(domain)) {
1118                 name = tmp_user;
1119         } else {
1120                 name = talloc_asprintf(mem_ctx, "%s%c%s",
1121                                        domain,
1122                                        *lp_winbind_separator(),
1123                                        tmp_user);
1124                 TALLOC_FREE(tmp_user);
1125         }
1126
1127         return name;
1128 }
1129
1130 /*
1131  * Winbindd socket accessor functions
1132  */
1133
1134 const char *get_winbind_pipe_dir(void)
1135 {
1136         return lp_parm_const_string(-1, "winbindd", "socket dir", WINBINDD_SOCKET_DIR);
1137 }
1138
1139 char *get_winbind_priv_pipe_dir(void)
1140 {
1141         return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
1142 }
1143
1144 /* Open the winbindd socket */
1145
1146 static int _winbindd_socket = -1;
1147 static int _winbindd_priv_socket = -1;
1148
1149 int open_winbindd_socket(void)
1150 {
1151         if (_winbindd_socket == -1) {
1152                 _winbindd_socket = create_pipe_sock(
1153                         get_winbind_pipe_dir(), WINBINDD_SOCKET_NAME, 0755);
1154                 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
1155                            _winbindd_socket));
1156         }
1157
1158         return _winbindd_socket;
1159 }
1160
1161 int open_winbindd_priv_socket(void)
1162 {
1163         if (_winbindd_priv_socket == -1) {
1164                 _winbindd_priv_socket = create_pipe_sock(
1165                         get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
1166                 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
1167                            _winbindd_priv_socket));
1168         }
1169
1170         return _winbindd_priv_socket;
1171 }
1172
1173 /*
1174  * Client list accessor functions
1175  */
1176
1177 static struct winbindd_cli_state *_client_list;
1178 static int _num_clients;
1179
1180 /* Return list of all connected clients */
1181
1182 struct winbindd_cli_state *winbindd_client_list(void)
1183 {
1184         return _client_list;
1185 }
1186
1187 /* Add a connection to the list */
1188
1189 void winbindd_add_client(struct winbindd_cli_state *cli)
1190 {
1191         DLIST_ADD(_client_list, cli);
1192         _num_clients++;
1193 }
1194
1195 /* Remove a client from the list */
1196
1197 void winbindd_remove_client(struct winbindd_cli_state *cli)
1198 {
1199         DLIST_REMOVE(_client_list, cli);
1200         _num_clients--;
1201 }
1202
1203 /* Close all open clients */
1204
1205 void winbindd_kill_all_clients(void)
1206 {
1207         struct winbindd_cli_state *cl = winbindd_client_list();
1208
1209         DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1210
1211         while (cl) {
1212                 struct winbindd_cli_state *next;
1213
1214                 next = cl->next;
1215                 winbindd_remove_client(cl);
1216                 cl = next;
1217         }
1218 }
1219
1220 /* Return number of open clients */
1221
1222 int winbindd_num_clients(void)
1223 {
1224         return _num_clients;
1225 }
1226
1227 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1228                                   TALLOC_CTX *mem_ctx,
1229                                   const DOM_SID *user_sid,
1230                                   uint32 *p_num_groups, DOM_SID **user_sids)
1231 {
1232         struct netr_SamInfo3 *info3 = NULL;
1233         NTSTATUS status = NT_STATUS_NO_MEMORY;
1234         size_t num_groups = 0;
1235
1236         DEBUG(3,(": lookup_usergroups_cached\n"));
1237
1238         *user_sids = NULL;
1239         *p_num_groups = 0;
1240
1241         info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1242
1243         if (info3 == NULL) {
1244                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1245         }
1246
1247         if (info3->base.groups.count == 0) {
1248                 TALLOC_FREE(info3);
1249                 return NT_STATUS_UNSUCCESSFUL;
1250         }
1251
1252         /* Skip Domain local groups outside our domain.
1253            We'll get these from the getsidaliases() RPC call. */
1254         status = sid_array_from_info3(mem_ctx, info3,
1255                                       user_sids,
1256                                       &num_groups,
1257                                       false, true);
1258
1259         if (!NT_STATUS_IS_OK(status)) {
1260                 TALLOC_FREE(info3);
1261                 return status;
1262         }
1263
1264         TALLOC_FREE(info3);
1265         *p_num_groups = num_groups;
1266         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1267
1268         DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1269
1270         return status;
1271 }
1272
1273 /*********************************************************************
1274  We use this to remove spaces from user and group names
1275 ********************************************************************/
1276
1277 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1278                              struct winbindd_domain *domain,
1279                              const char *name,
1280                              char **normalized)
1281 {
1282         NTSTATUS nt_status;
1283
1284         if (!name || !normalized) {
1285                 return NT_STATUS_INVALID_PARAMETER;
1286         }
1287
1288         if (!lp_winbind_normalize_names()) {
1289                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1290         }
1291
1292         /* Alias support and whitespace replacement are mutually
1293            exclusive */
1294
1295         nt_status = resolve_username_to_alias(mem_ctx, domain,
1296                                               name, normalized );
1297         if (NT_STATUS_IS_OK(nt_status)) {
1298                 /* special return code to let the caller know we
1299                    mapped to an alias */
1300                 return NT_STATUS_FILE_RENAMED;
1301         }
1302
1303         /* check for an unreachable domain */
1304
1305         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1306                 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1307                          domain->name));
1308                 set_domain_offline(domain);
1309                 return nt_status;
1310         }
1311
1312         /* deal with whitespace */
1313
1314         *normalized = talloc_strdup(mem_ctx, name);
1315         if (!(*normalized)) {
1316                 return NT_STATUS_NO_MEMORY;
1317         }
1318
1319         all_string_sub( *normalized, " ", "_", 0 );
1320
1321         return NT_STATUS_OK;
1322 }
1323
1324 /*********************************************************************
1325  We use this to do the inverse of normalize_name_map()
1326 ********************************************************************/
1327
1328 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1329                               char *name,
1330                               char **normalized)
1331 {
1332         NTSTATUS nt_status;
1333         struct winbindd_domain *domain = find_our_domain();
1334
1335         if (!name || !normalized) {
1336                 return NT_STATUS_INVALID_PARAMETER;
1337         }
1338
1339         if (!lp_winbind_normalize_names()) {
1340                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1341         }
1342
1343         /* Alias support and whitespace replacement are mutally
1344            exclusive */
1345
1346         /* When mapping from an alias to a username, we don't know the
1347            domain.  But we only need a domain structure to cache
1348            a successful lookup , so just our own domain structure for
1349            the seqnum. */
1350
1351         nt_status = resolve_alias_to_username(mem_ctx, domain,
1352                                               name, normalized);
1353         if (NT_STATUS_IS_OK(nt_status)) {
1354                 /* Special return code to let the caller know we mapped
1355                    from 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_unmap: 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  ********************************************************************/
1382
1383 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1384 {
1385         struct winbindd_tdc_domain *tdc = NULL;
1386         TALLOC_CTX *frame = talloc_stackframe();
1387         bool ret = false;
1388
1389         /* We can contact the domain if it is our primary domain */
1390
1391         if (domain->primary) {
1392                 return true;
1393         }
1394
1395         /* Trust the TDC cache and not the winbindd_domain flags */
1396
1397         if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1398                 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1399                           domain->name));
1400                 return false;
1401         }
1402
1403         /* Can always contact a domain that is in out forest */
1404
1405         if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1406                 ret = true;
1407                 goto done;
1408         }
1409
1410         /*
1411          * On a _member_ server, we cannot contact the domain if it
1412          * is running AD and we have no inbound trust.
1413          */
1414
1415         if (!IS_DC &&
1416              domain->active_directory &&
1417             ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1418         {
1419                 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1420                            "and we have no inbound trust.\n", domain->name));
1421                 goto done;
1422         }
1423
1424         /* Assume everything else is ok (probably not true but what
1425            can you do?) */
1426
1427         ret = true;
1428
1429 done:
1430         talloc_destroy(frame);
1431
1432         return ret;
1433 }
1434
1435 /*********************************************************************
1436  ********************************************************************/
1437
1438 bool winbindd_internal_child(struct winbindd_child *child)
1439 {
1440         if ((child == idmap_child()) || (child == locator_child())) {
1441                 return True;
1442         }
1443
1444         return False;
1445 }
1446
1447 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1448
1449 /*********************************************************************
1450  ********************************************************************/
1451
1452 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1453 {
1454         char *var = NULL;
1455         char addr[INET6_ADDRSTRLEN];
1456         const char *kdc = NULL;
1457         int lvl = 11;
1458
1459         if (!domain || !domain->alt_name || !*domain->alt_name) {
1460                 return;
1461         }
1462
1463         if (domain->initialized && !domain->active_directory) {
1464                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1465                         domain->alt_name));
1466                 return;
1467         }
1468
1469         print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1470         kdc = addr;
1471         if (!*kdc) {
1472                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1473                         domain->alt_name));
1474                 kdc = domain->dcname;
1475         }
1476
1477         if (!kdc || !*kdc) {
1478                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1479                         domain->alt_name));
1480                 return;
1481         }
1482
1483         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1484                                 domain->alt_name) == -1) {
1485                 return;
1486         }
1487
1488         DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1489                 var, kdc));
1490
1491         setenv(var, kdc, 1);
1492         free(var);
1493 }
1494
1495 /*********************************************************************
1496  ********************************************************************/
1497
1498 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1499 {
1500         struct winbindd_domain *our_dom = find_our_domain();
1501
1502         winbindd_set_locator_kdc_env(domain);
1503
1504         if (domain != our_dom) {
1505                 winbindd_set_locator_kdc_env(our_dom);
1506         }
1507 }
1508
1509 /*********************************************************************
1510  ********************************************************************/
1511
1512 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1513 {
1514         char *var = NULL;
1515
1516         if (!domain || !domain->alt_name || !*domain->alt_name) {
1517                 return;
1518         }
1519
1520         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1521                                 domain->alt_name) == -1) {
1522                 return;
1523         }
1524
1525         unsetenv(var);
1526         free(var);
1527 }
1528 #else
1529
1530 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1531 {
1532         return;
1533 }
1534
1535 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1536 {
1537         return;
1538 }
1539
1540 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1541
1542 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1543 {
1544         resp->data.auth.nt_status = NT_STATUS_V(result);
1545         fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1546
1547         /* we might have given a more useful error above */
1548         if (*resp->data.auth.error_string == '\0')
1549                 fstrcpy(resp->data.auth.error_string,
1550                         get_friendly_nt_error_msg(result));
1551         resp->data.auth.pam_error = nt_status_to_pam(result);
1552 }