Back to index

courier  0.68.2
list.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2001-2011 Double Precision, Inc.  See COPYING for
00003 ** distribution information.
00004 */
00005 
00006 
00007 #include      "config.h"
00008 #include      <stdio.h>
00009 #include      <stdlib.h>
00010 #include      <string.h>
00011 #include      <unistd.h>
00012 #include      <signal.h>
00013 #include      <ctype.h>
00014 #include      <time.h>
00015 #include      <errno.h>
00016 #include      <sys/types.h>
00017 #include      <sys/stat.h>
00018 #include      <sys/time.h>
00019 
00020 #include      "gpg.h"
00021 #include      "gpglib.h"
00022 
00023 #include      "unicode/unicode.h"
00024 #include      "numlib/numlib.h"
00025 
00026 extern int libmail_gpg_stdin, libmail_gpg_stdout, libmail_gpg_stderr;
00027 extern pid_t libmail_gpg_pid;
00028 
00029 /*
00030 ** List keys
00031 */
00032 
00033 static int dolist(int (*)(const char *, const char *, const char *, int,
00034                        struct gpg_list_info *),
00035                 int (*)(const char *, size_t, void *),
00036                 void *);
00037 
00038 static void definit(struct gpg_list_info *arg)
00039 {
00040 
00041 #define DEFINIT(c, a) if (!(c)) (c)=(a)
00042 
00043        DEFINIT(arg->charset, "iso-8859-1");
00044        DEFINIT(arg->disabled_msg, "[ This key is disabled ]");
00045        DEFINIT(arg->revoked_msg, "[ This key is revoked ]");
00046        DEFINIT(arg->expired_msg, "[ This key is expired ]");
00047        DEFINIT(arg->group_msg, "Group: @");
00048 }
00049 
00050 int libmail_gpg_listkeys(const char *gpgdir,
00051                int secret,
00052                int (*callback_func)(const char *, const char *,
00053                                   const char *,
00054                                   int,
00055                                   struct gpg_list_info *),
00056                int (*err_func)(const char *, size_t, void *),
00057                struct gpg_list_info *voidarg)
00058 {
00059        char *argvec[7];
00060        int rc;
00061 
00062        argvec[0]="gpg";
00063        argvec[1]= secret ? "--list-secret-keys":"--list-sigs";
00064        argvec[2]="--with-colons";
00065        argvec[3]="--fingerprint";
00066        argvec[4]="-q";
00067        argvec[5]="--no-tty";
00068        argvec[6]=0;
00069 
00070        definit(voidarg);
00071 
00072        if (libmail_gpg_fork(&libmail_gpg_stdin, &libmail_gpg_stdout,
00073                           &libmail_gpg_stderr, gpgdir, argvec) < 0)
00074               rc= -1;
00075        else
00076        {
00077               int rc2;
00078 
00079               rc=dolist(callback_func, err_func, voidarg);
00080 
00081               rc2=libmail_gpg_cleanup();
00082               if (rc2)
00083                      rc=rc2;
00084        }
00085        return (rc);
00086 }
00087 
00088 /*
00089 ** Parse output of gpg into physical lines.
00090 */
00091 
00092 struct gpg_callbackinfo {
00093        int (*err_func)(const char *, size_t, void *);
00094        /* stderr passthrough */
00095 
00096        struct gpg_list_info *voidarg;
00097        /* passthrough arg */
00098 
00099        /* Line buffer: */
00100        char *linebuffer;
00101        size_t linebufsize;
00102        size_t linebufcnt;
00103 
00104        /* Function that receives collected lines, + passthrough arg */
00105        int (*line_func)(char *, void *, struct gpg_list_info *);
00106        void *line_callback_arg;
00107 } ;
00108 
00109 static int libmail_gpg_line_stderr(const char *l, size_t c, void *vp)
00110 {
00111        return (0);
00112 }
00113 
00114 static int libmail_gpg_line_stdout(const char *l, size_t c, void *vp)
00115 {
00116        struct gpg_callbackinfo *gci=(struct gpg_callbackinfo *)vp;
00117        size_t i, j;
00118 
00119        if (c + gci->linebufcnt >= gci->linebufsize)
00120        {
00121               /* Need bigger line buffer */
00122 
00123               size_t news= c+gci->linebufcnt+256;
00124 
00125               char *newp= gci->linebuffer ? realloc(gci->linebuffer, news)
00126                      : malloc(news);
00127 
00128               if (!newp)
00129                      return (-1);
00130               gci->linebuffer=newp;
00131               gci->linebufsize=news;
00132        }
00133 
00134        memcpy(gci->linebuffer + gci->linebufcnt, l, c);
00135        gci->linebufcnt += c;
00136 
00137        /* Search for collected newlines, extract complete lines,
00138        ** invoke the callback function.
00139        */
00140 
00141        for (;;)
00142        {
00143               int rc;
00144 
00145               for (i=0; i<gci->linebufcnt; i++)
00146                      if (gci->linebuffer[i] == '\n')
00147                             break;
00148               if (i >= gci->linebufcnt)
00149                      break;
00150               gci->linebuffer[i++]=0;
00151 
00152               rc= (*gci->line_func)(gci->linebuffer, gci->line_callback_arg,
00153                                   gci->voidarg);
00154               j=0;
00155               while (i < gci->linebufcnt)
00156               {
00157                      gci->linebuffer[j]=gci->linebuffer[i];
00158                      ++i;
00159                      ++j;
00160               }
00161               gci->linebufcnt=j;
00162               if (rc)
00163                      return (rc);
00164        }
00165        return (0);
00166 }
00167 
00168 /*
00169 ** Parse list output of gpg into distrinct keys.
00170 */
00171 
00172 struct gpg_callbacklistinfo {
00173 
00174        int (*callback_func)(const char *, const char *, const char *, int,
00175                           struct gpg_list_info *);
00176        int invalid_flag;
00177        char fingerprint[128];
00178        char shortname[256];
00179        char *keybuffer;
00180        size_t keybufsize;
00181        size_t keybuflen;
00182 
00183        int seen_startofkey;
00184 } ;
00185 
00186 static int dolist_callback(char *, void *, struct gpg_list_info *);
00187 
00188 static int dolist(int (*callback_func)(const char *, const char *,
00189                                    const char *, int,
00190                                    struct gpg_list_info *),
00191                 int (*err_func)(const char *, size_t, void *),
00192                 void *voidarg)
00193 {
00194        struct gpg_callbackinfo gci;
00195        struct gpg_callbacklistinfo gcli;
00196        int rc, rc2;
00197 
00198        close(libmail_gpg_stdin);
00199        libmail_gpg_stdin= -1;
00200 
00201        memset(&gci, 0, sizeof(gci));
00202        gci.err_func=err_func;
00203        gci.voidarg=voidarg;
00204 
00205        gci.line_func= &dolist_callback;
00206        gci.line_callback_arg= &gcli;
00207 
00208        memset(&gcli, 0, sizeof(gcli));
00209        gcli.callback_func=callback_func;
00210 
00211        rc=libmail_gpg_read( libmail_gpg_line_stdout,
00212                           libmail_gpg_line_stderr,
00213                           NULL,
00214                           0,
00215                           &gci);
00216 
00217 
00218        rc2= (*gci.line_func)(NULL, gci.line_callback_arg,
00219                                      gci.voidarg);
00220        if (rc2)
00221               rc=rc2;
00222 
00223        if (gcli.keybuffer)
00224               free(gcli.keybuffer);
00225 
00226        if (gci.linebuffer)
00227               free(gci.linebuffer);
00228        return (rc);
00229 }
00230 
00231 static char *nextword(char *);
00232 
00233 static int nyb(int c)
00234 {
00235        static const char xdigits[]="0123456789ABCDEFabcdef";
00236 
00237        char *p=strchr(xdigits, c);
00238 
00239        if (!p)
00240               return (0);
00241 
00242        c= p-xdigits;
00243 
00244        if (c >= 16)
00245               c -= 6;
00246        return (c);
00247 }
00248 
00249 static int append_key(struct gpg_callbacklistinfo *, const char *);
00250 static int append_date(struct gpg_callbacklistinfo *, const char *);
00251 
00252 static int dolist_callback(char *line, void *vp1,
00253                         struct gpg_list_info *vp)
00254 {
00255        struct gpg_callbacklistinfo *gci=(struct gpg_callbacklistinfo *)vp1;
00256 
00257        char *rectype;
00258        char *trust;
00259        char *length;
00260        int algo;
00261        /*char *keyid;*/
00262        char *crdate;
00263        char *expdate;
00264        /*char *localid;*/
00265        /*char *ownertrust;*/
00266        char *userid;
00267        char *p;
00268        const char *stat;
00269 
00270        if (!line || strncmp(line, "pub", 3) == 0
00271            || strncmp(line, "sec", 3) == 0)
00272        {
00273               if (gci->seen_startofkey)
00274               {
00275                      int rc=(*gci->callback_func)(gci->fingerprint,
00276                                                gci->shortname,
00277                                                gci->keybuflen ?
00278                                                gci->keybuffer:"",
00279                                                gci->invalid_flag,
00280                                                vp);
00281                      gci->keybuflen=0;
00282                      gci->fingerprint[0]=0;
00283                      gci->shortname[0]=0;
00284                      if (rc)
00285                             return (rc);
00286               }
00287 
00288               if (!line)
00289                      return (0);
00290 
00291               gci->seen_startofkey=1;
00292        }
00293 
00294        if (!gci->seen_startofkey)
00295               return (0);
00296 
00297        p=line;
00298        rectype=p; p=nextword(p);
00299        trust=p; p=nextword(p);
00300        length=p; p=nextword(p);
00301        algo=atoi(p); p=nextword(p);
00302        /*keyid=p;*/ p=nextword(p);
00303        crdate=p; p=nextword(p);
00304        expdate=p; p=nextword(p);
00305        /*localid=p;*/ p=nextword(p);
00306        /*ownertrust=p;*/ p=nextword(p);
00307        userid=p; p=nextword(p);
00308 
00309        {
00310               char *q;
00311 
00312               for (p=q=userid; *p; )
00313               {
00314                      int n;
00315 
00316                      if (*p != '\\')
00317                      {
00318                             *q=*p;
00319                             ++p;
00320                             ++q;
00321                             continue;
00322                      }
00323                      ++p;
00324                      if (*p != 'x')
00325                      {
00326                             *q=*p;
00327                             if (*p)
00328                                    ++p;
00329                             ++q;
00330                             continue;
00331                      }
00332                      ++p;
00333                      n=nyb(*p);
00334                      if (*p)
00335                             ++p;
00336                      n=n * 16 + nyb(*p);
00337                      if (*p)
00338                             ++p;
00339                      *q=n;
00340                      ++q;
00341               }
00342               *q=0;
00343        }
00344 
00345        stat=0;
00346 
00347        if (strcmp(rectype, "fpr") == 0)
00348        {
00349               gci->fingerprint[0]=0;
00350               strncat(gci->fingerprint, userid,
00351                      sizeof(gci->fingerprint)-2);
00352               return (0);
00353        }
00354 
00355        if (strcmp(rectype, "pub") == 0 ||
00356            strcmp(rectype, "sec") == 0)
00357        {
00358               stat= *trust == 'd' ? vp->disabled_msg:
00359                      *trust == 'r' ? vp->revoked_msg:
00360                      *trust == 'e' ? vp->expired_msg:0;
00361 
00362        }
00363        else if (strcmp(rectype, "sub") &&
00364                strcmp(rectype, "ssb") &&
00365                strcmp(rectype, "uid") &&
00366                strcmp(rectype, "sig"))
00367               return (0);
00368 
00369        if (append_key(gci, rectype) ||
00370            append_key(gci, " "))
00371               return (-1);
00372 
00373 
00374        gci->invalid_flag= stat ? 1:0;
00375 
00376        {
00377               char buf[60];
00378 
00379               sprintf(buf, "%4.4s/%-8.8s", length,
00380                      algo == 1 ? "RSA":
00381                      algo == 16 ? "ElGamal":
00382                      algo == 17 ? "DSA":
00383                      algo == 20 ? "DSA":"???");
00384 
00385               if (algo == 0 || *length == 0)
00386                      sprintf(buf, "%13s", "");
00387 
00388               if (append_key(gci, buf))
00389                      return (-1);
00390        }
00391 
00392        userid=libmail_u_convert_fromutf8(userid, vp->charset, NULL);
00393        if (!userid)
00394               return (-1);
00395 
00396        if (strcmp(rectype, "pub") == 0 ||
00397            strcmp(rectype, "sec") == 0 ||
00398            (strcmp(rectype, "uid") == 0 && gci->shortname[0] == 0))
00399        {
00400               gci->shortname[0]=0;
00401               strncat(gci->shortname, userid,
00402                      sizeof(gci->shortname)-2);
00403 
00404        }
00405 
00406        if (append_key(gci, " ")
00407            || append_date(gci, crdate)
00408            || append_key(gci, " ")
00409            || append_date(gci, expdate)
00410            || append_key(gci, " ")
00411            || append_key(gci, userid)
00412            || append_key(gci, "\n"))
00413        {
00414               free(userid);
00415               return (-1);
00416        }
00417        free(userid);
00418 
00419        if (stat)
00420        {
00421               append_key(gci, "                  ");
00422               append_key(gci, stat);
00423               append_key(gci, "\n");
00424        }
00425 
00426        return (0);
00427 }
00428 
00429 static char *nextword(char *p)
00430 {
00431        while (*p && *p != ':')
00432               ++p;
00433 
00434        if (*p)
00435               *p++=0;
00436        return (p);
00437 }
00438 
00439 static int append_date(struct gpg_callbacklistinfo *gci, const char *dtval)
00440 {
00441        char buf[20];
00442 
00443        const char *t;
00444        struct tm tmbuf;
00445        time_t secs;
00446 
00447        if (strlen(dtval) == 10 && strchr(dtval, '-'))
00448               return append_key(gci, dtval); /* YYYY-MM-DD */
00449 
00450        t=strchr(dtval, 'T');
00451 
00452        if (t && (t-dtval) == 8) /* YYYYMMDDThhmmss */
00453        {
00454               sprintf(buf, "%.4s-%.2s-%.2s", dtval, dtval+4, dtval+6);
00455               return append_key(gci, buf);
00456        }
00457 
00458        secs=0;
00459        while (dtval)
00460        {
00461               if (*dtval < '0' || *dtval > '9')
00462                      break;
00463               secs = secs * 10 + (*dtval++ - '0');
00464        }
00465 
00466        if (secs == 0 || *dtval || localtime_r(&secs,  &tmbuf) == NULL)
00467               return append_key(gci, "          ");
00468 
00469        buf[strftime(buf, sizeof(buf)-1, "%Y-%m-%d", &tmbuf)]=0;
00470 
00471        return append_key(gci, buf);
00472 }
00473 
00474 static int append_key(struct gpg_callbacklistinfo *gci, const char *l)
00475 {
00476        int ll=strlen(l);
00477 
00478        if (ll + gci->keybuflen >= gci->keybufsize)
00479        {
00480               int n=ll + gci->keybuflen + 256;
00481 
00482               char *p= gci->keybuffer ? realloc(gci->keybuffer, n)
00483                      : malloc(n);
00484               if (!p)
00485                      return (-1);
00486               gci->keybuffer=p;
00487               gci->keybufsize=n;
00488        }
00489        strcpy(gci->keybuffer + gci->keybuflen, l);
00490        gci->keybuflen += ll;
00491        return (0);
00492 }
00493 
00494 int libmail_gpg_listgroups(const char *gpgdir,
00495                         int (*callback_func)(const char *, const char *,
00496                                           const char *,
00497                                           int,
00498                                           struct gpg_list_info *),
00499                         struct gpg_list_info *voidarg)
00500 {
00501        char *filename=libmail_gpg_options(gpgdir);
00502        FILE *fp;
00503        char buf[BUFSIZ];
00504        char *p;
00505        char *q;
00506        char *r;
00507        int rc;
00508 
00509        definit(voidarg);
00510 
00511        if (!filename)
00512               return 0;
00513 
00514        fp=fopen(filename, "r");
00515        free(filename);
00516 
00517        if (!fp)
00518               return 0;
00519 
00520        while (fgets(buf, sizeof(buf), fp))
00521        {
00522               if (strncmp(buf, "group", 5) ||
00523                   !isspace((int)(unsigned char)buf[5]))
00524                      continue;
00525 
00526               for (p=buf+5; *p && isspace((int)(unsigned char)*p); ++p)
00527                      ;
00528               q=strchr(p, '=');
00529               if (!q)
00530                      continue;
00531               *q=0;
00532 
00533 
00534               /* strip trailing spaces */
00535 
00536               for (q=r=p; *q; q++)
00537                      if (!isspace((int)(unsigned char)*q))
00538                             r=q+1;
00539               *r=0;
00540 
00541               if (*p == 0)
00542                      continue;
00543 
00544               q=libmail_u_convert_fromutf8(p, voidarg->charset, NULL);
00545 
00546               if (!q)
00547                      continue;
00548 
00549               r=malloc(strlen(q)+strlen(voidarg->group_msg)+1);
00550 
00551               if (!r)
00552               {
00553                      free(q);
00554                      continue;
00555               }
00556 
00557               strcpy(r, voidarg->group_msg);
00558               if ((p=strchr(r, '@')) != 0)
00559                      strcat(strcpy(p, q),
00560                             strchr(voidarg->group_msg, '@')+1);
00561 
00562 
00563               rc=(*callback_func)(p, r, r, 0, voidarg);
00564               free(q);
00565               free(r);
00566               if (rc)
00567               {
00568                      fclose(fp);
00569                      return rc;
00570               }
00571        }
00572        fclose(fp);
00573        return (0);
00574 }