TDBSAM update code from Aur?lien Degr?mont <adegremont@idealx.com>.
[tprouty/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-2002
6  * Copyright (C) Gerald Carter     2000
7  * Copyright (C) Jeremy Allison    2001
8  * Copyright (C) Andrew Bartlett   2002
9  * 
10  * This program is free software; you can redistribute it and/or modify it under
11  * the terms of the GNU General Public License as published by the Free
12  * Software Foundation; either version 2 of the License, or (at your option)
13  * any later version.
14  * 
15  * This program is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18  * more details.
19  * 
20  * You should have received a copy of the GNU General Public License along with
21  * this program; if not, write to the Free Software Foundation, Inc., 675
22  * Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 #include "includes.h"
26
27 #if 0 /* when made a module use this */
28
29 static int tdbsam_debug_level = DBGC_ALL;
30 #undef DBGC_CLASS
31 #define DBGC_CLASS tdbsam_debug_level
32
33 #else
34
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_PASSDB
37
38 #endif
39
40 #define TDBSAM_VERSION  1                       /* Most recent TDBSAM version */
41 #define PDB_VERSION             "20010830"
42 #define PASSDB_FILE_NAME        "passdb.tdb"
43 #define USERPREFIX              "USER_"
44 #define RIDPREFIX               "RID_"
45 #define tdbsamver_t     int32
46
47 struct tdbsam_privates {
48         TDB_CONTEXT     *passwd_tdb;
49         TDB_DATA        key;
50
51         /* retrive-once info */
52         const char *tdbsam_location;
53 };
54
55 /**
56  * Convert old TDBSAM to the latest version.
57  * @param pdb_tdb A pointer to the opened TDBSAM file which must be converted. 
58  *                This file must be opened with read/write access.
59  * @param from Current version of the TDBSAM file.
60  * @return True if the conversion has been successful, false otherwise. 
61  **/
62
63 static BOOL tdbsam_convert(TDB_CONTEXT *pdb_tdb, tdbsamver_t from) 
64 {
65         const char * vstring = "INFO/version";
66         SAM_ACCOUNT *user = NULL;
67         const char *prefix = USERPREFIX;
68         TDB_DATA        data, key, old_key;
69         uint8           *buf = NULL;
70         BOOL            ret;
71
72         if (pdb_tdb == NULL) {
73                 DEBUG(0,("tdbsam_convert: Bad TDB Context pointer.\n"));
74                 return False;
75         }
76
77         /* handle a Samba upgrade */
78         tdb_lock_bystring(pdb_tdb, vstring, 0);
79         
80         if (!NT_STATUS_IS_OK(pdb_init_sam(&user))) {
81                 DEBUG(0,("tdbsam_convert: cannot initialized a SAM_ACCOUNT.\n"));
82                 return False;
83         }
84
85         /* Enumerate all records and convert them */
86         key = tdb_firstkey(pdb_tdb);
87
88         while (key.dptr) {
89         
90                 /* skip all non-USER entries (eg. RIDs) */
91                 while ((key.dsize != 0) && (strncmp(key.dptr, prefix, strlen (prefix)))) {
92                         old_key = key;
93                         /* increment to next in line */
94                         key = tdb_nextkey(pdb_tdb, key);
95                         SAFE_FREE(old_key.dptr);
96                 }
97         
98                 if (key.dptr) {
99                         
100                         /* read from tdbsam */
101                         data = tdb_fetch(pdb_tdb, key);
102                         if (!data.dptr) {
103                                 DEBUG(0,("tdbsam_convert: database entry not found: %s.\n",key.dptr));
104                                 return False;
105                         }
106         
107                         if (!NT_STATUS_IS_OK(pdb_reset_sam(user))) {
108                                 DEBUG(0,("tdbsam_convert: cannot reset SAM_ACCOUNT.\n"));
109                                 SAFE_FREE(data.dptr);
110                                 return False;
111                         }
112                         
113                         /* unpack the buffer from the former format */
114                         DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) (version:%d)\n", key.dptr, from));
115                         switch (from) {
116                                 case 0:
117                                         ret = init_sam_from_buffer_v0(user, (uint8 *)data.dptr, data.dsize);
118                                         break;
119                                 case 1:
120                                         ret = init_sam_from_buffer_v1(user, (uint8 *)data.dptr, data.dsize);
121                                         break;
122                                 default:
123                                         /* unknown tdbsam version */
124                                         ret = False;
125                         }
126                         if (!ret) {
127                                 DEBUG(0,("tdbsam_convert: Bad SAM_ACCOUNT entry returned from TDB (key:%s) (version:%d)\n", key.dptr, from));
128                                 SAFE_FREE(data.dptr);
129                                 return False;
130                         }
131         
132                         /* pack from the buffer into the new format */
133                         DEBUG(10,("tdbsam_convert: Try packing a record (key:%s) (version:%d)\n", key.dptr, from));
134                         if ((data.dsize=init_buffer_from_sam (&buf, user, False)) == -1) {
135                                 DEBUG(0,("tdbsam_convert: cannot pack the SAM_ACCOUNT into the new format\n"));
136                                 SAFE_FREE(data.dptr);
137                                 return False;
138                         }
139                         data.dptr = (char *)buf;
140                         
141                         /* Store the buffer inside the TDBSAM */
142                         if (tdb_store(pdb_tdb, key, data, TDB_MODIFY) != TDB_SUCCESS) {
143                                 DEBUG(0,("tdbsam_convert: cannot store the SAM_ACCOUNT (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(pdb_tdb, key);
153                         SAFE_FREE(old_key.dptr);
154                 }
155                 
156         }
157
158         pdb_free_sam(&user);
159         
160         /* upgrade finished */
161         tdb_store_int32(pdb_tdb, vstring, TDBSAM_VERSION);
162         tdb_unlock_bystring(pdb_tdb, vstring);
163
164         return(True);   
165 }
166
167 /**
168  * Open the TDB passwd database, check version and convert it if needed.
169  * @param name filename of the tdbsam file.
170  * @param open_flags file access mode.
171  * @return a TDB_CONTEXT handle on the tdbsam file.
172  **/
173
174 static TDB_CONTEXT * tdbsam_tdbopen (const char *name, int open_flags)
175 {
176         TDB_CONTEXT     *pdb_tdb;
177         tdbsamver_t     version;
178         
179         /* Try to open tdb passwd */
180         if (!(pdb_tdb = tdb_open_log(name, 0, TDB_DEFAULT, open_flags, 0600)))
181                 return NULL;
182
183         /* Check the version */
184         version = (tdbsamver_t) tdb_fetch_int32(pdb_tdb, "INFO/version");
185         if (version == -1)
186                 version = 0;    /* Version not found, assume version 0 */
187         
188         /* Compare the version */
189         if (version > TDBSAM_VERSION) {
190                 /* Version more recent than the latest known */ 
191                 DEBUG(0, ("TDBSAM version unknown: %d\n", version));
192                 tdb_close(pdb_tdb);
193                 pdb_tdb = NULL;
194         } 
195         else if (version < TDBSAM_VERSION) {
196                 /* Older version, must be converted */
197                 DEBUG(1, ("TDBSAM version too old (%d), trying to convert it.\n", version));
198                 
199                 /* Reopen the pdb file with read-write access if needed */
200                 if (!(open_flags & O_RDWR)) {
201                         DEBUG(10, ("tdbsam_tdbopen: TDB file opened with read only access, reopen it with read-write access.\n"));
202                         tdb_close(pdb_tdb);
203                         pdb_tdb = tdb_open_log(name, 0, TDB_DEFAULT, (open_flags & 07777770) | O_RDWR, 0600);
204                 }
205                 
206                 /* Convert */
207                 if (!tdbsam_convert(pdb_tdb, version)){
208                         DEBUG(0, ("tdbsam_tdbopen: Error when trying to convert tdbsam: %s\n",name));
209                         tdb_close(pdb_tdb);
210                         pdb_tdb = NULL;
211                 } else {
212                         DEBUG(1, ("TDBSAM converted successfully.\n"));
213                 }
214
215                 /* Reopen the pdb file as it must be */
216                 if (!(open_flags & O_RDWR)) {
217                         tdb_close(pdb_tdb);
218                         pdb_tdb = tdb_open_log(name, 0, TDB_DEFAULT, open_flags, 0600);
219                 }
220         }
221         
222         return pdb_tdb;
223 }
224
225 /***************************************************************
226  Open the TDB passwd database for SAM account enumeration.
227 ****************************************************************/
228
229 static NTSTATUS tdbsam_setsampwent(struct pdb_methods *my_methods, BOOL update)
230 {
231         struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
232         
233         /* Open tdb passwd */
234         if (!(tdb_state->passwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, update?(O_RDWR|O_CREAT):O_RDONLY)))
235         {
236                 DEBUG(0, ("Unable to open/create TDB passwd\n"));
237                 return NT_STATUS_UNSUCCESSFUL;
238         }
239         
240         tdb_state->key = tdb_firstkey(tdb_state->passwd_tdb);
241
242         return NT_STATUS_OK;
243 }
244
245 static void close_tdb(struct tdbsam_privates *tdb_state) 
246 {
247         if (tdb_state->passwd_tdb) {
248                 tdb_close(tdb_state->passwd_tdb);
249                 tdb_state->passwd_tdb = NULL;
250         }
251 }
252
253 /***************************************************************
254  End enumeration of the TDB passwd list.
255 ****************************************************************/
256
257 static void tdbsam_endsampwent(struct pdb_methods *my_methods)
258 {
259         struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
260         SAFE_FREE(tdb_state->key.dptr);
261         close_tdb(tdb_state);
262         
263         DEBUG(7, ("endtdbpwent: closed sam database.\n"));
264 }
265
266 /*****************************************************************
267  Get one SAM_ACCOUNT from the TDB (next in line)
268 *****************************************************************/
269
270 static NTSTATUS tdbsam_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT *user)
271 {
272         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
273         struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
274         TDB_DATA        data, old_key;
275         const char *prefix = USERPREFIX;
276         int  prefixlen = strlen (prefix);
277
278
279         if (user==NULL) {
280                 DEBUG(0,("pdb_get_sampwent: SAM_ACCOUNT is NULL.\n"));
281                 return nt_status;
282         }
283
284         /* skip all non-USER entries (eg. RIDs) */
285         while ((tdb_state->key.dsize != 0) && (strncmp(tdb_state->key.dptr, prefix, prefixlen))) {
286
287                 old_key = tdb_state->key;
288
289                 /* increment to next in line */
290                 tdb_state->key = tdb_nextkey(tdb_state->passwd_tdb, tdb_state->key);
291
292                 SAFE_FREE(old_key.dptr);
293         }
294
295         /* do we have an valid iteration pointer? */
296         if(tdb_state->passwd_tdb == NULL) {
297                 DEBUG(0,("pdb_get_sampwent: Bad TDB Context pointer.\n"));
298                 return nt_status;
299         }
300
301         data = tdb_fetch(tdb_state->passwd_tdb, tdb_state->key);
302         if (!data.dptr) {
303                 DEBUG(5,("pdb_getsampwent: database entry not found.\n"));
304                 return nt_status;
305         }
306   
307         /* unpack the buffer */
308         if (!init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize)) {
309                 DEBUG(0,("pdb_getsampwent: Bad SAM_ACCOUNT entry returned from TDB!\n"));
310                 SAFE_FREE(data.dptr);
311                 return nt_status;
312         }
313         SAFE_FREE(data.dptr);
314         
315         old_key = tdb_state->key;
316         
317         /* increment to next in line */
318         tdb_state->key = tdb_nextkey(tdb_state->passwd_tdb, tdb_state->key);
319
320         SAFE_FREE(old_key.dptr);
321
322         return NT_STATUS_OK;
323 }
324
325 /******************************************************************
326  Lookup a name in the SAM TDB
327 ******************************************************************/
328
329 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods, SAM_ACCOUNT *user, const char *sname)
330 {
331         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
332         struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
333         TDB_CONTEXT     *pwd_tdb;
334         TDB_DATA        data, key;
335         fstring         keystr;
336         fstring         name;
337
338         if (user==NULL) {
339                 DEBUG(0,("pdb_getsampwnam: SAM_ACCOUNT is NULL.\n"));
340                 return nt_status;
341         }
342
343         
344         /* Data is stored in all lower-case */
345         fstrcpy(name, sname);
346         strlower_m(name);
347
348         /* set search key */
349         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
350         key.dptr = keystr;
351         key.dsize = strlen(keystr) + 1;
352
353         /* open the accounts TDB */
354         if (!(pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDONLY))) {
355         
356                 if (errno == ENOENT) {
357                         /*
358                          * TDB file doesn't exist, so try to create new one. This is useful to avoid
359                          * confusing error msg when adding user account first time
360                          */
361                         if (!(pwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT, O_CREAT, 0600))) {
362                                 DEBUG(0, ("pdb_getsampwnam: TDB passwd (%s) did not exist. File successfully created.\n",
363                                           tdb_state->tdbsam_location));
364                         } else {
365                                 DEBUG(0, ("pdb_getsampwnam: TDB passwd (%s) does not exist. Couldn't create new one. Error was: %s\n",
366                                           tdb_state->tdbsam_location, strerror(errno)));
367                         }
368                         
369                         /* requested user isn't there anyway */
370                         nt_status = NT_STATUS_NO_SUCH_USER;
371                         return nt_status;
372                 }
373                 DEBUG(0, ("pdb_getsampwnam: Unable to open TDB passwd (%s)!\n", tdb_state->tdbsam_location));
374                 return nt_status;
375         }
376
377         /* get the record */
378         data = tdb_fetch(pwd_tdb, key);
379         if (!data.dptr) {
380                 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
381                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
382                 DEBUGADD(5, (" Key: %s\n", keystr));
383                 tdb_close(pwd_tdb);
384                 return nt_status;
385         }
386   
387         /* unpack the buffer */
388         if (!init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize)) {
389                 DEBUG(0,("pdb_getsampwent: Bad SAM_ACCOUNT entry returned from TDB!\n"));
390                 SAFE_FREE(data.dptr);
391                 tdb_close(pwd_tdb);
392                 return nt_status;
393         }
394         SAFE_FREE(data.dptr);
395
396         /* no further use for database, close it now */
397         tdb_close(pwd_tdb);
398         
399         return NT_STATUS_OK;
400 }
401
402 /***************************************************************************
403  Search by rid
404  **************************************************************************/
405
406 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods, SAM_ACCOUNT *user, uint32 rid)
407 {
408         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
409         struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
410         TDB_CONTEXT             *pwd_tdb;
411         TDB_DATA                data, key;
412         fstring                 keystr;
413         fstring                 name;
414         
415         if (user==NULL) {
416                 DEBUG(0,("pdb_getsampwrid: SAM_ACCOUNT is NULL.\n"));
417                 return nt_status;
418         }
419
420         /* set search key */
421         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
422         key.dptr = keystr;
423         key.dsize = strlen (keystr) + 1;
424
425         /* open the accounts TDB */
426         if (!(pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDONLY))) {
427                 DEBUG(0, ("pdb_getsampwrid: Unable to open TDB rid database!\n"));
428                 return nt_status;
429         }
430
431         /* get the record */
432         data = tdb_fetch (pwd_tdb, key);
433         if (!data.dptr) {
434                 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
435                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
436                 tdb_close (pwd_tdb);
437                 return nt_status;
438         }
439
440
441         fstrcpy(name, data.dptr);
442         SAFE_FREE(data.dptr);
443         
444         tdb_close (pwd_tdb);
445         
446         return tdbsam_getsampwnam (my_methods, user, name);
447 }
448
449 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT * user, const DOM_SID *sid)
450 {
451         uint32 rid;
452         if (!sid_peek_check_rid(get_global_sam_sid(), sid, &rid))
453                 return NT_STATUS_UNSUCCESSFUL;
454         return tdbsam_getsampwrid(my_methods, user, rid);
455 }
456
457 /***************************************************************************
458  Delete a SAM_ACCOUNT
459 ****************************************************************************/
460
461 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT *sam_pass)
462 {
463         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
464         struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
465         TDB_CONTEXT     *pwd_tdb;
466         TDB_DATA        key;
467         fstring         keystr;
468         uint32          rid;
469         fstring         name;
470         
471         fstrcpy(name, pdb_get_username(sam_pass));
472         strlower_m(name);
473         
474         /* open the TDB */
475         if (!(pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDWR))) {
476                 DEBUG(0, ("Unable to open TDB passwd!"));
477                 return nt_status;
478         }
479   
480         /* set the search key */
481         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
482         key.dptr = keystr;
483         key.dsize = strlen (keystr) + 1;
484         
485         rid = pdb_get_user_rid(sam_pass);
486
487         /* it's outaa here!  8^) */
488         if (tdb_delete(pwd_tdb, key) != TDB_SUCCESS) {
489                 DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
490                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
491                 tdb_close(pwd_tdb); 
492                 return nt_status;
493         }       
494
495         /* delete also the RID key */
496
497         /* set the search key */
498         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
499         key.dptr = keystr;
500         key.dsize = strlen (keystr) + 1;
501
502         /* it's outaa here!  8^) */
503         if (tdb_delete(pwd_tdb, key) != TDB_SUCCESS) {
504                 DEBUG(5, ("Error deleting entry from tdb rid database!\n"));
505                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
506                 tdb_close(pwd_tdb); 
507                 return nt_status;
508         }
509         
510         tdb_close(pwd_tdb);
511         
512         return NT_STATUS_OK;
513 }
514
515 /***************************************************************************
516  Update the TDB SAM
517 ****************************************************************************/
518
519 static BOOL tdb_update_sam(struct pdb_methods *my_methods, SAM_ACCOUNT* newpwd, int flag)
520 {
521         struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
522         TDB_CONTEXT     *pwd_tdb = NULL;
523         TDB_DATA        key, data;
524         uint8           *buf = NULL;
525         fstring         keystr;
526         fstring         name;
527         BOOL            ret = True;
528         uint32          user_rid;
529
530         /* invalidate the existing TDB iterator if it is open */
531         
532         if (tdb_state->passwd_tdb) {
533                 tdb_close(tdb_state->passwd_tdb);
534                 tdb_state->passwd_tdb = NULL;
535         }
536
537         /* open the account TDB passwd*/
538         
539         pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDWR | O_CREAT);
540         
541         if (!pwd_tdb) {
542                 DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd (%s)!\n", 
543                         tdb_state->tdbsam_location));
544                 return False;
545         }
546
547         if (!pdb_get_group_rid(newpwd)) {
548                 DEBUG (0,("tdb_update_sam: Failing to store a SAM_ACCOUNT for [%s] without a primary group RID\n",
549                         pdb_get_username(newpwd)));
550                 ret = False;
551                 goto done;
552         }
553
554         if ( !(user_rid = pdb_get_user_rid(newpwd)) ) {
555                 DEBUG(0,("tdb_update_sam: SAM_ACCOUNT (%s) with no RID!\n", pdb_get_username(newpwd)));
556                 ret = False;
557                 goto done;
558         }
559
560         /* copy the SAM_ACCOUNT struct into a BYTE buffer for storage */
561         if ((data.dsize=init_buffer_from_sam (&buf, newpwd, False)) == -1) {
562                 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy SAM_ACCOUNT info BYTE buffer!\n"));
563                 ret = False;
564                 goto done;
565         }
566         data.dptr = (char *)buf;
567
568         fstrcpy(name, pdb_get_username(newpwd));
569         strlower_m(name);
570         
571         DEBUG(5, ("Storing %saccount %s with RID %d\n", flag == TDB_INSERT ? "(new) " : "", name, user_rid));
572
573         /* setup the USER index key */
574         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
575         key.dptr = keystr;
576         key.dsize = strlen(keystr) + 1;
577
578         /* add the account */
579         if (tdb_store(pwd_tdb, key, data, flag) != TDB_SUCCESS) {
580                 DEBUG(0, ("Unable to modify passwd TDB!"));
581                 DEBUGADD(0, (" Error: %s", tdb_errorstr(pwd_tdb)));
582                 DEBUGADD(0, (" occured while storing the main record (%s)\n", keystr));
583                 ret = False;
584                 goto done;
585         }
586         
587         /* setup RID data */
588         data.dsize = strlen(name) + 1;
589         data.dptr = name;
590
591         /* setup the RID index key */
592         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, user_rid);
593         key.dptr = keystr;
594         key.dsize = strlen (keystr) + 1;
595         
596         /* add the reference */
597         if (tdb_store(pwd_tdb, key, data, flag) != TDB_SUCCESS) {
598                 DEBUG(0, ("Unable to modify TDB passwd !"));
599                 DEBUGADD(0, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
600                 DEBUGADD(0, (" occured while storing the RID index (%s)\n", keystr));
601                 ret = False;
602                 goto done;
603         }
604
605 done:   
606         /* cleanup */
607         tdb_close (pwd_tdb);
608         SAFE_FREE(buf);
609         
610         return (ret);   
611 }
612
613 /***************************************************************************
614  Modifies an existing SAM_ACCOUNT
615 ****************************************************************************/
616
617 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, SAM_ACCOUNT *newpwd)
618 {
619         if (tdb_update_sam(my_methods, newpwd, TDB_MODIFY))
620                 return NT_STATUS_OK;
621         else
622                 return NT_STATUS_UNSUCCESSFUL;
623 }
624
625 /***************************************************************************
626  Adds an existing SAM_ACCOUNT
627 ****************************************************************************/
628
629 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, SAM_ACCOUNT *newpwd)
630 {
631         if (tdb_update_sam(my_methods, newpwd, TDB_INSERT))
632                 return NT_STATUS_OK;
633         else
634                 return NT_STATUS_UNSUCCESSFUL;
635 }
636
637 static void free_private_data(void **vp) 
638 {
639         struct tdbsam_privates **tdb_state = (struct tdbsam_privates **)vp;
640         close_tdb(*tdb_state);
641         *tdb_state = NULL;
642
643         /* No need to free any further, as it is talloc()ed */
644 }
645
646
647 static NTSTATUS pdb_init_tdbsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
648 {
649         NTSTATUS nt_status;
650         struct tdbsam_privates *tdb_state;
651
652         if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
653                 return nt_status;
654         }
655
656         (*pdb_method)->name = "tdbsam";
657
658         (*pdb_method)->setsampwent = tdbsam_setsampwent;
659         (*pdb_method)->endsampwent = tdbsam_endsampwent;
660         (*pdb_method)->getsampwent = tdbsam_getsampwent;
661         (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
662         (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
663         (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
664         (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
665         (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
666
667         tdb_state = talloc_zero(pdb_context->mem_ctx, sizeof(struct tdbsam_privates));
668
669         if (!tdb_state) {
670                 DEBUG(0, ("talloc() failed for tdbsam private_data!\n"));
671                 return NT_STATUS_NO_MEMORY;
672         }
673
674         if (location) {
675                 tdb_state->tdbsam_location = talloc_strdup(pdb_context->mem_ctx, location);
676         } else {
677                 pstring tdbfile;
678                 get_private_directory(tdbfile);
679                 pstrcat(tdbfile, "/");
680                 pstrcat(tdbfile, PASSDB_FILE_NAME);
681                 tdb_state->tdbsam_location = talloc_strdup(pdb_context->mem_ctx, tdbfile);
682         }
683
684         (*pdb_method)->private_data = tdb_state;
685
686         (*pdb_method)->free_private_data = free_private_data;
687
688         return NT_STATUS_OK;
689 }
690
691 NTSTATUS pdb_tdbsam_init(void)
692 {
693         return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
694 }