From: "Philipp A. Hartmann" <p...@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 <p...@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 <p...@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 <p...@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

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to