b9fb49ea7f67162c0ef6c7c156690b794d07b05d
[obnox/samba/samba-obnox.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 extern DOM_SID global_sid_Builtin;
28 extern struct winbindd_methods cache_methods;
29 extern struct winbindd_methods passdb_methods;
30
31 #undef DBGC_CLASS
32 #define DBGC_CLASS DBGC_WINBIND
33
34 /**
35  * @file winbindd_util.c
36  *
37  * Winbind daemon for NT domain authentication nss module.
38  **/
39
40
41 /**
42  * Used to clobber name fields that have an undefined value.
43  *
44  * Correct code should never look at a field that has this value.
45  **/
46
47 static const fstring name_deadbeef = "<deadbeef>";
48
49 /* The list of trusted domains.  Note that the list can be deleted and
50    recreated using the init_domain_list() function so pointers to
51    individual winbindd_domain structures cannot be made.  Keep a copy of
52    the domain name instead. */
53
54 static struct winbindd_domain *_domain_list;
55
56 /**
57    When was the last scan of trusted domains done?
58    
59    0 == not ever
60 */
61
62 static time_t last_trustdom_scan;
63
64 struct winbindd_domain *domain_list(void)
65 {
66         /* Initialise list */
67
68         if (!_domain_list) 
69                 if (!init_domain_list()) 
70                         return NULL;
71
72         return _domain_list;
73 }
74
75 /* Free all entries in the trusted domain list */
76
77 void free_domain_list(void)
78 {
79         struct winbindd_domain *domain = _domain_list;
80
81         while(domain) {
82                 struct winbindd_domain *next = domain->next;
83                 
84                 DLIST_REMOVE(_domain_list, domain);
85                 SAFE_FREE(domain);
86                 domain = next;
87         }
88 }
89
90 static BOOL is_internal_domain(const DOM_SID *sid)
91 {
92         if (sid == NULL)
93                 return False;
94
95         if (sid_compare_domain(sid, get_global_sam_sid()) == 0)
96                 return True;
97
98         if (sid_compare_domain(sid, &global_sid_Builtin) == 0)
99                 return True;
100
101         return False;
102 }
103
104
105 /* Add a trusted domain to our list of domains */
106 static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
107                                                   struct winbindd_methods *methods,
108                                                   DOM_SID *sid)
109 {
110         struct winbindd_domain *domain;
111         const char *alternative_name = NULL;
112         static const DOM_SID null_sid;
113         
114         /* ignore alt_name if we are not in an AD domain */
115         
116         if ( (lp_security() == SEC_ADS) && alt_name && *alt_name) {
117                 alternative_name = alt_name;
118         }
119         
120         /* We can't call domain_list() as this function is called from
121            init_domain_list() and we'll get stuck in a loop. */
122         for (domain = _domain_list; domain; domain = domain->next) {
123                 if (strequal(domain_name, domain->name) ||
124                     strequal(domain_name, domain->alt_name)) {
125                         return domain;
126                 }
127                 if (alternative_name && *alternative_name) {
128                         if (strequal(alternative_name, domain->name) ||
129                             strequal(alternative_name, domain->alt_name)) {
130                                 return domain;
131                         }
132                 }
133                 if (sid) {
134                         if (sid_equal(sid, &null_sid) ) {
135                                 
136                         } else if (sid_equal(sid, &domain->sid)) {
137                                 return domain;
138                         }
139                 }
140         }
141         
142         /* Create new domain entry */
143
144         if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
145                 return NULL;
146
147         /* Fill in fields */
148         
149         ZERO_STRUCTP(domain);
150
151         /* prioritise the short name */
152         if (strchr_m(domain_name, '.') && alternative_name && *alternative_name) {
153                 fstrcpy(domain->name, alternative_name);
154                 fstrcpy(domain->alt_name, domain_name);
155         } else {
156                 fstrcpy(domain->name, domain_name);
157                 if (alternative_name) {
158                         fstrcpy(domain->alt_name, alternative_name);
159                 }
160         }
161
162         domain->methods = methods;
163         domain->backend = NULL;
164         domain->internal = is_internal_domain(sid);
165         domain->sequence_number = DOM_SEQUENCE_NONE;
166         domain->last_seq_check = 0;
167         domain->initialized = False;
168         if (sid) {
169                 sid_copy(&domain->sid, sid);
170         }
171         
172         /* Link to domain list */
173         DLIST_ADD(_domain_list, domain);
174         
175         DEBUG(2,("Added domain %s %s %s\n", 
176                  domain->name, domain->alt_name,
177                  &domain->sid?sid_string_static(&domain->sid):""));
178         
179         return domain;
180 }
181
182 /********************************************************************
183   rescan our domains looking for new trusted domains
184 ********************************************************************/
185
186 static void add_trusted_domains( struct winbindd_domain *domain )
187 {
188         TALLOC_CTX *mem_ctx;
189         NTSTATUS result;
190         time_t t;
191         char **names;
192         char **alt_names;
193         int num_domains = 0;
194         DOM_SID *dom_sids, null_sid;
195         int i;
196         struct winbindd_domain *new_domain;
197
198         /* trusted domains might be disabled */
199         if (!lp_allow_trusted_domains()) {
200                 return;
201         }
202
203         DEBUG(5, ("scanning trusted domain list\n"));
204
205         if (!(mem_ctx = talloc_init("init_domain_list")))
206                 return;
207            
208         ZERO_STRUCTP(&null_sid);
209
210         t = time(NULL);
211         
212         /* ask the DC what domains it trusts */
213         
214         result = domain->methods->trusted_domains(domain, mem_ctx, (unsigned int *)&num_domains,
215                 &names, &alt_names, &dom_sids);
216                 
217         if ( NT_STATUS_IS_OK(result) ) {
218
219                 /* Add each domain to the trusted domain list */
220                 
221                 for(i = 0; i < num_domains; i++) {
222                         DEBUG(10,("Found domain %s\n", names[i]));
223                         add_trusted_domain(names[i], alt_names?alt_names[i]:NULL,
224                                            &cache_methods, &dom_sids[i]);
225                                            
226                         /* if the SID was empty, we better set it now */
227                         
228                         if ( sid_equal(&dom_sids[i], &null_sid) ) {
229                         
230                                 new_domain = find_domain_from_name(names[i]);
231                                  
232                                 /* this should never happen */
233                                 if ( !new_domain ) {    
234                                         DEBUG(0,("rescan_trust_domains: can't find the domain I just added! [%s]\n",
235                                                 names[i]));
236                                         break;
237                                 }
238                                  
239                                 /* call the cache method; which will operate on the winbindd_domain \
240                                    passed in and choose either rpc or ads as appropriate */
241
242                                 result = domain->methods->domain_sid( new_domain, &new_domain->sid );
243                                  
244                                 if ( NT_STATUS_IS_OK(result) )
245                                         sid_copy( &dom_sids[i], &new_domain->sid );
246                         }
247                         
248                         /* store trusted domain in the cache */
249                         trustdom_cache_store(names[i], alt_names ? alt_names[i] : NULL,
250                                              &dom_sids[i], t + WINBINDD_RESCAN_FREQ);
251                 }
252         }
253
254         talloc_destroy(mem_ctx);
255 }
256
257 /********************************************************************
258  Periodically we need to refresh the trusted domain cache for smbd 
259 ********************************************************************/
260
261 void rescan_trusted_domains( void )
262 {
263         time_t now = time(NULL);
264         struct winbindd_domain *mydomain = NULL;
265         
266         /* see if the time has come... */
267         
268         if ( (now > last_trustdom_scan) && ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
269                 return;
270                 
271         if ( (mydomain = find_our_domain()) == NULL ) {
272                 DEBUG(0,("rescan_trusted_domains: Can't find my own domain!\n"));
273                 return;
274         }
275         
276         /* this will only add new domains we didn't already know about */
277         
278         add_trusted_domains( mydomain );
279
280         last_trustdom_scan = now;
281         
282         return; 
283 }
284
285 /* Look up global info for the winbind daemon */
286 BOOL init_domain_list(void)
287 {
288         struct winbindd_domain *domain;
289
290         /* Free existing list */
291         free_domain_list();
292
293         /* Add ourselves as the first entry. */
294
295         if (IS_DC) {
296                 domain = add_trusted_domain(get_global_sam_name(), NULL,
297                                             &passdb_methods, get_global_sam_sid());
298         } else {
299         
300                 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
301                                              &cache_methods, NULL);
302         
303                 /* set flags about native_mode, active_directory */
304                 set_dc_type_and_flags(domain);
305         }
306
307         domain->primary = True;
308
309         /* get any alternate name for the primary domain */
310         
311         cache_methods.alternate_name(domain);
312         
313         /* now we have the correct netbios (short) domain name */
314         
315         if ( *domain->name )
316                 set_global_myworkgroup( domain->name );
317                 
318         if (!secrets_fetch_domain_sid(domain->name, &domain->sid)) {
319                 DEBUG(1, ("Could not fetch sid for our domain %s\n",
320                           domain->name));
321                 return False;
322         }
323
324         /* do an initial scan for trusted domains */
325         add_trusted_domains(domain);
326
327
328         /* Add our local SAM domains */
329
330         add_trusted_domain("BUILTIN", NULL, &passdb_methods,
331                            &global_sid_Builtin);
332
333         if (!IS_DC) {
334                 add_trusted_domain(get_global_sam_name(), NULL,
335                                    &passdb_methods, get_global_sam_sid());
336         }
337         
338         /* avoid rescanning this right away */
339         last_trustdom_scan = time(NULL);
340         return True;
341 }
342
343 /** 
344  * Given a domain name, return the struct winbindd domain info for it 
345  *
346  * @note Do *not* pass lp_workgroup() to this function.  domain_list
347  *       may modify it's value, and free that pointer.  Instead, our local
348  *       domain may be found by calling find_our_domain().
349  *       directly.
350  *
351  *
352  * @return The domain structure for the named domain, if it is working.
353  */
354
355 struct winbindd_domain *find_domain_from_name(const char *domain_name)
356 {
357         struct winbindd_domain *domain;
358
359         /* Search through list */
360
361         for (domain = domain_list(); domain != NULL; domain = domain->next) {
362                 if (strequal(domain_name, domain->name) ||
363                     (domain->alt_name[0] && strequal(domain_name, domain->alt_name))) {
364                         if (!domain->initialized)
365                                 set_dc_type_and_flags(domain);
366
367                         return domain;
368                 }
369         }
370
371         /* Not found */
372
373         return NULL;
374 }
375
376 /* Given a domain sid, return the struct winbindd domain info for it */
377
378 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
379 {
380         struct winbindd_domain *domain;
381
382         /* Search through list */
383
384         for (domain = domain_list(); domain != NULL; domain = domain->next) {
385                 if (sid_compare_domain(sid, &domain->sid) == 0) {
386                         if (!domain->initialized)
387                                 set_dc_type_and_flags(domain);
388                         return domain;
389                 }
390         }
391
392         /* Not found */
393
394         return NULL;
395 }
396
397 /* Given a domain sid, return the struct winbindd domain info for it */
398
399 struct winbindd_domain *find_our_domain(void)
400 {
401         struct winbindd_domain *domain;
402
403         /* Search through list */
404
405         for (domain = domain_list(); domain != NULL; domain = domain->next) {
406                 if (domain->primary)
407                         return domain;
408         }
409
410         /* Not found */
411
412         return NULL;
413 }
414
415 /* Find the appropriate domain to lookup a name or SID */
416
417 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
418 {
419         /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
420          * one to contact the external DC's. On member servers the internal
421          * domains are different: These are part of the local SAM. */
422
423         if (IS_DC || is_internal_domain(sid))
424                 return find_domain_from_sid(sid);
425
426         /* On a member server a query for SID or name can always go to our
427          * primary DC. */
428
429         return find_our_domain();
430 }
431
432 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
433 {
434         if (IS_DC || strequal(domain_name, "BUILTIN") ||
435             strequal(domain_name, get_global_sam_name()))
436                 return find_domain_from_name(domain_name);
437
438         return find_our_domain();
439 }
440
441 /* Lookup a sid in a domain from a name */
442
443 BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain, 
444                                  const char *domain_name,
445                                  const char *name, DOM_SID *sid, 
446                                  enum SID_NAME_USE *type)
447 {
448         NTSTATUS result;
449         TALLOC_CTX *mem_ctx;
450
451         mem_ctx = talloc_init("lookup_sid_by_name for %s\\%s\n",
452                               domain_name, name);
453         if (!mem_ctx) 
454                 return False;
455         
456         /* Lookup name */
457         result = domain->methods->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
458
459         talloc_destroy(mem_ctx);
460         
461         /* Return rid and type if lookup successful */
462         if (!NT_STATUS_IS_OK(result)) {
463                 *type = SID_NAME_UNKNOWN;
464         }
465
466         return NT_STATUS_IS_OK(result);
467 }
468
469 /**
470  * @brief Lookup a name in a domain from a sid.
471  *
472  * @param sid Security ID you want to look up.
473  * @param name On success, set to the name corresponding to @p sid.
474  * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
475  * @param type On success, contains the type of name: alias, group or
476  * user.
477  * @retval True if the name exists, in which case @p name and @p type
478  * are set, otherwise False.
479  **/
480 BOOL winbindd_lookup_name_by_sid(DOM_SID *sid,
481                                  fstring dom_name,
482                                  fstring name,
483                                  enum SID_NAME_USE *type)
484 {
485         char *names;
486         char *dom_names;
487         NTSTATUS result;
488         TALLOC_CTX *mem_ctx;
489         BOOL rv = False;
490         struct winbindd_domain *domain;
491
492         domain = find_lookup_domain_from_sid(sid);
493
494         if (!domain) {
495                 DEBUG(1,("Can't find domain from sid\n"));
496                 return False;
497         }
498
499         /* Lookup name */
500
501         if (!(mem_ctx = talloc_init("winbindd_lookup_name_by_sid")))
502                 return False;
503         
504         result = domain->methods->sid_to_name(domain, mem_ctx, sid, &dom_names, &names, type);
505
506         /* Return name and type if successful */
507         
508         if ((rv = NT_STATUS_IS_OK(result))) {
509                 fstrcpy(dom_name, dom_names);
510                 fstrcpy(name, names);
511         } else {
512                 *type = SID_NAME_UNKNOWN;
513                 fstrcpy(name, name_deadbeef);
514         }
515         
516         talloc_destroy(mem_ctx);
517
518         return rv;
519 }
520
521
522 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
523
524 void free_getent_state(struct getent_state *state)
525 {
526         struct getent_state *temp;
527
528         /* Iterate over state list */
529
530         temp = state;
531
532         while(temp != NULL) {
533                 struct getent_state *next;
534
535                 /* Free sam entries then list entry */
536
537                 SAFE_FREE(state->sam_entries);
538                 DLIST_REMOVE(state, state);
539                 next = temp->next;
540
541                 SAFE_FREE(temp);
542                 temp = next;
543         }
544 }
545
546 /* Parse winbindd related parameters */
547
548 BOOL winbindd_param_init(void)
549 {
550         /* Parse winbind uid and winbind_gid parameters */
551
552         if (!lp_idmap_uid(&server_state.uid_low, &server_state.uid_high)) {
553                 DEBUG(0, ("winbindd: idmap uid range missing or invalid\n"));
554                 DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
555                 return False;
556         }
557         
558         if (!lp_idmap_gid(&server_state.gid_low, &server_state.gid_high)) {
559                 DEBUG(0, ("winbindd: idmap gid range missing or invalid\n"));
560                 DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
561                 return False;
562         }
563         
564         return True;
565 }
566
567 /* Check if a domain is present in a comma-separated list of domains */
568
569 BOOL check_domain_env(char *domain_env, char *domain)
570 {
571         fstring name;
572         const char *tmp = domain_env;
573
574         while(next_token(&tmp, name, ",", sizeof(fstring))) {
575                 if (strequal(name, domain))
576                         return True;
577         }
578
579         return False;
580 }
581
582 /* Is this a domain which we may assume no DOMAIN\ prefix? */
583
584 static BOOL assume_domain(const char *domain) {
585         if ((lp_winbind_use_default_domain()  
586                   || lp_winbind_trusted_domains_only()) &&
587             strequal(lp_workgroup(), domain)) 
588                 return True;
589
590         if (strequal(get_global_sam_name(), domain)) 
591                 return True;
592         
593         return False;
594 }
595
596 /* Parse a string of the form DOMAIN/user into a domain and a user */
597
598 BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
599 {
600         char *p = strchr(domuser,*lp_winbind_separator());
601
602         if ( !p ) {
603                 fstrcpy(user, domuser);
604                 
605                 if ( assume_domain(lp_workgroup())) {
606                         fstrcpy(domain, lp_workgroup());
607                 } else {
608                         fstrcpy( domain, get_global_sam_name() ); 
609                 }
610         } 
611         else {
612                 fstrcpy(user, p+1);
613                 fstrcpy(domain, domuser);
614                 domain[PTR_DIFF(p, domuser)] = 0;
615         }
616         
617         strupper_m(domain);
618         
619         return True;
620 }
621
622 /*
623     Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
624     'winbind separator' options.
625     This means:
626         - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
627         lp_workgroup()
628
629     If we are a PDC or BDC, and this is for our domain, do likewise.
630
631     Also, if omit DOMAIN if 'winbind trusted domains only = true', as the 
632     username is then unqualified in unix
633          
634 */
635 void fill_domain_username(fstring name, const char *domain, const char *user)
636 {
637         strlower_m(CONST_DISCARD(char *, user));
638
639         if (assume_domain(domain)) {
640                 strlcpy(name, user, sizeof(fstring));
641         } else {
642                 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
643                          domain, *lp_winbind_separator(),
644                          user);
645         }
646 }
647
648 /*
649  * Winbindd socket accessor functions
650  */
651
652 char *get_winbind_priv_pipe_dir(void) 
653 {
654         return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
655 }
656
657 /* Open the winbindd socket */
658
659 static int _winbindd_socket = -1;
660 static int _winbindd_priv_socket = -1;
661
662 int open_winbindd_socket(void)
663 {
664         if (_winbindd_socket == -1) {
665                 _winbindd_socket = create_pipe_sock(
666                         WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME, 0755);
667                 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
668                            _winbindd_socket));
669         }
670
671         return _winbindd_socket;
672 }
673
674 int open_winbindd_priv_socket(void)
675 {
676         if (_winbindd_priv_socket == -1) {
677                 _winbindd_priv_socket = create_pipe_sock(
678                         get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
679                 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
680                            _winbindd_priv_socket));
681         }
682
683         return _winbindd_priv_socket;
684 }
685
686 /* Close the winbindd socket */
687
688 void close_winbindd_socket(void)
689 {
690         if (_winbindd_socket != -1) {
691                 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
692                            _winbindd_socket));
693                 close(_winbindd_socket);
694                 _winbindd_socket = -1;
695         }
696         if (_winbindd_priv_socket != -1) {
697                 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
698                            _winbindd_priv_socket));
699                 close(_winbindd_priv_socket);
700                 _winbindd_priv_socket = -1;
701         }
702 }
703
704 /*
705  * Client list accessor functions
706  */
707
708 static struct winbindd_cli_state *_client_list;
709 static int _num_clients;
710
711 /* Return list of all connected clients */
712
713 struct winbindd_cli_state *winbindd_client_list(void)
714 {
715         return _client_list;
716 }
717
718 /* Add a connection to the list */
719
720 void winbindd_add_client(struct winbindd_cli_state *cli)
721 {
722         DLIST_ADD(_client_list, cli);
723         _num_clients++;
724 }
725
726 /* Remove a client from the list */
727
728 void winbindd_remove_client(struct winbindd_cli_state *cli)
729 {
730         DLIST_REMOVE(_client_list, cli);
731         _num_clients--;
732 }
733
734 /* Demote a client to be the last in the list */
735
736 void winbindd_demote_client(struct winbindd_cli_state *cli)
737 {
738         struct winbindd_cli_state *tmp;
739         DLIST_DEMOTE(_client_list, cli, tmp);
740 }
741
742 /* Close all open clients */
743
744 void winbindd_kill_all_clients(void)
745 {
746         struct winbindd_cli_state *cl = winbindd_client_list();
747
748         DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
749
750         while (cl) {
751                 struct winbindd_cli_state *next;
752                 
753                 next = cl->next;
754                 winbindd_remove_client(cl);
755                 cl = next;
756         }
757 }
758
759 /* Return number of open clients */
760
761 int winbindd_num_clients(void)
762 {
763         return _num_clients;
764 }
765
766 /* Help with RID -> SID conversion */
767
768 DOM_SID *rid_to_talloced_sid(struct winbindd_domain *domain,
769                                     TALLOC_CTX *mem_ctx,
770                                     uint32 rid) 
771 {
772         DOM_SID *sid;
773         sid = TALLOC_P(mem_ctx, DOM_SID);
774         if (!sid) {
775                 smb_panic("rid_to_to_talloced_sid: talloc for DOM_SID failed!\n");
776         }
777         sid_copy(sid, &domain->sid);
778         sid_append_rid(sid, rid);
779         return sid;
780 }
781         
782 /*****************************************************************************
783  For idmap conversion: convert one record to new format
784  Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid
785  instead of the SID.
786 *****************************************************************************/
787 static int convert_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA data, void *state)
788 {
789         struct winbindd_domain *domain;
790         char *p;
791         DOM_SID sid;
792         uint32 rid;
793         fstring keystr;
794         fstring dom_name;
795         TDB_DATA key2;
796         BOOL *failed = (BOOL *)state;
797
798         DEBUG(10,("Converting %s\n", key.dptr));
799
800         p = strchr(key.dptr, '/');
801         if (!p)
802                 return 0;
803
804         *p = 0;
805         fstrcpy(dom_name, key.dptr);
806         *p++ = '/';
807
808         domain = find_domain_from_name(dom_name);
809         if (domain == NULL) {
810                 /* We must delete the old record. */
811                 DEBUG(0,("Unable to find domain %s\n", dom_name ));
812                 DEBUG(0,("deleting record %s\n", key.dptr ));
813
814                 if (tdb_delete(tdb, key) != 0) {
815                         DEBUG(0, ("Unable to delete record %s\n", key.dptr));
816                         *failed = True;
817                         return -1;
818                 }
819
820                 return 0;
821         }
822
823         rid = atoi(p);
824
825         sid_copy(&sid, &domain->sid);
826         sid_append_rid(&sid, rid);
827
828         sid_to_string(keystr, &sid);
829         key2.dptr = keystr;
830         key2.dsize = strlen(keystr) + 1;
831
832         if (tdb_store(tdb, key2, data, TDB_INSERT) != 0) {
833                 DEBUG(0,("Unable to add record %s\n", key2.dptr ));
834                 *failed = True;
835                 return -1;
836         }
837
838         if (tdb_store(tdb, data, key2, TDB_REPLACE) != 0) {
839                 DEBUG(0,("Unable to update record %s\n", data.dptr ));
840                 *failed = True;
841                 return -1;
842         }
843
844         if (tdb_delete(tdb, key) != 0) {
845                 DEBUG(0,("Unable to delete record %s\n", key.dptr ));
846                 *failed = True;
847                 return -1;
848         }
849
850         return 0;
851 }
852
853 /* These definitions are from sam/idmap_tdb.c. Replicated here just
854    out of laziness.... :-( */
855
856 /* High water mark keys */
857 #define HWM_GROUP  "GROUP HWM"
858 #define HWM_USER   "USER HWM"
859
860 /* idmap version determines auto-conversion */
861 #define IDMAP_VERSION 2
862
863
864 /*****************************************************************************
865  Convert the idmap database from an older version.
866 *****************************************************************************/
867
868 static BOOL idmap_convert(const char *idmap_name)
869 {
870         int32 vers;
871         BOOL bigendianheader;
872         BOOL failed = False;
873         TDB_CONTEXT *idmap_tdb;
874
875         if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
876                                         TDB_DEFAULT, O_RDWR,
877                                         0600))) {
878                 DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
879                 return False;
880         }
881
882         bigendianheader = (idmap_tdb->flags & TDB_BIGENDIAN) ? True : False;
883
884         vers = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION");
885
886         if (((vers == -1) && bigendianheader) || (IREV(vers) == IDMAP_VERSION)) {
887                 /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
888                 /*
889                  * high and low records were created on a
890                  * big endian machine and will need byte-reversing.
891                  */
892
893                 int32 wm;
894
895                 wm = tdb_fetch_int32(idmap_tdb, HWM_USER);
896
897                 if (wm != -1) {
898                         wm = IREV(wm);
899                 }  else {
900                         wm = server_state.uid_low;
901                 }
902
903                 if (tdb_store_int32(idmap_tdb, HWM_USER, wm) == -1) {
904                         DEBUG(0, ("idmap_convert: Unable to byteswap user hwm in idmap database\n"));
905                         tdb_close(idmap_tdb);
906                         return False;
907                 }
908
909                 wm = tdb_fetch_int32(idmap_tdb, HWM_GROUP);
910                 if (wm != -1) {
911                         wm = IREV(wm);
912                 } else {
913                         wm = server_state.gid_low;
914                 }
915
916                 if (tdb_store_int32(idmap_tdb, HWM_GROUP, wm) == -1) {
917                         DEBUG(0, ("idmap_convert: Unable to byteswap group hwm in idmap database\n"));
918                         tdb_close(idmap_tdb);
919                         return False;
920                 }
921         }
922
923         /* the old format stored as DOMAIN/rid - now we store the SID direct */
924         tdb_traverse(idmap_tdb, convert_fn, &failed);
925
926         if (failed) {
927                 DEBUG(0, ("Problem during conversion\n"));
928                 tdb_close(idmap_tdb);
929                 return False;
930         }
931
932         if (tdb_store_int32(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION) == -1) {
933                 DEBUG(0, ("idmap_convert: Unable to dtore idmap version in databse\n"));
934                 tdb_close(idmap_tdb);
935                 return False;
936         }
937
938         tdb_close(idmap_tdb);
939         return True;
940 }
941
942 /*****************************************************************************
943  Convert the idmap database from an older version if necessary
944 *****************************************************************************/
945
946 BOOL winbindd_upgrade_idmap(void)
947 {
948         pstring idmap_name;
949         pstring backup_name;
950         SMB_STRUCT_STAT stbuf;
951         TDB_CONTEXT *idmap_tdb;
952
953         pstrcpy(idmap_name, lock_path("winbindd_idmap.tdb"));
954
955         if (!file_exist(idmap_name, &stbuf)) {
956                 /* nothing to convert return */
957                 return True;
958         }
959
960         if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
961                                         TDB_DEFAULT, O_RDWR,
962                                         0600))) {
963                 DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
964                 return False;
965         }
966
967         if (tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION") == IDMAP_VERSION) {
968                 /* nothing to convert return */
969                 tdb_close(idmap_tdb);
970                 return True;
971         }
972
973         /* backup_tdb expects the tdb not to be open */
974         tdb_close(idmap_tdb);
975
976         DEBUG(0, ("Upgrading winbindd_idmap.tdb from an old version\n"));
977
978         pstrcpy(backup_name, idmap_name);
979         pstrcat(backup_name, ".bak");
980
981         if (backup_tdb(idmap_name, backup_name) != 0) {
982                 DEBUG(0, ("Could not backup idmap database\n"));
983                 return False;
984         }
985
986         return idmap_convert(idmap_name);
987 }
988
989 /*******************************************************************
990  wrapper around retrieving the trust account password
991 *******************************************************************/
992
993 BOOL get_trust_pw(const char *domain, uint8 ret_pwd[16],
994                           time_t *pass_last_set_time, uint32 *channel)
995 {
996         DOM_SID sid;
997         char *pwd;
998
999         /* if we are a DC and this is not our domain, then lookup an account
1000            for the domain trust */
1001            
1002         if ( IS_DC && !strequal(domain, lp_workgroup()) && lp_allow_trusted_domains() ) 
1003         {
1004                 if ( !secrets_fetch_trusted_domain_password(domain, &pwd, &sid, 
1005                         pass_last_set_time) ) 
1006                 {
1007                         DEBUG(0, ("get_trust_pw: could not fetch trust account "
1008                                   "password for trusted domain %s\n", domain));
1009                         return False;
1010                 }
1011                 
1012                 *channel = SEC_CHAN_DOMAIN;
1013                 E_md4hash(pwd, ret_pwd);
1014                 SAFE_FREE(pwd);
1015
1016                 return True;
1017         }
1018         else    /* just get the account for our domain (covers 
1019                    ROLE_DOMAIN_MEMBER as well */
1020         {
1021                 /* get the machine trust account for our domain */
1022
1023                 if ( !secrets_fetch_trust_account_password (lp_workgroup(), ret_pwd,
1024                         pass_last_set_time, channel) ) 
1025                 {
1026                         DEBUG(0, ("get_trust_pw: could not fetch trust account "
1027                                   "password for my domain %s\n", domain));
1028                         return False;
1029                 }
1030                 
1031                 return True;
1032         }
1033         
1034         /* Failure */
1035 }
1036