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