summaryrefslogtreecommitdiffstats
path: root/gpglib/list.c
diff options
context:
space:
mode:
authorSam Varshavchik2013-08-19 16:39:41 -0400
committerSam Varshavchik2013-08-25 14:43:51 -0400
commit9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch)
tree7a81a04cb51efb078ee350859a64be2ebc6b8813 /gpglib/list.c
parenta9520698b770168d1f33d6301463bb70a19655ec (diff)
downloadcourier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2
Initial checkin
Imported from subversion report, converted to git. Updated all paths in scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'gpglib/list.c')
-rw-r--r--gpglib/list.c574
1 files changed, 574 insertions, 0 deletions
diff --git a/gpglib/list.c b/gpglib/list.c
new file mode 100644
index 0000000..7b58355
--- /dev/null
+++ b/gpglib/list.c
@@ -0,0 +1,574 @@
+/*
+** Copyright 2001-2011 Double Precision, Inc. See COPYING for
+** distribution information.
+*/
+
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <ctype.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include "gpg.h"
+#include "gpglib.h"
+
+#include "unicode/unicode.h"
+#include "numlib/numlib.h"
+
+extern int libmail_gpg_stdin, libmail_gpg_stdout, libmail_gpg_stderr;
+extern pid_t libmail_gpg_pid;
+
+/*
+** List keys
+*/
+
+static int dolist(int (*)(const char *, const char *, const char *, int,
+ struct gpg_list_info *),
+ int (*)(const char *, size_t, void *),
+ void *);
+
+static void definit(struct gpg_list_info *arg)
+{
+
+#define DEFINIT(c, a) if (!(c)) (c)=(a)
+
+ DEFINIT(arg->charset, "iso-8859-1");
+ DEFINIT(arg->disabled_msg, "[ This key is disabled ]");
+ DEFINIT(arg->revoked_msg, "[ This key is revoked ]");
+ DEFINIT(arg->expired_msg, "[ This key is expired ]");
+ DEFINIT(arg->group_msg, "Group: @");
+}
+
+int libmail_gpg_listkeys(const char *gpgdir,
+ int secret,
+ int (*callback_func)(const char *, const char *,
+ const char *,
+ int,
+ struct gpg_list_info *),
+ int (*err_func)(const char *, size_t, void *),
+ struct gpg_list_info *voidarg)
+{
+ char *argvec[7];
+ int rc;
+
+ argvec[0]="gpg";
+ argvec[1]= secret ? "--list-secret-keys":"--list-sigs";
+ argvec[2]="--with-colons";
+ argvec[3]="--fingerprint";
+ argvec[4]="-q";
+ argvec[5]="--no-tty";
+ argvec[6]=0;
+
+ definit(voidarg);
+
+ if (libmail_gpg_fork(&libmail_gpg_stdin, &libmail_gpg_stdout,
+ &libmail_gpg_stderr, gpgdir, argvec) < 0)
+ rc= -1;
+ else
+ {
+ int rc2;
+
+ rc=dolist(callback_func, err_func, voidarg);
+
+ rc2=libmail_gpg_cleanup();
+ if (rc2)
+ rc=rc2;
+ }
+ return (rc);
+}
+
+/*
+** Parse output of gpg into physical lines.
+*/
+
+struct gpg_callbackinfo {
+ int (*err_func)(const char *, size_t, void *);
+ /* stderr passthrough */
+
+ struct gpg_list_info *voidarg;
+ /* passthrough arg */
+
+ /* Line buffer: */
+ char *linebuffer;
+ size_t linebufsize;
+ size_t linebufcnt;
+
+ /* Function that receives collected lines, + passthrough arg */
+ int (*line_func)(char *, void *, struct gpg_list_info *);
+ void *line_callback_arg;
+} ;
+
+static int libmail_gpg_line_stderr(const char *l, size_t c, void *vp)
+{
+ return (0);
+}
+
+static int libmail_gpg_line_stdout(const char *l, size_t c, void *vp)
+{
+ struct gpg_callbackinfo *gci=(struct gpg_callbackinfo *)vp;
+ size_t i, j;
+
+ if (c + gci->linebufcnt >= gci->linebufsize)
+ {
+ /* Need bigger line buffer */
+
+ size_t news= c+gci->linebufcnt+256;
+
+ char *newp= gci->linebuffer ? realloc(gci->linebuffer, news)
+ : malloc(news);
+
+ if (!newp)
+ return (-1);
+ gci->linebuffer=newp;
+ gci->linebufsize=news;
+ }
+
+ memcpy(gci->linebuffer + gci->linebufcnt, l, c);
+ gci->linebufcnt += c;
+
+ /* Search for collected newlines, extract complete lines,
+ ** invoke the callback function.
+ */
+
+ for (;;)
+ {
+ int rc;
+
+ for (i=0; i<gci->linebufcnt; i++)
+ if (gci->linebuffer[i] == '\n')
+ break;
+ if (i >= gci->linebufcnt)
+ break;
+ gci->linebuffer[i++]=0;
+
+ rc= (*gci->line_func)(gci->linebuffer, gci->line_callback_arg,
+ gci->voidarg);
+ j=0;
+ while (i < gci->linebufcnt)
+ {
+ gci->linebuffer[j]=gci->linebuffer[i];
+ ++i;
+ ++j;
+ }
+ gci->linebufcnt=j;
+ if (rc)
+ return (rc);
+ }
+ return (0);
+}
+
+/*
+** Parse list output of gpg into distrinct keys.
+*/
+
+struct gpg_callbacklistinfo {
+
+ int (*callback_func)(const char *, const char *, const char *, int,
+ struct gpg_list_info *);
+ int invalid_flag;
+ char fingerprint[128];
+ char shortname[256];
+ char *keybuffer;
+ size_t keybufsize;
+ size_t keybuflen;
+
+ int seen_startofkey;
+} ;
+
+static int dolist_callback(char *, void *, struct gpg_list_info *);
+
+static int dolist(int (*callback_func)(const char *, const char *,
+ const char *, int,
+ struct gpg_list_info *),
+ int (*err_func)(const char *, size_t, void *),
+ void *voidarg)
+{
+ struct gpg_callbackinfo gci;
+ struct gpg_callbacklistinfo gcli;
+ int rc, rc2;
+
+ close(libmail_gpg_stdin);
+ libmail_gpg_stdin= -1;
+
+ memset(&gci, 0, sizeof(gci));
+ gci.err_func=err_func;
+ gci.voidarg=voidarg;
+
+ gci.line_func= &dolist_callback;
+ gci.line_callback_arg= &gcli;
+
+ memset(&gcli, 0, sizeof(gcli));
+ gcli.callback_func=callback_func;
+
+ rc=libmail_gpg_read( libmail_gpg_line_stdout,
+ libmail_gpg_line_stderr,
+ NULL,
+ 0,
+ &gci);
+
+
+ rc2= (*gci.line_func)(NULL, gci.line_callback_arg,
+ gci.voidarg);
+ if (rc2)
+ rc=rc2;
+
+ if (gcli.keybuffer)
+ free(gcli.keybuffer);
+
+ if (gci.linebuffer)
+ free(gci.linebuffer);
+ return (rc);
+}
+
+static char *nextword(char *);
+
+static int nyb(int c)
+{
+ static const char xdigits[]="0123456789ABCDEFabcdef";
+
+ char *p=strchr(xdigits, c);
+
+ if (!p)
+ return (0);
+
+ c= p-xdigits;
+
+ if (c >= 16)
+ c -= 6;
+ return (c);
+}
+
+static int append_key(struct gpg_callbacklistinfo *, const char *);
+static int append_date(struct gpg_callbacklistinfo *, const char *);
+
+static int dolist_callback(char *line, void *vp1,
+ struct gpg_list_info *vp)
+{
+ struct gpg_callbacklistinfo *gci=(struct gpg_callbacklistinfo *)vp1;
+
+ char *rectype;
+ char *trust;
+ char *length;
+ int algo;
+ /*char *keyid;*/
+ char *crdate;
+ char *expdate;
+ /*char *localid;*/
+ /*char *ownertrust;*/
+ char *userid;
+ char *p;
+ const char *stat;
+
+ if (!line || strncmp(line, "pub", 3) == 0
+ || strncmp(line, "sec", 3) == 0)
+ {
+ if (gci->seen_startofkey)
+ {
+ int rc=(*gci->callback_func)(gci->fingerprint,
+ gci->shortname,
+ gci->keybuflen ?
+ gci->keybuffer:"",
+ gci->invalid_flag,
+ vp);
+ gci->keybuflen=0;
+ gci->fingerprint[0]=0;
+ gci->shortname[0]=0;
+ if (rc)
+ return (rc);
+ }
+
+ if (!line)
+ return (0);
+
+ gci->seen_startofkey=1;
+ }
+
+ if (!gci->seen_startofkey)
+ return (0);
+
+ p=line;
+ rectype=p; p=nextword(p);
+ trust=p; p=nextword(p);
+ length=p; p=nextword(p);
+ algo=atoi(p); p=nextword(p);
+ /*keyid=p;*/ p=nextword(p);
+ crdate=p; p=nextword(p);
+ expdate=p; p=nextword(p);
+ /*localid=p;*/ p=nextword(p);
+ /*ownertrust=p;*/ p=nextword(p);
+ userid=p; p=nextword(p);
+
+ {
+ char *q;
+
+ for (p=q=userid; *p; )
+ {
+ int n;
+
+ if (*p != '\\')
+ {
+ *q=*p;
+ ++p;
+ ++q;
+ continue;
+ }
+ ++p;
+ if (*p != 'x')
+ {
+ *q=*p;
+ if (*p)
+ ++p;
+ ++q;
+ continue;
+ }
+ ++p;
+ n=nyb(*p);
+ if (*p)
+ ++p;
+ n=n * 16 + nyb(*p);
+ if (*p)
+ ++p;
+ *q=n;
+ ++q;
+ }
+ *q=0;
+ }
+
+ stat=0;
+
+ if (strcmp(rectype, "fpr") == 0)
+ {
+ gci->fingerprint[0]=0;
+ strncat(gci->fingerprint, userid,
+ sizeof(gci->fingerprint)-2);
+ return (0);
+ }
+
+ if (strcmp(rectype, "pub") == 0 ||
+ strcmp(rectype, "sec") == 0)
+ {
+ stat= *trust == 'd' ? vp->disabled_msg:
+ *trust == 'r' ? vp->revoked_msg:
+ *trust == 'e' ? vp->expired_msg:0;
+
+ }
+ else if (strcmp(rectype, "sub") &&
+ strcmp(rectype, "ssb") &&
+ strcmp(rectype, "uid") &&
+ strcmp(rectype, "sig"))
+ return (0);
+
+ if (append_key(gci, rectype) ||
+ append_key(gci, " "))
+ return (-1);
+
+
+ gci->invalid_flag= stat ? 1:0;
+
+ {
+ char buf[60];
+
+ sprintf(buf, "%4.4s/%-8.8s", length,
+ algo == 1 ? "RSA":
+ algo == 16 ? "ElGamal":
+ algo == 17 ? "DSA":
+ algo == 20 ? "DSA":"???");
+
+ if (algo == 0 || *length == 0)
+ sprintf(buf, "%13s", "");
+
+ if (append_key(gci, buf))
+ return (-1);
+ }
+
+ userid=libmail_u_convert_fromutf8(userid, vp->charset, NULL);
+ if (!userid)
+ return (-1);
+
+ if (strcmp(rectype, "pub") == 0 ||
+ strcmp(rectype, "sec") == 0 ||
+ (strcmp(rectype, "uid") == 0 && gci->shortname[0] == 0))
+ {
+ gci->shortname[0]=0;
+ strncat(gci->shortname, userid,
+ sizeof(gci->shortname)-2);
+
+ }
+
+ if (append_key(gci, " ")
+ || append_date(gci, crdate)
+ || append_key(gci, " ")
+ || append_date(gci, expdate)
+ || append_key(gci, " ")
+ || append_key(gci, userid)
+ || append_key(gci, "\n"))
+ {
+ free(userid);
+ return (-1);
+ }
+ free(userid);
+
+ if (stat)
+ {
+ append_key(gci, " ");
+ append_key(gci, stat);
+ append_key(gci, "\n");
+ }
+
+ return (0);
+}
+
+static char *nextword(char *p)
+{
+ while (*p && *p != ':')
+ ++p;
+
+ if (*p)
+ *p++=0;
+ return (p);
+}
+
+static int append_date(struct gpg_callbacklistinfo *gci, const char *dtval)
+{
+ char buf[20];
+
+ const char *t;
+ struct tm tmbuf;
+ time_t secs;
+
+ if (strlen(dtval) == 10 && strchr(dtval, '-'))
+ return append_key(gci, dtval); /* YYYY-MM-DD */
+
+ t=strchr(dtval, 'T');
+
+ if (t && (t-dtval) == 8) /* YYYYMMDDThhmmss */
+ {
+ sprintf(buf, "%.4s-%.2s-%.2s", dtval, dtval+4, dtval+6);
+ return append_key(gci, buf);
+ }
+
+ secs=0;
+ while (dtval)
+ {
+ if (*dtval < '0' || *dtval > '9')
+ break;
+ secs = secs * 10 + (*dtval++ - '0');
+ }
+
+ if (secs == 0 || *dtval || localtime_r(&secs, &tmbuf) == NULL)
+ return append_key(gci, " ");
+
+ buf[strftime(buf, sizeof(buf)-1, "%Y-%m-%d", &tmbuf)]=0;
+
+ return append_key(gci, buf);
+}
+
+static int append_key(struct gpg_callbacklistinfo *gci, const char *l)
+{
+ int ll=strlen(l);
+
+ if (ll + gci->keybuflen >= gci->keybufsize)
+ {
+ int n=ll + gci->keybuflen + 256;
+
+ char *p= gci->keybuffer ? realloc(gci->keybuffer, n)
+ : malloc(n);
+ if (!p)
+ return (-1);
+ gci->keybuffer=p;
+ gci->keybufsize=n;
+ }
+ strcpy(gci->keybuffer + gci->keybuflen, l);
+ gci->keybuflen += ll;
+ return (0);
+}
+
+int libmail_gpg_listgroups(const char *gpgdir,
+ int (*callback_func)(const char *, const char *,
+ const char *,
+ int,
+ struct gpg_list_info *),
+ struct gpg_list_info *voidarg)
+{
+ char *filename=libmail_gpg_options(gpgdir);
+ FILE *fp;
+ char buf[BUFSIZ];
+ char *p;
+ char *q;
+ char *r;
+ int rc;
+
+ definit(voidarg);
+
+ if (!filename)
+ return 0;
+
+ fp=fopen(filename, "r");
+ free(filename);
+
+ if (!fp)
+ return 0;
+
+ while (fgets(buf, sizeof(buf), fp))
+ {
+ if (strncmp(buf, "group", 5) ||
+ !isspace((int)(unsigned char)buf[5]))
+ continue;
+
+ for (p=buf+5; *p && isspace((int)(unsigned char)*p); ++p)
+ ;
+ q=strchr(p, '=');
+ if (!q)
+ continue;
+ *q=0;
+
+
+ /* strip trailing spaces */
+
+ for (q=r=p; *q; q++)
+ if (!isspace((int)(unsigned char)*q))
+ r=q+1;
+ *r=0;
+
+ if (*p == 0)
+ continue;
+
+ q=libmail_u_convert_fromutf8(p, voidarg->charset, NULL);
+
+ if (!q)
+ continue;
+
+ r=malloc(strlen(q)+strlen(voidarg->group_msg)+1);
+
+ if (!r)
+ {
+ free(q);
+ continue;
+ }
+
+ strcpy(r, voidarg->group_msg);
+ if ((p=strchr(r, '@')) != 0)
+ strcat(strcpy(p, q),
+ strchr(voidarg->group_msg, '@')+1);
+
+
+ rc=(*callback_func)(p, r, r, 0, voidarg);
+ free(q);
+ free(r);
+ if (rc)
+ {
+ fclose(fp);
+ return rc;
+ }
+ }
+ fclose(fp);
+ return (0);
+}