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