1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-26 10:04:02 +03:00

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)
This commit is contained in:
Simo Sorce 2003-06-24 14:02:21 +00:00
parent 52e4b4d5ab
commit 52826c034e
5 changed files with 413 additions and 171 deletions

View File

@ -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)

View File

@ -842,6 +842,9 @@ int main(int argc, char **argv)
/* Winbind daemon initialisation */
if (!winbindd_upgrade_idmap())
return 1;
if (!idmap_init())
return 1;

View File

@ -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);
}

201
source3/tdb/tdbback.c Normal file
View File

@ -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;
}

View File

@ -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