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