s3:dbwrap: move all .c and .h files of dbwrap to lib/dbwrap/
[ira/wip.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-2009
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 3 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, see <http://www.gnu.org/licenses/>.
23  */
24
25 #include "includes.h"
26 #include "system/filesys.h"
27 #include "passdb.h"
28 #include "dbwrap/dbwrap.h"
29 #include "dbwrap/dbwrap_open.h"
30 #include "../libcli/security/security.h"
31 #include "util_tdb.h"
32
33 #if 0 /* when made a module use this */
34
35 static int tdbsam_debug_level = DBGC_ALL;
36 #undef DBGC_CLASS
37 #define DBGC_CLASS tdbsam_debug_level
38
39 #else
40
41 #undef DBGC_CLASS
42 #define DBGC_CLASS DBGC_PASSDB
43
44 #endif
45
46 #define TDBSAM_VERSION  4       /* Most recent TDBSAM version */
47 #define TDBSAM_MINOR_VERSION    0       /* Most recent TDBSAM minor version */
48 #define TDBSAM_VERSION_STRING   "INFO/version"
49 #define TDBSAM_MINOR_VERSION_STRING     "INFO/minor_version"
50 #define PASSDB_FILE_NAME        "passdb.tdb"
51 #define USERPREFIX              "USER_"
52 #define USERPREFIX_LEN          5
53 #define RIDPREFIX               "RID_"
54 #define PRIVPREFIX              "PRIV_"
55 #define NEXT_RID_STRING         "NEXT_RID"
56
57 /* GLOBAL TDB SAM CONTEXT */
58
59 static struct db_context *db_sam;
60 static char *tdbsam_filename;
61
62 struct tdbsam_convert_state {
63         int32_t from;
64         bool success;
65 };
66
67 static int tdbsam_convert_one(struct db_record *rec, void *priv)
68 {
69         struct tdbsam_convert_state *state =
70                 (struct tdbsam_convert_state *)priv;
71         struct samu *user;
72         TDB_DATA data;
73         NTSTATUS status;
74         bool ret;
75
76         if (rec->key.dsize < USERPREFIX_LEN) {
77                 return 0;
78         }
79         if (strncmp((char *)rec->key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
80                 return 0;
81         }
82
83         user = samu_new(talloc_tos());
84         if (user == NULL) {
85                 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
86                 state->success = false;
87                 return -1;
88         }
89
90         DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) "
91                   "(version:%d)\n", rec->key.dptr, state->from));
92
93         switch (state->from) {
94         case 0:
95                 ret = init_samu_from_buffer(user, SAMU_BUFFER_V0,
96                                             (uint8 *)rec->value.dptr,
97                                             rec->value.dsize);
98                 break;
99         case 1:
100                 ret = init_samu_from_buffer(user, SAMU_BUFFER_V1,
101                                             (uint8 *)rec->value.dptr,
102                                             rec->value.dsize);
103                 break;
104         case 2:
105                 ret = init_samu_from_buffer(user, SAMU_BUFFER_V2,
106                                             (uint8 *)rec->value.dptr,
107                                             rec->value.dsize);
108                 break;
109         case 3:
110                 ret = init_samu_from_buffer(user, SAMU_BUFFER_V3,
111                                             (uint8 *)rec->value.dptr,
112                                             rec->value.dsize);
113                 break;
114         case 4:
115                 ret = init_samu_from_buffer(user, SAMU_BUFFER_V4,
116                                             (uint8 *)rec->value.dptr,
117                                             rec->value.dsize);
118                 break;
119         default:
120                 /* unknown tdbsam version */
121                 ret = False;
122         }
123         if (!ret) {
124                 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
125                          "from TDB (key:%s) (version:%d)\n", rec->key.dptr,
126                          state->from));
127                 TALLOC_FREE(user);
128                 state->success = false;
129                 return -1;
130         }
131
132         data.dsize = init_buffer_from_samu(&data.dptr, user, false);
133         TALLOC_FREE(user);
134
135         if (data.dsize == -1) {
136                 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into "
137                          "the new format\n"));
138                 state->success = false;
139                 return -1;
140         }
141
142         status = rec->store(rec, data, TDB_MODIFY);
143         if (!NT_STATUS_IS_OK(status)) {
144                 DEBUG(0, ("Could not store the new record: %s\n",
145                           nt_errstr(status)));
146                 state->success = false;
147                 return -1;
148         }
149
150         return 0;
151 }
152
153 /**********************************************************************
154  Struct and function to backup an old record.
155  *********************************************************************/
156
157 struct tdbsam_backup_state {
158         struct db_context *new_db;
159         bool success;
160 };
161
162 static int backup_copy_fn(struct db_record *orig_rec, void *state)
163 {
164         struct tdbsam_backup_state *bs = (struct tdbsam_backup_state *)state;
165         struct db_record *new_rec;
166         NTSTATUS status;
167
168         new_rec = bs->new_db->fetch_locked(bs->new_db, talloc_tos(), orig_rec->key);
169         if (new_rec == NULL) {
170                 bs->success = false;
171                 return 1;
172         }
173
174         status = new_rec->store(new_rec, orig_rec->value, TDB_INSERT);
175
176         TALLOC_FREE(new_rec);
177
178         if (!NT_STATUS_IS_OK(status)) {
179                 bs->success = false;
180                 return 1;
181         }
182         return 0;
183 }
184
185 /**********************************************************************
186  Make a backup of an old passdb and replace the new one with it. We
187  have to do this as between 3.0.x and 3.2.x the hash function changed
188  by mistake (used unsigned char * instead of char *). This means the
189  previous simple update code will fail due to not being able to find
190  existing records to replace in the tdbsam_convert_one() function. JRA.
191  *********************************************************************/
192
193 static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
194 {
195         TALLOC_CTX *frame = talloc_stackframe();
196         const char *tmp_fname = NULL;
197         struct db_context *tmp_db = NULL;
198         struct db_context *orig_db = *pp_db;
199         struct tdbsam_backup_state bs;
200         int ret;
201
202         tmp_fname = talloc_asprintf(frame, "%s.tmp", dbname);
203         if (!tmp_fname) {
204                 TALLOC_FREE(frame);
205                 return false;
206         }
207
208         unlink(tmp_fname);
209
210         /* Remember to open this on the NULL context. We need
211          * it to stay around after we return from here. */
212
213         tmp_db = db_open(NULL, tmp_fname, 0,
214                                 TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
215         if (tmp_db == NULL) {
216                 DEBUG(0, ("tdbsam_convert_backup: Failed to create backup TDB passwd "
217                           "[%s]\n", tmp_fname));
218                 TALLOC_FREE(frame);
219                 return false;
220         }
221
222         if (orig_db->transaction_start(orig_db) != 0) {
223                 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (1)\n"));
224                 unlink(tmp_fname);
225                 TALLOC_FREE(tmp_db);
226                 TALLOC_FREE(frame);
227                 return false;
228         }
229         if (tmp_db->transaction_start(tmp_db) != 0) {
230                 DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (2)\n"));
231                 orig_db->transaction_cancel(orig_db);
232                 unlink(tmp_fname);
233                 TALLOC_FREE(tmp_db);
234                 TALLOC_FREE(frame);
235                 return false;
236         }
237
238         bs.new_db = tmp_db;
239         bs.success = true;
240
241         ret = orig_db->traverse(orig_db, backup_copy_fn, (void *)&bs);
242         if (ret < 0) {
243                 DEBUG(0, ("tdbsam_convert_backup: traverse failed\n"));
244                 goto cancel;
245         }
246
247         if (!bs.success) {
248                 DEBUG(0, ("tdbsam_convert_backup: Rewriting records failed\n"));
249                 goto cancel;
250         }
251
252         if (orig_db->transaction_commit(orig_db) != 0) {
253                 smb_panic("tdbsam_convert_backup: orig commit failed\n");
254         }
255         if (tmp_db->transaction_commit(tmp_db) != 0) {
256                 smb_panic("tdbsam_convert_backup: orig commit failed\n");
257         }
258
259         /* be sure to close the DBs _before_ renaming the file */
260
261         TALLOC_FREE(orig_db);
262         TALLOC_FREE(tmp_db);
263
264         /* This is safe from other users as we know we're
265          * under a mutex here. */
266
267         if (rename(tmp_fname, dbname) == -1) {
268                 DEBUG(0, ("tdbsam_convert_backup: rename of %s to %s failed %s\n",
269                         tmp_fname,
270                         dbname,
271                         strerror(errno)));
272                 smb_panic("tdbsam_convert_backup: replace passdb failed\n");
273         }
274
275         TALLOC_FREE(frame);
276
277         /* re-open the converted TDB */
278
279         orig_db = db_open(NULL, dbname, 0,
280                           TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
281         if (orig_db == NULL) {
282                 DEBUG(0, ("tdbsam_convert_backup: Failed to re-open "
283                           "converted passdb TDB [%s]\n", dbname));
284                 return false;
285         }
286
287         DEBUG(1, ("tdbsam_convert_backup: updated %s file.\n",
288                 dbname ));
289
290         /* Replace the global db pointer. */
291         *pp_db = orig_db;
292         return true;
293
294   cancel:
295
296         if (orig_db->transaction_cancel(orig_db) != 0) {
297                 smb_panic("tdbsam_convert: transaction_cancel failed");
298         }
299
300         if (tmp_db->transaction_cancel(tmp_db) != 0) {
301                 smb_panic("tdbsam_convert: transaction_cancel failed");
302         }
303
304         unlink(tmp_fname);
305         TALLOC_FREE(tmp_db);
306         TALLOC_FREE(frame);
307         return false;
308 }
309
310 static bool tdbsam_upgrade_next_rid(struct db_context *db)
311 {
312         TDB_CONTEXT *tdb;
313         uint32 rid;
314         bool ok = false;
315
316         ok = dbwrap_fetch_uint32(db, NEXT_RID_STRING, &rid);
317         if (ok) {
318                 return true;
319         }
320
321         tdb = tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
322                            TDB_DEFAULT, O_RDONLY, 0644);
323
324         if (tdb) {
325                 ok = tdb_fetch_uint32(tdb, "RID_COUNTER", &rid);
326                 if (!ok) {
327                         rid = BASE_RID;
328                 }
329                 tdb_close(tdb);
330         } else {
331                 rid = BASE_RID;
332         }
333
334         if (dbwrap_store_uint32(db, NEXT_RID_STRING, rid) != 0) {
335                 return false;
336         }
337
338         return true;
339 }
340
341 static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32 from)
342 {
343         struct tdbsam_convert_state state;
344         struct db_context *db = NULL;
345         int ret;
346
347         /* We only need the update backup for local db's. */
348         if (db_is_local(name) && !tdbsam_convert_backup(name, pp_db)) {
349                 DEBUG(0, ("tdbsam_convert: Could not backup %s\n", name));
350                 return false;
351         }
352
353         db = *pp_db;
354         state.from = from;
355         state.success = true;
356
357         if (db->transaction_start(db) != 0) {
358                 DEBUG(0, ("tdbsam_convert: Could not start transaction\n"));
359                 return false;
360         }
361
362         if (!tdbsam_upgrade_next_rid(db)) {
363                 DEBUG(0, ("tdbsam_convert: tdbsam_upgrade_next_rid failed\n"));
364                 goto cancel;
365         }
366
367         ret = db->traverse(db, tdbsam_convert_one, &state);
368         if (ret < 0) {
369                 DEBUG(0, ("tdbsam_convert: traverse failed\n"));
370                 goto cancel;
371         }
372
373         if (!state.success) {
374                 DEBUG(0, ("tdbsam_convert: Converting records failed\n"));
375                 goto cancel;
376         }
377
378         if (dbwrap_store_int32(db, TDBSAM_VERSION_STRING,
379                                TDBSAM_VERSION) != 0) {
380                 DEBUG(0, ("tdbsam_convert: Could not store tdbsam version\n"));
381                 goto cancel;
382         }
383
384         if (dbwrap_store_int32(db, TDBSAM_MINOR_VERSION_STRING,
385                                TDBSAM_MINOR_VERSION) != 0) {
386                 DEBUG(0, ("tdbsam_convert: Could not store tdbsam minor version\n"));
387                 goto cancel;
388         }
389
390         if (db->transaction_commit(db) != 0) {
391                 DEBUG(0, ("tdbsam_convert: Could not commit transaction\n"));
392                 return false;
393         }
394
395         return true;
396
397  cancel:
398         if (db->transaction_cancel(db) != 0) {
399                 smb_panic("tdbsam_convert: transaction_cancel failed");
400         }
401
402         return false;
403 }
404
405 /*********************************************************************
406  Open the tdbsam file based on the absolute path specified.
407  Uses a reference count to allow multiple open calls.
408 *********************************************************************/
409
410 static bool tdbsam_open( const char *name )
411 {
412         int32   version;
413         int32   minor_version;
414
415         /* check if we are already open */
416
417         if ( db_sam ) {
418                 return true;
419         }
420
421         /* Try to open tdb passwd.  Create a new one if necessary */
422
423         db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
424         if (db_sam == NULL) {
425                 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
426                           "[%s]\n", name));
427                 return false;
428         }
429
430         /* Check the version */
431         version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
432         if (version == -1) {
433                 version = 0;    /* Version not found, assume version 0 */
434         }
435
436         /* Get the minor version */
437         minor_version = dbwrap_fetch_int32(db_sam, TDBSAM_MINOR_VERSION_STRING);
438         if (minor_version == -1) {
439                 minor_version = 0; /* Minor version not found, assume 0 */
440         }
441
442         /* Compare the version */
443         if (version > TDBSAM_VERSION) {
444                 /* Version more recent than the latest known */
445                 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
446                 TALLOC_FREE(db_sam);
447                 return false;
448         }
449
450         if ( version < TDBSAM_VERSION ||
451                         (version == TDBSAM_VERSION &&
452                          minor_version < TDBSAM_MINOR_VERSION) ) {
453                 /*
454                  * Ok - we think we're going to have to convert.
455                  * Due to the backup process we now must do to
456                  * upgrade we have to get a mutex and re-check
457                  * the version. Someone else may have upgraded
458                  * whilst we were checking.
459                  */
460
461                 struct named_mutex *mtx = grab_named_mutex(NULL,
462                                                 "tdbsam_upgrade_mutex",
463                                                 600);
464
465                 if (!mtx) {
466                         DEBUG(0, ("tdbsam_open: failed to grab mutex.\n"));
467                         TALLOC_FREE(db_sam);
468                         return false;
469                 }
470
471                 /* Re-check the version */
472                 version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
473                 if (version == -1) {
474                         version = 0;    /* Version not found, assume version 0 */
475                 }
476
477                 /* Re-check the minor version */
478                 minor_version = dbwrap_fetch_int32(db_sam, TDBSAM_MINOR_VERSION_STRING);
479                 if (minor_version == -1) {
480                         minor_version = 0; /* Minor version not found, assume 0 */
481                 }
482
483                 /* Compare the version */
484                 if (version > TDBSAM_VERSION) {
485                         /* Version more recent than the latest known */
486                         DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
487                         TALLOC_FREE(db_sam);
488                         TALLOC_FREE(mtx);
489                         return false;
490                 }
491
492                 if ( version < TDBSAM_VERSION ||
493                                 (version == TDBSAM_VERSION &&
494                                  minor_version < TDBSAM_MINOR_VERSION) ) {
495                         /*
496                          * Note that minor versions we read that are greater
497                          * than the current minor version we have hard coded
498                          * are assumed to be compatible if they have the same
499                          * major version. That allows previous versions of the
500                          * passdb code that don't know about minor versions to
501                          * still use this database. JRA.
502                          */
503
504                         DEBUG(1, ("tdbsam_open: Converting version %d.%d database to "
505                                   "version %d.%d.\n",
506                                         version,
507                                         minor_version,
508                                         TDBSAM_VERSION,
509                                         TDBSAM_MINOR_VERSION));
510
511                         if ( !tdbsam_convert(&db_sam, name, version) ) {
512                                 DEBUG(0, ("tdbsam_open: Error when trying to convert "
513                                           "tdbsam [%s]\n",name));
514                                 TALLOC_FREE(db_sam);
515                                 TALLOC_FREE(mtx);
516                                 return false;
517                         }
518
519                         DEBUG(3, ("TDBSAM converted successfully.\n"));
520                 }
521                 TALLOC_FREE(mtx);
522         }
523
524         DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
525
526         return true;
527 }
528
529 /******************************************************************
530  Lookup a name in the SAM TDB
531 ******************************************************************/
532
533 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
534                                     struct samu *user, const char *sname)
535 {
536         TDB_DATA        data;
537         fstring         keystr;
538         fstring         name;
539
540         if ( !user ) {
541                 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
542                 return NT_STATUS_NO_MEMORY;
543         }
544
545         /* Data is stored in all lower-case */
546         fstrcpy(name, sname);
547         strlower_m(name);
548
549         /* set search key */
550         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
551
552         /* open the database */
553
554         if ( !tdbsam_open( tdbsam_filename ) ) {
555                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
556                 return NT_STATUS_ACCESS_DENIED;
557         }
558
559         /* get the record */
560
561         data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
562         if (!data.dptr) {
563                 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
564                 DEBUGADD(5, (" Key: %s\n", keystr));
565                 return NT_STATUS_NO_SUCH_USER;
566         }
567
568         /* unpack the buffer */
569
570         if (!init_samu_from_buffer(user, SAMU_BUFFER_LATEST, data.dptr, data.dsize)) {
571                 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
572                 SAFE_FREE(data.dptr);
573                 return NT_STATUS_NO_MEMORY;
574         }
575
576         /* success */
577
578         TALLOC_FREE(data.dptr);
579
580         return NT_STATUS_OK;
581 }
582
583 /***************************************************************************
584  Search by rid
585  **************************************************************************/
586
587 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
588                                     struct samu *user, uint32 rid)
589 {
590         NTSTATUS                nt_status = NT_STATUS_UNSUCCESSFUL;
591         TDB_DATA                data;
592         fstring                 keystr;
593         fstring                 name;
594
595         if ( !user ) {
596                 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
597                 return nt_status;
598         }
599
600         /* set search key */
601
602         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
603
604         /* open the database */
605
606         if ( !tdbsam_open( tdbsam_filename ) ) {
607                 DEBUG(0,("tdbsam_getsampwrid: failed to open %s!\n", tdbsam_filename));
608                 return NT_STATUS_ACCESS_DENIED;
609         }
610
611         /* get the record */
612
613         data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
614         if (!data.dptr) {
615                 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
616                 return NT_STATUS_UNSUCCESSFUL;
617         }
618
619         fstrcpy(name, (const char *)data.dptr);
620         TALLOC_FREE(data.dptr);
621
622         return tdbsam_getsampwnam (my_methods, user, name);
623 }
624
625 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
626                                    struct samu * user, const struct dom_sid *sid)
627 {
628         uint32 rid;
629
630         if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
631                 return NT_STATUS_UNSUCCESSFUL;
632
633         return tdbsam_getsampwrid(my_methods, user, rid);
634 }
635
636 static bool tdb_delete_samacct_only( struct samu *sam_pass )
637 {
638         fstring         keystr;
639         fstring         name;
640         NTSTATUS status;
641
642         fstrcpy(name, pdb_get_username(sam_pass));
643         strlower_m(name);
644
645         /* set the search key */
646
647         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
648
649         /* it's outaa here!  8^) */
650         if ( !tdbsam_open( tdbsam_filename ) ) {
651                 DEBUG(0,("tdb_delete_samacct_only: failed to open %s!\n",
652                          tdbsam_filename));
653                 return false;
654         }
655
656         status = dbwrap_delete_bystring(db_sam, keystr);
657         if (!NT_STATUS_IS_OK(status)) {
658                 DEBUG(5, ("Error deleting entry from tdb passwd "
659                           "database: %s!\n", nt_errstr(status)));
660                 return false;
661         }
662
663         return true;
664 }
665
666 /***************************************************************************
667  Delete a struct samu records for the username and RID key
668 ****************************************************************************/
669
670 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
671                                           struct samu *sam_pass)
672 {
673         NTSTATUS        nt_status = NT_STATUS_UNSUCCESSFUL;
674         fstring         keystr;
675         uint32          rid;
676         fstring         name;
677
678         /* open the database */
679
680         if ( !tdbsam_open( tdbsam_filename ) ) {
681                 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
682                          tdbsam_filename));
683                 return NT_STATUS_ACCESS_DENIED;
684         }
685
686         fstrcpy(name, pdb_get_username(sam_pass));
687         strlower_m(name);
688
689         /* set the search key */
690
691         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
692
693         rid = pdb_get_user_rid(sam_pass);
694
695         /* it's outaa here!  8^) */
696
697         if (db_sam->transaction_start(db_sam) != 0) {
698                 DEBUG(0, ("Could not start transaction\n"));
699                 return NT_STATUS_UNSUCCESSFUL;
700         }
701
702         nt_status = dbwrap_delete_bystring(db_sam, keystr);
703         if (!NT_STATUS_IS_OK(nt_status)) {
704                 DEBUG(5, ("Error deleting entry from tdb passwd "
705                           "database: %s!\n", nt_errstr(nt_status)));
706                 goto cancel;
707         }
708
709         /* set the search key */
710
711         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
712
713         /* it's outaa here!  8^) */
714
715         nt_status = dbwrap_delete_bystring(db_sam, keystr);
716         if (!NT_STATUS_IS_OK(nt_status)) {
717                 DEBUG(5, ("Error deleting entry from tdb rid "
718                           "database: %s!\n", nt_errstr(nt_status)));
719                 goto cancel;
720         }
721
722         if (db_sam->transaction_commit(db_sam) != 0) {
723                 DEBUG(0, ("Could not commit transaction\n"));
724                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
725         }
726
727         return NT_STATUS_OK;
728
729  cancel:
730         if (db_sam->transaction_cancel(db_sam) != 0) {
731                 smb_panic("transaction_cancel failed");
732         }
733
734         return nt_status;
735 }
736
737
738 /***************************************************************************
739  Update the TDB SAM account record only
740  Assumes that the tdbsam is already open 
741 ****************************************************************************/
742 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
743 {
744         TDB_DATA        data;
745         uint8           *buf = NULL;
746         fstring         keystr;
747         fstring         name;
748         bool            ret = false;
749         NTSTATUS status;
750
751         /* copy the struct samu struct into a BYTE buffer for storage */
752
753         if ( (data.dsize=init_buffer_from_samu(&buf, newpwd, False)) == -1 ) {
754                 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
755                 goto done;
756         }
757         data.dptr = buf;
758
759         fstrcpy(name, pdb_get_username(newpwd));
760         strlower_m(name);
761
762         DEBUG(5, ("Storing %saccount %s with RID %d\n",
763                   flag == TDB_INSERT ? "(new) " : "", name,
764                   pdb_get_user_rid(newpwd)));
765
766         /* setup the USER index key */
767         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
768
769         /* add the account */
770
771         status = dbwrap_store_bystring(db_sam, keystr, data, flag);
772         if (!NT_STATUS_IS_OK(status)) {
773                 DEBUG(0, ("Unable to modify passwd TDB: %s!",
774                           nt_errstr(status)));
775                 goto done;
776         }
777
778         ret = true;
779
780 done:
781         /* cleanup */
782         SAFE_FREE(buf);
783         return ret;
784 }
785
786 /***************************************************************************
787  Update the TDB SAM RID record only
788  Assumes that the tdbsam is already open
789 ****************************************************************************/
790 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
791 {
792         TDB_DATA        data;
793         fstring         keystr;
794         fstring         name;
795         NTSTATUS status;
796
797         fstrcpy(name, pdb_get_username(newpwd));
798         strlower_m(name);
799
800         /* setup RID data */
801         data = string_term_tdb_data(name);
802
803         /* setup the RID index key */
804         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
805                  pdb_get_user_rid(newpwd));
806
807         /* add the reference */
808         status = dbwrap_store_bystring(db_sam, keystr, data, flag);
809         if (!NT_STATUS_IS_OK(status)) {
810                 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
811                           nt_errstr(status)));
812                 return false;
813         }
814
815         return true;
816
817 }
818
819 /***************************************************************************
820  Update the TDB SAM
821 ****************************************************************************/
822
823 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
824                            int flag)
825 {
826         uint32_t oldrid;
827         uint32_t newrid;
828
829         if (!(newrid = pdb_get_user_rid(newpwd))) {
830                 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
831                          pdb_get_username(newpwd)));
832                 return False;
833         }
834
835         oldrid = newrid;
836
837         /* open the database */
838
839         if ( !tdbsam_open( tdbsam_filename ) ) {
840                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
841                 return False;
842         }
843
844         if (db_sam->transaction_start(db_sam) != 0) {
845                 DEBUG(0, ("Could not start transaction\n"));
846                 return false;
847         }
848
849         /* If we are updating, we may be changing this users RID. Retrieve the old RID
850            so we can check. */
851
852         if (flag == TDB_MODIFY) {
853                 struct samu *account = samu_new(talloc_tos());
854                 if (account == NULL) {
855                         DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
856                         goto cancel;
857                 }
858                 if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) {
859                         DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
860                                 pdb_get_username(newpwd)));
861                         TALLOC_FREE(account);
862                         goto cancel;
863                 }
864                 if (!(oldrid = pdb_get_user_rid(account))) {
865                         DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
866                         TALLOC_FREE(account);
867                         goto cancel;
868                 }
869                 TALLOC_FREE(account);
870         }
871
872         /* Update the new samu entry. */
873         if (!tdb_update_samacct_only(newpwd, flag)) {
874                 goto cancel;
875         }
876
877         /* Now take care of the case where the RID changed. We need
878          * to delete the old RID key and add the new. */
879
880         if (flag == TDB_MODIFY && newrid != oldrid) { 
881                 fstring keystr;
882
883                 /* Delete old RID key */
884                 DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid));
885                 slprintf(keystr, sizeof(keystr) - 1, "%s%.8x", RIDPREFIX, oldrid);
886                 if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) {
887                         DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr));
888                         goto cancel;
889                 }
890                 /* Insert new RID key */
891                 DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid));
892                 if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) {
893                         goto cancel;
894                 }
895         } else {
896                 DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
897                         flag == TDB_MODIFY ? "Updating" : "Inserting", newrid));
898                 if (!tdb_update_ridrec_only(newpwd, flag)) {
899                         goto cancel;
900                 }
901         }
902
903         if (db_sam->transaction_commit(db_sam) != 0) {
904                 DEBUG(0, ("Could not commit transaction\n"));
905                 return false;
906         }
907
908         return true;
909
910  cancel:
911         if (db_sam->transaction_cancel(db_sam) != 0) {
912                 smb_panic("transaction_cancel failed");
913         }
914         return false;
915 }
916
917 /***************************************************************************
918  Modifies an existing struct samu
919 ****************************************************************************/
920
921 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
922 {
923         if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
924                 return NT_STATUS_UNSUCCESSFUL;
925         
926         return NT_STATUS_OK;
927 }
928
929 /***************************************************************************
930  Adds an existing struct samu
931 ****************************************************************************/
932
933 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
934 {
935         if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
936                 return NT_STATUS_UNSUCCESSFUL;
937                 
938         return NT_STATUS_OK;
939 }
940
941 /***************************************************************************
942  Renames a struct samu
943  - check for the posix user/rename user script
944  - Add and lock the new user record
945  - rename the posix user
946  - rewrite the rid->username record
947  - delete the old user
948  - unlock the new user record
949 ***************************************************************************/
950 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
951                                           struct samu *old_acct,
952                                           const char *newname)
953 {
954         struct samu      *new_acct = NULL;
955         char *rename_script = NULL;
956         int              rename_ret;
957         fstring          oldname_lower;
958         fstring          newname_lower;
959
960         /* can't do anything without an external script */
961
962         if ( !(new_acct = samu_new( talloc_tos() )) ) {
963                 return NT_STATUS_NO_MEMORY;
964         }
965
966         rename_script = talloc_strdup(new_acct, lp_renameuser_script());
967         if (!rename_script) {
968                 TALLOC_FREE(new_acct);
969                 return NT_STATUS_NO_MEMORY;
970         }
971         if (!*rename_script) {
972                 TALLOC_FREE(new_acct);
973                 return NT_STATUS_ACCESS_DENIED;
974         }
975
976         if ( !pdb_copy_sam_account(new_acct, old_acct)
977                 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
978         {
979                 TALLOC_FREE(new_acct);
980                 return NT_STATUS_NO_MEMORY;
981         }
982
983         /* open the database */
984         if ( !tdbsam_open( tdbsam_filename ) ) {
985                 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
986                           tdbsam_filename));
987                 TALLOC_FREE(new_acct);
988                 return NT_STATUS_ACCESS_DENIED;
989         }
990
991         if (db_sam->transaction_start(db_sam) != 0) {
992                 DEBUG(0, ("Could not start transaction\n"));
993                 TALLOC_FREE(new_acct);
994                 return NT_STATUS_ACCESS_DENIED;
995
996         }
997
998         /* add the new account and lock it */
999         if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
1000                 goto cancel;
1001         }
1002
1003         /* Rename the posix user.  Follow the semantics of _samr_create_user()
1004            so that we lower case the posix name but preserve the case in passdb */
1005
1006         fstrcpy( oldname_lower, pdb_get_username(old_acct) );
1007         strlower_m( oldname_lower );
1008
1009         fstrcpy( newname_lower, newname );
1010         strlower_m( newname_lower );
1011
1012         rename_script = talloc_string_sub2(new_acct,
1013                                 rename_script,
1014                                 "%unew",
1015                                 newname_lower,
1016                                 true,
1017                                 false,
1018                                 true);
1019         if (!rename_script) {
1020                 goto cancel;
1021         }
1022         rename_script = talloc_string_sub2(new_acct,
1023                                 rename_script,
1024                                 "%uold",
1025                                 oldname_lower,
1026                                 true,
1027                                 false,
1028                                 true);
1029         if (!rename_script) {
1030                 goto cancel;
1031         }
1032         rename_ret = smbrun(rename_script, NULL);
1033
1034         DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
1035                                 rename_script, rename_ret));
1036
1037         if (rename_ret != 0) {
1038                 goto cancel;
1039         }
1040
1041         smb_nscd_flush_user_cache();
1042
1043         /* rewrite the rid->username record */
1044
1045         if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1046                 goto cancel;
1047         }
1048
1049         tdb_delete_samacct_only( old_acct );
1050
1051         if (db_sam->transaction_commit(db_sam) != 0) {
1052                 /*
1053                  * Ok, we're screwed. We've changed the posix account, but
1054                  * could not adapt passdb.tdb. Shall we change the posix
1055                  * account back?
1056                  */
1057                 DEBUG(0, ("transaction_commit failed\n"));
1058                 TALLOC_FREE(new_acct);
1059                 return NT_STATUS_INTERNAL_DB_CORRUPTION;        
1060         }
1061
1062         TALLOC_FREE(new_acct );
1063         return NT_STATUS_OK;
1064
1065  cancel:
1066         if (db_sam->transaction_cancel(db_sam) != 0) {
1067                 smb_panic("transaction_cancel failed");
1068         }
1069
1070         TALLOC_FREE(new_acct);
1071
1072         return NT_STATUS_ACCESS_DENIED; 
1073 }
1074
1075 static uint32_t tdbsam_capabilities(struct pdb_methods *methods)
1076 {
1077         return PDB_CAP_STORE_RIDS;
1078 }
1079
1080 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
1081 {
1082         uint32 rid;
1083         NTSTATUS status;
1084
1085         rid = BASE_RID;         /* Default if not set */
1086
1087         if (!tdbsam_open(tdbsam_filename)) {
1088                 DEBUG(0,("tdbsam_new_rid: failed to open %s!\n",
1089                         tdbsam_filename));
1090                 return false;
1091         }
1092
1093         status = dbwrap_trans_change_uint32_atomic(db_sam, NEXT_RID_STRING,
1094                                                    &rid, 1);
1095         if (!NT_STATUS_IS_OK(status)) {
1096                 DEBUG(3, ("tdbsam_new_rid: Failed to increase %s: %s\n",
1097                         NEXT_RID_STRING, nt_errstr(status)));
1098                 return false;
1099         }
1100
1101         *prid = rid;
1102
1103         return true;
1104 }
1105
1106 struct tdbsam_search_state {
1107         struct pdb_methods *methods;
1108         uint32_t acct_flags;
1109
1110         uint32_t *rids;
1111         uint32_t num_rids;
1112         ssize_t array_size;
1113         uint32_t current;
1114 };
1115
1116 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
1117 {
1118         struct tdbsam_search_state *state = talloc_get_type_abort(
1119                 private_data, struct tdbsam_search_state);
1120         size_t prefixlen = strlen(RIDPREFIX);
1121         uint32 rid;
1122
1123         if ((rec->key.dsize < prefixlen)
1124             || (strncmp((char *)rec->key.dptr, RIDPREFIX, prefixlen))) {
1125                 return 0;
1126         }
1127
1128         rid = strtoul((char *)rec->key.dptr+prefixlen, NULL, 16);
1129
1130         ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
1131                            &state->array_size);
1132
1133         return 0;
1134 }
1135
1136 static void tdbsam_search_end(struct pdb_search *search)
1137 {
1138         struct tdbsam_search_state *state = talloc_get_type_abort(
1139                 search->private_data, struct tdbsam_search_state);
1140         TALLOC_FREE(state);
1141 }
1142
1143 static bool tdbsam_search_next_entry(struct pdb_search *search,
1144                                      struct samr_displayentry *entry)
1145 {
1146         struct tdbsam_search_state *state = talloc_get_type_abort(
1147                 search->private_data, struct tdbsam_search_state);
1148         struct samu *user = NULL;
1149         NTSTATUS status;
1150         uint32_t rid;
1151
1152  again:
1153         TALLOC_FREE(user);
1154         user = samu_new(talloc_tos());
1155         if (user == NULL) {
1156                 DEBUG(0, ("samu_new failed\n"));
1157                 return false;
1158         }
1159
1160         if (state->current == state->num_rids) {
1161                 return false;
1162         }
1163
1164         rid = state->rids[state->current++];
1165
1166         status = tdbsam_getsampwrid(state->methods, user, rid);
1167
1168         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1169                 /*
1170                  * Someone has deleted that user since we listed the RIDs
1171                  */
1172                 goto again;
1173         }
1174
1175         if (!NT_STATUS_IS_OK(status)) {
1176                 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
1177                            nt_errstr(status)));
1178                 TALLOC_FREE(user);
1179                 return false;
1180         }
1181
1182         if ((state->acct_flags != 0) &&
1183             ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
1184                 goto again;
1185         }
1186
1187         entry->acct_flags = pdb_get_acct_ctrl(user);
1188         entry->rid = rid;
1189         entry->account_name = talloc_strdup(search, pdb_get_username(user));
1190         entry->fullname = talloc_strdup(search, pdb_get_fullname(user));
1191         entry->description = talloc_strdup(search, pdb_get_acct_desc(user));
1192
1193         TALLOC_FREE(user);
1194
1195         if ((entry->account_name == NULL) || (entry->fullname == NULL)
1196             || (entry->description == NULL)) {
1197                 DEBUG(0, ("talloc_strdup failed\n"));
1198                 return false;
1199         }
1200
1201         return true;
1202 }
1203
1204 static bool tdbsam_search_users(struct pdb_methods *methods,
1205                                 struct pdb_search *search,
1206                                 uint32 acct_flags)
1207 {
1208         struct tdbsam_search_state *state;
1209
1210         if (!tdbsam_open(tdbsam_filename)) {
1211                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
1212                          tdbsam_filename));
1213                 return false;
1214         }
1215
1216         state = talloc_zero(search, struct tdbsam_search_state);
1217         if (state == NULL) {
1218                 DEBUG(0, ("talloc failed\n"));
1219                 return false;
1220         }
1221         state->acct_flags = acct_flags;
1222         state->methods = methods;
1223
1224         db_sam->traverse_read(db_sam, tdbsam_collect_rids, state);
1225
1226         search->private_data = state;
1227         search->next_entry = tdbsam_search_next_entry;
1228         search->search_end = tdbsam_search_end;
1229
1230         return true;
1231 }
1232
1233 /*********************************************************************
1234  Initialize the tdb sam backend.  Setup the dispath table of methods,
1235  open the tdb, etc...
1236 *********************************************************************/
1237
1238 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1239 {
1240         NTSTATUS nt_status;
1241         char *tdbfile = NULL;
1242         const char *pfile = location;
1243
1244         if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1245                 return nt_status;
1246         }
1247
1248         (*pdb_method)->name = "tdbsam";
1249
1250         (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1251         (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1252         (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1253         (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1254         (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1255         (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1256         (*pdb_method)->search_users = tdbsam_search_users;
1257
1258         (*pdb_method)->capabilities = tdbsam_capabilities;
1259         (*pdb_method)->new_rid = tdbsam_new_rid;
1260
1261         /* save the path for later */
1262
1263         if (!location) {
1264                 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
1265                              PASSDB_FILE_NAME) < 0) {
1266                         return NT_STATUS_NO_MEMORY;
1267                 }
1268                 pfile = tdbfile;
1269         }
1270         tdbsam_filename = SMB_STRDUP(pfile);
1271         if (!tdbsam_filename) {
1272                 return NT_STATUS_NO_MEMORY;
1273         }
1274         SAFE_FREE(tdbfile);
1275
1276         /* no private data */
1277
1278         (*pdb_method)->private_data      = NULL;
1279         (*pdb_method)->free_private_data = NULL;
1280
1281         return NT_STATUS_OK;
1282 }
1283
1284 NTSTATUS pdb_tdbsam_init(void)
1285 {
1286         return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
1287 }