aboutsummaryrefslogtreecommitdiffstats
path: root/src/rspamadm/signtool.c
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2016-02-17 14:56:55 +0000
committerVsevolod Stakhov <vsevolod@highsecure.ru>2016-02-17 14:57:16 +0000
commit9240d07929d71c468639038ba8fd1512a1ad499a (patch)
treeacbc2e13691d31ad7fd618ec629103d3b754fa70 /src/rspamadm/signtool.c
parent3d8ee7b0193d55486fdb9314f4096ec88661f9e4 (diff)
downloadrspamd-9240d07929d71c468639038ba8fd1512a1ad499a.tar.gz
rspamd-9240d07929d71c468639038ba8fd1512a1ad499a.zip
Add tool to edit signed files using text editor
Diffstat (limited to 'src/rspamadm/signtool.c')
-rw-r--r--src/rspamadm/signtool.c167
1 files changed, 165 insertions, 2 deletions
diff --git a/src/rspamadm/signtool.c b/src/rspamadm/signtool.c
index 942c01850..9b19e1b65 100644
--- a/src/rspamadm/signtool.c
+++ b/src/rspamadm/signtool.c
@@ -32,6 +32,8 @@ static gchar *pubkey_file = NULL;
static gchar *pubkey = NULL;
static gchar *pubout = NULL;
static gchar *keypair_file = NULL;
+static gchar *editor = NULL;
+static gboolean edit = FALSE;
enum rspamd_cryptobox_mode mode = RSPAMD_CRYPTOBOX_MODE_25519;
static void rspamadm_signtool (gint argc, gchar **argv);
@@ -61,6 +63,10 @@ static GOptionEntry entries[] = {
"UCL with keypair to load for signing", NULL},
{"quiet", 'q', 0, G_OPTION_ARG_NONE, &quiet,
"Be quiet", NULL},
+ {"edit", 'e', 0, G_OPTION_ARG_NONE, &edit,
+ "Run editor and sign the edited file", NULL},
+ {"editor", '\0', 0, G_OPTION_ARG_STRING, &editor,
+ "Use the specified editor instead of $EDITOR environment var", NULL},
{NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL}
};
@@ -80,15 +86,151 @@ rspamadm_signtool_help (gboolean full_help)
"-k: load signing keypair from ucl file\n"
"-S: append suffix for signatures and store them in files\n"
"-q: be quiet\n"
+ "-e: opens file for editing and sign the result\n"
+ "--editor: use the specified editor instead of $EDITOR environment var\n"
"--help: shows available options and commands";
}
else {
- help_str = "Create encryption key pairs";
+ help_str = "Sign and verify files tool";
}
return help_str;
}
+static gint
+rspamadm_edit_file (const gchar *fname)
+{
+ gchar tmppath[PATH_MAX], run_cmdline[PATH_MAX];
+ guchar *map;
+ gsize len = 0;
+ gint fd_out, retcode, child_argc;
+ GPid child_pid;
+ gchar *tmpdir, **child_argv = NULL;
+ GError *err = NULL;
+
+ if (editor == NULL) {
+ editor = getenv ("EDITOR");
+ }
+
+ if (editor == NULL) {
+ rspamd_fprintf (stderr, "cannot find editor: specify $EDITOR "
+ "environment variable or pass --editor argument\n");
+ exit (EXIT_FAILURE);
+ }
+
+ tmpdir = getenv ("TMPDIR");
+ if (tmpdir == NULL) {
+ tmpdir = "/tmp";
+ }
+
+ map = rspamd_file_xmap (fname, PROT_READ, &len);
+
+ if (map == NULL) {
+ rspamd_fprintf (stderr, "cannot open %s: %s\n", fname,
+ strerror (errno));
+ exit (errno);
+ }
+
+ rspamd_snprintf (tmppath, sizeof (tmppath),
+ "%s/rspamd_sign-XXXXXXXXXX", tmpdir);
+ fd_out = mkstemp (tmppath);
+
+ if (fd_out == -1) {
+ rspamd_fprintf (stderr, "cannot open tempfile %s: %s\n", tmppath,
+ strerror (errno));
+ exit (errno);
+ }
+
+ if (write (fd_out, map, len) == -1) {
+ rspamd_fprintf (stderr, "cannot write to tempfile %s: %s\n", tmppath,
+ strerror (errno));
+ unlink (tmppath);
+ munmap (map, len);
+ close (fd_out);
+ exit (errno);
+ }
+
+ munmap (map, len);
+ fsync (fd_out);
+ close (fd_out);
+
+ /* Now we spawn editor with the filename as argument */
+ rspamd_snprintf (run_cmdline, sizeof (run_cmdline), "%s %s", editor, tmppath);
+ if (!g_shell_parse_argv (run_cmdline, &child_argc,
+ &child_argv, &err)) {
+ rspamd_fprintf (stderr, "cannot exec %s: %e\n", editor,
+ err);
+ unlink (tmppath);
+ exit (errno);
+ }
+
+ if (!g_spawn_async (NULL, child_argv, NULL,
+ G_SPAWN_CHILD_INHERITS_STDIN|G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD,
+ NULL, NULL, &child_pid, &err)) {
+ rspamd_fprintf (stderr, "cannot exec %s: %e\n", editor,
+ err);
+ unlink (tmppath);
+ exit (errno);
+ }
+
+ g_strfreev (child_argv);
+
+ for (;;) {
+ if (waitpid ((pid_t)child_pid, &retcode, 0) != -1) {
+ break;
+ }
+
+ if (errno != EINTR) {
+ rspamd_fprintf (stderr, "failed to wait for %s: %s\n", editor,
+ strerror (errno));
+ unlink (tmppath);
+ exit (errno);
+ }
+ }
+
+ if (!g_spawn_check_exit_status (retcode, &err)) {
+ unlink (tmppath);
+ rspamd_fprintf (stderr, "%s returned error code: %d - %e\n", editor,
+ retcode, err);
+ exit (retcode);
+ }
+
+ map = rspamd_file_xmap (tmppath, PROT_READ, &len);
+
+ if (map == NULL) {
+ rspamd_fprintf (stderr, "cannot map %s: %s\n", tmppath,
+ strerror (errno));
+ unlink (tmppath);
+ close (fd_out);
+ exit (errno);
+ }
+
+ rspamd_snprintf (run_cmdline, sizeof (run_cmdline), "%s.new", fname);
+ fd_out = rspamd_file_xopen (run_cmdline, O_RDWR|O_CREAT|O_TRUNC,
+ 00600);
+
+ if (fd_out == -1) {
+ rspamd_fprintf (stderr, "cannot open new file %s: %s\n", run_cmdline,
+ strerror (errno));
+ unlink (tmppath);
+ exit (errno);
+ }
+
+ if (write (fd_out, map, len) == -1) {
+ rspamd_fprintf (stderr, "cannot write new file %s: %s\n", run_cmdline,
+ strerror (errno));
+ unlink (tmppath);
+ unlink (run_cmdline);
+ close (fd_out);
+ exit (errno);
+ }
+
+ unlink (tmppath);
+ (void)lseek (fd_out, 0, SEEK_SET);
+
+ return fd_out;
+}
+
static bool
rspamadm_sign_file (const gchar *fname, struct rspamd_cryptobox_keypair *kp)
{
@@ -103,7 +245,13 @@ rspamadm_sign_file (const gchar *fname, struct rspamd_cryptobox_keypair *kp)
suffix = ".sig";
}
- fd_input = rspamd_file_xopen (fname, O_RDONLY, 0);
+ if (edit) {
+ /* We need to open editor and then sign the temporary file */
+ fd_input = rspamadm_edit_file (fname);
+ }
+ else {
+ fd_input = rspamd_file_xopen (fname, O_RDONLY, 0);
+ }
if (fd_input == -1) {
rspamd_fprintf (stderr, "cannot open %s: %s\n", fname,
@@ -138,6 +286,21 @@ rspamadm_sign_file (const gchar *fname, struct rspamd_cryptobox_keypair *kp)
sk = rspamd_keypair_component (kp, RSPAMD_KEYPAIR_COMPONENT_SK, NULL);
rspamd_cryptobox_sign (sig, NULL, map, st.st_size, sk, mode);
+
+ if (edit) {
+ /* We also need to rename .new file */
+ rspamd_snprintf (sigpath, sizeof (sigpath), "%s.new", fname);
+
+ if (rename (sigpath, fname) == -1) {
+ rspamd_fprintf (stderr, "cannot rename %s to %s: %s\n", sigpath, fname,
+ strerror (errno));
+ exit (errno);
+ }
+
+ unlink (sigpath);
+ }
+
+ rspamd_snprintf (sigpath, sizeof (sigpath), "%s%s", fname, suffix);
g_assert (write (fd_sig, sig, rspamd_cryptobox_signature_bytes (mode)) != -1);
close (fd_sig);
munmap (map, st.st_size);