TODO s3:smbd: add smbXsrv_version_* infrastructure
authorStefan Metzmacher <metze@samba.org>
Tue, 8 May 2012 14:01:21 +0000 (16:01 +0200)
committerStefan Metzmacher <metze@samba.org>
Wed, 16 May 2012 06:10:15 +0000 (08:10 +0200)
metze

source3/Makefile.in
source3/librpc/idl/smbXsrv.idl
source3/smbd/globals.h
source3/smbd/server.c
source3/smbd/smbXsrv_version.c [new file with mode: 0644]
source3/wscript_build

index 407b878835be71d007971e5d0d79d9c0ab8eb053..2803636d00937628dbc91ec22dade1b5172a3c00 100644 (file)
@@ -973,6 +973,7 @@ SMBD_OBJ_SRV = smbd/server_reload.o \
               smbd/smb2_setinfo.o \
               smbd/smb2_break.o \
               librpc/gen_ndr/ndr_smbXsrv.o \
+              smbd/smbXsrv_version.o \
               $(MANGLE_OBJ) @VFS_STATIC@
 
 SMBD_OBJ_BASE = $(PARAM_WITHOUT_REG_OBJ) $(SMBD_OBJ_SRV) $(LIBSMB_OBJ) \
index 8f232d4673ac58d5c71c6cd86eba07f4429d8076..dd69a4b1587eecdb7a82f202c19b463bed46f064 100644 (file)
@@ -1,5 +1,7 @@
 #include "idl_types.h"
 
+import "server_id.idl";
+
 [
        pointer_default(unique)
 ]
index 2b324c34dcfbe8fbb8f8943e939951c28eb8323f..6755cf2b6a37233a8003fe8c737baa2bd6aa9594 100644 (file)
@@ -358,6 +358,9 @@ struct smbXsrv_connection {
        } smb2;
 };
 
+NTSTATUS smbXsrv_version_global_init(const struct server_id *server_id);
+uint32_t smbXsrv_version_global_current(void);
+
 NTSTATUS smbXsrv_connection_init_tables(struct smbXsrv_connection *conn,
                                        enum protocol_types protocol);
 
index d6c7874fb811ff54b0f6db4c0defd0d7877d2f37..a6304ff8e39f68a96242b99f13ea9a067ea6ec4d 100644 (file)
@@ -1072,6 +1072,7 @@ extern void build_options(bool screen);
        NTSTATUS status;
        struct tevent_context *ev_ctx;
        struct messaging_context *msg_ctx;
+       struct server_id server_id;
        struct tevent_signal *se;
        char *np_dir = NULL;
 
@@ -1390,6 +1391,12 @@ extern void build_options(bool screen);
                exit(1);
        }
 
+       server_id = messaging_server_id(msg_ctx);
+       status = smbXsrv_version_global_init(&server_id);
+       if (!NT_STATUS_IS_OK(status)) {
+               exit(1);
+       }
+
        if (!sessionid_init()) {
                exit(1);
        }
diff --git a/source3/smbd/smbXsrv_version.c b/source3/smbd/smbXsrv_version.c
new file mode 100644 (file)
index 0000000..68f81ab
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Stefan Metzmacher 2012
+
+   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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include <tevent.h>
+#include "smbd/smbd.h"
+#include "smbd/globals.h"
+#include "dbwrap/dbwrap.h"
+#include "dbwrap/dbwrap_open.h"
+#include "lib/util/util_tdb.h"
+#include "librpc/gen_ndr/ndr_smbXsrv.h"
+#include "serverid.h"
+
+static struct db_context *smbXsrv_version_global_db_ctx = NULL;
+static uint32_t smbXsrv_version_global_current_version = UINT32_MAX;
+
+NTSTATUS smbXsrv_version_global_init(const struct server_id *server_id)
+{
+       const char *global_path = NULL;
+       struct db_context *db_ctx = NULL;
+       struct db_record *db_rec = NULL;
+       TDB_DATA key;
+       TDB_DATA val;
+       DATA_BLOB blob;
+       struct smbXsrv_version_globalB global_blob;
+       enum ndr_err_code ndr_err;
+       struct smbXsrv_version_global0 *global = NULL;
+       uint32_t i;
+       uint32_t num_valid = 0;
+       struct smbXsrv_version_node0 *valid = NULL;
+       struct smbXsrv_version_node0 *local_node = NULL;
+       bool exists;
+       NTSTATUS status;
+       TALLOC_CTX *frame = talloc_stackframe();
+
+       DEBUG(0,("smbXsrv_version_global_init: %s\n", __location__));
+
+       if (smbXsrv_version_global_db_ctx != NULL) {
+               return NT_STATUS_OK;
+       }
+
+       DEBUG(0,("smbXsrv_version_global_init: %s\n", __location__));
+       global_path = lock_path("smbXsrv_version_global.tdb");
+
+       db_ctx = db_open(NULL, global_path,
+                        0, /* hash_size */
+                        TDB_DEFAULT |
+                        TDB_CLEAR_IF_FIRST |
+                        TDB_INCOMPATIBLE_HASH,
+                        O_RDWR | O_CREAT, 0600,
+                        DBWRAP_LOCK_ORDER_1);
+       if (db_ctx == NULL) {
+               status = map_nt_error_from_unix_common(errno);
+
+               return status;
+       }
+
+       DEBUG(0,("smbXsrv_version_global_init: %s\n", __location__));
+       key = string_term_tdb_data("smbXsrv_version_global");
+
+       db_rec = dbwrap_fetch_locked(db_ctx, db_ctx, key);
+       if (db_rec == NULL) {
+               return NT_STATUS_INTERNAL_DB_ERROR;
+       }
+
+       DEBUG(0,("smbXsrv_version_global_init: %s\n", __location__));
+       val = dbwrap_record_get_value(db_rec);
+       if (val.dsize == 0) {
+               global = talloc_zero(frame, struct smbXsrv_version_global0);
+               if (global == NULL) {
+                       TALLOC_FREE(frame);
+                       return NT_STATUS_NO_MEMORY;
+               }
+               ZERO_STRUCT(global_blob);
+               global_blob.version = SMBXSRV_VERSION_CURRENT;
+               global_blob.info.info0 = global;
+       } else {
+               blob = data_blob_const(val.dptr, val.dsize);
+
+               ndr_err = ndr_pull_struct_blob_all(&blob, frame, &global_blob,
+                       (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_version_globalB);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       TALLOC_FREE(frame);
+                       // TODO map...
+                       return status;
+               }
+
+               switch (global_blob.version) {
+               case SMBXSRV_VERSION_CURRENT:
+                       global = global_blob.info.info0;
+                       if (global == NULL) {
+                               status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+                               break;
+                       }
+                       status = NT_STATUS_OK;
+                       break;
+               default:
+                       status = NT_STATUS_REVISION_MISMATCH;
+                       DEBUG(0,("smbXsrv_version_global_init - %s\n",
+                                nt_errstr(status)));
+                       NDR_PRINT_DEBUG(smbXsrv_version_globalB, &global_blob);
+                       TALLOC_FREE(frame);
+                       return status;
+               }
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0,("smbXsrv_version_global_init - %s\n",
+                                nt_errstr(status)));
+                       NDR_PRINT_DEBUG(smbXsrv_version_globalB, &global_blob);
+                       TALLOC_FREE(frame);
+                       return status;
+               }
+       }
+
+       DEBUG(0,("smbXsrv_version_global_init: %s\n", __location__));
+       valid = talloc_zero_array(global,
+                                 struct smbXsrv_version_node0,
+                                 global->num_nodes + 1);
+       if (valid == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       DEBUG(0,("smbXsrv_version_global_init: %s\n", __location__));
+       num_valid = 0;
+       for (i=0; i < global->num_nodes; i++) {
+               struct smbXsrv_version_node0 *n = &global->nodes[i];
+
+       DEBUG(0,("smbXsrv_version_global_init: %s\n", __location__));
+               exists = serverid_exists(&n->server_id);
+               if (!exists) {
+                       continue;
+               }
+
+               if (n->min_version > n->max_version) {
+                       status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+                       DEBUG(0,("smbXsrv_version_global_init - %s\n",
+                                nt_errstr(status)));
+                       NDR_PRINT_DEBUG(smbXsrv_version_globalB, &global_blob);
+                       TALLOC_FREE(frame);
+                       return status;
+               }
+
+               if (n->min_version > global_blob.version) {
+                       status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+                       DEBUG(0,("smbXsrv_version_global_init - %s\n",
+                                nt_errstr(status)));
+                       NDR_PRINT_DEBUG(smbXsrv_version_globalB, &global_blob);
+                       TALLOC_FREE(frame);
+                       return status;
+               }
+
+               if (n->max_version < global_blob.version) {
+                       status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+                       DEBUG(0,("smbXsrv_version_global_init - %s\n",
+                                nt_errstr(status)));
+                       NDR_PRINT_DEBUG(smbXsrv_version_globalB, &global_blob);
+                       TALLOC_FREE(frame);
+                       return status;
+               }
+
+               valid[num_valid] = *n;
+               if (server_id->vnn == n->server_id.vnn) {
+                       local_node = &valid[num_valid];
+               }
+               num_valid++;
+       }
+
+       DEBUG(0,("smbXsrv_version_global_init: %s\n", __location__));
+       if (local_node == NULL) {
+               local_node = &valid[num_valid];
+               num_valid++;
+               local_node->server_id = *server_id;
+               local_node->min_version = SMBXSRV_VERSION_0;
+               local_node->max_version = SMBXSRV_VERSION_CURRENT;
+               local_node->current_version = global_blob.version;
+       }
+
+       DEBUG(0,("smbXsrv_version_global_init: %s\n", __location__));
+       global->num_nodes = num_valid;
+       global->nodes = valid;
+
+       global_blob.seqnum += 1;
+       global_blob.info.info0 = global;
+
+       ndr_err = ndr_push_struct_blob(&blob, db_rec, &global_blob,
+                       (ndr_push_flags_fn_t)ndr_push_smbXsrv_version_globalB);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+       DEBUG(0,("smbXsrv_version_global_init: %s\n", __location__));
+               //status = ndr_err_code;
+               TALLOC_FREE(frame);
+               //TODO status = map
+               return status;
+       }
+
+       DEBUG(0,("smbXsrv_version_global_init\n"));
+       NDR_PRINT_DEBUG(smbXsrv_version_globalB, &global_blob);
+
+       val = make_tdb_data(blob.data, blob.length);
+       status = dbwrap_record_store(db_rec, val, TDB_REPLACE);
+       TALLOC_FREE(db_rec);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       DEBUG(0,("smbXsrv_version_global_init\n"));
+       NDR_PRINT_DEBUG(smbXsrv_version_globalB, &global_blob);
+
+       smbXsrv_version_global_db_ctx = db_ctx;
+       smbXsrv_version_global_current_version = global_blob.version;
+
+       TALLOC_FREE(frame);
+       return NT_STATUS_OK;
+}
+
+uint32_t smbXsrv_version_global_current(void)
+{
+       return smbXsrv_version_global_current_version;
+}
index 10ccf55becd179aae184213677fdeddda3e3fe63..1093bd182d04f6c5cdb536f4b5498b898f084b51 100755 (executable)
@@ -375,6 +375,7 @@ SMBD_SRC_SRV = '''smbd/server_reload.c smbd/files.c smbd/connection.c
                smbd/smb2_getinfo.c
                smbd/smb2_setinfo.c
                smbd/smb2_break.c
+               smbd/smbXsrv_version.c
                smbd/server_exit.c
                ${MANGLE_SRC}'''