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