git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Philipp A. Hartmann" <pah@qo.cx>
To: git@vger.kernel.org
Cc: Jeff King <peff@peff.net>,
	John Szakmeister <john@szakmeister.net>,
	"Philipp A. Hartmann" <pah@qo.cx>
Subject: [PATCH 2/4] contrib: add generic credential helper
Date: Thu, 23 Aug 2012 18:57:46 +0200	[thread overview]
Message-ID: <1345741068-11004-3-git-send-email-pah@qo.cx> (raw)
In-Reply-To: <1345741068-11004-1-git-send-email-pah@qo.cx>

From: "Philipp A. Hartmann" <pah@qo.cx>

This adds a generic implementation for credential helpers.

It provides a header file credential_helper.h containing
a simplified credential API and common helper functions.
The implementation in credential_helper.c already provides
a main() function and chooses the credential operation
from a function table:

  struct credential_operation const credential_helper_ops[] =
  {
      { "get",   my_backend_get   },
      { "store", my_backend_store },
      { "erase", my_backend_erase },
      CREDENTIAL_OP_END
  };

With this, a specific credential helper backend usually only
needs to implement these operation callbacks.

Signed-off-by: Philipp A. Hartmann <pah@qo.cx>
---
 contrib/credential/helper/credential_helper.c |  149 +++++++++++++++++++++++++
 contrib/credential/helper/credential_helper.h |  116 +++++++++++++++++++
 2 files changed, 265 insertions(+)
 create mode 100644 contrib/credential/helper/credential_helper.c
 create mode 100644 contrib/credential/helper/credential_helper.h

diff --git a/contrib/credential/helper/credential_helper.c b/contrib/credential/helper/credential_helper.c
new file mode 100644
index 0000000..e99c2ec
--- /dev/null
+++ b/contrib/credential/helper/credential_helper.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2012 Philipp A. Hartmann <pah@qo.cx>
+ *
+ * This file is licensed under the GPL v2, or a later version
+ * at the discretion of Linus.
+ *
+ * This credential struct and API is simplified from git's
+ * credential.{h,c} to be used within credential helper
+ * implementations.
+ */
+
+#include <credential_helper.h>
+
+void credential_init(struct credential *c)
+{
+	memset(c, 0, sizeof(*c));
+}
+
+void credential_clear(struct credential *c)
+{
+	free(c->protocol);
+	free(c->host);
+	free(c->path);
+	free(c->username);
+	free_password(c->password);
+
+	credential_init(c);
+}
+
+int credential_read(struct credential *c)
+{
+	char    buf[1024];
+	ssize_t line_len = 0;
+	char   *key      = buf;
+	char   *value;
+
+	while (fgets(buf, sizeof(buf), stdin))
+	{
+		line_len = strlen(buf);
+
+		if(buf[line_len-1]=='\n')
+			buf[--line_len]='\0';
+
+		if(!line_len)
+			break;
+
+		value = strchr(buf,'=');
+		if(!value) {
+			warning("invalid credential line: %s", key);
+			return -1;
+		}
+		*value++ = '\0';
+
+		if (!strcmp(key, "protocol")) {
+			free(c->protocol);
+			c->protocol = xstrdup(value);
+		} else if (!strcmp(key, "host")) {
+			free(c->host);
+			c->host = xstrdup(value);
+			value = strrchr(c->host,':');
+			if (value) {
+				*value++ = '\0';
+				c->port = atoi(value);
+			}
+		} else if (!strcmp(key, "path")) {
+			free(c->path);
+			c->path = xstrdup(value);
+		} else if (!strcmp(key, "username")) {
+			free(c->username);
+			c->username = xstrdup(value);
+		} else if (!strcmp(key, "password")) {
+			free_password(c->password);
+			c->password = xstrdup(value);
+			while (*value) *value++ = '\0';
+		}
+		/*
+		 * Ignore other lines; we don't know what they mean, but
+		 * this future-proofs us when later versions of git do
+		 * learn new lines, and the helpers are updated to match.
+		 */
+	}
+	return 0;
+}
+
+void credential_write_item(FILE *fp, const char *key, const char *value)
+{
+	if (!value)
+		return;
+	fprintf(fp, "%s=%s\n", key, value);
+}
+
+void credential_write(const struct credential *c)
+{
+	/* only write username/password, if set */
+	credential_write_item(stdout, "username", c->username);
+	credential_write_item(stdout, "password", c->password);
+}
+
+static void usage(const char *name)
+{
+	struct credential_operation const *try_op = credential_helper_ops;
+	const char *basename = strrchr(name,'/');
+
+	basename = (basename) ? basename + 1 : name;
+	fprintf(stderr, "Usage: %s <", basename);
+	while(try_op->name) {
+		fprintf(stderr,"%s",(try_op++)->name);
+		if(try_op->name)
+			fprintf(stderr,"%s","|");
+	}
+	fprintf(stderr,"%s",">\n");
+}
+
+/*
+ * generic main function for credential helpers
+ */
+int main(int argc, char *argv[])
+{
+	int ret = EXIT_SUCCESS;
+
+	struct credential_operation const *try_op = credential_helper_ops;
+	struct credential                  cred   = CREDENTIAL_INIT;
+
+	if (!argv[1]) {
+		usage(argv[0]);
+		goto out;
+	}
+
+	/* lookup operation callback */
+	while(try_op->name && strcmp(argv[1], try_op->name))
+		try_op++;
+
+	/* unsupported operation given -- ignore silently */
+	if(!try_op->name || !try_op->op)
+		goto out;
+
+	ret = credential_read(&cred);
+	if(ret)
+		goto out;
+
+	/* perform credential operation */
+	ret = (*try_op->op)(&cred);
+
+	credential_write(&cred);
+
+out:
+	credential_clear(&cred);
+	return ret;
+}
diff --git a/contrib/credential/helper/credential_helper.h b/contrib/credential/helper/credential_helper.h
new file mode 100644
index 0000000..8266078
--- /dev/null
+++ b/contrib/credential/helper/credential_helper.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2012 Philipp A. Hartmann <pah@qo.cx>
+ *
+ * This file is licensed under the GPL v2, or a later version
+ * at the discretion of Linus.
+ *
+ * This credential struct and API is simplified from git's
+ * credential.{h,c} to be used within credential helper
+ * implementations.
+ */
+#ifndef CREDENTIAL_HELPER_H_INCLUDED_
+#define CREDENTIAL_HELPER_H_INCLUDED_
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <errno.h>
+
+struct credential
+{
+	char          *protocol;
+	char          *host;
+	unsigned short port;
+	char          *path;
+	char          *username;
+	char          *password;
+};
+
+#define CREDENTIAL_INIT \
+  { NULL,NULL,0,NULL,NULL,NULL }
+
+void credential_init(struct credential *c);
+void credential_clear(struct credential *c);
+int  credential_read(struct credential *c);
+void credential_write(const struct credential *c);
+
+typedef int (*credential_op_cb)(struct credential*);
+
+struct credential_operation
+{
+	char             *name;
+	credential_op_cb op;
+};
+
+#define CREDENTIAL_OP_END \
+  { NULL,NULL }
+
+/*
+ * Table with operation callbacks is defined in concrete
+ * credential helper implementation and contains entries
+ * like { "get", function_to_get_credential } terminated
+ * by CREDENTIAL_OP_END.
+ */
+extern struct credential_operation const credential_helper_ops[];
+
+/* ---------------- common helper functions ---------------- */
+
+static inline void free_password(char *password)
+{
+	char *c = password;
+	if (!password)
+		return;
+
+	while (*c) *c++ = '\0';
+	free(password);
+}
+
+static inline void warning(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	fprintf(stderr, "warning: ");
+	vfprintf(stderr, fmt, ap);
+	fprintf(stderr, "\n" );
+	va_end(ap);
+}
+
+static inline void error(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	fprintf(stderr, "error: ");
+	vfprintf(stderr, fmt, ap);
+	fprintf(stderr, "\n" );
+	va_end(ap);
+}
+
+static inline void die(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap,fmt);
+	error(fmt, ap);
+	va_end(ap);
+	exit(EXIT_FAILURE);
+}
+
+static inline void die_errno(int err)
+{
+	error("%s", strerror(err));
+	exit(EXIT_FAILURE);
+}
+
+static inline char *xstrdup(const char *str)
+{
+	char *ret = strdup(str);
+	if (!ret)
+		die_errno(errno);
+
+	return ret;
+}
+
+#endif /* CREDENTIAL_HELPER_H_INCLUDED_ */
-- 
1.7.10.4

  parent reply	other threads:[~2012-08-23 17:07 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-08-23 16:57 [PATCH] contrib: GnomeKeyring support + generic helper implementation Philipp A. Hartmann
2012-08-23 16:57 ` [PATCH 1/4] contrib: add credential helper for GnomeKeyring Philipp A. Hartmann
2012-08-23 16:57 ` Philipp A. Hartmann [this message]
2012-08-23 16:57 ` [PATCH 3/4] gnome-keyring: port to generic helper implementation Philipp A. Hartmann
2012-08-23 16:57 ` [PATCH 4/4] osxkeychain: port to generic credential " Philipp A. Hartmann
2012-08-24 18:15 ` [PATCH] contrib: GnomeKeyring support + generic " Junio C Hamano
2012-08-24 21:33   ` Jeff King
2012-08-24 21:46     ` Junio C Hamano
2012-08-26 17:46       ` Junio C Hamano
2012-08-26 18:16         ` Philipp A. Hartmann
2012-08-26 22:04           ` [PATCH 5/4] wincred: port to generic credential helper (UNTESTED) Philipp A. Hartmann
2012-08-26 22:45             ` [PATCH 5/4 v2] " Philipp A. Hartmann
2012-08-30 18:27             ` [PATCH 5/4] " Erik Faye-Lund
2012-08-30 20:11               ` Junio C Hamano
2012-08-31 15:44               ` Erik Faye-Lund
2012-09-01 12:42                 ` [PATCH 5/4 v3] wincred: port to generic credential helper Philipp A. Hartmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1345741068-11004-3-git-send-email-pah@qo.cx \
    --to=pah@qo.cx \
    --cc=git@vger.kernel.org \
    --cc=john@szakmeister.net \
    --cc=peff@peff.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).