The branch, master has been updated via a71ad96 ldb: Add ldbdump, based on tdbdump via 4b2f3c6 ldb: Remove no-longer-existing ltdb_unpack_data_free from ldb_tdb.h via cc6d0de ldb: Change ltdb_unpack_data to take an ldb_context via 42c379f samba-tool: Add samba-tool processes subcommand via a732f2a pymessaging: Add irpc_servers_byname() and irpc_all_servers() via 76b7348 pymessaging: Use the server_id IDL structure rather than a tuple via 3b4ef03 imessaging: Add irpc_all_servers() to list all available servers from 39e58d6 s3fs-utils: Free the popt context in smbcacls and smbquotas.
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit a71ad96bd046f1199e67b4fe8fc7783cbd8dd771 Author: Andrew Bartlett <abart...@samba.org> Date: Tue Oct 30 15:41:27 2012 +1100 ldb: Add ldbdump, based on tdbdump This uses a tdb_traverse or (more usefully) the tdb_rescue API, like tdbdump. The difference here is that it uses ldb helper functions to further eliminate faulty records, which avoids creating duplicates in the output. (The duplicates come from parts of records that are left in blank space in the db, which tdb_rescue finds, but which are not actually a full record). Andrew Bartlett Autobuild-User(master): Andrew Bartlett <abart...@samba.org> Autobuild-Date(master): Tue Oct 30 23:56:11 CET 2012 on sn-devel-104 commit 4b2f3c6dec997b0dd4bcafeae662a71ebd34e12b Author: Andrew Bartlett <abart...@samba.org> Date: Tue Oct 30 10:22:28 2012 +1100 ldb: Remove no-longer-existing ltdb_unpack_data_free from ldb_tdb.h commit cc6d0decc7980028293168aee267e7610752fc80 Author: Andrew Bartlett <abart...@samba.org> Date: Tue Oct 30 10:21:42 2012 +1100 ldb: Change ltdb_unpack_data to take an ldb_context It always de-references the module to find the ldb anyway. Andrew Bartlett commit 42c379f0dfdeb36598bb2636aa2b6e3ca4410930 Author: Andrew Bartlett <abart...@samba.org> Date: Mon Oct 29 15:36:36 2012 +1100 samba-tool: Add samba-tool processes subcommand This will allow administrators to inspect the process list in a similar way to what running on a platform with setproctitle might permit. --pid= returns the registered server names for a PID (eg kdc, cldap_server) --name= returns the pids registered with a particular name. Andrew Bartlett commit a732f2a621665923322422c5a3d788c9d1aa8df9 Author: Andrew Bartlett <abart...@samba.org> Date: Mon Oct 29 15:34:41 2012 +1100 pymessaging: Add irpc_servers_byname() and irpc_all_servers() This will allow python scripts to inspect the process list. Andrew Bartlett commit 76b7348299870279acec5b7c9f02f4e4b2461703 Author: Andrew Bartlett <abart...@samba.org> Date: Mon Oct 29 15:33:59 2012 +1100 pymessaging: Use the server_id IDL structure rather than a tuple This will make it easier to pass this structure in and out. The tuple is still accepted as input. Andrew Bartlett commit 3b4ef03097293f758d8f11cbe434063ed1dc6b91 Author: Andrew Bartlett <abart...@samba.org> Date: Mon Oct 29 15:32:21 2012 +1100 imessaging: Add irpc_all_servers() to list all available servers This is implemented with a tdb_traverse_read(), and will allow a tool to disover the name and server_id of all Samba processes, as each process registers itself to recieve messages. Andrew Bartlett ----------------------------------------------------------------------- Summary of changes: lib/ldb/ldb_tdb/ldb_index.c | 2 +- lib/ldb/ldb_tdb/ldb_pack.c | 4 +- lib/ldb/ldb_tdb/ldb_search.c | 6 +- lib/ldb/ldb_tdb/ldb_tdb.c | 2 +- lib/ldb/ldb_tdb/ldb_tdb.h | 4 +- lib/ldb/tools/ldbdump.c | 219 ++++++++++++++++++++ lib/ldb/wscript | 4 + librpc/wscript_build | 5 + source4/lib/messaging/irpc.h | 2 + source4/lib/messaging/messaging.c | 71 +++++++ source4/lib/messaging/pymessaging.c | 124 +++++++++++- source4/librpc/idl/irpc.idl | 13 +- source4/librpc/wscript_build | 6 + source4/scripting/python/samba/netcmd/main.py | 2 + source4/scripting/python/samba/netcmd/processes.py | 78 +++++++ source4/scripting/python/samba/tests/messaging.py | 13 +- .../python/samba/tests/samba_tool/processes.py | 35 +++ source4/selftest/tests.py | 1 + 18 files changed, 572 insertions(+), 19 deletions(-) create mode 100644 lib/ldb/tools/ldbdump.c create mode 100644 source4/scripting/python/samba/netcmd/processes.py create mode 100644 source4/scripting/python/samba/tests/samba_tool/processes.py Changeset truncated at 500 lines: diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c index d2ef4b8..50c6ded 100644 --- a/lib/ldb/ldb_tdb/ldb_index.c +++ b/lib/ldb/ldb_tdb/ldb_index.c @@ -1509,7 +1509,7 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void * return -1; } - ret = ltdb_unpack_data(module, &data, msg); + ret = ltdb_unpack_data(ldb, &data, msg); if (ret != 0) { ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid data for index %s\n", ldb_dn_get_linearized(msg->dn)); diff --git a/lib/ldb/ldb_tdb/ldb_pack.c b/lib/ldb/ldb_tdb/ldb_pack.c index 7c13065..003be15 100644 --- a/lib/ldb/ldb_tdb/ldb_pack.c +++ b/lib/ldb/ldb_tdb/ldb_pack.c @@ -154,18 +154,16 @@ int ltdb_pack_data(struct ldb_module *module, Free with ltdb_unpack_data_free() */ -int ltdb_unpack_data(struct ldb_module *module, +int ltdb_unpack_data(struct ldb_context *ldb, const TDB_DATA *data, struct ldb_message *message) { - struct ldb_context *ldb; uint8_t *p; unsigned int remaining; unsigned int i, j; unsigned format; size_t len; - ldb = ldb_module_get_ctx(module); message->elements = NULL; p = data->dptr; diff --git a/lib/ldb/ldb_tdb/ldb_search.c b/lib/ldb/ldb_tdb/ldb_search.c index 703ad6a..4fb8510 100644 --- a/lib/ldb/ldb_tdb/ldb_search.c +++ b/lib/ldb/ldb_tdb/ldb_search.c @@ -244,9 +244,9 @@ static int ltdb_parse_data_unpack(TDB_DATA key, TDB_DATA data, { struct ltdb_parse_data_unpack_ctx *ctx = private_data; - int ret = ltdb_unpack_data(ctx->module, &data, ctx->msg); + struct ldb_context *ldb = ldb_module_get_ctx(ctx->module); + int ret = ltdb_unpack_data(ldb, &data, ctx->msg); if (ret == -1) { - struct ldb_context *ldb = ldb_module_get_ctx(ctx->module); ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid data for index %*.*s\n", (int)key.dsize, (int)key.dsize, key.dptr); return LDB_ERR_OPERATIONS_ERROR; @@ -440,7 +440,7 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi } /* unpack the record */ - ret = ltdb_unpack_data(ac->module, &data, msg); + ret = ltdb_unpack_data(ldb, &data, msg); if (ret == -1) { talloc_free(msg); return -1; diff --git a/lib/ldb/ldb_tdb/ldb_tdb.c b/lib/ldb/ldb_tdb/ldb_tdb.c index 3c18150..0e7c74c 100644 --- a/lib/ldb/ldb_tdb/ldb_tdb.c +++ b/lib/ldb/ldb_tdb/ldb_tdb.c @@ -693,7 +693,7 @@ int ltdb_modify_internal(struct ldb_module *module, goto done; } - ret = ltdb_unpack_data(module, &tdb_data, msg2); + ret = ltdb_unpack_data(ldb_module_get_ctx(module), &tdb_data, msg2); free(tdb_data.dptr); if (ret == -1) { ret = LDB_ERR_OTHER; diff --git a/lib/ldb/ldb_tdb/ldb_tdb.h b/lib/ldb/ldb_tdb/ldb_tdb.h index c89dd7f..dd71626 100644 --- a/lib/ldb/ldb_tdb/ldb_tdb.h +++ b/lib/ldb/ldb_tdb/ldb_tdb.h @@ -97,9 +97,7 @@ int ltdb_index_transaction_cancel(struct ldb_module *module); int ltdb_pack_data(struct ldb_module *module, const struct ldb_message *message, TDB_DATA *data); -void ltdb_unpack_data_free(struct ldb_module *module, - struct ldb_message *message); -int ltdb_unpack_data(struct ldb_module *module, +int ltdb_unpack_data(struct ldb_context *ldb, const TDB_DATA *data, struct ldb_message *message); diff --git a/lib/ldb/tools/ldbdump.c b/lib/ldb/tools/ldbdump.c new file mode 100644 index 0000000..7a2ba3d --- /dev/null +++ b/lib/ldb/tools/ldbdump.c @@ -0,0 +1,219 @@ +/* + Unix SMB/CIFS implementation. + simple ldb tdb dump util + Copyright (C) Andrew Tridgell 2001 + Copyright (C) Andrew Bartlett 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 "replace.h" +#include "system/locale.h" +#include "system/time.h" +#include "system/filesys.h" +#include "system/wait.h" +#include <tdb.h> +#include <ldb.h> +#include "../ldb_tdb/ldb_tdb.h" + +static struct ldb_context *ldb; +bool show_index = false; +bool validate_contents = false; + +static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state) +{ + int ret, i, j; + struct ldb_dn *dn = state; + struct ldb_message *msg = talloc_zero(NULL, struct ldb_message); + struct ldb_ldif ldif = { + .msg = msg, + .changetype = LDB_CHANGETYPE_NONE + }; + if (!msg) { + return -1; + } + ret = ltdb_unpack_data(ldb, &dbuf, msg); + if (ret != 0) { + fprintf(stderr, "Failed to parse record %*.*s as an LDB record\n", (int)key.dsize, (int)key.dsize, (char *)key.dptr); + TALLOC_FREE(msg); + return 0; + } + + if (dn && ldb_dn_compare(msg->dn, dn) != 0) { + TALLOC_FREE(msg); + return 0; + } + + if (!show_index && ldb_dn_is_special(msg->dn)) { + const char *dn_lin = ldb_dn_get_linearized(msg->dn); + if ((strcmp(dn_lin, LTDB_BASEINFO) == 0) || (strncmp(dn_lin, LTDB_INDEX ":", strlen( LTDB_INDEX ":")) == 0)) { + TALLOC_FREE(msg); + return 0; + } + } + + if (!validate_contents || ldb_dn_is_special(msg->dn)) { + ldb_ldif_write_file(ldb, stdout, &ldif); + TALLOC_FREE(msg); + return 0; + } + + for (i=0;i<msg->num_elements;i++) { + const struct ldb_schema_attribute *a; + + a = ldb_schema_attribute_by_name(ldb, msg->elements[i].name); + for (j=0;j<msg->elements[i].num_values;j++) { + struct ldb_val v; + ret = a->syntax->ldif_write_fn(ldb, msg, &msg->elements[i].values[j], &v); + if (ret != 0) { + v = msg->elements[i].values[j]; + if (ldb_should_b64_encode(ldb, &v)) { + v.data = (uint8_t *)ldb_base64_encode(ldb, (char *)v.data, v.length); + v.length = strlen((char *)v.data); + } + fprintf(stderr, "On %s element %s value %d (%*.*s) failed to convert to LDIF correctly, skipping possibly corrupt record\n", + ldb_dn_get_linearized(msg->dn), + msg->elements[i].name, + j, (int)v.length, (int)v.length, + v.data); + TALLOC_FREE(msg); + return 0; + } + } + } + ldb_ldif_write_file(ldb, stdout, &ldif); + TALLOC_FREE(msg); + + return 0; +} + +static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level, + const char *fmt, ...) +{ + va_list ap; + const char *name = tdb_name(tdb); + const char *prefix = ""; + + if (!name) + name = "unnamed"; + + switch (level) { + case TDB_DEBUG_ERROR: + prefix = "ERROR: "; + break; + case TDB_DEBUG_WARNING: + prefix = "WARNING: "; + break; + case TDB_DEBUG_TRACE: + return; + + default: + case TDB_DEBUG_FATAL: + prefix = "FATAL: "; + break; + } + + va_start(ap, fmt); + fprintf(stderr, "tdb(%s): %s", name, prefix); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +static void emergency_walk(TDB_DATA key, TDB_DATA dbuf, void *keyname) +{ + traverse_fn(NULL, key, dbuf, keyname); +} + +static int dump_tdb(const char *fname, struct ldb_dn *dn, bool emergency) +{ + TDB_CONTEXT *tdb; + struct tdb_logging_context logfn = { log_stderr }; + + tdb = tdb_open_ex(fname, 0, 0, O_RDONLY, 0, &logfn, NULL); + if (!tdb) { + fprintf(stderr, "Failed to open %s\n", fname); + return 1; + } + + if (emergency) { + return tdb_rescue(tdb, emergency_walk, dn) == 0; + } + return tdb_traverse(tdb, traverse_fn, dn) == -1 ? 1 : 0; +} + +static void usage( void) +{ + printf( "Usage: tdbdump [options] <filename>\n\n"); + printf( " -h this help message\n"); + printf( " -d DN dumps DN only\n"); + printf( " -e emergency dump, for corrupt databases\n"); + printf( " -i include index and @BASEINFO records in dump\n"); + printf( " -c validate contents of the records\n"); +} + + int main(int argc, char *argv[]) +{ + bool emergency = false; + int c, rc; + char *fname; + struct ldb_dn *dn = NULL; + + ldb = ldb_init(NULL, NULL); + if (ldb == NULL) { + fprintf(stderr, "ldb: ldb_init failed()"); + exit(1); + } + + rc = ldb_modules_hook(ldb, LDB_MODULE_HOOK_CMDLINE_PRECONNECT); + if (rc != LDB_SUCCESS) { + fprintf(stderr, "ldb: failed to run preconnect hooks (needed to get Samba LDIF handlers): %s\n", ldb_strerror(rc)); + exit(1); + } + + if (argc < 2) { + printf("Usage: ldbdump <fname>\n"); + exit(1); + } + + while ((c = getopt( argc, argv, "hd:ec")) != -1) { + switch (c) { + case 'h': + usage(); + exit( 0); + case 'd': + dn = ldb_dn_new(ldb, ldb, optarg); + if (!dn) { + fprintf(stderr, "ldb failed to parse %s as a DN\n", optarg); + exit(1); + } + break; + case 'e': + emergency = true; + break; + case 'i': + show_index = true; + break; + case 'c': + validate_contents = true; + break; + default: + usage(); + exit( 1); + } + } + + fname = argv[optind]; + + return dump_tdb(fname, dn, emergency); +} diff --git a/lib/ldb/wscript b/lib/ldb/wscript index 566c05e..66fa24b 100755 --- a/lib/ldb/wscript +++ b/lib/ldb/wscript @@ -253,6 +253,10 @@ def build(bld): bld.SAMBA_BINARY('ldbtest', 'tools/ldbtest.c', deps='ldb-cmdline ldb', install=False) + # ldbdump doesn't get installed + bld.SAMBA_BINARY('ldbdump', 'tools/ldbdump.c ldb_tdb/ldb_pack.c', deps='ldb-cmdline ldb', + install=False) + bld.SAMBA_LIBRARY('ldb-cmdline', source='tools/ldbutil.c tools/cmdline.c', deps='ldb dl popt', diff --git a/librpc/wscript_build b/librpc/wscript_build index 0eeb01b..8a4c169 100644 --- a/librpc/wscript_build +++ b/librpc/wscript_build @@ -559,6 +559,11 @@ bld.SAMBA_SUBSYSTEM('RPC_NDR_SCERPC', public_deps='dcerpc-binding NDR_SCERPC' ) +bld.SAMBA_SUBSYSTEM('RPC_NDR_SERVER_ID', + source='gen_ndr/ndr_server_id_c.c', + public_deps='dcerpc-binding NDR_SERVER_ID' + ) + bld.SAMBA_SUBSYSTEM('RPC_NDR_NTSVCS', source='gen_ndr/ndr_ntsvcs_c.c', public_deps='dcerpc-binding ndr-standard' diff --git a/source4/lib/messaging/irpc.h b/source4/lib/messaging/irpc.h index 15f8259..456d190 100644 --- a/source4/lib/messaging/irpc.h +++ b/source4/lib/messaging/irpc.h @@ -75,6 +75,8 @@ void irpc_binding_handle_add_security_token(struct dcerpc_binding_handle *h, NTSTATUS irpc_add_name(struct imessaging_context *msg_ctx, const char *name); struct server_id *irpc_servers_byname(struct imessaging_context *msg_ctx, TALLOC_CTX *mem_ctx, const char *name); +struct irpc_name_records *irpc_all_servers(struct imessaging_context *msg_ctx, + TALLOC_CTX *mem_ctx); void irpc_remove_name(struct imessaging_context *msg_ctx, const char *name); NTSTATUS irpc_send_reply(struct irpc_message *m, NTSTATUS status); diff --git a/source4/lib/messaging/messaging.c b/source4/lib/messaging/messaging.c index 4d69b94..6618897 100644 --- a/source4/lib/messaging/messaging.c +++ b/source4/lib/messaging/messaging.c @@ -985,6 +985,77 @@ struct server_id *irpc_servers_byname(struct imessaging_context *msg_ctx, return ret; } +static int all_servers_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state) +{ + struct irpc_name_records *name_records = talloc_get_type(state, struct irpc_name_records); + struct irpc_name_record *name_record; + int i; + + name_records->names + = talloc_realloc(name_records, name_records->names, + struct irpc_name_record *, name_records->num_records+1); + if (!name_records->names) { + return -1; + } + + name_records->names[name_records->num_records] = name_record + = talloc(name_records->names, + struct irpc_name_record); + if (!name_record) { + return -1; + } + + name_records->num_records++; + + name_record->name + = talloc_strndup(name_record, + (const char *)key.dptr, key.dsize); + if (!name_record->name) { + return -1; + } + + name_record->count = data.dsize / sizeof(struct server_id); + name_record->ids = talloc_array(name_record, + struct server_id, + name_record->count); + if (name_record->ids == NULL) { + return -1; + } + for (i=0;i<name_record->count;i++) { + name_record->ids[i] = ((struct server_id *)data.dptr)[i]; + } + return 0; +} + +/* + return a list of server ids for a server name +*/ +struct irpc_name_records *irpc_all_servers(struct imessaging_context *msg_ctx, + TALLOC_CTX *mem_ctx) +{ + struct tdb_wrap *t; + int ret; + struct irpc_name_records *name_records = talloc_zero(mem_ctx, struct irpc_name_records); + if (name_records == NULL) { + return NULL; + } + + t = irpc_namedb_open(msg_ctx); + if (t == NULL) { + return NULL; + } + + ret = tdb_traverse_read(t->tdb, all_servers_func, name_records); + if (ret == -1) { + talloc_free(t); + return NULL; + } + + talloc_free(t); + + return name_records; +} + /* remove a name from a messaging context */ diff --git a/source4/lib/messaging/pymessaging.c b/source4/lib/messaging/pymessaging.c index e8ef4a8..fca46e6 100644 --- a/source4/lib/messaging/pymessaging.c +++ b/source4/lib/messaging/pymessaging.c @@ -26,12 +26,14 @@ #include "librpc/rpc/pyrpc_util.h" #include "librpc/ndr/libndr.h" #include "lib/messaging/messaging.h" +#include "lib/messaging/irpc.h" #include "lib/events/events.h" #include "cluster/cluster.h" #include "param/param.h" #include "param/pyparam.h" #include "librpc/rpc/dcerpc.h" #include "librpc/gen_ndr/server_id.h" +#include <pytalloc.h> void initmessaging(void); @@ -40,10 +42,14 @@ extern PyTypeObject imessaging_Type; static bool server_id_from_py(PyObject *object, struct server_id *server_id) { if (!PyTuple_Check(object)) { - PyErr_SetString(PyExc_ValueError, "Expected tuple"); - return false; - } + if (!py_check_dcerpc_type(object, "server_id", "server_id")) { + PyErr_SetString(PyExc_ValueError, "Expected tuple or server_id"); + return false; + } + *server_id = *pytalloc_get_type(object, struct server_id); + return true; + } if (PyTuple_Size(object) == 3) { return PyArg_ParseTuple(object, "iii", &server_id->pid, &server_id->task_id, &server_id->vnn); } else { @@ -215,6 +221,101 @@ static PyObject *py_imessaging_deregister(PyObject *self, PyObject *args, PyObje Py_RETURN_NONE; } +static PyObject *py_irpc_servers_byname(PyObject *self, PyObject *args, PyObject *kwargs) +{ + imessaging_Object *iface = (imessaging_Object *)self; + char *server_name; + struct server_id *ids; + PyObject *pylist; + int i; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + if (!mem_ctx) { + PyErr_NoMemory(); + return NULL; + } + + if (!PyArg_ParseTuple(args, "s", &server_name)) { + TALLOC_FREE(mem_ctx); + return NULL; + } + -- Samba Shared Repository