source: trunk/samba/source/nsswitch/winbindd_util.c @ 30

Last change on this file since 30 was 30, checked in by Paul Smedley, 14 years ago

Code updated to Samba 3.0.25rc2 level

File size: 28.4 KB
Line 
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 2 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, write to the Free Software
21   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
24#include "includes.h"
25#include "winbindd.h"
26
27#undef DBGC_CLASS
28#define DBGC_CLASS DBGC_WINBIND
29
30extern struct winbindd_methods cache_methods;
31extern struct winbindd_methods passdb_methods;
32
33/**
34 * @file winbindd_util.c
35 *
36 * Winbind daemon for NT domain authentication nss module.
37 **/
38
39
40/**
41 * Used to clobber name fields that have an undefined value.
42 *
43 * Correct code should never look at a field that has this value.
44 **/
45
46static const fstring name_deadbeef = "<deadbeef>";
47
48/* The list of trusted domains.  Note that the list can be deleted and
49   recreated using the init_domain_list() function so pointers to
50   individual winbindd_domain structures cannot be made.  Keep a copy of
51   the domain name instead. */
52
53static struct winbindd_domain *_domain_list;
54
55/**
56   When was the last scan of trusted domains done?
57   
58   0 == not ever
59*/
60
61static time_t last_trustdom_scan;
62
63struct winbindd_domain *domain_list(void)
64{
65        /* Initialise list */
66
67        if ((!_domain_list) && (!init_domain_list())) {
68                smb_panic("Init_domain_list failed\n");
69        }
70
71        return _domain_list;
72}
73
74/* Free all entries in the trusted domain list */
75
76void free_domain_list(void)
77{
78        struct winbindd_domain *domain = _domain_list;
79
80        while(domain) {
81                struct winbindd_domain *next = domain->next;
82               
83                DLIST_REMOVE(_domain_list, domain);
84                SAFE_FREE(domain);
85                domain = next;
86        }
87}
88
89static BOOL is_internal_domain(const DOM_SID *sid)
90{
91        if (sid == NULL)
92                return False;
93
94        return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
95}
96
97static BOOL is_in_internal_domain(const DOM_SID *sid)
98{
99        if (sid == NULL)
100                return False;
101
102        return (sid_check_is_in_our_domain(sid) || sid_check_is_in_builtin(sid));
103}
104
105
106/* Add a trusted domain to our list of domains */
107static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
108                                                  struct winbindd_methods *methods,
109                                                  const DOM_SID *sid)
110{
111        struct winbindd_domain *domain;
112        const char *alternative_name = NULL;
113       
114        /* ignore alt_name if we are not in an AD domain */
115       
116        if ( (lp_security() == SEC_ADS) && alt_name && *alt_name) {
117                alternative_name = alt_name;
118        }
119       
120        /* We can't call domain_list() as this function is called from
121           init_domain_list() and we'll get stuck in a loop. */
122        for (domain = _domain_list; domain; domain = domain->next) {
123                if (strequal(domain_name, domain->name) ||
124                    strequal(domain_name, domain->alt_name)) {
125                        return domain;
126                }
127                if (alternative_name && *alternative_name) {
128                        if (strequal(alternative_name, domain->name) ||
129                            strequal(alternative_name, domain->alt_name)) {
130                                return domain;
131                        }
132                }
133                if (sid) {
134                        if (is_null_sid(sid)) {
135                               
136                        } else if (sid_equal(sid, &domain->sid)) {
137                                return domain;
138                        }
139                }
140        }
141       
142        /* Create new domain entry */
143
144        if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
145                return NULL;
146
147        /* Fill in fields */
148       
149        ZERO_STRUCTP(domain);
150
151        /* prioritise the short name */
152        if (strchr_m(domain_name, '.') && alternative_name && *alternative_name) {
153                fstrcpy(domain->name, alternative_name);
154                fstrcpy(domain->alt_name, domain_name);
155        } else {
156                fstrcpy(domain->name, domain_name);
157                if (alternative_name) {
158                        fstrcpy(domain->alt_name, alternative_name);
159                }
160        }
161
162        domain->methods = methods;
163        domain->backend = NULL;
164        domain->internal = is_internal_domain(sid);
165        domain->sequence_number = DOM_SEQUENCE_NONE;
166        domain->last_seq_check = 0;
167        domain->initialized = False;
168        domain->online = is_internal_domain(sid);
169        domain->check_online_timeout = 0;
170        if (sid) {
171                sid_copy(&domain->sid, sid);
172        }
173       
174        /* Link to domain list */
175        DLIST_ADD(_domain_list, domain);
176       
177        DEBUG(2,("Added domain %s %s %s\n", 
178                 domain->name, domain->alt_name,
179                 &domain->sid?sid_string_static(&domain->sid):""));
180       
181        return domain;
182}
183
184/********************************************************************
185  rescan our domains looking for new trusted domains
186********************************************************************/
187
188struct trustdom_state {
189        TALLOC_CTX *mem_ctx;
190        struct winbindd_response *response;
191};
192
193static void trustdom_recv(void *private_data, BOOL success);
194
195static void add_trusted_domains( struct winbindd_domain *domain )
196{
197        TALLOC_CTX *mem_ctx;
198        struct winbindd_request *request;
199        struct winbindd_response *response;
200
201        struct trustdom_state *state;
202
203        mem_ctx = talloc_init("add_trusted_domains");
204        if (mem_ctx == NULL) {
205                DEBUG(0, ("talloc_init failed\n"));
206                return;
207        }
208
209        request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
210        response = TALLOC_P(mem_ctx, struct winbindd_response);
211        state = TALLOC_P(mem_ctx, struct trustdom_state);
212
213        if ((request == NULL) || (response == NULL) || (state == NULL)) {
214                DEBUG(0, ("talloc failed\n"));
215                talloc_destroy(mem_ctx);
216                return;
217        }
218
219        state->mem_ctx = mem_ctx;
220        state->response = response;
221
222        request->length = sizeof(*request);
223        request->cmd = WINBINDD_LIST_TRUSTDOM;
224
225        async_domain_request(mem_ctx, domain, request, response,
226                             trustdom_recv, state);
227}
228
229static void trustdom_recv(void *private_data, BOOL success)
230{
231        struct trustdom_state *state =
232                talloc_get_type_abort(private_data, struct trustdom_state);
233        struct winbindd_response *response = state->response;
234        char *p;
235
236        if ((!success) || (response->result != WINBINDD_OK)) {
237                DEBUG(1, ("Could not receive trustdoms\n"));
238                talloc_destroy(state->mem_ctx);
239                return;
240        }
241
242        p = (char *)response->extra_data.data;
243
244        while ((p != NULL) && (*p != '\0')) {
245                char *q, *sidstr, *alt_name;
246                DOM_SID sid;
247
248                alt_name = strchr(p, '\\');
249                if (alt_name == NULL) {
250                        DEBUG(0, ("Got invalid trustdom response\n"));
251                        break;
252                }
253
254                *alt_name = '\0';
255                alt_name += 1;
256
257                sidstr = strchr(alt_name, '\\');
258                if (sidstr == NULL) {
259                        DEBUG(0, ("Got invalid trustdom response\n"));
260                        break;
261                }
262
263                *sidstr = '\0';
264                sidstr += 1;
265
266                q = strchr(sidstr, '\n');
267                if (q != NULL)
268                        *q = '\0';
269
270                if (!string_to_sid(&sid, sidstr)) {
271                        /* Allow NULL sid for sibling domains */
272                        if ( strcmp(sidstr,"S-0-0") == 0) {
273                                sid_copy( &sid, &global_sid_NULL);                             
274                        } else {                               
275                                DEBUG(0, ("Got invalid trustdom response\n"));
276                                break;
277                        }                       
278                }
279
280                if (find_domain_from_name_noinit(p) == NULL) {
281                        struct winbindd_domain *domain;
282                        char *alternate_name = NULL;
283                       
284                        /* use the real alt_name if we have one, else pass in NULL */
285
286                        if ( !strequal( alt_name, "(null)" ) )
287                                alternate_name = alt_name;
288
289                        domain = add_trusted_domain(p, alternate_name,
290                                                    &cache_methods,
291                                                    &sid);
292                        setup_domain_child(domain, &domain->child, NULL);
293                }
294                p=q;
295                if (p != NULL)
296                        p += 1;
297        }
298
299        SAFE_FREE(response->extra_data.data);
300        talloc_destroy(state->mem_ctx);
301}
302
303/********************************************************************
304 Periodically we need to refresh the trusted domain cache for smbd
305********************************************************************/
306
307void rescan_trusted_domains( void )
308{
309        time_t now = time(NULL);
310       
311        /* see if the time has come... */
312       
313        if ((now >= last_trustdom_scan) &&
314            ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
315                return;
316               
317        /* this will only add new domains we didn't already know about */
318       
319        add_trusted_domains( find_our_domain() );
320
321        last_trustdom_scan = now;
322       
323        return; 
324}
325
326struct init_child_state {
327        TALLOC_CTX *mem_ctx;
328        struct winbindd_domain *domain;
329        struct winbindd_request *request;
330        struct winbindd_response *response;
331        void (*continuation)(void *private_data, BOOL success);
332        void *private_data;
333};
334
335static void init_child_recv(void *private_data, BOOL success);
336static void init_child_getdc_recv(void *private_data, BOOL success);
337
338enum winbindd_result init_child_connection(struct winbindd_domain *domain,
339                                           void (*continuation)(void *private_data,
340                                                                BOOL success),
341                                           void *private_data)
342{
343        TALLOC_CTX *mem_ctx;
344        struct winbindd_request *request;
345        struct winbindd_response *response;
346        struct init_child_state *state;
347        struct winbindd_domain *request_domain;
348
349        mem_ctx = talloc_init("init_child_connection");
350        if (mem_ctx == NULL) {
351                DEBUG(0, ("talloc_init failed\n"));
352                return WINBINDD_ERROR;
353        }
354
355        request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
356        response = TALLOC_P(mem_ctx, struct winbindd_response);
357        state = TALLOC_P(mem_ctx, struct init_child_state);
358
359        if ((request == NULL) || (response == NULL) || (state == NULL)) {
360                DEBUG(0, ("talloc failed\n"));
361                TALLOC_FREE(mem_ctx);
362                continuation(private_data, False);
363                return WINBINDD_ERROR;
364        }
365
366        request->length = sizeof(*request);
367
368        state->mem_ctx = mem_ctx;
369        state->domain = domain;
370        state->request = request;
371        state->response = response;
372        state->continuation = continuation;
373        state->private_data = private_data;
374
375        if (IS_DC || domain->primary) {
376                /* The primary domain has to find the DC name itself */
377                request->cmd = WINBINDD_INIT_CONNECTION;
378                fstrcpy(request->domain_name, domain->name);
379                request->data.init_conn.is_primary = True;
380                fstrcpy(request->data.init_conn.dcname, "");
381                async_request(mem_ctx, &domain->child, request, response,
382                              init_child_recv, state);
383                return WINBINDD_PENDING;
384        }
385
386        /* This is *not* the primary domain, let's ask our DC about a DC
387         * name */
388
389        request->cmd = WINBINDD_GETDCNAME;
390        fstrcpy(request->domain_name, domain->name);
391
392        request_domain = find_our_domain();
393       
394        async_domain_request(mem_ctx, request_domain, request, response,
395                             init_child_getdc_recv, state);
396        return WINBINDD_PENDING;
397}
398
399static void init_child_getdc_recv(void *private_data, BOOL success)
400{
401        struct init_child_state *state =
402                talloc_get_type_abort(private_data, struct init_child_state);
403        const char *dcname = "";
404
405        DEBUG(10, ("Received getdcname response\n"));
406
407        if (success && (state->response->result == WINBINDD_OK)) {
408                dcname = state->response->data.dc_name;
409        }
410
411        state->request->cmd = WINBINDD_INIT_CONNECTION;
412        fstrcpy(state->request->domain_name, state->domain->name);
413        state->request->data.init_conn.is_primary = False;
414        fstrcpy(state->request->data.init_conn.dcname, dcname);
415
416        async_request(state->mem_ctx, &state->domain->child,
417                      state->request, state->response,
418                      init_child_recv, state);
419}
420
421static void init_child_recv(void *private_data, BOOL success)
422{
423        struct init_child_state *state =
424                talloc_get_type_abort(private_data, struct init_child_state);
425
426        DEBUG(5, ("Received child initialization response for domain %s\n",
427                  state->domain->name));
428
429        if ((!success) || (state->response->result != WINBINDD_OK)) {
430                DEBUG(3, ("Could not init child\n"));
431                state->continuation(state->private_data, False);
432                talloc_destroy(state->mem_ctx);
433                return;
434        }
435
436        fstrcpy(state->domain->name,
437                state->response->data.domain_info.name);
438        fstrcpy(state->domain->alt_name,
439                state->response->data.domain_info.alt_name);
440        string_to_sid(&state->domain->sid,
441                      state->response->data.domain_info.sid);
442        state->domain->native_mode =
443                state->response->data.domain_info.native_mode;
444        state->domain->active_directory =
445                state->response->data.domain_info.active_directory;
446        state->domain->sequence_number =
447                state->response->data.domain_info.sequence_number;
448
449        init_dc_connection(state->domain);
450
451        if (state->continuation != NULL)
452                state->continuation(state->private_data, True);
453        talloc_destroy(state->mem_ctx);
454}
455
456enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
457                                                   struct winbindd_cli_state *state)
458{
459        /* Ensure null termination */
460        state->request.domain_name
461                [sizeof(state->request.domain_name)-1]='\0';
462        state->request.data.init_conn.dcname
463                [sizeof(state->request.data.init_conn.dcname)-1]='\0';
464
465        if (strlen(state->request.data.init_conn.dcname) > 0) {
466                fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
467        }
468
469        init_dc_connection(domain);
470
471        if (!domain->initialized) {
472                /* If we return error here we can't do any cached authentication,
473                   but we may be in disconnected mode and can't initialize correctly.
474                   Do what the previous code did and just return without initialization,
475                   once we go online we'll re-initialize.
476                */
477                DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
478                        "online = %d\n", domain->name, (int)domain->online ));
479        }
480
481        fstrcpy(state->response.data.domain_info.name, domain->name);
482        fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
483        fstrcpy(state->response.data.domain_info.sid,
484                sid_string_static(&domain->sid));
485       
486        state->response.data.domain_info.native_mode
487                = domain->native_mode;
488        state->response.data.domain_info.active_directory
489                = domain->active_directory;
490        state->response.data.domain_info.primary
491                = domain->primary;
492        state->response.data.domain_info.sequence_number =
493                domain->sequence_number;
494
495        return WINBINDD_OK;
496}
497
498/* Look up global info for the winbind daemon */
499BOOL init_domain_list(void)
500{
501        struct winbindd_domain *domain;
502        int role = lp_server_role();
503
504        /* Free existing list */
505        free_domain_list();
506
507        /* Add ourselves as the first entry. */
508
509        if ( role == ROLE_DOMAIN_MEMBER ) {
510                DOM_SID our_sid;
511
512                if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
513                        DEBUG(0, ("Could not fetch our SID - did we join?\n"));
514                        return False;
515                }
516       
517                domain = add_trusted_domain( lp_workgroup(), lp_realm(),
518                                             &cache_methods, &our_sid);
519                domain->primary = True;
520                setup_domain_child(domain, &domain->child, NULL);
521               
522                /* Even in the parent winbindd we'll need to
523                   talk to the DC, so try and see if we can
524                   contact it. Theoretically this isn't neccessary
525                   as the init_dc_connection() in init_child_recv()
526                   will do this, but we can start detecting the DC
527                   early here. */
528                set_domain_online_request(domain);
529        }
530
531        /* Local SAM */
532
533        domain = add_trusted_domain(get_global_sam_name(), NULL,
534                                    &passdb_methods, get_global_sam_sid());
535        if ( role != ROLE_DOMAIN_MEMBER ) {
536                domain->primary = True;
537        }
538        setup_domain_child(domain, &domain->child, NULL);
539
540        /* BUILTIN domain */
541
542        domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
543                                    &global_sid_Builtin);
544        setup_domain_child(domain, &domain->child, NULL);
545
546        return True;
547}
548
549/**
550 * Given a domain name, return the struct winbindd domain info for it
551 *
552 * @note Do *not* pass lp_workgroup() to this function.  domain_list
553 *       may modify it's value, and free that pointer.  Instead, our local
554 *       domain may be found by calling find_our_domain().
555 *       directly.
556 *
557 *
558 * @return The domain structure for the named domain, if it is working.
559 */
560
561struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
562{
563        struct winbindd_domain *domain;
564
565        /* Search through list */
566
567        for (domain = domain_list(); domain != NULL; domain = domain->next) {
568                if (strequal(domain_name, domain->name) ||
569                    (domain->alt_name[0] &&
570                     strequal(domain_name, domain->alt_name))) {
571                        return domain;
572                }
573        }
574
575        /* Not found */
576
577        return NULL;
578}
579
580struct winbindd_domain *find_domain_from_name(const char *domain_name)
581{
582        struct winbindd_domain *domain;
583
584        domain = find_domain_from_name_noinit(domain_name);
585
586        if (domain == NULL)
587                return NULL;
588
589        if (!domain->initialized)
590                init_dc_connection(domain);
591
592        return domain;
593}
594
595/* Given a domain sid, return the struct winbindd domain info for it */
596
597struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
598{
599        struct winbindd_domain *domain;
600
601        /* Search through list */
602
603        for (domain = domain_list(); domain != NULL; domain = domain->next) {
604                if (sid_compare_domain(sid, &domain->sid) == 0)
605                        return domain;
606        }
607
608        /* Not found */
609
610        return NULL;
611}
612
613/* Given a domain sid, return the struct winbindd domain info for it */
614
615struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
616{
617        struct winbindd_domain *domain;
618
619        domain = find_domain_from_sid_noinit(sid);
620
621        if (domain == NULL)
622                return NULL;
623
624        if (!domain->initialized)
625                init_dc_connection(domain);
626
627        return domain;
628}
629
630struct winbindd_domain *find_our_domain(void)
631{
632        struct winbindd_domain *domain;
633
634        /* Search through list */
635
636        for (domain = domain_list(); domain != NULL; domain = domain->next) {
637                if (domain->primary)
638                        return domain;
639        }
640
641        smb_panic("Could not find our domain\n");
642        return NULL;
643}
644
645struct winbindd_domain *find_root_domain(void)
646{
647        struct winbindd_domain *ours = find_our_domain();       
648       
649        if ( !ours )
650                return NULL;
651       
652        if ( strlen(ours->forest_name) == 0 )
653                return NULL;
654       
655        return find_domain_from_name( ours->forest_name );
656}
657
658struct winbindd_domain *find_builtin_domain(void)
659{
660        DOM_SID sid;
661        struct winbindd_domain *domain;
662
663        string_to_sid(&sid, "S-1-5-32");
664        domain = find_domain_from_sid(&sid);
665
666        if (domain == NULL)
667                smb_panic("Could not find BUILTIN domain\n");
668
669        return domain;
670}
671
672/* Find the appropriate domain to lookup a name or SID */
673
674struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
675{
676        /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
677         * one to contact the external DC's. On member servers the internal
678         * domains are different: These are part of the local SAM. */
679
680        DEBUG(10, ("find_lookup_domain_from_sid(%s)\n",
681                   sid_string_static(sid)));
682
683        if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
684                DEBUG(10, ("calling find_domain_from_sid\n"));
685                return find_domain_from_sid(sid);
686        }
687
688        /* On a member server a query for SID or name can always go to our
689         * primary DC. */
690
691        DEBUG(10, ("calling find_our_domain\n"));
692        return find_our_domain();
693}
694
695struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
696{
697        if (IS_DC || strequal(domain_name, "BUILTIN") ||
698            strequal(domain_name, get_global_sam_name()))
699                return find_domain_from_name_noinit(domain_name);
700
701        return find_our_domain();
702}
703
704/* Lookup a sid in a domain from a name */
705
706BOOL winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
707                                 struct winbindd_domain *domain, 
708                                 const char *domain_name,
709                                 const char *name, DOM_SID *sid, 
710                                 enum lsa_SidType *type)
711{
712        NTSTATUS result;
713
714        /* Lookup name */
715        result = domain->methods->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
716
717        /* Return sid and type if lookup successful */
718        if (!NT_STATUS_IS_OK(result)) {
719                *type = SID_NAME_UNKNOWN;
720        }
721
722        return NT_STATUS_IS_OK(result);
723}
724
725/**
726 * @brief Lookup a name in a domain from a sid.
727 *
728 * @param sid Security ID you want to look up.
729 * @param name On success, set to the name corresponding to @p sid.
730 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
731 * @param type On success, contains the type of name: alias, group or
732 * user.
733 * @retval True if the name exists, in which case @p name and @p type
734 * are set, otherwise False.
735 **/
736BOOL winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
737                                 DOM_SID *sid,
738                                 char **dom_name,
739                                 char **name,
740                                 enum lsa_SidType *type)
741{
742        NTSTATUS result;
743        struct winbindd_domain *domain;
744
745        *dom_name = NULL;
746        *name = NULL;
747
748        domain = find_lookup_domain_from_sid(sid);
749
750        if (!domain) {
751                DEBUG(1,("Can't find domain from sid\n"));
752                return False;
753        }
754
755        /* Lookup name */
756
757        result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
758
759        /* Return name and type if successful */
760       
761        if (NT_STATUS_IS_OK(result)) {
762                return True;
763        }
764
765        *type = SID_NAME_UNKNOWN;
766       
767        return False;
768}
769
770/* Free state information held for {set,get,end}{pw,gr}ent() functions */
771
772void free_getent_state(struct getent_state *state)
773{
774        struct getent_state *temp;
775
776        /* Iterate over state list */
777
778        temp = state;
779
780        while(temp != NULL) {
781                struct getent_state *next;
782
783                /* Free sam entries then list entry */
784
785                SAFE_FREE(state->sam_entries);
786                DLIST_REMOVE(state, state);
787                next = temp->next;
788
789                SAFE_FREE(temp);
790                temp = next;
791        }
792}
793
794/* Is this a domain which we may assume no DOMAIN\ prefix? */
795
796static BOOL assume_domain(const char *domain)
797{
798        /* never assume the domain on a standalone server */
799
800        if ( lp_server_role() == ROLE_STANDALONE )
801                return False;
802
803        /* domain member servers may possibly assume for the domain name */
804
805        if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
806                if ( !strequal(lp_workgroup(), domain) )
807                        return False;
808
809                if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
810                        return True;
811        } 
812
813        /* only left with a domain controller */
814
815        if ( strequal(get_global_sam_name(), domain) )  {
816                return True;
817        }
818       
819        return False;
820}
821
822/* Parse a string of the form DOMAIN\user into a domain and a user */
823
824BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
825{
826        char *p = strchr(domuser,*lp_winbind_separator());
827
828        if ( !p ) {
829                fstrcpy(user, domuser);
830
831                if ( assume_domain(lp_workgroup())) {
832                        fstrcpy(domain, lp_workgroup());
833                } else {
834                        return False;
835                }
836        } else {
837                fstrcpy(user, p+1);
838                fstrcpy(domain, domuser);
839                domain[PTR_DIFF(p, domuser)] = 0;
840        }
841       
842        strupper_m(domain);
843       
844        return True;
845}
846
847BOOL parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
848                              char **domain, char **user)
849{
850        fstring fstr_domain, fstr_user;
851        if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
852                return False;
853        }
854        *domain = talloc_strdup(mem_ctx, fstr_domain);
855        *user = talloc_strdup(mem_ctx, fstr_user);
856        return ((*domain != NULL) && (*user != NULL));
857}
858
859/* Ensure an incoming username from NSS is fully qualified. Replace the
860   incoming fstring with DOMAIN <separator> user. Returns the same
861   values as parse_domain_user() but also replaces the incoming username.
862   Used to ensure all names are fully qualified within winbindd.
863   Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
864   The protocol definitions of auth_crap, chng_pswd_auth_crap
865   really should be changed to use this instead of doing things
866   by hand. JRA. */
867
868BOOL canonicalize_username(fstring username_inout, fstring domain, fstring user)
869{
870        if (!parse_domain_user(username_inout, domain, user)) {
871                return False;
872        }
873        slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
874                 domain, *lp_winbind_separator(),
875                 user);
876        return True;
877}
878
879/*
880    Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
881    'winbind separator' options.
882    This means:
883        - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
884        lp_workgroup()
885
886    If we are a PDC or BDC, and this is for our domain, do likewise.
887
888    Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
889    username is then unqualified in unix
890
891    We always canonicalize as UPPERCASE DOMAIN, lowercase username.
892*/
893void fill_domain_username(fstring name, const char *domain, const char *user, BOOL can_assume)
894{
895        fstring tmp_user;
896
897        fstrcpy(tmp_user, user);
898        strlower_m(tmp_user);
899
900        if (can_assume && assume_domain(domain)) {
901                strlcpy(name, tmp_user, sizeof(fstring));
902        } else {
903                slprintf(name, sizeof(fstring) - 1, "%s%c%s",
904                         domain, *lp_winbind_separator(),
905                         tmp_user);
906        }
907}
908
909/*
910 * Winbindd socket accessor functions
911 */
912
913char *get_winbind_priv_pipe_dir(void) 
914{
915        return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
916}
917
918/* Open the winbindd socket */
919
920static int _winbindd_socket = -1;
921static int _winbindd_priv_socket = -1;
922
923int open_winbindd_socket(void)
924{
925        if (_winbindd_socket == -1) {
926                _winbindd_socket = create_pipe_sock(
927                        WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME, 0755);
928                DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
929                           _winbindd_socket));
930        }
931
932        return _winbindd_socket;
933}
934
935int open_winbindd_priv_socket(void)
936{
937        if (_winbindd_priv_socket == -1) {
938                _winbindd_priv_socket = create_pipe_sock(
939                        get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
940                DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
941                           _winbindd_priv_socket));
942        }
943
944        return _winbindd_priv_socket;
945}
946
947/* Close the winbindd socket */
948
949void close_winbindd_socket(void)
950{
951        if (_winbindd_socket != -1) {
952                DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
953                           _winbindd_socket));
954                close(_winbindd_socket);
955                _winbindd_socket = -1;
956        }
957        if (_winbindd_priv_socket != -1) {
958                DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
959                           _winbindd_priv_socket));
960                close(_winbindd_priv_socket);
961                _winbindd_priv_socket = -1;
962        }
963}
964
965/*
966 * Client list accessor functions
967 */
968
969static struct winbindd_cli_state *_client_list;
970static int _num_clients;
971
972/* Return list of all connected clients */
973
974struct winbindd_cli_state *winbindd_client_list(void)
975{
976        return _client_list;
977}
978
979/* Add a connection to the list */
980
981void winbindd_add_client(struct winbindd_cli_state *cli)
982{
983        DLIST_ADD(_client_list, cli);
984        _num_clients++;
985}
986
987/* Remove a client from the list */
988
989void winbindd_remove_client(struct winbindd_cli_state *cli)
990{
991        DLIST_REMOVE(_client_list, cli);
992        _num_clients--;
993}
994
995/* Close all open clients */
996
997void winbindd_kill_all_clients(void)
998{
999        struct winbindd_cli_state *cl = winbindd_client_list();
1000
1001        DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1002
1003        while (cl) {
1004                struct winbindd_cli_state *next;
1005               
1006                next = cl->next;
1007                winbindd_remove_client(cl);
1008                cl = next;
1009        }
1010}
1011
1012/* Return number of open clients */
1013
1014int winbindd_num_clients(void)
1015{
1016        return _num_clients;
1017}
1018
1019NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1020                                  TALLOC_CTX *mem_ctx,
1021                                  const DOM_SID *user_sid,
1022                                  uint32 *p_num_groups, DOM_SID **user_sids)
1023{
1024        NET_USER_INFO_3 *info3 = NULL;
1025        NTSTATUS status = NT_STATUS_NO_MEMORY;
1026        int i;
1027        size_t num_groups = 0;
1028        DOM_SID group_sid, primary_group;
1029       
1030        DEBUG(3,(": lookup_usergroups_cached\n"));
1031       
1032        *user_sids = NULL;
1033        num_groups = 0;
1034        *p_num_groups = 0;
1035
1036        info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1037
1038        if (info3 == NULL) {
1039                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1040        }
1041
1042        if (info3->num_groups == 0) {
1043                SAFE_FREE(info3);
1044                return NT_STATUS_UNSUCCESSFUL;
1045        }
1046       
1047        /* always add the primary group to the sid array */
1048        sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
1049       
1050        if (!add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups)) {
1051                SAFE_FREE(info3);
1052                return NT_STATUS_NO_MEMORY;
1053        }
1054
1055        for (i=0; i<info3->num_groups; i++) {
1056                sid_copy(&group_sid, &info3->dom_sid.sid);
1057                sid_append_rid(&group_sid, info3->gids[i].g_rid);
1058
1059                if (!add_sid_to_array(mem_ctx, &group_sid, user_sids,
1060                                 &num_groups)) {
1061                        SAFE_FREE(info3);
1062                        return NT_STATUS_NO_MEMORY;
1063                }
1064        }
1065
1066        SAFE_FREE(info3);
1067        *p_num_groups = num_groups;
1068        status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1069       
1070        DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1071
1072        return status;
1073}
1074
1075/*********************************************************************
1076 We use this to remove spaces from user and group names
1077********************************************************************/
1078
1079void ws_name_replace( char *name, char replace )
1080{
1081        char replace_char[2] = { 0x0, 0x0 };
1082   
1083        if ( !lp_winbind_normalize_names() || (replace == '\0') ) 
1084                return;
1085
1086        replace_char[0] = replace;     
1087        all_string_sub( name, " ", replace_char, 0 );
1088
1089        return; 
1090}
1091
1092/*********************************************************************
1093 We use this to do the inverse of ws_name_replace()
1094********************************************************************/
1095
1096void ws_name_return( char *name, char replace )
1097{
1098        char replace_char[2] = { 0x0, 0x0 };
1099   
1100        if ( !lp_winbind_normalize_names() || (replace == '\0') ) 
1101                return;
1102       
1103        replace_char[0] = replace;     
1104        all_string_sub( name, replace_char, " ", 0 );
1105
1106        return; 
1107}
Note: See TracBrowser for help on using the repository browser.