summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregor Beck <gbeck@sernet.de>2012-07-16 09:34:15 +0200
committerAndrew Bartlett <abartlet@samba.org>2012-08-16 06:56:51 +1000
commit1c2bae062d202c69d5b92b634f6b9ced3ea2a0ba (patch)
tree634d86ac8c03fc27166e7571053396b14aefb3f8
parent65976d680acd48aa9f59664f715fa9ce40185955 (diff)
downloadsamba-1c2bae062d202c69d5b92b634f6b9ced3ea2a0ba.tar.gz
samba-1c2bae062d202c69d5b92b634f6b9ced3ea2a0ba.tar.bz2
samba-1c2bae062d202c69d5b92b634f6b9ced3ea2a0ba.zip
s3:net add command "connections cleanup"
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
-rw-r--r--source3/Makefile.in2
-rw-r--r--source3/utils/net.c7
-rw-r--r--source3/utils/net_connections.c273
-rw-r--r--source3/utils/net_proto.h4
-rwxr-xr-xsource3/wscript_build2
5 files changed, 286 insertions, 2 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in
index 2635cfa8b6..7753979a19 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -1226,7 +1226,7 @@ NET_OBJ1 = utils/net.o utils/net_ads.o utils/net_help.o \
$(PASSWD_UTIL_OBJ) utils/net_dns.o utils/net_ads_gpo.o \
utils/net_conf.o utils/net_join.o utils/net_user.o \
utils/net_group.o utils/net_file.o utils/net_registry.o utils/net_registry_check.o\
- auth/token_util.o utils/net_dom.o utils/net_share.o \
+ auth/token_util.o utils/net_dom.o utils/net_share.o utils/net_connections.o\
utils/net_g_lock.o \
utils/net_serverid.o \
utils/net_eventlog.o \
diff --git a/source3/utils/net.c b/source3/utils/net.c
index eccb522dc9..075ccc177f 100644
--- a/source3/utils/net.c
+++ b/source3/utils/net.c
@@ -715,6 +715,13 @@ static struct functable net_func[] = {
N_(" Use 'net help registry' to get more information about "
"'net registry' commands.")
},
+ { "connections",
+ net_connections,
+ NET_TRANSPORT_LOCAL,
+ N_("Fiddle with connectinos tdb"),
+ N_(" Use 'net help connections' to get more information about "
+ "'net connections' commands.")
+ },
{ "eventlog",
net_eventlog,
NET_TRANSPORT_LOCAL,
diff --git a/source3/utils/net_connections.c b/source3/utils/net_connections.c
new file mode 100644
index 0000000000..6864814b8c
--- /dev/null
+++ b/source3/utils/net_connections.c
@@ -0,0 +1,273 @@
+/*
+ * Samba Unix/Linux SMB client library
+ * Distributed SMB/CIFS Server Management Utility
+ * fiddle with connections tdb
+ *
+ * Copyright (C) Gregor Beck 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 "net.h"
+#include "serverid.h"
+#include "popt_common.h"
+#include "dbwrap/dbwrap.h"
+#include "util_tdb.h"
+#include "messages.h"
+#include "system/filesys.h"
+#include "interact.h"
+#include "lib/conn_tdb.h"
+
+struct cclean_ctx {
+ struct server_id *ids;
+ int *cnums;
+ const char **names;
+ unsigned num;
+
+ bool *exists;
+ unsigned num_orphans;
+
+ bool verbose;
+ bool dry_run;
+};
+
+
+static char *serverid_str(const struct server_id id)
+{
+ return talloc_asprintf(talloc_tos(), "pid %u, vnn %u, uid %lu",
+ (unsigned)id.pid, (unsigned)id.vnn, id.unique_id);
+}
+
+static void print_record(const char *msg,
+ const struct connections_key *k,
+ const struct connections_data *d)
+{
+ char *idstr = serverid_str(k->pid);
+ d_printf("%s: connection %d (%s) ", msg, k->cnum, idstr);
+ if (d == NULL) {
+ d_printf("<no data>\n");
+ } else {
+ d_printf("to \"%s\" from %u:%u@%s[%s] %s\n", d->servicename,
+ (unsigned)d->uid, (unsigned)d->gid, d->machine,
+ d->addr, time_to_asc(d->start));
+ }
+ talloc_free(idstr);
+}
+
+static int read_connections_fn(const struct connections_key *key,
+ const struct connections_data *data,
+ void *cclean_ctx)
+{
+ struct cclean_ctx *ctx = (struct cclean_ctx *)cclean_ctx;
+ unsigned length = talloc_array_length(ctx->cnums);
+ if (length <= ctx->num) {
+ int n = MAX(2*length, 16);
+ void *tmp;
+
+ tmp = talloc_realloc(ctx, ctx->ids, struct server_id, n);
+ if (tmp == NULL) {
+ goto talloc_failed;
+ }
+ ctx->ids = (struct server_id *)tmp;
+
+ tmp = talloc_realloc(ctx, ctx->cnums, int, n);
+ if (tmp == NULL) {
+ goto talloc_failed;
+ }
+ ctx->cnums = (int *)tmp;
+
+ tmp = talloc_realloc(ctx, ctx->names, const char *, n);
+ if (tmp == NULL) {
+ goto talloc_failed;
+ }
+ ctx->names = (const char **)tmp;
+ }
+
+ if (ctx->verbose) {
+ print_record("Read", key, data);
+ }
+
+ ctx->ids[ctx->num] = key->pid;
+ ctx->cnums[ctx->num] = key->cnum;
+ ctx->names[ctx->num] = talloc_strndup(ctx, key->name, FSTRING_LEN);
+ if (ctx->names[ctx->num] == NULL) {
+ goto talloc_failed;
+ }
+ ctx->num++;
+
+ return 0;
+
+talloc_failed:
+ DEBUG(0, ("Out of memory\n"));
+ return -1;
+}
+
+static int read_connections(struct cclean_ctx *ctx)
+{
+ int ret = connections_forall_read(
+ &read_connections_fn,
+ ctx);
+ if (ret < 0) {
+ return ret;
+ }
+ if (ret != ctx->num) {
+ DEBUG(0, ("Skipped %d invalid entries\n", ret - ctx->num));
+ }
+ return 0;
+}
+
+static int check_connections(struct cclean_ctx *ctx)
+{
+ int i, ret = -1;
+
+ ctx->exists = talloc_realloc(ctx, ctx->exists, bool, MAX(1, ctx->num));
+ if (ctx->exists == NULL) {
+ DEBUG(0, ("Out of memory\n"));
+ goto done;
+ }
+
+ if (!serverids_exist(ctx->ids, ctx->num, ctx->exists)) {
+ DEBUG(0, ("serverids_exist() failed\n"));
+ goto done;
+ }
+
+ ctx->num_orphans = 0;
+ for (i=0; i<ctx->num; i++) {
+ if (!ctx->exists[i]) {
+ char *idstr = serverid_str(ctx->ids[i]);
+ d_printf("Orphaned entry: %s\n", idstr);
+ talloc_free(idstr);
+ ctx->num_orphans++;
+ }
+ }
+ ret = 0;
+done:
+ return ret;
+}
+
+static int delete_orphans(struct cclean_ctx *ctx)
+{
+ NTSTATUS status;
+ struct db_record *conn;
+ int i, ret = 0;
+
+ for (i=0; i<ctx->num; i++) {
+ if (!ctx->exists[i]) {
+ TDB_DATA key, value;
+ conn = connections_fetch_entry_ext(NULL,
+ ctx->ids[i],
+ ctx->cnums[i],
+ ctx->names[i]);
+
+ key = dbwrap_record_get_key(conn);
+ value = dbwrap_record_get_value(conn);
+
+ print_record("Delete record",
+ (struct connections_key *)key.dptr,
+ (struct connections_data *)value.dptr);
+
+ if (!ctx->dry_run) {
+ status = dbwrap_record_delete(conn);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Failed to delete record: %s\n",
+ nt_errstr(status)));
+ ret = -2;
+ }
+ }
+ TALLOC_FREE(conn);
+ }
+ }
+ return ret;
+}
+
+static int cclean(bool verbose, bool dry_run, bool automatic)
+{
+ int ret;
+ struct cclean_ctx *ctx = talloc_zero(talloc_tos(), struct cclean_ctx);
+ if (ctx == NULL) {
+ d_printf("Out of memory\n");
+ goto done;
+ }
+
+ ctx->verbose = verbose;
+ ctx->dry_run = dry_run;
+
+ ret = read_connections(ctx);
+ if (ret != 0) {
+ d_printf("Failed to read connections\n");
+ goto done;
+ }
+ d_printf("Read %u connections\n", ctx->num);
+
+ ret = check_connections(ctx);
+ if (ret != 0) {
+ d_printf("Failed to check connections\n");
+ goto done;
+ }
+ d_printf("Found %u orphans\n", ctx->num_orphans);
+
+ if (ctx->num_orphans == 0) {
+ goto done;
+ }
+
+ if (!automatic) {
+ int act = interact_prompt("Delete ([y]es/[n]o)", "yn", 'n');
+ if (tolower(act) != 'y') {
+ ret = 0;
+ goto done;
+ }
+ }
+ ret = delete_orphans(ctx);
+ if (ret != 0) {
+ d_printf("Failed to delete all orphans\n");
+ }
+done:
+ talloc_free(ctx);
+ return ret;
+}
+
+static int net_connections_cleanup(struct net_context *c,
+ int argc, const char **argv)
+{
+ return cclean(c->opt_verbose, c->opt_testmode, c->opt_auto);
+}
+
+int net_connections(struct net_context *c, int argc, const char **argv)
+{
+ int ret = -1;
+
+ struct functable func[] = {
+ {
+ "cleanup",
+ net_connections_cleanup,
+ NET_TRANSPORT_LOCAL,
+ N_("Remove orphaned entries from connections.tdb"),
+ N_("net connections cleanup\n"
+ " Remove orphaned entries from connections.tdb")
+ },
+ { NULL, NULL, 0, NULL, NULL }
+ };
+
+ if (!c->display_usage) {
+ if (!connections_init(!c->opt_testmode)) {
+ DEBUG(0, ("Failed to open connections tdb\n"));
+ return -1;
+ }
+ }
+
+ ret = net_run_function(c, argc, argv, "net connections", func);
+
+ return ret;
+}
diff --git a/source3/utils/net_proto.h b/source3/utils/net_proto.h
index 3f99e14e6e..a683abb67e 100644
--- a/source3/utils/net_proto.h
+++ b/source3/utils/net_proto.h
@@ -132,6 +132,10 @@ int net_rap(struct net_context *c, int argc, const char **argv);
int net_registry(struct net_context *c, int argc, const char **argv);
+/* The following definitions come from utils/net_connections.c */
+
+int net_connections(struct net_context *c, int argc, const char **argv);
+
/* The following definitions come from utils/net_rpc.c */
NTSTATUS net_get_remote_domain_sid(struct cli_state *cli, TALLOC_CTX *mem_ctx,
diff --git a/source3/wscript_build b/source3/wscript_build
index 2fc65550c9..dfd452257d 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -515,7 +515,7 @@ NET_SRC1 = '''utils/net.c utils/net_ads.c utils/net_help.c
utils/net_util.c utils/net_rpc_sh_acct.c utils/net_rpc_audit.c
utils/net_dns.c utils/net_ads_gpo.c
utils/net_conf.c utils/net_join.c utils/net_user.c
- utils/net_group.c utils/net_file.c utils/net_registry.c
+ utils/net_group.c utils/net_file.c utils/net_registry.c utils/net_connections.c
utils/net_registry_check.c
utils/net_dom.c utils/net_share.c
utils/net_g_lock.c