summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimo Sorce <idra@samba.org>2003-06-24 14:02:21 +0000
committerSimo Sorce <idra@samba.org>2003-06-24 14:02:21 +0000
commit52826c034e8973c86c8e08d460377e33749005c6 (patch)
treec41ebf27a1e16cd8c2895360962140ce4f1fa131
parent52e4b4d5abf8136959b21d7cc0ad11c480a7f471 (diff)
downloadsamba-52826c034e8973c86c8e08d460377e33749005c6.tar.gz
samba-52826c034e8973c86c8e08d460377e33749005c6.tar.bz2
samba-52826c034e8973c86c8e08d460377e33749005c6.zip
add tdb backup function separation and winbind idmap upgrade code form
pre-2.2.4 tdb database format. tx volker for your work on this (This used to be commit 2bdbeb9e97a59ecd16f74fbb04ab5ca57b28a757)
-rw-r--r--source3/Makefile.in4
-rw-r--r--source3/nsswitch/winbindd.c3
-rw-r--r--source3/nsswitch/winbindd_util.c206
-rw-r--r--source3/tdb/tdbback.c201
-rw-r--r--source3/tdb/tdbbackup.c170
5 files changed, 413 insertions, 171 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in
index d82d731549..7cf07c15b4 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -159,7 +159,7 @@ MODULES = $(VFS_MODULES) $(PDB_MODULES) $(RPC_MODULES) $(IDMAP_MODULES) $(CHARSE
######################################################################
TDBBASE_OBJ = tdb/tdb.o tdb/spinlock.o
-TDB_OBJ = $(TDBBASE_OBJ) tdb/tdbutil.o
+TDB_OBJ = $(TDBBASE_OBJ) tdb/tdbutil.o tdb/tdbback.o
SMBLDAP_OBJ = @SMBLDAP@
@@ -613,7 +613,7 @@ WINBIND_NSS_PICOBJS = $(WINBIND_NSS_OBJ:.o=.po)
POPT_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
popt/popthelp.o popt/poptparse.o
-TDBBACKUP_OBJ = tdb/tdbbackup.o $(TDBBASE_OBJ)
+TDBBACKUP_OBJ = tdb/tdbbackup.o tdb/tdbback.o $(TDBBASE_OBJ)
NTLM_AUTH_OBJ = utils/ntlm_auth.o $(LIBSAMBA_OBJ) $(POPT_LIB_OBJ)
diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c
index d777fe37dd..85403eedeb 100644
--- a/source3/nsswitch/winbindd.c
+++ b/source3/nsswitch/winbindd.c
@@ -842,6 +842,9 @@ int main(int argc, char **argv)
/* Winbind daemon initialisation */
+ if (!winbindd_upgrade_idmap())
+ return 1;
+
if (!idmap_init())
return 1;
diff --git a/source3/nsswitch/winbindd_util.c b/source3/nsswitch/winbindd_util.c
index c92241b256..5ba0d767d5 100644
--- a/source3/nsswitch/winbindd_util.c
+++ b/source3/nsswitch/winbindd_util.c
@@ -574,3 +574,209 @@ DOM_SID *rid_to_talloced_sid(struct winbindd_domain *domain,
return sid;
}
+/*****************************************************************************
+ For idmap conversion: convert one record to new format
+ Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid
+ instead of the SID.
+*****************************************************************************/
+static int convert_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA data, void *state)
+{
+ struct winbindd_domain *domain;
+ char *p;
+ DOM_SID sid;
+ uint32 rid;
+ fstring keystr;
+ fstring dom_name;
+ TDB_DATA key2;
+ BOOL *failed = (BOOL *)state;
+
+ DEBUG(10,("Converting %s\n", key.dptr));
+
+ p = strchr(key.dptr, '/');
+ if (!p)
+ return 0;
+
+ *p = 0;
+ fstrcpy(dom_name, key.dptr);
+ *p++ = '/';
+
+ domain = find_domain_from_name(dom_name);
+ if (domain == NULL) {
+ /* We must delete the old record. */
+ DEBUG(0,("Unable to find domain %s\n", dom_name ));
+ DEBUG(0,("deleting record %s\n", key.dptr ));
+
+ if (tdb_delete(tdb, key) != 0) {
+ DEBUG(0, ("Unable to delete record %s\n", key.dptr));
+ *failed = True;
+ return -1;
+ }
+
+ return 0;
+ }
+
+ rid = atoi(p);
+
+ sid_copy(&sid, &domain->sid);
+ sid_append_rid(&sid, rid);
+
+ sid_to_string(keystr, &sid);
+ key2.dptr = keystr;
+ key2.dsize = strlen(keystr) + 1;
+
+ if (tdb_store(tdb, key2, data, TDB_INSERT) != 0) {
+ DEBUG(0,("Unable to add record %s\n", key2.dptr ));
+ *failed = True;
+ return -1;
+ }
+
+ if (tdb_store(tdb, data, key2, TDB_REPLACE) != 0) {
+ DEBUG(0,("Unable to update record %s\n", data.dptr ));
+ *failed = True;
+ return -1;
+ }
+
+ if (tdb_delete(tdb, key) != 0) {
+ DEBUG(0,("Unable to delete record %s\n", key.dptr ));
+ *failed = True;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* These definitions are from sam/idmap_tdb.c. Replicated here just
+ out of laziness.... :-( */
+
+/* High water mark keys */
+#define HWM_GROUP "GROUP HWM"
+#define HWM_USER "USER HWM"
+
+/* idmap version determines auto-conversion */
+#define IDMAP_VERSION 2
+
+
+/*****************************************************************************
+ Convert the idmap database from an older version.
+*****************************************************************************/
+
+static BOOL idmap_convert(const char *idmap_name)
+{
+ int32 vers;
+ BOOL bigendianheader;
+ BOOL failed = False;
+ TDB_CONTEXT *idmap_tdb;
+
+ if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
+ TDB_DEFAULT, O_RDWR,
+ 0600))) {
+ DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
+ return False;
+ }
+
+ bigendianheader = (idmap_tdb->flags & TDB_BIGENDIAN) ? True : False;
+
+ vers = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION");
+
+ if (((vers == -1) && bigendianheader) || (IREV(vers) == IDMAP_VERSION)) {
+ /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
+ /*
+ * high and low records were created on a
+ * big endian machine and will need byte-reversing.
+ */
+
+ int32 wm;
+
+ wm = tdb_fetch_int32(idmap_tdb, HWM_USER);
+
+ if (wm != -1) {
+ wm = IREV(wm);
+ } else {
+ wm = server_state.uid_low;
+ }
+
+ if (tdb_store_int32(idmap_tdb, HWM_USER, wm) == -1) {
+ DEBUG(0, ("idmap_convert: Unable to byteswap user hwm in idmap database\n"));
+ tdb_close(idmap_tdb);
+ return False;
+ }
+
+ wm = tdb_fetch_int32(idmap_tdb, HWM_GROUP);
+ if (wm != -1) {
+ wm = IREV(wm);
+ } else {
+ wm = server_state.gid_low;
+ }
+
+ if (tdb_store_int32(idmap_tdb, HWM_GROUP, wm) == -1) {
+ DEBUG(0, ("idmap_convert: Unable to byteswap group hwm in idmap database\n"));
+ tdb_close(idmap_tdb);
+ return False;
+ }
+ }
+
+ /* the old format stored as DOMAIN/rid - now we store the SID direct */
+ tdb_traverse(idmap_tdb, convert_fn, &failed);
+
+ if (failed) {
+ DEBUG(0, ("Problem during conversion\n"));
+ tdb_close(idmap_tdb);
+ return False;
+ }
+
+ if (tdb_store_int32(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION) == -1) {
+ DEBUG(0, ("idmap_convert: Unable to dtore idmap version in databse\n"));
+ tdb_close(idmap_tdb);
+ return False;
+ }
+
+ tdb_close(idmap_tdb);
+ return True;
+}
+
+/*****************************************************************************
+ Convert the idmap database from an older version if necessary
+*****************************************************************************/
+
+BOOL winbindd_upgrade_idmap(void)
+{
+ pstring idmap_name;
+ pstring backup_name;
+ SMB_STRUCT_STAT stbuf;
+ TDB_CONTEXT *idmap_tdb;
+
+ pstrcpy(idmap_name, lock_path("winbindd_idmap.tdb"));
+
+ if (!file_exist(idmap_name, &stbuf)) {
+ /* nothing to convert return */
+ return True;
+ }
+
+ if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
+ TDB_DEFAULT, O_RDWR,
+ 0600))) {
+ DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
+ return False;
+ }
+
+ if (tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION") == IDMAP_VERSION) {
+ /* nothing to convert return */
+ tdb_close(idmap_tdb);
+ return True;
+ }
+
+ /* backup_tdb expects the tdb not to be open */
+ tdb_close(idmap_tdb);
+
+ DEBUG(0, ("Upgrading winbindd_idmap.tdb from an old version\n"));
+
+ pstrcpy(backup_name, idmap_name);
+ pstrcat(backup_name, ".bak");
+
+ if (backup_tdb(idmap_name, backup_name) != 0) {
+ DEBUG(0, ("Could not backup idmap database\n"));
+ return False;
+ }
+
+ return idmap_convert(idmap_name);
+}
diff --git a/source3/tdb/tdbback.c b/source3/tdb/tdbback.c
new file mode 100644
index 0000000000..744cface55
--- /dev/null
+++ b/source3/tdb/tdbback.c
@@ -0,0 +1,201 @@
+/*
+ Unix SMB/CIFS implementation.
+ low level tdb backup and restore utility
+ Copyright (C) Andrew Tridgell 2002
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <signal.h>
+#include "tdb.h"
+
+static int failed;
+
+char *add_suffix(const char *name, const char *suffix)
+{
+ char *ret;
+ int len = strlen(name) + strlen(suffix) + 1;
+ ret = malloc(len);
+ if (!ret) {
+ fprintf(stderr,"Out of memory!\n");
+ exit(1);
+ }
+ strncpy(ret, name, len);
+ strncat(ret, suffix, len);
+ return ret;
+}
+
+static int copy_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ TDB_CONTEXT *tdb_new = (TDB_CONTEXT *)state;
+
+ if (tdb_store(tdb_new, key, dbuf, TDB_INSERT) != 0) {
+ fprintf(stderr,"Failed to insert into %s\n", tdb_new->name);
+ failed = 1;
+ return 1;
+ }
+ return 0;
+}
+
+
+static int test_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ return 0;
+}
+
+/*
+ carefully backup a tdb, validating the contents and
+ only doing the backup if its OK
+ this function is also used for restore
+*/
+int backup_tdb(const char *old_name, const char *new_name)
+{
+ TDB_CONTEXT *tdb;
+ TDB_CONTEXT *tdb_new;
+ char *tmp_name;
+ struct stat st;
+ int count1, count2;
+
+ tmp_name = add_suffix(new_name, ".tmp");
+
+ /* stat the old tdb to find its permissions */
+ if (stat(old_name, &st) != 0) {
+ perror(old_name);
+ return 1;
+ }
+
+ /* open the old tdb */
+ tdb = tdb_open(old_name, 0, 0, O_RDWR, 0);
+ if (!tdb) {
+ printf("Failed to open %s\n", old_name);
+ return 1;
+ }
+
+ /* create the new tdb */
+ unlink(tmp_name);
+ tdb_new = tdb_open(tmp_name, tdb->header.hash_size,
+ TDB_DEFAULT, O_RDWR|O_CREAT|O_EXCL,
+ st.st_mode & 0777);
+ if (!tdb_new) {
+ perror(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* lock the old tdb */
+ if (tdb_lockall(tdb) != 0) {
+ fprintf(stderr,"Failed to lock %s\n", old_name);
+ tdb_close(tdb);
+ tdb_close(tdb_new);
+ unlink(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ failed = 0;
+
+ /* traverse and copy */
+ count1 = tdb_traverse(tdb, copy_fn, (void *)tdb_new);
+ if (count1 < 0 || failed) {
+ fprintf(stderr,"failed to copy %s\n", old_name);
+ tdb_close(tdb);
+ tdb_close(tdb_new);
+ unlink(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* close the old tdb */
+ tdb_close(tdb);
+
+ /* close the new tdb and re-open read-only */
+ tdb_close(tdb_new);
+ tdb_new = tdb_open(tmp_name, 0, TDB_DEFAULT, O_RDONLY, 0);
+ if (!tdb_new) {
+ fprintf(stderr,"failed to reopen %s\n", tmp_name);
+ unlink(tmp_name);
+ perror(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* traverse the new tdb to confirm */
+ count2 = tdb_traverse(tdb_new, test_fn, 0);
+ if (count2 != count1) {
+ fprintf(stderr,"failed to copy %s\n", old_name);
+ tdb_close(tdb_new);
+ unlink(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* make sure the new tdb has reached stable storage */
+ fsync(tdb_new->fd);
+
+ /* close the new tdb and rename it to .bak */
+ tdb_close(tdb_new);
+ unlink(new_name);
+ if (rename(tmp_name, new_name) != 0) {
+ perror(new_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ free(tmp_name);
+
+ return 0;
+}
+
+
+
+/*
+ verify a tdb and if it is corrupt then restore from *.bak
+*/
+int verify_tdb(const char *fname, const char *bak_name)
+{
+ TDB_CONTEXT *tdb;
+ int count = -1;
+
+ /* open the tdb */
+ tdb = tdb_open(fname, 0, 0, O_RDONLY, 0);
+
+ /* traverse the tdb, then close it */
+ if (tdb) {
+ count = tdb_traverse(tdb, test_fn, NULL);
+ tdb_close(tdb);
+ }
+
+ /* count is < 0 means an error */
+ if (count < 0) {
+ printf("restoring %s\n", fname);
+ return backup_tdb(bak_name, fname);
+ }
+
+ printf("%s : %d records\n", fname, count);
+
+ return 0;
+}
diff --git a/source3/tdb/tdbbackup.c b/source3/tdb/tdbbackup.c
index 4c82ebbaa7..0eaf6b6c0b 100644
--- a/source3/tdb/tdbbackup.c
+++ b/source3/tdb/tdbbackup.c
@@ -55,175 +55,7 @@
#include <ctype.h>
#include <signal.h>
#include "tdb.h"
-
-static int failed;
-
-static char *add_suffix(const char *name, const char *suffix)
-{
- char *ret;
- int len = strlen(name) + strlen(suffix) + 1;
- ret = malloc(len);
- if (!ret) {
- fprintf(stderr,"Out of memory!\n");
- exit(1);
- }
- strncpy(ret, name, len);
- strncat(ret, suffix, len);
- return ret;
-}
-
-static int copy_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
-{
- TDB_CONTEXT *tdb_new = (TDB_CONTEXT *)state;
-
- if (tdb_store(tdb_new, key, dbuf, TDB_INSERT) != 0) {
- fprintf(stderr,"Failed to insert into %s\n", tdb_new->name);
- failed = 1;
- return 1;
- }
- return 0;
-}
-
-
-static int test_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
-{
- return 0;
-}
-
-/*
- carefully backup a tdb, validating the contents and
- only doing the backup if its OK
- this function is also used for restore
-*/
-static int backup_tdb(const char *old_name, const char *new_name)
-{
- TDB_CONTEXT *tdb;
- TDB_CONTEXT *tdb_new;
- char *tmp_name;
- struct stat st;
- int count1, count2;
-
- tmp_name = add_suffix(new_name, ".tmp");
-
- /* stat the old tdb to find its permissions */
- if (stat(old_name, &st) != 0) {
- perror(old_name);
- return 1;
- }
-
- /* open the old tdb */
- tdb = tdb_open(old_name, 0, 0, O_RDWR, 0);
- if (!tdb) {
- printf("Failed to open %s\n", old_name);
- return 1;
- }
-
- /* create the new tdb */
- unlink(tmp_name);
- tdb_new = tdb_open(tmp_name, tdb->header.hash_size,
- TDB_DEFAULT, O_RDWR|O_CREAT|O_EXCL,
- st.st_mode & 0777);
- if (!tdb_new) {
- perror(tmp_name);
- free(tmp_name);
- return 1;
- }
-
- /* lock the old tdb */
- if (tdb_lockall(tdb) != 0) {
- fprintf(stderr,"Failed to lock %s\n", old_name);
- tdb_close(tdb);
- tdb_close(tdb_new);
- unlink(tmp_name);
- free(tmp_name);
- return 1;
- }
-
- failed = 0;
-
- /* traverse and copy */
- count1 = tdb_traverse(tdb, copy_fn, (void *)tdb_new);
- if (count1 < 0 || failed) {
- fprintf(stderr,"failed to copy %s\n", old_name);
- tdb_close(tdb);
- tdb_close(tdb_new);
- unlink(tmp_name);
- free(tmp_name);
- return 1;
- }
-
- /* close the old tdb */
- tdb_close(tdb);
-
- /* close the new tdb and re-open read-only */
- tdb_close(tdb_new);
- tdb_new = tdb_open(tmp_name, 0, TDB_DEFAULT, O_RDONLY, 0);
- if (!tdb_new) {
- fprintf(stderr,"failed to reopen %s\n", tmp_name);
- unlink(tmp_name);
- perror(tmp_name);
- free(tmp_name);
- return 1;
- }
-
- /* traverse the new tdb to confirm */
- count2 = tdb_traverse(tdb_new, test_fn, 0);
- if (count2 != count1) {
- fprintf(stderr,"failed to copy %s\n", old_name);
- tdb_close(tdb_new);
- unlink(tmp_name);
- free(tmp_name);
- return 1;
- }
-
- /* make sure the new tdb has reached stable storage */
- fsync(tdb_new->fd);
-
- /* close the new tdb and rename it to .bak */
- tdb_close(tdb_new);
- unlink(new_name);
- if (rename(tmp_name, new_name) != 0) {
- perror(new_name);
- free(tmp_name);
- return 1;
- }
-
- printf("%s : %d records\n", old_name, count1);
- free(tmp_name);
-
- return 0;
-}
-
-
-
-/*
- verify a tdb and if it is corrupt then restore from *.bak
-*/
-static int verify_tdb(const char *fname, const char *bak_name)
-{
- TDB_CONTEXT *tdb;
- int count = -1;
-
- /* open the tdb */
- tdb = tdb_open(fname, 0, 0, O_RDONLY, 0);
-
- /* traverse the tdb, then close it */
- if (tdb) {
- count = tdb_traverse(tdb, test_fn, NULL);
- tdb_close(tdb);
- }
-
- /* count is < 0 means an error */
- if (count < 0) {
- printf("restoring %s\n", fname);
- return backup_tdb(bak_name, fname);
- }
-
- printf("%s : %d records\n", fname, count);
-
- return 0;
-}
-
+#include "tdbback.h"
/*
see if one file is newer than another