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