r13576: This is the beginnings of moving the SAM_ACCOUNT data structure
[jra/samba/.git] / source3 / passdb / pdb_tdb.c
1 /*
2  * Unix SMB/CIFS implementation. 
3  * SMB parameters and setup
4  * Copyright (C) Andrew Tridgell   1992-1998
5  * Copyright (C) Simo Sorce        2000-2003
6  * Copyright (C) Gerald Carter     2000-2006
7  * Copyright (C) Jeremy Allison    2001
8  * Copyright (C) Andrew Bartlett   2002
9  * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
10  * 
11  * This program is free software; you can redistribute it and/or modify it under
12  * the terms of the GNU General Public License as published by the Free
13  * Software Foundation; either version 2 of the License, or (at your option)
14  * any later version.
15  * 
16  * This program is distributed in the hope that it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
19  * more details.
20  * 
21  * You should have received a copy of the GNU General Public License along with
22  * this program; if not, write to the Free Software Foundation, Inc., 675
23  * Mass Ave, Cambridge, MA 02139, USA.
24  */
25
26 #include "includes.h"
27
28 #if 0 /* when made a module use this */
29
30 static int tdbsam_debug_level = DBGC_ALL;
31 #undef DBGC_CLASS
32 #define DBGC_CLASS tdbsam_debug_level
33
34 #else
35
36 #undef DBGC_CLASS
37 #define DBGC_CLASS DBGC_PASSDB
38
39 #endif
40
41 #define TDBSAM_VERSION  2       /* Most recent TDBSAM version */
42 #define TDBSAM_VERSION_STRING   "INFO/version"
43 #define PASSDB_FILE_NAME        "passdb.tdb"
44 #define USERPREFIX              "USER_"
45 #define RIDPREFIX               "RID_"
46 #define PRIVPREFIX              "PRIV_"
47
48 struct pwent_list {
49         struct pwent_list *prev, *next;
50         TDB_DATA key;
51 };
52 static struct pwent_list *tdbsam_pwent_list;
53
54 /* GLOBAL TDB SAM CONTEXT */
55
56 static TDB_CONTEXT *tdbsam;
57 static int ref_count = 0;
58 static pstring tdbsam_filename;
59
60 /**
61  * Convert old TDBSAM to the latest version.
62  * @param pdb_tdb A pointer to the opened TDBSAM file which must be converted. 
63  *                This file must be opened with read/write access.
64  * @param from Current version of the TDBSAM file.
65  * @return True if the conversion has been successful, false otherwise. 
66  **/
67
68 static BOOL tdbsam_convert(int32 from) 
69 {
70         const char      *vstring = TDBSAM_VERSION_STRING;
71         const char      *prefix = USERPREFIX;
72         TDB_DATA        data, key, old_key;
73         uint8           *buf = NULL;
74         BOOL            ret;
75
76         /* handle a Samba upgrade */
77         tdb_lock_bystring(tdbsam, vstring, 0);
78         
79         /* Enumerate all records and convert them */
80         key = tdb_firstkey(tdbsam);
81
82         while (key.dptr) {
83         
84                 /* skip all non-USER entries (eg. RIDs) */
85                 while ((key.dsize != 0) && (strncmp(key.dptr, prefix, strlen (prefix)))) {
86                         old_key = key;
87                         /* increment to next in line */
88                         key = tdb_nextkey(tdbsam, key);
89                         SAFE_FREE(old_key.dptr);
90                 }
91         
92                 if (key.dptr) {
93                         struct samu *user = NULL;
94
95                         /* read from tdbsam */
96                         data = tdb_fetch(tdbsam, key);
97                         if (!data.dptr) {
98                                 DEBUG(0,("tdbsam_convert: database entry not found: %s.\n",key.dptr));
99                                 return False;
100                         }
101         
102                         /* unpack the buffer from the former format */
103                         pdb_init_sam( &user );
104                         DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) (version:%d)\n", key.dptr, from));
105                         switch (from) {
106                                 case 0:
107                                         ret = init_sam_from_buffer_v0(user, (uint8 *)data.dptr, data.dsize);
108                                         break;
109                                 case 1:
110                                         ret = init_sam_from_buffer_v1(user, (uint8 *)data.dptr, data.dsize);
111                                         break;
112                                 case 2:
113                                         ret = init_sam_from_buffer_v2(user, (uint8 *)data.dptr, data.dsize);
114                                         break;
115                                 default:
116                                         /* unknown tdbsam version */
117                                         ret = False;
118                         }
119                         if (!ret) {
120                                 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned from TDB (key:%s) (version:%d)\n", key.dptr, from));
121                                 SAFE_FREE(data.dptr);
122                                 TALLOC_FREE(user );
123                                 return False;
124                         }
125         
126                         /* We're finished with the old data. */
127                         SAFE_FREE(data.dptr);
128
129                         /* pack from the buffer into the new format */
130                         
131                         DEBUG(10,("tdbsam_convert: Try packing a record (key:%s) (version:%d)\n", key.dptr, from));
132                         data.dsize = init_buffer_from_sam (&buf, user, False);
133                         TALLOC_FREE(user );
134                         
135                         if ( data.dsize == -1 ) {
136                                 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into the new format\n"));
137                                 return False;
138                         }
139                         data.dptr = (char *)buf;
140                         
141                         /* Store the buffer inside the TDBSAM */
142                         if (tdb_store(tdbsam, key, data, TDB_MODIFY) != TDB_SUCCESS) {
143                                 DEBUG(0,("tdbsam_convert: cannot store the struct samu (key:%s) in new format\n",key.dptr));
144                                 SAFE_FREE(data.dptr);
145                                 return False;
146                         }
147                         
148                         SAFE_FREE(data.dptr);
149                         
150                         /* increment to next in line */
151                         old_key = key;
152                         key = tdb_nextkey(tdbsam, key);
153                         SAFE_FREE(old_key.dptr);
154                 }
155                 
156         }
157
158         
159         /* upgrade finished */
160         tdb_store_int32(tdbsam, vstring, TDBSAM_VERSION);
161         tdb_unlock_bystring(tdbsam, vstring);
162
163         return(True);   
164 }
165
166 /*********************************************************************
167  Open the tdbsam file based on the absolute path specified.
168  Uses a reference count to allow multiple open calls.
169 *********************************************************************/
170
171 static BOOL tdbsam_open( const char *name )
172 {
173         int32   version;
174         
175         /* check if we are already open */
176         
177         if ( tdbsam ) {
178                 ref_count++;
179                 DEBUG(8,("tdbsam_open: Incrementing open reference count.  Ref count is now %d\n", 
180                         ref_count));
181                 return True;
182         }
183         
184         SMB_ASSERT( ref_count == 0 );
185         
186         /* Try to open tdb passwd.  Create a new one if necessary */
187         
188         if (!(tdbsam = tdb_open_log(name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600))) {
189                 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd [%s]\n", name));
190                 return False;
191         }
192
193         /* Check the version */
194         version = tdb_fetch_int32( tdbsam, TDBSAM_VERSION_STRING );
195         
196         if (version == -1)
197                 version = 0;    /* Version not found, assume version 0 */
198         
199         /* Compare the version */
200         if (version > TDBSAM_VERSION) {
201                 /* Version more recent than the latest known */ 
202                 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
203                 tdb_close( tdbsam );
204                 return False;
205         } 
206         
207         
208         if ( version < TDBSAM_VERSION ) {       
209                 DEBUG(1, ("tdbsam_open: Converting version %d database to version %d.\n", 
210                         version, TDBSAM_VERSION));
211                 
212                 if ( !tdbsam_convert(version) ) {
213                         DEBUG(0, ("tdbsam_open: Error when trying to convert tdbsam [%s]\n",name));
214                         tdb_close(tdbsam);
215                         return False;
216                 }
217                         
218                 DEBUG(3, ("TDBSAM converted successfully.\n"));
219         }
220         
221         /* set the initial reference count */
222
223         ref_count = 1;
224
225         DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));      
226         
227         return True;
228 }
229
230 /****************************************************************************
231  wrapper atound tdb_close() to handle the reference count
232 ****************************************************************************/
233
234 void tdbsam_close( void )
235 {
236         ref_count--;
237         
238         DEBUG(8,("tdbsam_close: Reference count is now %d.\n", ref_count));
239
240         SMB_ASSERT(ref_count >= 0 );
241         
242         if ( ref_count == 0 ) {
243                 tdb_close( tdbsam );
244                 tdbsam = NULL;
245         }
246         
247         return;
248 }
249
250 /****************************************************************************
251  creates a list of user keys
252 ****************************************************************************/
253
254 static int tdbsam_traverse_setpwent(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
255 {
256         const char *prefix = USERPREFIX;
257         int  prefixlen = strlen (prefix);
258         struct pwent_list *ptr;
259         
260         if ( strncmp(key.dptr, prefix, prefixlen) == 0 ) {
261                 if ( !(ptr=SMB_MALLOC_P(struct pwent_list)) ) {
262                         DEBUG(0,("tdbsam_traverse_setpwent: Failed to malloc new entry for list\n"));
263                         
264                         /* just return 0 and let the traversal continue */
265                         return 0;
266                 }
267                 ZERO_STRUCTP(ptr);
268                 
269                 /* save a copy of the key */
270                 
271                 ptr->key.dptr = memdup( key.dptr, key.dsize );
272                 ptr->key.dsize = key.dsize;
273                 
274                 DLIST_ADD( tdbsam_pwent_list, ptr );
275         
276         }
277         
278         
279         return 0;
280 }
281
282 /***************************************************************
283  Open the TDB passwd database for SAM account enumeration.
284  Save a list of user keys for iteration.
285 ****************************************************************/
286
287 static NTSTATUS tdbsam_setsampwent(struct pdb_methods *my_methods, BOOL update, uint16 acb_mask)
288 {
289         if ( !tdbsam_open( tdbsam_filename ) ) {
290                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
291                 return NT_STATUS_ACCESS_DENIED;
292         }
293
294         tdb_traverse( tdbsam, tdbsam_traverse_setpwent, NULL );
295
296         return NT_STATUS_OK;
297 }
298
299
300 /***************************************************************
301  End enumeration of the TDB passwd list.
302 ****************************************************************/
303
304 static void tdbsam_endsampwent(struct pdb_methods *my_methods)
305 {
306         struct pwent_list *ptr, *ptr_next;
307         
308         /* clear out any remaining entries in the list */
309         
310         for ( ptr=tdbsam_pwent_list; ptr; ptr = ptr_next ) {
311                 ptr_next = ptr->next;
312                 DLIST_REMOVE( tdbsam_pwent_list, ptr );
313                 SAFE_FREE( ptr->key.dptr);
314                 SAFE_FREE( ptr );
315         }
316         
317         DEBUG(7, ("endtdbpwent: closed sam database.\n"));
318
319         tdbsam_close();
320 }
321
322 /*****************************************************************
323  Get one struct samu from the TDB (next in line)
324 *****************************************************************/
325
326 static NTSTATUS tdbsam_getsampwent(struct pdb_methods *my_methods, struct samu *user)
327 {
328         NTSTATUS                nt_status = NT_STATUS_UNSUCCESSFUL;
329         TDB_DATA                data;
330         struct pwent_list       *pkey;
331
332         if ( !user ) {
333                 DEBUG(0,("tdbsam_getsampwent: struct samu is NULL.\n"));
334                 return nt_status;
335         }
336
337         if ( !tdbsam_pwent_list ) {
338                 DEBUG(4,("tdbsam_getsampwent: end of list\n"));
339                 return nt_status;
340         }
341         
342         /* pull the next entry */
343                 
344         pkey = tdbsam_pwent_list;
345         DLIST_REMOVE( tdbsam_pwent_list, pkey );
346         
347         data = tdb_fetch(tdbsam, pkey->key);
348
349         SAFE_FREE( pkey->key.dptr);
350         SAFE_FREE( pkey);
351         
352         if ( !data.dptr ) {
353                 DEBUG(5,("pdb_getsampwent: database entry not found.  Was the user deleted?\n"));
354                 return nt_status;
355         }
356   
357         if ( !init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize) ) {
358                 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
359         }
360         
361         SAFE_FREE( data.dptr );
362
363         return NT_STATUS_OK;
364 }
365
366 /******************************************************************
367  Lookup a name in the SAM TDB
368 ******************************************************************/
369
370 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods, struct samu *user, const char *sname)
371 {
372         NTSTATUS        result;
373         TDB_DATA        data, key;
374         fstring         keystr;
375         fstring         name;
376
377         if ( !user ) {
378                 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
379                 return NT_STATUS_NO_MEMORY;
380         }
381
382         /* Data is stored in all lower-case */
383         fstrcpy(name, sname);
384         strlower_m(name);
385
386         /* set search key */
387         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
388         key.dptr = keystr;
389         key.dsize = strlen(keystr) + 1;
390
391         /* open the database */
392                 
393         if ( !tdbsam_open( tdbsam_filename ) ) {
394                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
395                 return NT_STATUS_ACCESS_DENIED;
396         }
397         
398         /* get the record */
399         
400         data = tdb_fetch(tdbsam, key);
401         if (!data.dptr) {
402                 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
403                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
404                 DEBUGADD(5, (" Key: %s\n", keystr));
405                 result = NT_STATUS_NO_SUCH_USER;
406                 goto done;
407         }
408   
409         /* unpack the buffer */
410         
411         if (!init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize)) {
412                 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
413                 SAFE_FREE(data.dptr);
414                 result = NT_STATUS_NO_MEMORY;
415                 goto done;
416         }
417         
418         result = NT_STATUS_OK;
419         
420  done:
421         SAFE_FREE(data.dptr);
422         tdbsam_close();
423         
424         return result;
425 }
426
427 /***************************************************************************
428  Search by rid
429  **************************************************************************/
430
431 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods, struct samu *user, uint32 rid)
432 {
433         NTSTATUS                nt_status = NT_STATUS_UNSUCCESSFUL;
434         TDB_DATA                data, key;
435         fstring                 keystr;
436         fstring                 name;
437
438         if ( !user ) {
439                 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
440                 return nt_status;
441         }
442         
443         /* set search key */
444         
445         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
446         key.dptr = keystr;
447         key.dsize = strlen (keystr) + 1;
448
449         /* open the database */
450                 
451         if ( !tdbsam_open( tdbsam_filename ) ) {
452                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
453                 return NT_STATUS_ACCESS_DENIED;
454         }
455
456         /* get the record */
457         
458         data = tdb_fetch (tdbsam, key);
459         if (!data.dptr) {
460                 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
461                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
462                 nt_status = NT_STATUS_UNSUCCESSFUL;
463                 goto done;
464         }
465
466         fstrcpy(name, data.dptr);
467         SAFE_FREE(data.dptr);
468         
469         nt_status = tdbsam_getsampwnam (my_methods, user, name);
470
471  done:
472         /* cleanup */
473         
474         tdbsam_close();
475                 
476         return nt_status;
477 }
478
479 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods, struct samu * user, const DOM_SID *sid)
480 {
481         uint32 rid;
482         
483         if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
484                 return NT_STATUS_UNSUCCESSFUL;
485
486         return tdbsam_getsampwrid(my_methods, user, rid);
487 }
488
489 static BOOL tdb_delete_samacct_only( struct samu *sam_pass )
490 {
491         TDB_DATA        key;
492         fstring         keystr;
493         fstring         name;
494
495         fstrcpy(name, pdb_get_username(sam_pass));
496         strlower_m(name);
497         
498         /* set the search key */
499         
500         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
501         key.dptr = keystr;
502         key.dsize = strlen (keystr) + 1;
503         
504         /* it's outaa here!  8^) */
505         
506         if (tdb_delete(tdbsam, key) != TDB_SUCCESS) {
507                 DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
508                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
509                 return False;
510         }
511         
512         return True;
513 }
514
515 /***************************************************************************
516  Delete a struct samu records for the username and RID key
517 ****************************************************************************/
518
519 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods, struct samu *sam_pass)
520 {
521         NTSTATUS        nt_status = NT_STATUS_UNSUCCESSFUL;
522         TDB_DATA        key;
523         fstring         keystr;
524         uint32          rid;
525         fstring         name;
526         
527         /* make sure we have an open handle to the tdb.  Should have happened 
528            at module  initialization time */
529            
530         if ( !tdbsam ) {
531                 DEBUG(0,("tdbsam_getsampwrid: tdbsam not open!\n"));
532                 return NT_STATUS_NO_SUCH_USER;
533         }
534
535         fstrcpy(name, pdb_get_username(sam_pass));
536         strlower_m(name);
537         
538         /* set the search key */
539
540         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
541         key.dptr = keystr;
542         key.dsize = strlen (keystr) + 1;
543         
544         rid = pdb_get_user_rid(sam_pass);
545
546         /* open the database */
547                 
548         if ( !tdbsam_open( tdbsam_filename ) ) {
549                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
550                 return NT_STATUS_ACCESS_DENIED;
551         }
552         
553         /* it's outaa here!  8^) */
554
555         if ( tdb_delete(tdbsam, key) != TDB_SUCCESS ) {
556                 DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
557                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
558                 nt_status = NT_STATUS_UNSUCCESSFUL;
559                 goto done;
560         }
561
562         /* set the search key */
563         
564         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
565         key.dptr = keystr;
566         key.dsize = strlen (keystr) + 1;
567
568         /* it's outaa here!  8^) */
569         
570         if ( tdb_delete(tdbsam, key) != TDB_SUCCESS ) {
571                 DEBUG(5, ("Error deleting entry from tdb rid database!\n"));
572                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
573                 nt_status = NT_STATUS_UNSUCCESSFUL;
574                 goto done;
575         }
576
577         nt_status = NT_STATUS_OK;
578         
579  done:
580         tdbsam_close();
581         
582         return nt_status;
583 }
584
585
586 /***************************************************************************
587  Update the TDB SAM account record only
588  Assumes that the tdbsam is already open 
589 ****************************************************************************/
590 static BOOL tdb_update_samacct_only( struct samu* newpwd, int flag )
591 {
592         TDB_DATA        key, data;
593         uint8           *buf = NULL;
594         fstring         keystr;
595         fstring         name;
596         BOOL            ret = True;
597
598         /* copy the struct samu struct into a BYTE buffer for storage */
599         
600         if ( (data.dsize=init_buffer_from_sam (&buf, newpwd, False)) == -1 ) {
601                 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
602                 ret = False;
603                 goto done;
604         }
605         data.dptr = (char *)buf;
606
607         fstrcpy(name, pdb_get_username(newpwd));
608         strlower_m(name);
609         
610         DEBUG(5, ("Storing %saccount %s with RID %d\n", 
611                   flag == TDB_INSERT ? "(new) " : "", name, 
612                   pdb_get_user_rid(newpwd)));
613
614         /* setup the USER index key */
615         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
616         key.dptr = keystr;
617         key.dsize = strlen(keystr) + 1;
618
619         /* add the account */
620         
621         if ( tdb_store(tdbsam, key, data, flag) != TDB_SUCCESS ) {
622                 DEBUG(0, ("Unable to modify passwd TDB!"));
623                 DEBUGADD(0, (" Error: %s", tdb_errorstr(tdbsam)));
624                 DEBUGADD(0, (" occured while storing the main record (%s)\n",
625                              keystr));
626                 ret = False;
627                 goto done;
628         }
629
630 done:   
631         /* cleanup */
632         SAFE_FREE(buf);
633         
634         return ret;
635 }
636
637 /***************************************************************************
638  Update the TDB SAM RID record only
639  Assumes that the tdbsam is already open 
640 ****************************************************************************/
641 static BOOL tdb_update_ridrec_only( struct samu* newpwd, int flag )
642 {
643         TDB_DATA        key, data;
644         fstring         keystr;
645         fstring         name;
646
647         fstrcpy(name, pdb_get_username(newpwd));
648         strlower_m(name);
649
650         /* setup RID data */
651         data.dsize = strlen(name) + 1;
652         data.dptr = name;
653
654         /* setup the RID index key */
655         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,  pdb_get_user_rid(newpwd));
656         key.dptr = keystr;
657         key.dsize = strlen (keystr) + 1;
658         
659         /* add the reference */
660         if (tdb_store(tdbsam, key, data, flag) != TDB_SUCCESS) {
661                 DEBUG(0, ("Unable to modify TDB passwd !"));
662                 DEBUGADD(0, (" Error: %s\n", tdb_errorstr(tdbsam)));
663                 DEBUGADD(0, (" occured while storing the RID index (%s)\n", keystr));
664                 return False;
665         }
666
667         return True;
668
669 }
670
671 /***************************************************************************
672  Update the TDB SAM
673 ****************************************************************************/
674
675 static BOOL tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd, int flag)
676 {
677         uint32          user_rid;
678         BOOL            result = True;
679
680         /* invalidate the existing TDB iterator if it is open */
681         
682         tdbsam_endsampwent( my_methods );
683         
684         if ( !pdb_get_group_rid(newpwd) ) {
685                 DEBUG (0,("tdb_update_sam: Failing to store a struct samu for [%s] "
686                         "without a primary group RID\n", pdb_get_username(newpwd)));
687                 return False;
688         }
689
690         if ( !(user_rid = pdb_get_user_rid(newpwd)) ) {
691                 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n", pdb_get_username(newpwd)));
692                 return False;
693         }
694
695         /* open the database */
696                 
697         if ( !tdbsam_open( tdbsam_filename ) ) {
698                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
699                 return False;
700         }
701         
702         if ( !tdb_update_samacct_only(newpwd, flag) || !tdb_update_ridrec_only(newpwd, flag)) {
703                 result = False;
704         }
705
706         /* cleanup */
707
708         tdbsam_close();
709         
710         return result;  
711 }
712
713 /***************************************************************************
714  Modifies an existing struct samu
715 ****************************************************************************/
716
717 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
718 {
719         if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
720                 return NT_STATUS_UNSUCCESSFUL;
721         
722         return NT_STATUS_OK;
723 }
724
725 /***************************************************************************
726  Adds an existing struct samu
727 ****************************************************************************/
728
729 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
730 {
731         if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
732                 return NT_STATUS_UNSUCCESSFUL;
733                 
734         return NT_STATUS_OK;
735 }
736
737 /***************************************************************************
738  Renames a struct samu
739  - check for the posix user/rename user script
740  - Add and lock the new user record
741  - rename the posix user
742  - rewrite the rid->username record
743  - delete the old user
744  - unlock the new user record
745 ***************************************************************************/
746 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
747                                           struct samu *old_acct, 
748                                           const char *newname)
749 {
750         struct samu      *new_acct = NULL;
751         pstring          rename_script;
752         BOOL             interim_account = False;
753         int              rename_ret;
754
755         /* make sure we have an open handle to the tdb.  Should have happened 
756            at module  initialization time */
757            
758         if ( !tdbsam ) {
759                 DEBUG(0,("tdbsam_getsampwrid: tdbsam not open!\n"));
760                 return NT_STATUS_NO_SUCH_USER;
761         }
762         
763         /* can't do anything without an external script */
764         
765         pstrcpy(rename_script, lp_renameuser_script() );
766         if ( ! *rename_script )
767                 return NT_STATUS_ACCESS_DENIED;
768
769         /* invalidate the existing TDB iterator if it is open */
770         
771         tdbsam_endsampwent( my_methods );
772
773         if ( !pdb_copy_sam_account(old_acct, &new_acct) 
774                 || !pdb_set_username(new_acct, newname, PDB_CHANGED)) 
775         {
776                 TALLOC_FREE(new_acct );
777                 return NT_STATUS_NO_MEMORY;
778         }
779
780         /* open the database */
781                 
782         if ( !tdbsam_open( tdbsam_filename ) ) {
783                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
784                 TALLOC_FREE(new_acct );
785                 return NT_STATUS_ACCESS_DENIED;
786         }
787
788         /* add the new account and lock it */
789         
790         if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) 
791         {
792                 goto done;
793         }
794         
795         interim_account = True;
796
797         if ( tdb_lock_bystring(tdbsam, newname, 30) == -1 ) {
798                 goto done;
799         }
800
801         /* rename the posix user */
802         
803         pstring_sub(rename_script, "%unew", newname);
804         pstring_sub(rename_script, "%uold", pdb_get_username(old_acct));
805         rename_ret = smbrun(rename_script, NULL);
806
807         DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n", rename_script, rename_ret));
808
809         if (rename_ret) 
810                 goto done; 
811
812         /* rewrite the rid->username record */
813         
814         if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) )
815                 goto done;
816         interim_account = False;
817         tdb_unlock_bystring( tdbsam, newname );
818
819         tdb_delete_samacct_only( old_acct );
820         
821         tdbsam_close();
822         
823         TALLOC_FREE(new_acct );
824         return NT_STATUS_OK;
825
826 done:   
827         /* cleanup */
828         if (interim_account) {
829                 tdb_unlock_bystring(tdbsam, newname);
830                 tdb_delete_samacct_only(new_acct);
831         }
832         
833         tdbsam_close();
834         
835         if (new_acct)
836                 TALLOC_FREE(new_acct);
837         
838         return NT_STATUS_ACCESS_DENIED; 
839 }
840
841 static BOOL tdbsam_rid_algorithm(struct pdb_methods *methods)
842 {
843         return False;
844 }
845
846 /*
847  * Historically, winbind was responsible for allocating RIDs, so the next RID
848  * value was stored in winbindd_idmap.tdb. It has been moved to passdb now,
849  * but for compatibility reasons we still keep the the next RID counter in
850  * winbindd_idmap.tdb.
851  */
852
853 /*****************************************************************************
854  Initialise idmap database. For now (Dec 2005) this is a copy of the code in
855  sam/idmap_tdb.c. Maybe at a later stage we can remove that capability from
856  winbind completely and store the RID counter in passdb.tdb.
857
858  Dont' fully initialize with the HWM values, if it's new, we're only
859  interested in the RID counter.
860 *****************************************************************************/
861
862 static BOOL init_idmap_tdb(TDB_CONTEXT *tdb)
863 {
864         int32 version;
865
866         if (tdb_lock_bystring(tdb, "IDMAP_VERSION", 0) != 0) {
867                 DEBUG(0, ("Could not lock IDMAP_VERSION\n"));
868                 return False;
869         }
870
871         version = tdb_fetch_int32(tdb, "IDMAP_VERSION");
872
873         if (version == -1) {
874                 /* No key found, must be a new db */
875                 if (tdb_store_int32(tdb, "IDMAP_VERSION",
876                                     IDMAP_VERSION) != 0) {
877                         DEBUG(0, ("Could not store IDMAP_VERSION\n"));
878                         tdb_unlock_bystring(tdb, "IDMAP_VERSION");
879                         return False;
880                 }
881                 version = IDMAP_VERSION;
882         }
883
884         if (version != IDMAP_VERSION) {
885                 DEBUG(0, ("Expected IDMAP_VERSION=%d, found %d. Please "
886                           "start winbind once\n", IDMAP_VERSION, version));
887                 tdb_unlock_bystring(tdb, "IDMAP_VERSION");
888                 return False;
889         }
890
891         tdb_unlock_bystring(tdb, "IDMAP_VERSION");
892         return True;
893 }
894
895 static BOOL tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
896 {
897         TDB_CONTEXT *tdb;
898         uint32 rid;
899         BOOL ret = False;
900
901         tdb = tdb_open_log(lock_path("winbindd_idmap.tdb"), 0,
902                            TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
903
904         if (tdb == NULL) {
905                 DEBUG(1, ("Could not open idmap: %s\n", strerror(errno)));
906                 goto done;
907         }
908
909         if (!init_idmap_tdb(tdb)) {
910                 DEBUG(1, ("Could not init idmap\n"));
911                 goto done;
912         }
913
914         rid = BASE_RID;         /* Default if not set */
915
916         if (!tdb_change_uint32_atomic(tdb, "RID_COUNTER", &rid, 1)) {
917                 DEBUG(3, ("tdbsam_new_rid: Failed to increase RID_COUNTER\n"));
918                 goto done;
919         }
920
921         *prid = rid;
922         ret = True;
923
924  done:
925         if ((tdb != NULL) && (tdb_close(tdb) != 0)) {
926                 smb_panic("tdb_close(idmap_tdb) failed\n");
927         }
928
929         return ret;
930 }
931
932 /*********************************************************************
933  Initialize the tdb sam backend.  Setup the dispath table of methods,
934  open the tdb, etc...
935 *********************************************************************/
936
937 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
938 {
939         NTSTATUS nt_status;
940         pstring tdbfile;
941         const char *pfile = location;
942
943         if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
944                 return nt_status;
945         }
946
947         (*pdb_method)->name = "tdbsam";
948
949         (*pdb_method)->setsampwent = tdbsam_setsampwent;
950         (*pdb_method)->endsampwent = tdbsam_endsampwent;
951         (*pdb_method)->getsampwent = tdbsam_getsampwent;
952         (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
953         (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
954         (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
955         (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
956         (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
957         (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
958
959         (*pdb_method)->rid_algorithm = tdbsam_rid_algorithm;
960         (*pdb_method)->new_rid = tdbsam_new_rid;
961
962         /* save the path for later */
963                            
964         if ( !location ) {
965                 pstr_sprintf( tdbfile, "%s/%s", lp_private_dir(), PASSDB_FILE_NAME );
966                 pfile = tdbfile;
967         }
968         pstrcpy( tdbsam_filename, pfile );
969
970         /* no private data */
971         
972         (*pdb_method)->private_data      = NULL;
973         (*pdb_method)->free_private_data = NULL;
974
975         return NT_STATUS_OK;
976 }
977
978 NTSTATUS pdb_tdbsam_init(void)
979 {
980         return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
981 }