docs: fix a typo in history file
[bbaumbach/samba-autobuild/.git] / source3 / passdb / pdb_tdb.c
index 73fcfee4b35304dfeca5a668772e16eaf9b1f96f..161030fed8b9aba4096a75f9191b6e9998b25a94 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) Andrew Tridgell   1992-1998
  * Copyright (C) Simo Sorce        2000-2003
  * Copyright (C) Gerald Carter     2000-2006
- * Copyright (C) Jeremy Allison    2001
+ * Copyright (C) Jeremy Allison    2001-2009
  * Copyright (C) Andrew Bartlett   2002
  * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
  * 
  */
 
 #include "includes.h"
+#include "system/filesys.h"
+#include "passdb.h"
+#include "dbwrap/dbwrap.h"
+#include "dbwrap/dbwrap_open.h"
+#include "../libcli/security/security.h"
+#include "util_tdb.h"
+#include "passdb/pdb_tdb.h"
+#include "lib/util/smb_strtox.h"
+#include "lib/util/string_wrappers.h"
 
 #if 0 /* when made a module use this */
 
@@ -38,7 +47,9 @@ static int tdbsam_debug_level = DBGC_ALL;
 #endif
 
 #define TDBSAM_VERSION 4       /* Most recent TDBSAM version */
+#define TDBSAM_MINOR_VERSION   0       /* Most recent TDBSAM minor version */
 #define TDBSAM_VERSION_STRING  "INFO/version"
+#define TDBSAM_MINOR_VERSION_STRING    "INFO/minor_version"
 #define PASSDB_FILE_NAME       "passdb.tdb"
 #define USERPREFIX             "USER_"
 #define USERPREFIX_LEN         5
@@ -50,6 +61,7 @@ static int tdbsam_debug_level = DBGC_ALL;
 
 static struct db_context *db_sam;
 static char *tdbsam_filename;
+static bool map_builtin;
 
 struct tdbsam_convert_state {
        int32_t from;
@@ -64,11 +76,15 @@ static int tdbsam_convert_one(struct db_record *rec, void *priv)
        TDB_DATA data;
        NTSTATUS status;
        bool ret;
+       TDB_DATA key;
+       TDB_DATA value;
 
-       if (rec->key.dsize < USERPREFIX_LEN) {
+       key = dbwrap_record_get_key(rec);
+
+       if (key.dsize < USERPREFIX_LEN) {
                return 0;
        }
-       if (strncmp((char *)rec->key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
+       if (strncmp((char *)key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
                return 0;
        }
 
@@ -80,33 +96,35 @@ static int tdbsam_convert_one(struct db_record *rec, void *priv)
        }
 
        DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) "
-                 "(version:%d)\n", rec->key.dptr, state->from));
+                 "(version:%d)\n", (char *)key.dptr, state->from));
+
+       value = dbwrap_record_get_value(rec);
 
        switch (state->from) {
        case 0:
                ret = init_samu_from_buffer(user, SAMU_BUFFER_V0,
-                                           (uint8 *)rec->value.dptr,
-                                           rec->value.dsize);
+                                           (uint8_t *)value.dptr,
+                                           value.dsize);
                break;
        case 1:
                ret = init_samu_from_buffer(user, SAMU_BUFFER_V1,
-                                           (uint8 *)rec->value.dptr,
-                                           rec->value.dsize);
+                                           (uint8_t *)value.dptr,
+                                           value.dsize);
                break;
        case 2:
                ret = init_samu_from_buffer(user, SAMU_BUFFER_V2,
-                                           (uint8 *)rec->value.dptr,
-                                           rec->value.dsize);
+                                           (uint8_t *)value.dptr,
+                                           value.dsize);
                break;
        case 3:
                ret = init_samu_from_buffer(user, SAMU_BUFFER_V3,
-                                           (uint8 *)rec->value.dptr,
-                                           rec->value.dsize);
+                                           (uint8_t *)value.dptr,
+                                           value.dsize);
                break;
        case 4:
                ret = init_samu_from_buffer(user, SAMU_BUFFER_V4,
-                                           (uint8 *)rec->value.dptr,
-                                           rec->value.dsize);
+                                           (uint8_t *)value.dptr,
+                                           value.dsize);
                break;
        default:
                /* unknown tdbsam version */
@@ -114,7 +132,7 @@ static int tdbsam_convert_one(struct db_record *rec, void *priv)
        }
        if (!ret) {
                DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
-                        "from TDB (key:%s) (version:%d)\n", rec->key.dptr,
+                        "from TDB (key:%s) (version:%d)\n", (char *)key.dptr,
                         state->from));
                TALLOC_FREE(user);
                state->success = false;
@@ -131,7 +149,7 @@ static int tdbsam_convert_one(struct db_record *rec, void *priv)
                return -1;
        }
 
-       status = rec->store(rec, data, TDB_MODIFY);
+       status = dbwrap_record_store(rec, data, TDB_MODIFY);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(0, ("Could not store the new record: %s\n",
                          nt_errstr(status)));
@@ -156,14 +174,20 @@ static int backup_copy_fn(struct db_record *orig_rec, void *state)
        struct tdbsam_backup_state *bs = (struct tdbsam_backup_state *)state;
        struct db_record *new_rec;
        NTSTATUS status;
+       TDB_DATA key;
+       TDB_DATA value;
+
+       key = dbwrap_record_get_key(orig_rec);
 
-       new_rec = bs->new_db->fetch_locked(bs->new_db, talloc_tos(), orig_rec->key);
+       new_rec = dbwrap_fetch_locked(bs->new_db, talloc_tos(), key);
        if (new_rec == NULL) {
                bs->success = false;
                return 1;
        }
 
-       status = new_rec->store(new_rec, orig_rec->value, TDB_INSERT);
+       value = dbwrap_record_get_value(orig_rec);
+
+       status = dbwrap_record_store(new_rec, value, TDB_INSERT);
 
        TALLOC_FREE(new_rec);
 
@@ -189,7 +213,7 @@ static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
        struct db_context *tmp_db = NULL;
        struct db_context *orig_db = *pp_db;
        struct tdbsam_backup_state bs;
-       int ret;
+       NTSTATUS status;
 
        tmp_fname = talloc_asprintf(frame, "%s.tmp", dbname);
        if (!tmp_fname) {
@@ -203,7 +227,8 @@ static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
         * it to stay around after we return from here. */
 
        tmp_db = db_open(NULL, tmp_fname, 0,
-                               TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
+                        TDB_DEFAULT, O_CREAT|O_RDWR, 0600,
+                        DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
        if (tmp_db == NULL) {
                DEBUG(0, ("tdbsam_convert_backup: Failed to create backup TDB passwd "
                          "[%s]\n", tmp_fname));
@@ -211,16 +236,16 @@ static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
                return false;
        }
 
-       if (orig_db->transaction_start(orig_db) != 0) {
+       if (dbwrap_transaction_start(orig_db) != 0) {
                DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (1)\n"));
                unlink(tmp_fname);
                TALLOC_FREE(tmp_db);
                TALLOC_FREE(frame);
                return false;
        }
-       if (tmp_db->transaction_start(tmp_db) != 0) {
+       if (dbwrap_transaction_start(tmp_db) != 0) {
                DEBUG(0, ("tdbsam_convert_backup: Could not start transaction (2)\n"));
-               orig_db->transaction_cancel(orig_db);
+               dbwrap_transaction_cancel(orig_db);
                unlink(tmp_fname);
                TALLOC_FREE(tmp_db);
                TALLOC_FREE(frame);
@@ -230,8 +255,8 @@ static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
        bs.new_db = tmp_db;
        bs.success = true;
 
-        ret = orig_db->traverse(orig_db, backup_copy_fn, (void *)&bs);
-        if (ret < 0) {
+        status = dbwrap_traverse(orig_db, backup_copy_fn, (void *)&bs, NULL);
+        if (!NT_STATUS_IS_OK(status)) {
                 DEBUG(0, ("tdbsam_convert_backup: traverse failed\n"));
                 goto cancel;
         }
@@ -241,13 +266,18 @@ static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
                goto cancel;
        }
 
-       if (orig_db->transaction_commit(orig_db) != 0) {
+       if (dbwrap_transaction_commit(orig_db) != 0) {
                smb_panic("tdbsam_convert_backup: orig commit failed\n");
        }
-       if (tmp_db->transaction_commit(tmp_db) != 0) {
+       if (dbwrap_transaction_commit(tmp_db) != 0) {
                smb_panic("tdbsam_convert_backup: orig commit failed\n");
        }
 
+       /* be sure to close the DBs _before_ renaming the file */
+
+       TALLOC_FREE(orig_db);
+       TALLOC_FREE(tmp_db);
+
        /* This is safe from other users as we know we're
         * under a mutex here. */
 
@@ -260,22 +290,32 @@ static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
        }
 
        TALLOC_FREE(frame);
-       TALLOC_FREE(orig_db);
+
+       /* re-open the converted TDB */
+
+       orig_db = db_open(NULL, dbname, 0,
+                         TDB_DEFAULT, O_CREAT|O_RDWR, 0600,
+                         DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
+       if (orig_db == NULL) {
+               DEBUG(0, ("tdbsam_convert_backup: Failed to re-open "
+                         "converted passdb TDB [%s]\n", dbname));
+               return false;
+       }
 
        DEBUG(1, ("tdbsam_convert_backup: updated %s file.\n",
                dbname ));
 
        /* Replace the global db pointer. */
-       *pp_db = tmp_db;
+       *pp_db = orig_db;
        return true;
 
   cancel:
 
-       if (orig_db->transaction_cancel(orig_db) != 0) {
+       if (dbwrap_transaction_cancel(orig_db) != 0) {
                smb_panic("tdbsam_convert: transaction_cancel failed");
        }
 
-       if (tmp_db->transaction_cancel(tmp_db) != 0) {
+       if (dbwrap_transaction_cancel(tmp_db) != 0) {
                smb_panic("tdbsam_convert: transaction_cancel failed");
        }
 
@@ -288,17 +328,24 @@ static bool tdbsam_convert_backup(const char *dbname, struct db_context **pp_db)
 static bool tdbsam_upgrade_next_rid(struct db_context *db)
 {
        TDB_CONTEXT *tdb;
-       uint32 rid;
+       uint32_t rid;
        bool ok = false;
+       NTSTATUS status;
+       char *db_path;
 
-       ok = dbwrap_fetch_uint32(db, NEXT_RID_STRING, &rid);
-       if (ok) {
+       status = dbwrap_fetch_uint32_bystring(db, NEXT_RID_STRING, &rid);
+       if (NT_STATUS_IS_OK(status)) {
                return true;
        }
 
-       tdb = tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
-                          TDB_DEFAULT, O_RDONLY, 0644);
+       db_path = state_path(talloc_tos(), "winbindd_idmap.tdb");
+       if (db_path == NULL) {
+               return false;
+       }
 
+       tdb = tdb_open_log(db_path, 0,
+                          TDB_DEFAULT, O_RDONLY, 0644);
+       TALLOC_FREE(db_path);
        if (tdb) {
                ok = tdb_fetch_uint32(tdb, "RID_COUNTER", &rid);
                if (!ok) {
@@ -309,20 +356,22 @@ static bool tdbsam_upgrade_next_rid(struct db_context *db)
                rid = BASE_RID;
        }
 
-       if (dbwrap_store_uint32(db, NEXT_RID_STRING, rid) != 0) {
+       status = dbwrap_store_uint32_bystring(db, NEXT_RID_STRING, rid);
+       if (!NT_STATUS_IS_OK(status)) {
                return false;
        }
 
        return true;
 }
 
-static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32 from)
+static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32_t from)
 {
        struct tdbsam_convert_state state;
        struct db_context *db = NULL;
-       int ret;
+       NTSTATUS status;
 
-       if (!tdbsam_convert_backup(name, pp_db)) {
+       /* We only need the update backup for local db's. */
+       if (db_is_local(name) && !tdbsam_convert_backup(name, pp_db)) {
                DEBUG(0, ("tdbsam_convert: Could not backup %s\n", name));
                return false;
        }
@@ -331,7 +380,7 @@ static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32 fr
        state.from = from;
        state.success = true;
 
-       if (db->transaction_start(db) != 0) {
+       if (dbwrap_transaction_start(db) != 0) {
                DEBUG(0, ("tdbsam_convert: Could not start transaction\n"));
                return false;
        }
@@ -341,8 +390,8 @@ static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32 fr
                goto cancel;
        }
 
-       ret = db->traverse(db, tdbsam_convert_one, &state);
-       if (ret < 0) {
+       status = dbwrap_traverse(db, tdbsam_convert_one, &state, NULL);
+       if (!NT_STATUS_IS_OK(status)) {
                DEBUG(0, ("tdbsam_convert: traverse failed\n"));
                goto cancel;
        }
@@ -352,13 +401,23 @@ static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32 fr
                goto cancel;
        }
 
-       if (dbwrap_store_int32(db, TDBSAM_VERSION_STRING,
-                              TDBSAM_VERSION) != 0) {
-               DEBUG(0, ("tdbsam_convert: Could not store tdbsam version\n"));
+       status = dbwrap_store_int32_bystring(db, TDBSAM_VERSION_STRING,
+                                            TDBSAM_VERSION);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("tdbsam_convert: Could not store tdbsam version: "
+                         "%s\n", nt_errstr(status)));
                goto cancel;
        }
 
-       if (db->transaction_commit(db) != 0) {
+       status = dbwrap_store_int32_bystring(db, TDBSAM_MINOR_VERSION_STRING,
+                                            TDBSAM_MINOR_VERSION);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("tdbsam_convert: Could not store tdbsam minor "
+                         "version: %s\n", nt_errstr(status)));
+               goto cancel;
+       }
+
+       if (dbwrap_transaction_commit(db) != 0) {
                DEBUG(0, ("tdbsam_convert: Could not commit transaction\n"));
                return false;
        }
@@ -366,7 +425,7 @@ static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32 fr
        return true;
 
  cancel:
-       if (db->transaction_cancel(db) != 0) {
+       if (dbwrap_transaction_cancel(db) != 0) {
                smb_panic("tdbsam_convert: transaction_cancel failed");
        }
 
@@ -380,7 +439,9 @@ static bool tdbsam_convert(struct db_context **pp_db, const char *name, int32 fr
 
 static bool tdbsam_open( const char *name )
 {
-       int32   version;
+       int32_t version;
+       int32_t minor_version;
+       NTSTATUS status;
 
        /* check if we are already open */
 
@@ -390,7 +451,8 @@ static bool tdbsam_open( const char *name )
 
        /* Try to open tdb passwd.  Create a new one if necessary */
 
-       db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
+       db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600,
+                        DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
        if (db_sam == NULL) {
                DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
                          "[%s]\n", name));
@@ -398,11 +460,19 @@ static bool tdbsam_open( const char *name )
        }
 
        /* Check the version */
-       version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
-       if (version == -1) {
+       status = dbwrap_fetch_int32_bystring(db_sam, TDBSAM_VERSION_STRING,
+                                            &version);
+       if (!NT_STATUS_IS_OK(status)) {
                version = 0;    /* Version not found, assume version 0 */
        }
 
+       /* Get the minor version */
+       status = dbwrap_fetch_int32_bystring(
+               db_sam, TDBSAM_MINOR_VERSION_STRING, &minor_version);
+       if (!NT_STATUS_IS_OK(status)) {
+               minor_version = 0; /* Minor version not found, assume 0 */
+       }
+
        /* Compare the version */
        if (version > TDBSAM_VERSION) {
                /* Version more recent than the latest known */
@@ -411,7 +481,9 @@ static bool tdbsam_open( const char *name )
                return false;
        }
 
-       if ( version < TDBSAM_VERSION ) {
+       if ( version < TDBSAM_VERSION ||
+                       (version == TDBSAM_VERSION &&
+                        minor_version < TDBSAM_MINOR_VERSION) ) {
                /*
                 * Ok - we think we're going to have to convert.
                 * Due to the backup process we now must do to
@@ -431,11 +503,19 @@ static bool tdbsam_open( const char *name )
                }
 
                /* Re-check the version */
-               version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
-               if (version == -1) {
+               status = dbwrap_fetch_int32_bystring(
+                       db_sam, TDBSAM_VERSION_STRING, &version);
+               if (!NT_STATUS_IS_OK(status)) {
                        version = 0;    /* Version not found, assume version 0 */
                }
 
+               /* Re-check the minor version */
+               status = dbwrap_fetch_int32_bystring(
+                       db_sam, TDBSAM_MINOR_VERSION_STRING, &minor_version);
+               if (!NT_STATUS_IS_OK(status)) {
+                       minor_version = 0; /* Minor version not found, assume 0 */
+               }
+
                /* Compare the version */
                if (version > TDBSAM_VERSION) {
                        /* Version more recent than the latest known */
@@ -445,9 +525,24 @@ static bool tdbsam_open( const char *name )
                        return false;
                }
 
-               if ( version < TDBSAM_VERSION ) {
-                       DEBUG(1, ("tdbsam_open: Converting version %d database to "
-                                 "version %d.\n", version, TDBSAM_VERSION));
+               if ( version < TDBSAM_VERSION ||
+                               (version == TDBSAM_VERSION &&
+                                minor_version < TDBSAM_MINOR_VERSION) ) {
+                       /*
+                        * Note that minor versions we read that are greater
+                        * than the current minor version we have hard coded
+                        * are assumed to be compatible if they have the same
+                        * major version. That allows previous versions of the
+                        * passdb code that don't know about minor versions to
+                        * still use this database. JRA.
+                        */
+
+                       DEBUG(1, ("tdbsam_open: Converting version %d.%d database to "
+                                 "version %d.%d.\n",
+                                       version,
+                                       minor_version,
+                                       TDBSAM_VERSION,
+                                       TDBSAM_MINOR_VERSION));
 
                        if ( !tdbsam_convert(&db_sam, name, version) ) {
                                DEBUG(0, ("tdbsam_open: Error when trying to convert "
@@ -477,6 +572,7 @@ static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
        TDB_DATA        data;
        fstring         keystr;
        fstring         name;
+       NTSTATUS status;
 
        if ( !user ) {
                DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
@@ -485,10 +581,12 @@ static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
 
        /* Data is stored in all lower-case */
        fstrcpy(name, sname);
-       strlower_m(name);
+       if (!strlower_m(name)) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
 
        /* set search key */
-       slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
+       fstr_sprintf(keystr, "%s%s", USERPREFIX, name);
 
        /* open the database */
 
@@ -499,18 +597,24 @@ static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
 
        /* get the record */
 
-       data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
-       if (!data.dptr) {
+       status = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr, &data);
+       if (!NT_STATUS_IS_OK(status)) {
                DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
                DEBUGADD(5, (" Key: %s\n", keystr));
                return NT_STATUS_NO_SUCH_USER;
        }
 
+       if (data.dsize == 0) {
+               DEBUG(5, ("%s: Got 0-sized record for key %s\n", __func__,
+                         keystr));
+               return NT_STATUS_NO_SUCH_USER;
+       }
+
        /* unpack the buffer */
 
        if (!init_samu_from_buffer(user, SAMU_BUFFER_LATEST, data.dptr, data.dsize)) {
                DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
-               SAFE_FREE(data.dptr);
+               TALLOC_FREE(data.dptr);
                return NT_STATUS_NO_MEMORY;
        }
 
@@ -526,7 +630,7 @@ static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
  **************************************************************************/
 
 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
-                                   struct samu *user, uint32 rid)
+                                   struct samu *user, uint32_t rid)
 {
        NTSTATUS                nt_status = NT_STATUS_UNSUCCESSFUL;
        TDB_DATA                data;
@@ -540,7 +644,7 @@ static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
 
        /* set search key */
 
-       slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
+       fstr_sprintf(keystr, "%s%.8x", RIDPREFIX, rid);
 
        /* open the database */
 
@@ -551,10 +655,10 @@ static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
 
        /* get the record */
 
-       data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
-       if (!data.dptr) {
+       nt_status = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr, &data);
+       if (!NT_STATUS_IS_OK(nt_status)) {
                DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
-               return NT_STATUS_UNSUCCESSFUL;
+               return nt_status;
        }
 
        fstrcpy(name, (const char *)data.dptr);
@@ -564,9 +668,9 @@ static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
 }
 
 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
-                                  struct samu * user, const DOM_SID *sid)
+                                  struct samu * user, const struct dom_sid *sid)
 {
-       uint32 rid;
+       uint32_t rid;
 
        if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
                return NT_STATUS_UNSUCCESSFUL;
@@ -581,11 +685,13 @@ static bool tdb_delete_samacct_only( struct samu *sam_pass )
        NTSTATUS status;
 
        fstrcpy(name, pdb_get_username(sam_pass));
-       strlower_m(name);
+       if (!strlower_m(name)) {
+               return false;
+       }
 
        /* set the search key */
 
-       slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
+       fstr_sprintf(keystr, "%s%s", USERPREFIX, name);
 
        /* it's outaa here!  8^) */
        if ( !tdbsam_open( tdbsam_filename ) ) {
@@ -611,9 +717,9 @@ static bool tdb_delete_samacct_only( struct samu *sam_pass )
 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
                                          struct samu *sam_pass)
 {
-       NTSTATUS        nt_status = NT_STATUS_UNSUCCESSFUL;
+       NTSTATUS        nt_status;
        fstring         keystr;
-       uint32          rid;
+       uint32_t        rid;
        fstring         name;
 
        /* open the database */
@@ -625,17 +731,19 @@ static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
        }
 
        fstrcpy(name, pdb_get_username(sam_pass));
-       strlower_m(name);
+       if (!strlower_m(name)) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
 
        /* set the search key */
 
-       slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
+       fstr_sprintf(keystr, "%s%s", USERPREFIX, name);
 
        rid = pdb_get_user_rid(sam_pass);
 
        /* it's outaa here!  8^) */
 
-       if (db_sam->transaction_start(db_sam) != 0) {
+       if (dbwrap_transaction_start(db_sam) != 0) {
                DEBUG(0, ("Could not start transaction\n"));
                return NT_STATUS_UNSUCCESSFUL;
        }
@@ -649,7 +757,7 @@ static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
 
        /* set the search key */
 
-       slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
+       fstr_sprintf(keystr, "%s%.8x", RIDPREFIX, rid);
 
        /* it's outaa here!  8^) */
 
@@ -660,7 +768,7 @@ static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
                goto cancel;
        }
 
-       if (db_sam->transaction_commit(db_sam) != 0) {
+       if (dbwrap_transaction_commit(db_sam) != 0) {
                DEBUG(0, ("Could not commit transaction\n"));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
@@ -668,7 +776,7 @@ static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
        return NT_STATUS_OK;
 
  cancel:
-       if (db_sam->transaction_cancel(db_sam) != 0) {
+       if (dbwrap_transaction_cancel(db_sam) != 0) {
                smb_panic("transaction_cancel failed");
        }
 
@@ -683,7 +791,7 @@ static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
 {
        TDB_DATA        data;
-       uint8           *buf = NULL;
+       uint8_t         *buf = NULL;
        fstring         keystr;
        fstring         name;
        bool            ret = false;
@@ -698,14 +806,16 @@ static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
        data.dptr = buf;
 
        fstrcpy(name, pdb_get_username(newpwd));
-       strlower_m(name);
+       if (!strlower_m(name)) {
+               goto done;
+       }
 
        DEBUG(5, ("Storing %saccount %s with RID %d\n",
                  flag == TDB_INSERT ? "(new) " : "", name,
                  pdb_get_user_rid(newpwd)));
 
        /* setup the USER index key */
-       slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
+       fstr_sprintf(keystr, "%s%s", USERPREFIX, name);
 
        /* add the account */
 
@@ -736,14 +846,15 @@ static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
        NTSTATUS status;
 
        fstrcpy(name, pdb_get_username(newpwd));
-       strlower_m(name);
+       if (!strlower_m(name)) {
+               return false;
+       }
 
        /* setup RID data */
        data = string_term_tdb_data(name);
 
        /* setup the RID index key */
-       slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
-                pdb_get_user_rid(newpwd));
+       fstr_sprintf(keystr, "%s%.8x", RIDPREFIX, pdb_get_user_rid(newpwd));
 
        /* add the reference */
        status = dbwrap_store_bystring(db_sam, keystr, data, flag);
@@ -764,12 +875,17 @@ static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
                           int flag)
 {
-       if (!pdb_get_user_rid(newpwd)) {
+       uint32_t oldrid;
+       uint32_t newrid;
+
+       if (!(newrid = pdb_get_user_rid(newpwd))) {
                DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
                         pdb_get_username(newpwd)));
                return False;
        }
 
+       oldrid = newrid;
+
        /* open the database */
 
        if ( !tdbsam_open( tdbsam_filename ) ) {
@@ -777,17 +893,66 @@ static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
                return False;
        }
 
-       if (db_sam->transaction_start(db_sam) != 0) {
+       if (dbwrap_transaction_start(db_sam) != 0) {
                DEBUG(0, ("Could not start transaction\n"));
                return false;
        }
 
-       if (!tdb_update_samacct_only(newpwd, flag)
-           || !tdb_update_ridrec_only(newpwd, flag)) {
+       /* If we are updating, we may be changing this users RID. Retrieve the old RID
+          so we can check. */
+
+       if (flag == TDB_MODIFY) {
+               struct samu *account = samu_new(talloc_tos());
+               if (account == NULL) {
+                       DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
+                       goto cancel;
+               }
+               if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) {
+                       DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
+                               pdb_get_username(newpwd)));
+                       TALLOC_FREE(account);
+                       goto cancel;
+               }
+               if (!(oldrid = pdb_get_user_rid(account))) {
+                       DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
+                       TALLOC_FREE(account);
+                       goto cancel;
+               }
+               TALLOC_FREE(account);
+       }
+
+       /* Update the new samu entry. */
+       if (!tdb_update_samacct_only(newpwd, flag)) {
                goto cancel;
        }
 
-       if (db_sam->transaction_commit(db_sam) != 0) {
+       /* Now take care of the case where the RID changed. We need
+        * to delete the old RID key and add the new. */
+
+       if (flag == TDB_MODIFY && newrid != oldrid) { 
+               fstring keystr;
+
+               /* Delete old RID key */
+               DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid));
+               fstr_sprintf(keystr, "%s%.8x", RIDPREFIX, oldrid);
+               if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) {
+                       DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr));
+                       goto cancel;
+               }
+               /* Insert new RID key */
+               DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid));
+               if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) {
+                       goto cancel;
+               }
+       } else {
+               DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
+                       flag == TDB_MODIFY ? "Updating" : "Inserting", newrid));
+               if (!tdb_update_ridrec_only(newpwd, flag)) {
+                       goto cancel;
+               }
+       }
+
+       if (dbwrap_transaction_commit(db_sam) != 0) {
                DEBUG(0, ("Could not commit transaction\n"));
                return false;
        }
@@ -795,7 +960,7 @@ static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
        return true;
 
  cancel:
-       if (db_sam->transaction_cancel(db_sam) != 0) {
+       if (dbwrap_transaction_cancel(db_sam) != 0) {
                smb_panic("transaction_cancel failed");
        }
        return false;
@@ -838,6 +1003,8 @@ static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
                                          struct samu *old_acct,
                                          const char *newname)
 {
+       const struct loadparm_substitution *lp_sub =
+               loadparm_s3_global_substitution();
        struct samu      *new_acct = NULL;
        char *rename_script = NULL;
        int              rename_ret;
@@ -850,7 +1017,7 @@ static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
                return NT_STATUS_NO_MEMORY;
        }
 
-       rename_script = talloc_strdup(new_acct, lp_renameuser_script());
+       rename_script = lp_rename_user_script(new_acct, lp_sub);
        if (!rename_script) {
                TALLOC_FREE(new_acct);
                return NT_STATUS_NO_MEMORY;
@@ -875,7 +1042,7 @@ static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
                return NT_STATUS_ACCESS_DENIED;
        }
 
-       if (db_sam->transaction_start(db_sam) != 0) {
+       if (dbwrap_transaction_start(db_sam) != 0) {
                DEBUG(0, ("Could not start transaction\n"));
                TALLOC_FREE(new_acct);
                return NT_STATUS_ACCESS_DENIED;
@@ -891,10 +1058,14 @@ static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
           so that we lower case the posix name but preserve the case in passdb */
 
        fstrcpy( oldname_lower, pdb_get_username(old_acct) );
-       strlower_m( oldname_lower );
+       if (!strlower_m( oldname_lower )) {
+               goto cancel;
+       }
 
        fstrcpy( newname_lower, newname );
-       strlower_m( newname_lower );
+       if (!strlower_m( newname_lower )) {
+               goto cancel;
+       }
 
        rename_script = talloc_string_sub2(new_acct,
                                rename_script,
@@ -916,7 +1087,7 @@ static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
        if (!rename_script) {
                goto cancel;
        }
-       rename_ret = smbrun(rename_script, NULL);
+       rename_ret = smbrun(rename_script, NULL, NULL);
 
        DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
                                rename_script, rename_ret));
@@ -935,7 +1106,7 @@ static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
 
        tdb_delete_samacct_only( old_acct );
 
-       if (db_sam->transaction_commit(db_sam) != 0) {
+       if (dbwrap_transaction_commit(db_sam) != 0) {
                /*
                 * Ok, we're screwed. We've changed the posix account, but
                 * could not adapt passdb.tdb. Shall we change the posix
@@ -950,7 +1121,7 @@ static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
        return NT_STATUS_OK;
 
  cancel:
-       if (db_sam->transaction_cancel(db_sam) != 0) {
+       if (dbwrap_transaction_cancel(db_sam) != 0) {
                smb_panic("transaction_cancel failed");
        }
 
@@ -959,14 +1130,15 @@ static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
        return NT_STATUS_ACCESS_DENIED; 
 }
 
-static bool tdbsam_rid_algorithm(struct pdb_methods *methods)
+static uint32_t tdbsam_capabilities(struct pdb_methods *methods)
 {
-       return False;
+       return PDB_CAP_STORE_RIDS;
 }
 
-static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
+static bool tdbsam_new_rid(struct pdb_methods *methods, uint32_t *prid)
 {
-       uint32 rid;
+       uint32_t rid;
+       NTSTATUS status;
 
        rid = BASE_RID;         /* Default if not set */
 
@@ -976,9 +1148,11 @@ static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
                return false;
        }
 
-       if (dbwrap_change_uint32_atomic(db_sam, NEXT_RID_STRING, &rid, 1) != 0) {
-               DEBUG(3, ("tdbsam_new_rid: Failed to increase %s\n",
-                       NEXT_RID_STRING));
+       status = dbwrap_trans_change_uint32_atomic_bystring(
+               db_sam, NEXT_RID_STRING, &rid, 1);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(3, ("tdbsam_new_rid: Failed to increase %s: %s\n",
+                       NEXT_RID_STRING, nt_errstr(status)));
                return false;
        }
 
@@ -1002,16 +1176,27 @@ static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
        struct tdbsam_search_state *state = talloc_get_type_abort(
                private_data, struct tdbsam_search_state);
        size_t prefixlen = strlen(RIDPREFIX);
-       uint32 rid;
+       uint32_t rid;
+       int error = 0;
+       TDB_DATA key;
+
+       key = dbwrap_record_get_key(rec);
 
-       if ((rec->key.dsize < prefixlen)
-           || (strncmp((char *)rec->key.dptr, RIDPREFIX, prefixlen))) {
+       if ((key.dsize < prefixlen)
+           || (strncmp((char *)key.dptr, RIDPREFIX, prefixlen))) {
                return 0;
        }
 
-       rid = strtoul((char *)rec->key.dptr+prefixlen, NULL, 16);
+       rid = smb_strtoul((char *)key.dptr+prefixlen,
+                         NULL,
+                         16,
+                         &error,
+                         SMB_STR_STANDARD);
+       if (error != 0) {
+               return 0;
+       }
 
-       ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
+       ADD_TO_LARGE_ARRAY(state, uint32_t, rid, &state->rids, &state->num_rids,
                           &state->array_size);
 
        return 0;
@@ -1042,6 +1227,7 @@ static bool tdbsam_search_next_entry(struct pdb_search *search,
        }
 
        if (state->current == state->num_rids) {
+               TALLOC_FREE(user);
                return false;
        }
 
@@ -1087,7 +1273,7 @@ static bool tdbsam_search_next_entry(struct pdb_search *search,
 
 static bool tdbsam_search_users(struct pdb_methods *methods,
                                struct pdb_search *search,
-                               uint32 acct_flags)
+                               uint32_t acct_flags)
 {
        struct tdbsam_search_state *state;
 
@@ -1105,7 +1291,7 @@ static bool tdbsam_search_users(struct pdb_methods *methods,
        state->acct_flags = acct_flags;
        state->methods = methods;
 
-       db_sam->traverse_read(db_sam, tdbsam_collect_rids, state);
+       dbwrap_traverse_read(db_sam, tdbsam_collect_rids, state, NULL);
 
        search->private_data = state;
        search->next_entry = tdbsam_search_next_entry;
@@ -1114,6 +1300,11 @@ static bool tdbsam_search_users(struct pdb_methods *methods,
        return true;
 }
 
+static bool tdbsam_is_responsible_for_builtin(struct pdb_methods *m)
+{
+       return map_builtin;
+}
+
 /*********************************************************************
  Initialize the tdb sam backend.  Setup the dispath table of methods,
  open the tdb, etc...
@@ -1139,9 +1330,13 @@ static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *loc
        (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
        (*pdb_method)->search_users = tdbsam_search_users;
 
-       (*pdb_method)->rid_algorithm = tdbsam_rid_algorithm;
+       (*pdb_method)->capabilities = tdbsam_capabilities;
        (*pdb_method)->new_rid = tdbsam_new_rid;
 
+       (*pdb_method)->is_responsible_for_builtin =
+                                       tdbsam_is_responsible_for_builtin;
+       map_builtin = lp_parm_bool(-1, "tdbsam", "map builtin", true);
+
        /* save the path for later */
 
        if (!location) {
@@ -1165,7 +1360,7 @@ static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *loc
        return NT_STATUS_OK;
 }
 
-NTSTATUS pdb_tdbsam_init(void)
+NTSTATUS pdb_tdbsam_init(TALLOC_CTX *ctx)
 {
        return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
 }