{"thread":{"id":"28597","subject":"[PATCH v2] Split GPG interface into its own helper library","startedAt":"2011-10-06T00:46:36Z","lastAt":"2011-10-06T00:46:36Z","messageCount":1,"participants":["Junio C Hamano"],"isPatch":true,"patchVersion":2,"patchTotal":null},"messages":[{"id":"176986","messageId":"7vipo33q1f.fsf@alter.siamese.dyndns.org","threadId":"28597","inReplyTo":null,"subject":"[PATCH v2] Split GPG interface into its own helper library","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-10-06T00:46:36Z","receivedAt":"2011-10-06T00:46:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This mostly moves existing code from builtin/tag.c (for signing)\nand builtin/verify-tag.c (for verifying) to a new gpg-interface.c\nfile to provide a more generic library interface.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\n * This is a re-roll of what was queued as part of jc/signed-push\n   topic. The helper is now aware of user.signingkey configuration\n   and can use it across all the future users.\n\n Makefile             |    2 +\n builtin/tag.c        |   76 +++-----------------------------\n builtin/verify-tag.c |   35 +-------------\n gpg-interface.c      |  119 ++++++++++++++++++++++++++++++++++++++++++++++++++\n gpg-interface.h      |   14 ++++++\n 5 files changed, 144 insertions(+), 102 deletions(-)\n create mode 100644 gpg-interface.c\n create mode 100644 gpg-interface.h\n\ndiff --git a/Makefile b/Makefile\nindex 8d6d451..2183223 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -530,6 +530,7 @@ LIB_H += exec_cmd.h\n LIB_H += fsck.h\n LIB_H += gettext.h\n LIB_H += git-compat-util.h\n+LIB_H += gpg-interface.h\n LIB_H += graph.h\n LIB_H += grep.h\n LIB_H += hash.h\n@@ -620,6 +621,7 @@ LIB_OBJS += entry.o\n LIB_OBJS += environment.o\n LIB_OBJS += exec_cmd.o\n LIB_OBJS += fsck.o\n+LIB_OBJS += gpg-interface.o\n LIB_OBJS += graph.o\n LIB_OBJS += grep.o\n LIB_OBJS += hash.o\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex 667515e..3141680 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -14,6 +14,7 @@\n #include \"parse-options.h\"\n #include \"diff.h\"\n #include \"revision.h\"\n+#include \"gpg-interface.h\"\n \n static const char * const git_tag_usage[] = {\n \t\"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]\",\n@@ -23,8 +24,6 @@ static const char * const git_tag_usage[] = {\n \tNULL\n };\n \n-static char signingkey[1000];\n-\n struct tag_filter {\n \tconst char **patterns;\n \tint lines;\n@@ -208,60 +207,7 @@ static int verify_tag(const char *name, const char *ref,\n \n static int do_sign(struct strbuf *buffer)\n {\n-\tstruct child_process gpg;\n-\tconst char *args[4];\n-\tchar *bracket;\n-\tint len;\n-\tint i, j;\n-\n-\tif (!*signingkey) {\n-\t\tif (strlcpy(signingkey, git_committer_info(IDENT_ERROR_ON_NO_NAME),\n-\t\t\t\tsizeof(signingkey)) > sizeof(signingkey) - 1)\n-\t\t\treturn error(_(\"committer info too long.\"));\n-\t\tbracket = strchr(signingkey, '>');\n-\t\tif (bracket)\n-\t\t\tbracket[1] = '\\0';\n-\t}\n-\n-\t/* When the username signingkey is bad, program could be terminated\n-\t * because gpg exits without reading and then write gets SIGPIPE. */\n-\tsignal(SIGPIPE, SIG_IGN);\n-\n-\tmemset(&gpg, 0, sizeof(gpg));\n-\tgpg.argv = args;\n-\tgpg.in = -1;\n-\tgpg.out = -1;\n-\targs[0] = \"gpg\";\n-\targs[1] = \"-bsau\";\n-\targs[2] = signingkey;\n-\targs[3] = NULL;\n-\n-\tif (start_command(&gpg))\n-\t\treturn error(_(\"could not run gpg.\"));\n-\n-\tif (write_in_full(gpg.in, buffer->buf, buffer->len) != buffer->len) {\n-\t\tclose(gpg.in);\n-\t\tclose(gpg.out);\n-\t\tfinish_command(&gpg);\n-\t\treturn error(_(\"gpg did not accept the tag data\"));\n-\t}\n-\tclose(gpg.in);\n-\tlen = strbuf_read(buffer, gpg.out, 1024);\n-\tclose(gpg.out);\n-\n-\tif (finish_command(&gpg) || !len || len < 0)\n-\t\treturn error(_(\"gpg failed to sign the tag\"));\n-\n-\t/* Strip CR from the line endings, in case we are on Windows. */\n-\tfor (i = j = 0; i < buffer->len; i++)\n-\t\tif (buffer->buf[i] != '\\r') {\n-\t\t\tif (i != j)\n-\t\t\t\tbuffer->buf[j] = buffer->buf[i];\n-\t\t\tj++;\n-\t\t}\n-\tstrbuf_setlen(buffer, j);\n-\n-\treturn 0;\n+\treturn sign_buffer(buffer, get_signing_key());\n }\n \n static const char tag_template[] =\n@@ -270,21 +216,11 @@ static const char tag_template[] =\n \t\"# Write a tag message\\n\"\n \t\"#\\n\");\n \n-static void set_signingkey(const char *value)\n-{\n-\tif (strlcpy(signingkey, value, sizeof(signingkey)) >= sizeof(signingkey))\n-\t\tdie(_(\"signing key value too long (%.10s...)\"), value);\n-}\n-\n static int git_tag_config(const char *var, const char *value, void *cb)\n {\n-\tif (!strcmp(var, \"user.signingkey\")) {\n-\t\tif (!value)\n-\t\t\treturn config_error_nonbool(var);\n-\t\tset_signingkey(value);\n-\t\treturn 0;\n-\t}\n-\n+\tint status = git_gpg_config(var, value, cb);\n+\tif (status)\n+\t\treturn status;\n \treturn git_default_config(var, value, cb);\n }\n \n@@ -463,7 +399,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \n \tif (keyid) {\n \t\tsign = 1;\n-\t\tset_signingkey(keyid);\n+\t\tset_signing_key(keyid);\n \t}\n \tif (sign)\n \t\tannotate = 1;\ndiff --git a/builtin/verify-tag.c b/builtin/verify-tag.c\nindex 3134766..8b4f742 100644\n--- a/builtin/verify-tag.c\n+++ b/builtin/verify-tag.c\n@@ -11,6 +11,7 @@\n #include \"run-command.h\"\n #include <signal.h>\n #include \"parse-options.h\"\n+#include \"gpg-interface.h\"\n \n static const char * const verify_tag_usage[] = {\n \t\t\"git verify-tag [-v|--verbose] <tag>...\",\n@@ -19,42 +20,12 @@ static const char * const verify_tag_usage[] = {\n \n static int run_gpg_verify(const char *buf, unsigned long size, int verbose)\n {\n-\tstruct child_process gpg;\n-\tconst char *args_gpg[] = {\"gpg\", \"--verify\", \"FILE\", \"-\", NULL};\n-\tchar path[PATH_MAX];\n-\tsize_t len;\n-\tint fd, ret;\n+\tint len;\n \n-\tfd = git_mkstemp(path, PATH_MAX, \".git_vtag_tmpXXXXXX\");\n-\tif (fd < 0)\n-\t\treturn error(\"could not create temporary file '%s': %s\",\n-\t\t\t\t\t\tpath, strerror(errno));\n-\tif (write_in_full(fd, buf, size) < 0)\n-\t\treturn error(\"failed writing temporary file '%s': %s\",\n-\t\t\t\t\t\tpath, strerror(errno));\n-\tclose(fd);\n-\n-\t/* find the length without signature */\n \tlen = parse_signature(buf, size);\n \tif (verbose)\n \t\twrite_in_full(1, buf, len);\n-\n-\tmemset(&gpg, 0, sizeof(gpg));\n-\tgpg.argv = args_gpg;\n-\tgpg.in = -1;\n-\targs_gpg[2] = path;\n-\tif (start_command(&gpg)) {\n-\t\tunlink(path);\n-\t\treturn error(\"could not run gpg.\");\n-\t}\n-\n-\twrite_in_full(gpg.in, buf, len);\n-\tclose(gpg.in);\n-\tret = finish_command(&gpg);\n-\n-\tunlink_or_warn(path);\n-\n-\treturn ret;\n+\treturn verify_signed_buffer(buf, size, len);\n }\n \n static int verify_tag(const char *name, int verbose)\ndiff --git a/gpg-interface.c b/gpg-interface.c\nnew file mode 100644\nindex 0000000..98e8154\n--- /dev/null\n+++ b/gpg-interface.c\n@@ -0,0 +1,119 @@\n+/*\n+ * Copyright (c) 2011, Google Inc.\n+ */\n+#include \"cache.h\"\n+#include \"run-command.h\"\n+#include \"strbuf.h\"\n+#include \"gpg-interface.h\"\n+#include \"sigchain.h\"\n+\n+static char *configured_signing_key;\n+\n+void set_signing_key(const char *key)\n+{\n+\tfree(configured_signing_key);\n+\tconfigured_signing_key = xstrdup(key);\n+}\n+\n+int git_gpg_config(const char *var, const char *value, void *cb)\n+{\n+\tif (!strcmp(var, \"user.signingkey\")) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n+\t\tset_signing_key(value);\n+\t}\n+\treturn 0;\n+}\n+\n+const char *get_signing_key(void)\n+{\n+\tif (configured_signing_key)\n+\t\treturn configured_signing_key;\n+\treturn git_committer_info(IDENT_ERROR_ON_NO_NAME|IDENT_NO_DATE);\n+}\n+\n+int sign_buffer(struct strbuf *buffer, const char *signing_key)\n+{\n+\tstruct child_process gpg;\n+\tconst char *args[4];\n+\tssize_t len;\n+\tint i, j;\n+\n+\tmemset(&gpg, 0, sizeof(gpg));\n+\tgpg.argv = args;\n+\tgpg.in = -1;\n+\tgpg.out = -1;\n+\targs[0] = \"gpg\";\n+\targs[1] = \"-bsau\";\n+\targs[2] = signing_key;\n+\targs[3] = NULL;\n+\n+\tif (start_command(&gpg))\n+\t\treturn error(_(\"could not run gpg.\"));\n+\n+\t/*\n+\t * When the username signingkey is bad, program could be terminated\n+\t * because gpg exits without reading and then write gets SIGPIPE.\n+\t */\n+\tsigchain_push(SIGPIPE, SIG_IGN);\n+\n+\tif (write_in_full(gpg.in, buffer->buf, buffer->len) != buffer->len) {\n+\t\tclose(gpg.in);\n+\t\tclose(gpg.out);\n+\t\tfinish_command(&gpg);\n+\t\treturn error(_(\"gpg did not accept the data\"));\n+\t}\n+\tclose(gpg.in);\n+\tlen = strbuf_read(buffer, gpg.out, 1024);\n+\tclose(gpg.out);\n+\n+\tsigchain_pop(SIGPIPE);\n+\n+\tif (finish_command(&gpg) || !len || len < 0)\n+\t\treturn error(_(\"gpg failed to sign the data\"));\n+\n+\t/* Strip CR from the line endings, in case we are on Windows. */\n+\tfor (i = j = 0; i < buffer->len; i++)\n+\t\tif (buffer->buf[i] != '\\r') {\n+\t\t\tif (i != j)\n+\t\t\t\tbuffer->buf[j] = buffer->buf[i];\n+\t\t\tj++;\n+\t\t}\n+\tstrbuf_setlen(buffer, j);\n+\n+\treturn 0;\n+}\n+\n+int verify_signed_buffer(const char *buf, size_t total, size_t payload)\n+{\n+\tstruct child_process gpg;\n+\tconst char *args_gpg[] = {\"gpg\", \"--verify\", \"FILE\", \"-\", NULL};\n+\tchar path[PATH_MAX];\n+\tint fd, ret;\n+\n+\tfd = git_mkstemp(path, PATH_MAX, \".git_vtag_tmpXXXXXX\");\n+\tif (fd < 0)\n+\t\treturn error(\"could not create temporary file '%s': %s\",\n+\t\t\t     path, strerror(errno));\n+\tif (write_in_full(fd, buf, total) < 0)\n+\t\treturn error(\"failed writing temporary file '%s': %s\",\n+\t\t\t     path, strerror(errno));\n+\tclose(fd);\n+\n+\tmemset(&gpg, 0, sizeof(gpg));\n+\tgpg.argv = args_gpg;\n+\tgpg.in = -1;\n+\targs_gpg[2] = path;\n+\tif (start_command(&gpg)) {\n+\t\tunlink(path);\n+\t\treturn error(\"could not run gpg.\");\n+\t}\n+\n+\twrite_in_full(gpg.in, buf, payload);\n+\tclose(gpg.in);\n+\tret = finish_command(&gpg);\n+\n+\tunlink_or_warn(path);\n+\n+\treturn ret;\n+}\ndiff --git a/gpg-interface.h b/gpg-interface.h\nnew file mode 100644\nindex 0000000..4e459fe\n--- /dev/null\n+++ b/gpg-interface.h\n@@ -0,0 +1,14 @@\n+#ifndef GPG_INTERFACE_H\n+#define GPG_INTERFACE_H\n+\n+/*\n+ * Copyright (c) 2011, Google Inc.\n+ */\n+\n+extern int sign_buffer(struct strbuf *buffer, const char *signing_key);\n+extern int verify_signed_buffer(const char *buffer, size_t total, size_t payload);\n+extern int git_gpg_config(const char *, const char *, void *);\n+extern void set_signing_key(const char *);\n+extern const char *get_signing_key(void);\n+\n+#endif\n-- \n1.7.7.138.g7f41b6\n"}]}