From 4b184eaea1aca5b69a7e9509353e6c4d73cce2c1 Mon Sep 17 00:00:00 2001 From: Björn Jacke Date: Fri, 27 Mar 2009 13:05:00 +0100 Subject: s3/cups: add encryption support --- source3/configure.in | 1 + source3/include/proto.h | 1 + source3/param/loadparm.c | 34 ++++++++++++++++++++++++++++++++++ source3/printing/print_cups.c | 5 +++++ 4 files changed, 41 insertions(+) diff --git a/source3/configure.in b/source3/configure.in index 1cf8d9ca4a..0850bf5a7f 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -788,6 +788,7 @@ if test x$enable_cups != xno; then x"$ac_cv_header_cups_language_h" = xyes; then AC_DEFINE(HAVE_CUPS,1,[Whether we have CUPS]) samba_cv_HAVE_CUPS=yes + AC_CHECK_LIB_EXT(cups, PRINT_LIBS, httpConnectEncrypt) else AC_MSG_WARN([cups-config around but cups-devel not installed]) CFLAGS=$ac_save_CFLAGS diff --git a/source3/include/proto.h b/source3/include/proto.h index 77be0aba09..2e76764e01 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -4125,6 +4125,7 @@ const char **lp_admin_users(int ); const char **lp_svcctl_list(void); char *lp_cups_options(int ); char *lp_cups_server(void); +int lp_cups_encrypt(void); char *lp_iprint_server(void); int lp_cups_connection_timeout(void); const char *lp_ctdbd_socket(void); diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 66fb8bf1bc..8da1f6348f 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -54,6 +54,10 @@ #include "includes.h" #include "printing.h" +#ifdef HAVE_HTTPCONNECTENCRYPT +#include +#endif + bool bLoaded = False; extern enum protocol_types Protocol; @@ -257,6 +261,7 @@ struct global { int ldap_debug_threshold; int iAclCompat; char *szCupsServer; + int CupsEncrypt; char *szIPrintServer; char *ctdbdSocket; char **szClusterAddresses; @@ -774,6 +779,8 @@ static const struct enum_list enum_case[] = { {-1, NULL} }; + + static const struct enum_list enum_bool_auto[] = { {False, "No"}, {False, "False"}, @@ -2628,6 +2635,16 @@ static struct parm_struct parm_table[] = { .flags = FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL, }, { + .label = "cups encrypt", + .type = P_ENUM, + .p_class = P_GLOBAL, + .ptr = &Globals.CupsEncrypt, + .special = NULL, + .enum_list = enum_bool_auto, + .flags = FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL, + }, + { + .label = "cups connection timeout", .type = P_INTEGER, .p_class = P_GLOBAL, @@ -5471,6 +5488,23 @@ FN_LOCAL_LIST(lp_admin_users, szAdminUsers) FN_GLOBAL_LIST(lp_svcctl_list, &Globals.szServicesList) FN_LOCAL_STRING(lp_cups_options, szCupsOptions) FN_GLOBAL_STRING(lp_cups_server, &Globals.szCupsServer) +int lp_cups_encrypt(void) +{ +#ifdef HAVE_HTTPCONNECTENCRYPT + switch (Globals.CupsEncrypt) { + case Auto: + Globals.CupsEncrypt = HTTP_ENCRYPT_REQUIRED; + break; + case True: + Globals.CupsEncrypt = HTTP_ENCRYPT_ALWAYS; + break; + case False: + Globals.CupsEncrypt = HTTP_ENCRYPT_NEVER; + break; + } +#endif + return Globals.CupsEncrypt; +} FN_GLOBAL_STRING(lp_iprint_server, &Globals.szIPrintServer) FN_GLOBAL_INTEGER(lp_cups_connection_timeout, &Globals.cups_connection_timeout) FN_GLOBAL_CONST_STRING(lp_ctdbd_socket, &Globals.ctdbdSocket) diff --git a/source3/printing/print_cups.c b/source3/printing/print_cups.c index 8e792a944a..7edfb5edbe 100644 --- a/source3/printing/print_cups.c +++ b/source3/printing/print_cups.c @@ -93,7 +93,12 @@ static http_t *cups_connect(TALLOC_CTX *frame) alarm(timeout); } +#ifdef HAVE_HTTPCONNECTENCRYPT + http = httpConnectEncrypt(server, port, lp_cups_encrypt()); +#else http = httpConnect(server, port); +#endif + CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN); alarm(0); -- cgit From 5b33918947914f6d6805e6ac43436cac58388a59 Mon Sep 17 00:00:00 2001 From: Björn Jacke Date: Fri, 27 Mar 2009 13:05:49 +0100 Subject: s3/cups: add documentation for new cups encrypt parameter --- docs-xml/smbdotconf/printing/cupsencrypt.xml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 docs-xml/smbdotconf/printing/cupsencrypt.xml diff --git a/docs-xml/smbdotconf/printing/cupsencrypt.xml b/docs-xml/smbdotconf/printing/cupsencrypt.xml new file mode 100644 index 0000000000..f93b1c5935 --- /dev/null +++ b/docs-xml/smbdotconf/printing/cupsencrypt.xml @@ -0,0 +1,25 @@ + + + + This parameter is only applicable if + is set to cups and if you use CUPS newer than + 1.0.x.It is used to define whether or not Samba should use encryption + when talking to the CUPS server. Possible values are + auto, yes and + no + + + + When set to auto we will try to do a TLS handshake on each CUPS + connection setup. If that fails, we will fall back to unencrypted + operation. + + + + +"no" + -- cgit From 9be2e2fdce9f0823f428afd492c066eb5e097f59 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 30 Mar 2009 15:05:39 -0700 Subject: Ensure files starting with multiple dots are hidden if "hide dot files" is set. Thanks to Barry Kelly for pointing this one out. Jeremy. --- source3/smbd/dosmode.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c index 555718bd83..5ae7151303 100644 --- a/source3/smbd/dosmode.c +++ b/source3/smbd/dosmode.c @@ -325,8 +325,10 @@ uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT } else { p = path; } - - if (p[0] == '.' && p[1] != '.' && p[1] != 0) { + + /* Only . and .. are not hidden. */ + if (p[0] == '.' && !((p[1] == '\0') || + (p[1] == '.' && p[2] == '\0'))) { result |= aHIDDEN; } } @@ -484,8 +486,10 @@ uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf) } else { p = path; } - - if (p[0] == '.' && p[1] != '.' && p[1] != 0) { + + /* Only . and .. are not hidden. */ + if (p[0] == '.' && !((p[1] == '\0') || + (p[1] == '.' && p[2] == '\0'))) { result |= aHIDDEN; } } -- cgit From b90863c0b7b860b006ac49c9396711ff351f777f Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Tue, 31 Mar 2009 13:15:54 +1100 Subject: Add tdb_transaction_prepare_commit() Using tdb_transaction_prepare_commit() gives us 2-phase commits. This allows us to safely commit across multiple tdb databases at once, with reasonable transaction semantics Signed-off-by: tridge@samba.org --- lib/tdb/common/transaction.c | 176 ++++++++++++++++++++++++++++++------------- lib/tdb/docs/README | 8 ++ lib/tdb/include/tdb.h | 1 + 3 files changed, 133 insertions(+), 52 deletions(-) diff --git a/lib/tdb/common/transaction.c b/lib/tdb/common/transaction.c index 7acda640c8..1cb7063a38 100644 --- a/lib/tdb/common/transaction.c +++ b/lib/tdb/common/transaction.c @@ -116,6 +116,10 @@ struct tdb_transaction { but don't create a new transaction */ int nesting; + /* set when a prepare has already occurred */ + bool prepared; + tdb_off_t magic_offset; + /* old file size before transaction */ tdb_len_t old_map_size; }; @@ -130,6 +134,14 @@ static int transaction_read(struct tdb_context *tdb, tdb_off_t off, void *buf, { uint32_t blk; + /* Only a commit is allowed on a prepared transaction */ + if (tdb->transaction->prepared) { + tdb->ecode = TDB_ERR_EINVAL; + TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_read: transaction already prepared, read not allowed\n")); + tdb->transaction->transaction_error = 1; + return -1; + } + /* break it down into block sized ops */ while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) { tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size); @@ -187,6 +199,14 @@ static int transaction_write(struct tdb_context *tdb, tdb_off_t off, { uint32_t blk; + /* Only a commit is allowed on a prepared transaction */ + if (tdb->transaction->prepared) { + tdb->ecode = TDB_ERR_EINVAL; + TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_write: transaction already prepared, write not allowed\n")); + tdb->transaction->transaction_error = 1; + return -1; + } + /* if the write is to a hash head, then update the transaction hash heads */ if (len == sizeof(tdb_off_t) && off >= FREELIST_TOP && @@ -497,12 +517,38 @@ fail: } +/* + sync to disk +*/ +static int transaction_sync(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t length) +{ + if (fsync(tdb->fd) != 0) { + tdb->ecode = TDB_ERR_IO; + TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: fsync failed\n")); + return -1; + } +#ifdef HAVE_MMAP + if (tdb->map_ptr) { + tdb_off_t moffset = offset & ~(tdb->page_size-1); + if (msync(moffset + (char *)tdb->map_ptr, + length + (offset - moffset), MS_SYNC) != 0) { + tdb->ecode = TDB_ERR_IO; + TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: msync failed - %s\n", + strerror(errno))); + return -1; + } + } +#endif + return 0; +} + + /* cancel the current transaction */ int tdb_transaction_cancel(struct tdb_context *tdb) { - int i; + int i, ret = 0; if (tdb->transaction == NULL) { TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_cancel: no transaction\n")); @@ -525,6 +571,18 @@ int tdb_transaction_cancel(struct tdb_context *tdb) } SAFE_FREE(tdb->transaction->blocks); + if (tdb->transaction->magic_offset) { + const struct tdb_methods *methods = tdb->transaction->io_methods; + uint32_t zero = 0; + + /* remove the recovery marker */ + if (methods->tdb_write(tdb, tdb->transaction->magic_offset, &zero, 4) == -1 || + transaction_sync(tdb, tdb->transaction->magic_offset, 4) == -1) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_cancel: failed to remove recovery magic\n")); + ret = -1; + } + } + /* remove any global lock created during the transaction */ if (tdb->global_lock.count != 0) { tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 4*tdb->header.hash_size); @@ -550,32 +608,7 @@ int tdb_transaction_cancel(struct tdb_context *tdb) SAFE_FREE(tdb->transaction->hash_heads); SAFE_FREE(tdb->transaction); - return 0; -} - -/* - sync to disk -*/ -static int transaction_sync(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t length) -{ - if (fsync(tdb->fd) != 0) { - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: fsync failed\n")); - return -1; - } -#ifdef HAVE_MMAP - if (tdb->map_ptr) { - tdb_off_t moffset = offset & ~(tdb->page_size-1); - if (msync(moffset + (char *)tdb->map_ptr, - length + (offset - moffset), MS_SYNC) != 0) { - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: msync failed - %s\n", - strerror(errno))); - return -1; - } - } -#endif - return 0; + return ret; } @@ -826,36 +859,39 @@ static int transaction_setup_recovery(struct tdb_context *tdb, } /* - commit the current transaction + prepare to commit the current transaction */ -int tdb_transaction_commit(struct tdb_context *tdb) +int tdb_transaction_prepare_commit(struct tdb_context *tdb) { const struct tdb_methods *methods; - tdb_off_t magic_offset = 0; - uint32_t zero = 0; int i; if (tdb->transaction == NULL) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: no transaction\n")); + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: no transaction\n")); + return -1; + } + + if (tdb->transaction->prepared) { + tdb->ecode = TDB_ERR_EINVAL; + tdb_transaction_cancel(tdb); + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: transaction already prepared\n")); return -1; } if (tdb->transaction->transaction_error) { tdb->ecode = TDB_ERR_IO; tdb_transaction_cancel(tdb); - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: transaction error pending\n")); + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: transaction error pending\n")); return -1; } if (tdb->transaction->nesting != 0) { - tdb->transaction->nesting--; return 0; } /* check for a null transaction */ if (tdb->transaction->blocks == NULL) { - tdb_transaction_cancel(tdb); return 0; } @@ -865,14 +901,14 @@ int tdb_transaction_commit(struct tdb_context *tdb) nested their locks properly, so fail the transaction */ if (tdb->num_locks || tdb->global_lock.count) { tdb->ecode = TDB_ERR_LOCK; - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: locks pending on commit\n")); + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: locks pending on commit\n")); tdb_transaction_cancel(tdb); return -1; } /* upgrade the main transaction lock region to a write lock */ if (tdb_brlock_upgrade(tdb, FREELIST_TOP, 0) == -1) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: failed to upgrade hash locks\n")); + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to upgrade hash locks\n")); tdb->ecode = TDB_ERR_LOCK; tdb_transaction_cancel(tdb); return -1; @@ -881,7 +917,7 @@ int tdb_transaction_commit(struct tdb_context *tdb) /* get the global lock - this prevents new users attaching to the database during the commit */ if (tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: failed to get global lock\n")); + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to get global lock\n")); tdb->ecode = TDB_ERR_LOCK; tdb_transaction_cancel(tdb); return -1; @@ -889,21 +925,23 @@ int tdb_transaction_commit(struct tdb_context *tdb) if (!(tdb->flags & TDB_NOSYNC)) { /* write the recovery data to the end of the file */ - if (transaction_setup_recovery(tdb, &magic_offset) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: failed to setup recovery data\n")); + if (transaction_setup_recovery(tdb, &tdb->transaction->magic_offset) == -1) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: failed to setup recovery data\n")); tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1); tdb_transaction_cancel(tdb); return -1; } } + tdb->transaction->prepared = true; + /* expand the file to the new size if needed */ if (tdb->map_size != tdb->transaction->old_map_size) { if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size, tdb->map_size - tdb->transaction->old_map_size) == -1) { tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: expansion failed\n")); + TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: expansion failed\n")); tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1); tdb_transaction_cancel(tdb); return -1; @@ -912,6 +950,51 @@ int tdb_transaction_commit(struct tdb_context *tdb) methods->tdb_oob(tdb, tdb->map_size + 1, 1); } + /* Keep the global lock until the actual commit */ + + return 0; +} + +/* + commit the current transaction +*/ +int tdb_transaction_commit(struct tdb_context *tdb) +{ + const struct tdb_methods *methods; + int i; + + if (tdb->transaction == NULL) { + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: no transaction\n")); + return -1; + } + + if (tdb->transaction->transaction_error) { + tdb->ecode = TDB_ERR_IO; + tdb_transaction_cancel(tdb); + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: transaction error pending\n")); + return -1; + } + + + if (tdb->transaction->nesting != 0) { + tdb->transaction->nesting--; + return 0; + } + + /* check for a null transaction */ + if (tdb->transaction->blocks == NULL) { + tdb_transaction_cancel(tdb); + return 0; + } + + if (!tdb->transaction->prepared) { + int ret = tdb_transaction_prepare_commit(tdb); + if (ret) + return ret; + } + + methods = tdb->transaction->io_methods; + /* perform all the writes */ for (i=0;itransaction->num_blocks;i++) { tdb_off_t offset; @@ -953,17 +1036,6 @@ int tdb_transaction_commit(struct tdb_context *tdb) if (transaction_sync(tdb, 0, tdb->map_size) == -1) { return -1; } - - /* remove the recovery marker */ - if (methods->tdb_write(tdb, magic_offset, &zero, 4) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: failed to remove recovery magic\n")); - return -1; - } - - /* ensure the recovery marker has been removed on disk */ - if (transaction_sync(tdb, magic_offset, 4) == -1) { - return -1; - } } tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1); diff --git a/lib/tdb/docs/README b/lib/tdb/docs/README index 63fcf5e049..454e4ba032 100644 --- a/lib/tdb/docs/README +++ b/lib/tdb/docs/README @@ -236,3 +236,11 @@ int tdb_transaction_commit(TDB_CONTEXT *tdb) commit a current transaction, updating the database and releasing the transaction locks. +---------------------------------------------------------------------- +int tdb_transaction_prepare_commit(TDB_CONTEXT *tdb) + + prepare to commit a current transaction, for two-phase commits. + Once prepared for commit, the only allowed calls are + tdb_transaction_commit() or tdb_transaction_cancel(). Preparing + allocates disk space for the pending updates, so a subsequent + commit should succeed (barring any hardware failures). diff --git a/lib/tdb/include/tdb.h b/lib/tdb/include/tdb.h index 94b5e366b9..22496f56f0 100644 --- a/lib/tdb/include/tdb.h +++ b/lib/tdb/include/tdb.h @@ -129,6 +129,7 @@ int tdb_fd(struct tdb_context *tdb); tdb_log_func tdb_log_fn(struct tdb_context *tdb); void *tdb_get_logging_private(struct tdb_context *tdb); int tdb_transaction_start(struct tdb_context *tdb); +int tdb_transaction_prepare_commit(struct tdb_context *tdb); int tdb_transaction_commit(struct tdb_context *tdb); int tdb_transaction_cancel(struct tdb_context *tdb); int tdb_transaction_recover(struct tdb_context *tdb); -- cgit From 84547b8dba3c0cf4e20b3c50d9386081d475df6b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 31 Mar 2009 13:59:03 +1100 Subject: added basic testing of tdb_transaction_prepare_commit() in tdbtorture --- lib/tdb/tools/tdbtorture.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/tdb/tools/tdbtorture.c b/lib/tdb/tools/tdbtorture.c index 9265cf07aa..0c9bbd613d 100644 --- a/lib/tdb/tools/tdbtorture.c +++ b/lib/tdb/tools/tdbtorture.c @@ -18,6 +18,7 @@ #define STORE_PROB 4 #define APPEND_PROB 6 #define TRANSACTION_PROB 10 +#define TRANSACTION_PREPARE_PROB 2 #define LOCKSTORE_PROB 5 #define TRAVERSE_PROB 20 #define TRAVERSE_READ_PROB 20 @@ -109,6 +110,11 @@ static void addrec_db(void) goto next; } if (in_transaction && random() % TRANSACTION_PROB == 0) { + if (random() % TRANSACTION_PREPARE_PROB == 0) { + if (tdb_transaction_prepare_commit(db) != 0) { + fatal("tdb_transaction_prepare_commit failed"); + } + } if (tdb_transaction_commit(db) != 0) { fatal("tdb_transaction_commit failed"); } -- cgit From 7a5e6940cf9578f865a559102c76f7c64b0ff47d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 31 Mar 2009 15:06:23 +1100 Subject: up the version to 1.1.4 with the addition of tdb_transaction_prepare_commit() --- lib/tdb/configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tdb/configure.ac b/lib/tdb/configure.ac index 2feaa6f5f5..c42a970721 100644 --- a/lib/tdb/configure.ac +++ b/lib/tdb/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.50) AC_DEFUN([SMB_MODULE_DEFAULT], [echo -n ""]) AC_DEFUN([SMB_LIBRARY_ENABLE], [echo -n ""]) AC_DEFUN([SMB_ENABLE], [echo -n ""]) -AC_INIT(tdb, 1.1.3) +AC_INIT(tdb, 1.1.4) AC_CONFIG_SRCDIR([common/tdb.c]) AC_CONFIG_HEADER(include/config.h) AC_LIBREPLACE_ALL_CHECKS -- cgit From 6688ee80b2d2247825efd82ee212ec926e422250 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 31 Mar 2009 15:07:54 +1100 Subject: added support for a prepare_commit() op in ldb modules This op will be used by the partition module to give us good transaction semantics across the 4 partitions that sam.ldb uses. --- source4/lib/ldb/external/libtdb.m4 | 2 +- source4/lib/ldb/include/ldb_module.h | 1 + source4/lib/ldb/ldb.mk | 2 +- source4/lib/ldb/ldb_tdb/ldb_tdb.c | 33 +++++++++++++++++++++++++++++++-- source4/lib/ldb/ldb_tdb/ldb_tdb.h | 1 + source4/min_versions.m4 | 2 +- 6 files changed, 36 insertions(+), 5 deletions(-) diff --git a/source4/lib/ldb/external/libtdb.m4 b/source4/lib/ldb/external/libtdb.m4 index 8c2cab702f..cdfc5ea2fb 100644 --- a/source4/lib/ldb/external/libtdb.m4 +++ b/source4/lib/ldb/external/libtdb.m4 @@ -4,4 +4,4 @@ AC_SUBST(TDB_LIBS) AC_CHECK_HEADER(tdb.h, [AC_CHECK_LIB(tdb, tdb_open, [TDB_LIBS="-ltdb"]) ], - [PKG_CHECK_MODULES(TDB, tdb >= 1.1.0)]) + [PKG_CHECK_MODULES(TDB, tdb >= 1.1.4)]) diff --git a/source4/lib/ldb/include/ldb_module.h b/source4/lib/ldb/include/ldb_module.h index 4e1019184d..e07fd43e27 100644 --- a/source4/lib/ldb/include/ldb_module.h +++ b/source4/lib/ldb/include/ldb_module.h @@ -52,6 +52,7 @@ struct ldb_module_ops { int (*request)(struct ldb_module *, struct ldb_request *); /* match any other operation */ int (*extended)(struct ldb_module *, struct ldb_request *); /* extended operations */ int (*start_transaction)(struct ldb_module *); + int (*prepare_commit)(struct ldb_module *); int (*end_transaction)(struct ldb_module *); int (*del_transaction)(struct ldb_module *); int (*sequence_number)(struct ldb_module *, struct ldb_request *); diff --git a/source4/lib/ldb/ldb.mk b/source4/lib/ldb/ldb.mk index ff8c1f3baf..0589baf5d4 100644 --- a/source4/lib/ldb/ldb.mk +++ b/source4/lib/ldb/ldb.mk @@ -66,7 +66,7 @@ build-python:: ldb.$(SHLIBEXT) pyldb.o: $(ldbdir)/pyldb.c $(CC) $(PICFLAG) -c $(ldbdir)/pyldb.c $(CFLAGS) `$(PYTHON_CONFIG) --cflags` - + ldb.$(SHLIBEXT): pyldb.o $(SHLD) $(SHLD_FLAGS) -o ldb.$(SHLIBEXT) pyldb.o $(LIB_FLAGS) `$(PYTHON_CONFIG) --ldflags` diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.c b/source4/lib/ldb/ldb_tdb/ldb_tdb.c index 9df62be936..0f84b67afa 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_tdb.c +++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.c @@ -857,18 +857,46 @@ static int ltdb_start_trans(struct ldb_module *module) return LDB_SUCCESS; } -static int ltdb_end_trans(struct ldb_module *module) +static int ltdb_prepare_commit(struct ldb_module *module) { void *data = ldb_module_get_private(module); struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private); - ltdb->in_transaction--; + if (ltdb->in_transaction != 1) { + return LDB_SUCCESS; + } if (ltdb_index_transaction_commit(module) != 0) { tdb_transaction_cancel(ltdb->tdb); + ltdb->in_transaction--; + return ltdb_err_map(tdb_error(ltdb->tdb)); + } + + if (tdb_transaction_prepare_commit(ltdb->tdb) != 0) { + ltdb->in_transaction--; return ltdb_err_map(tdb_error(ltdb->tdb)); } + ltdb->prepared_commit = true; + + return LDB_SUCCESS; +} + +static int ltdb_end_trans(struct ldb_module *module) +{ + void *data = ldb_module_get_private(module); + struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private); + + if (!ltdb->prepared_commit) { + int ret = ltdb_prepare_commit(module); + if (ret != LDB_SUCCESS) { + return ret; + } + } + + ltdb->in_transaction--; + ltdb->prepared_commit = false; + if (tdb_transaction_commit(ltdb->tdb) != 0) { return ltdb_err_map(tdb_error(ltdb->tdb)); } @@ -1209,6 +1237,7 @@ static const struct ldb_module_ops ltdb_ops = { .extended = ltdb_handle_request, .start_transaction = ltdb_start_trans, .end_transaction = ltdb_end_trans, + .prepare_commit = ltdb_prepare_commit, .del_transaction = ltdb_del_trans, }; diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.h b/source4/lib/ldb/ldb_tdb/ldb_tdb.h index 5a1c8fee2d..370cd0729b 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_tdb.h +++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.h @@ -30,6 +30,7 @@ struct ltdb_private { bool check_base; struct ltdb_idxptr *idxptr; + bool prepared_commit; }; /* diff --git a/source4/min_versions.m4 b/source4/min_versions.m4 index 1dd3501b99..c7892a2108 100644 --- a/source4/min_versions.m4 +++ b/source4/min_versions.m4 @@ -1,6 +1,6 @@ # Minimum and exact required versions for various libraries # if we use the ones installed in the system. -define(TDB_MIN_VERSION,1.1.3) +define(TDB_MIN_VERSION,1.1.4) define(TALLOC_MIN_VERSION,1.3.0) define(LDB_REQUIRED_VERSION,0.9.3) define(TEVENT_REQUIRED_VERSION,0.9.5) -- cgit From 16a1903c546ac8e5ebc2a1952ce37f8ad819379b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 31 Mar 2009 15:08:36 +1100 Subject: use the prepare_commit op in the partition code This makes multi-partition ldb's much safer --- source4/dsdb/samdb/ldb_modules/partition.c | 63 +++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/source4/dsdb/samdb/ldb_modules/partition.c b/source4/dsdb/samdb/ldb_modules/partition.c index 71a1b8e942..3231f7ab0f 100644 --- a/source4/dsdb/samdb/ldb_modules/partition.c +++ b/source4/dsdb/samdb/ldb_modules/partition.c @@ -73,11 +73,14 @@ static struct partition_context *partition_init_ctx(struct ldb_module *module, s return ac; } -#define PARTITION_FIND_OP(module, op) do { \ - struct ldb_context *ldbctx = module->ldb; \ +#define PARTITION_FIND_OP_NOERROR(module, op) do { \ while (module && module->ops->op == NULL) module = module->next; \ +} while (0) + +#define PARTITION_FIND_OP(module, op) do { \ + PARTITION_FIND_OP_NOERROR(module, op); \ if (module == NULL) { \ - ldb_asprintf_errstring(ldbctx, \ + ldb_asprintf_errstring(module->ldb, \ "Unable to find backend operation for " #op ); \ return LDB_ERR_OPERATIONS_ERROR; \ } \ @@ -654,7 +657,7 @@ static int partition_start_trans(struct ldb_module *module) /* end a transaction */ static int partition_end_trans(struct ldb_module *module) { - int i, ret; + int i, ret, final_ret; struct partition_private_data *data = talloc_get_type(module->private_data, struct partition_private_data); ret = ldb_next_end_trans(module); @@ -662,28 +665,60 @@ static int partition_end_trans(struct ldb_module *module) return ret; } + /* if the backend has a prepare_commit op then use that, to ensure + that all partitions are committed safely together */ + for (i=0; data && data->partitions && data->partitions[i]; i++) { + struct ldb_module *next_end = data->partitions[i]->module; + struct ldb_module *next_prepare = data->partitions[i]->module; + struct ldb_module *next_del = data->partitions[i]->module; + + PARTITION_FIND_OP_NOERROR(next_prepare, prepare_commit); + if (next_prepare == NULL) { + continue; + } + + PARTITION_FIND_OP(next_end, end_transaction); + PARTITION_FIND_OP(next_del, del_transaction); + + if (next_end != next_prepare || next_del != next_end) { + ldb_asprintf_errstring(module->ldb, "ERROR: Mismatch between prepare and commit ops in ldb module"); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = next_prepare->ops->prepare_commit(next_prepare); + if (ret != LDB_SUCCESS) { + /* if one fails, cancel all but this one */ + int j; + for (j=0; data->partitions[j]; j++) { + if (j == i) continue; + next_del = data->partitions[j]->module; + PARTITION_FIND_OP(next_del, del_transaction); + next_del->ops->del_transaction(next_del); + } + ldb_next_del_trans(module); + return ret; + } + } + /* Look at base DN */ /* Figure out which partition it is under */ /* Skip the lot if 'data' isn't here yet (initialistion) */ + final_ret = LDB_SUCCESS; + for (i=0; data && data->partitions && data->partitions[i]; i++) { struct ldb_module *next = data->partitions[i]->module; PARTITION_FIND_OP(next, end_transaction); ret = next->ops->end_transaction(next); if (ret != LDB_SUCCESS) { - /* Back it out, if it fails on one */ - for (i--; i >= 0; i--) { - next = data->partitions[i]->module; - PARTITION_FIND_OP(next, del_transaction); - - next->ops->del_transaction(next); - } - ldb_next_del_trans(module); - return ret; + /* this should only be happening if we had a serious + OS or hardware error */ + ldb_asprintf_errstring(module->ldb, "ERROR: partition commit error"); + final_ret = ret; } } - return LDB_SUCCESS; + return final_ret; } /* delete a transaction */ -- cgit From 79b7ba9b106791958cc42d68b11d9dea2a77f6f3 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 31 Mar 2009 15:14:09 +1100 Subject: change ldb version number (as ldb_module structure has changed) --- source4/lib/ldb/configure.ac | 2 +- source4/min_versions.m4 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source4/lib/ldb/configure.ac b/source4/lib/ldb/configure.ac index d61b31afd4..b98cc88537 100644 --- a/source4/lib/ldb/configure.ac +++ b/source4/lib/ldb/configure.ac @@ -11,7 +11,7 @@ AC_DEFUN([SMB_MODULE_DEFAULT], [echo -n ""]) AC_DEFUN([SMB_LIBRARY_ENABLE], [echo -n ""]) AC_DEFUN([SMB_EXT_LIB], [echo -n ""]) AC_DEFUN([SMB_ENABLE], [echo -n ""]) -AC_INIT(ldb, 0.9.3) +AC_INIT(ldb, 0.9.4) AC_CONFIG_SRCDIR([common/ldb.c]) AC_LIBREPLACE_ALL_CHECKS diff --git a/source4/min_versions.m4 b/source4/min_versions.m4 index c7892a2108..0469fb827a 100644 --- a/source4/min_versions.m4 +++ b/source4/min_versions.m4 @@ -2,5 +2,5 @@ # if we use the ones installed in the system. define(TDB_MIN_VERSION,1.1.4) define(TALLOC_MIN_VERSION,1.3.0) -define(LDB_REQUIRED_VERSION,0.9.3) +define(LDB_REQUIRED_VERSION,0.9.4) define(TEVENT_REQUIRED_VERSION,0.9.5) -- cgit