LCOV - code coverage report
Current view: top level - tests/openpgp - fake-pinentry.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 115 146 78.8 %
Date: 2016-11-29 15:00:56 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /* Fake pinentry program for the OpenPGP test suite.
       2             :  *
       3             :  * Copyright (C) 2016 g10 code GmbH
       4             :  *
       5             :  * This file is part of GnuPG.
       6             :  *
       7             :  * GnuPG is free software; you can redistribute it and/or modify
       8             :  * it under the terms of the GNU General Public License as published by
       9             :  * the Free Software Foundation; either version 3 of the License, or
      10             :  * (at your option) any later version.
      11             :  *
      12             :  * GnuPG is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :  * GNU General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License
      18             :  * along with this program; if not, see <https://www.gnu.org/licenses/>.
      19             :  */
      20             : 
      21             : #include <errno.h>
      22             : #include <stdlib.h>
      23             : #include <stdio.h>
      24             : #include <string.h>
      25             : #include <stdarg.h>
      26             : #include <unistd.h>
      27             : 
      28             : static FILE *log_stream;
      29             : 
      30             : 
      31             : static int
      32         349 : reply (const char *fmt, ...)
      33             : {
      34             :   int result;
      35             :   va_list ap;
      36             : 
      37         349 :   if (log_stream)
      38             :     {
      39          26 :       fprintf (log_stream, "> ");
      40          26 :       va_start (ap, fmt);
      41          26 :       vfprintf (log_stream, fmt, ap);
      42          26 :       va_end (ap);
      43             :     }
      44         349 :   va_start (ap, fmt);
      45         349 :   result = vprintf (fmt, ap);
      46         349 :   va_end (ap);
      47             : 
      48         349 :   fflush (stdout);
      49         349 :   return result;
      50             : }
      51             : 
      52             : 
      53             : /* Return the first line from FNAME, removing it from the file.  */
      54             : static char *
      55           1 : get_passphrase (const char *fname)
      56             : {
      57           1 :   char *passphrase = NULL;
      58             :   size_t fname_len;
      59             :   char *fname_new;
      60             :   FILE *source, *sink;
      61             :   char linebuf[80];
      62             : 
      63           1 :   fname_len = strlen (fname);
      64           1 :   fname_new = malloc (fname_len + 5);
      65           1 :   if (fname_new == NULL)
      66             :     {
      67           0 :       perror ("malloc");
      68           0 :       exit (1);
      69             :     }
      70           1 :   snprintf (fname_new, fname_len + 5, "%s.new", fname);
      71             : 
      72           1 :   source = fopen (fname, "r");
      73           1 :   if (! source)
      74             :     {
      75           0 :       perror (fname);
      76           0 :       exit (1);
      77             :     }
      78             : 
      79           1 :   sink = fopen (fname_new, "w");
      80           1 :   if (! sink)
      81             :     {
      82           0 :       perror (fname_new);
      83           0 :       exit (1);
      84             :     }
      85             : 
      86           3 :   while (fgets (linebuf, sizeof linebuf, source))
      87             :     {
      88           1 :       linebuf[sizeof linebuf - 1] = 0;
      89           1 :       if (passphrase == NULL)
      90             :         {
      91           1 :           passphrase = strdup (linebuf);
      92           1 :           if (passphrase == NULL)
      93             :             {
      94           0 :               perror ("strdup");
      95           0 :               exit (1);
      96             :             }
      97             :         }
      98             :       else
      99           0 :         fputs (linebuf, sink);
     100             :     }
     101             : 
     102           1 :   if (ferror (source))
     103             :     {
     104           0 :       perror (fname);
     105           0 :       exit (1);
     106             :     }
     107             : 
     108           1 :   if (ferror (sink))
     109             :     {
     110           0 :       perror (fname_new);
     111           0 :       exit (1);
     112             :     }
     113             : 
     114           1 :   fclose (source);
     115           1 :   fclose (sink);
     116           1 :   if (remove (fname))
     117             :     {
     118           0 :       fprintf (stderr, "Failed to remove %s: %s",
     119           0 :                fname, strerror (errno));
     120           0 :       exit (1);
     121             :     }
     122             : 
     123           1 :   if (rename (fname_new, fname))
     124             :     {
     125           0 :       fprintf (stderr, "Failed to rename %s to %s: %s",
     126           0 :                fname, fname_new, strerror (errno));
     127           0 :       exit (1);
     128             :     }
     129           1 :   return passphrase;
     130             : }
     131             : 
     132             : 
     133             : #define whitespacep(p)   (*(p) == ' ' || *(p) == '\t' \
     134             :                           || *(p) == '\r' || *(p) == '\n')
     135             : 
     136             : /* rstrip line.  */
     137             : static void
     138         299 : rstrip (char *buffer)
     139             : {
     140             :   char *p;
     141         299 :   if (!*buffer)
     142         299 :     return; /* This is to avoid p = buffer - 1 */
     143         598 :   for (p = buffer + strlen (buffer) - 1; p >= buffer; p--)
     144             :     {
     145         598 :       if (! whitespacep (p))
     146         299 :         break;
     147         299 :       *p = 0;
     148             :     }
     149             : }
     150             : 
     151             : 
     152             : /* Skip over options in LINE.
     153             : 
     154             :    Blanks after the options are also removed.  Options are indicated
     155             :    by two leading dashes followed by a string consisting of non-space
     156             :    characters.  The special option "--" indicates an explicit end of
     157             :    options; all what follows will not be considered an option.  The
     158             :    first no-option string also indicates the end of option parsing. */
     159             : char *
     160          14 : skip_options (const char *line)
     161             : {
     162          28 :   while (whitespacep (line))
     163           0 :     line++;
     164          31 :   while (*line == '-' && line[1] == '-')
     165             :     {
     166         195 :       while (*line && !whitespacep (line))
     167         189 :         line++;
     168           7 :       while (whitespacep (line))
     169           1 :         line++;
     170             :     }
     171          14 :   return (char*) line;
     172             : }
     173             : 
     174             : 
     175             : /* Return a pointer to the argument of the option with NAME.  If such
     176             :    an option is not given, NULL is returned. */
     177             : char *
     178          26 : option_value (const char *line, const char *name)
     179             : {
     180             :   char *s;
     181          26 :   int n = strlen (name);
     182             : 
     183          26 :   s = strstr (line, name);
     184          26 :   if (s && s >= skip_options (line))
     185           0 :     return NULL;
     186          26 :   if (s && (s == line || whitespacep (s-1))
     187           2 :       && s[n] && (whitespacep (s+n) || s[n] == '='))
     188             :     {
     189           2 :       s += n + 1;
     190           2 :       s += strspn (s, " ");
     191           2 :       if (*s && !whitespacep(s))
     192           2 :         return s;
     193             :     }
     194          24 :   return NULL;
     195             : }
     196             : 
     197             : int
     198          13 : main (int argc, char **argv)
     199             : {
     200             :   char *args;
     201          13 :   char *option_user_data = NULL;
     202             :   int got_environment_user_data;
     203             :   char *logfile;
     204             :   char *passphrasefile;
     205             :   char *passphrase;
     206             : 
     207             :   /* We get our options via PINENTRY_USER_DATA.  */
     208             :   (void) argc, (void) argv;
     209             : 
     210          13 :   setvbuf (stdin, NULL, _IOLBF, BUFSIZ);
     211          13 :   setvbuf (stdout, NULL, _IOLBF, BUFSIZ);
     212             : 
     213          13 :   args = getenv ("PINENTRY_USER_DATA");
     214          13 :   got_environment_user_data = !!args;
     215          13 :   if (! args)
     216           8 :     args = "";
     217             : 
     218             :  restart:
     219          13 :   logfile = option_value (args, "--logfile");
     220          13 :   if (logfile)
     221             :     {
     222           1 :       char *p = logfile, more;
     223          51 :       while (*p && ! whitespacep (p))
     224          49 :         p++;
     225           1 :       more = !! *p;
     226           1 :       *p = 0;
     227           1 :       args = more ? p+1 : p;
     228             : 
     229           1 :       log_stream = fopen (logfile, "a");
     230           1 :       if (! log_stream)
     231             :         {
     232           0 :           perror (logfile);
     233           0 :           return 1;
     234             :         }
     235             :     }
     236             : 
     237          13 :   passphrasefile = option_value (args, "--passphrasefile");
     238          13 :   if (passphrasefile)
     239             :     {
     240           1 :       char *p = passphrasefile, more;
     241          50 :       while (*p && ! whitespacep (p))
     242          48 :         p++;
     243           1 :       more = !! *p;
     244           1 :       *p = 0;
     245           1 :       args = more ? p+1 : p;
     246             : 
     247           1 :       passphrase = get_passphrase (passphrasefile);
     248           1 :       if (! passphrase)
     249             :         {
     250           0 :           reply ("# Passphrasefile '%s' is empty.  Terminating.\n",
     251             :                  passphrasefile);
     252           0 :           return 1;
     253             :         }
     254             : 
     255           1 :       rstrip (passphrase);
     256             :     }
     257             :   else
     258             :     {
     259          12 :       passphrase = skip_options (args);
     260          12 :       if (*passphrase == 0)
     261           8 :         passphrase = "no PINENTRY_USER_DATA -- using default passphrase";
     262             :     }
     263             : 
     264          13 :   reply ("# fake-pinentry(%u) started.  Passphrase='%s'.\n",
     265          13 :          (unsigned int)getpid (), passphrase);
     266          13 :   reply ("OK - what's up?\n");
     267             : 
     268          13 :   while (! feof (stdin))
     269             :     {
     270             :       char buffer[1024];
     271             : 
     272         298 :       if (fgets (buffer, sizeof buffer, stdin) == NULL)
     273          13 :         break;
     274             : 
     275         298 :       if (log_stream)
     276          22 :         fprintf (log_stream, "< %s", buffer);
     277             : 
     278         298 :       rstrip (buffer);
     279             : 
     280             : #define OPT_USER_DATA   "OPTION pinentry-user-data="
     281             : 
     282         298 :       if (strncmp (buffer, "GETPIN", 6) == 0)
     283          12 :         reply ("D %s\n", passphrase);
     284         286 :       else if (strncmp (buffer, "BYE", 3) == 0)
     285             :         {
     286          13 :           reply ("OK\n");
     287          13 :           break;
     288             :         }
     289         273 :       else if (strncmp (buffer, OPT_USER_DATA, strlen (OPT_USER_DATA)) == 0)
     290             :         {
     291           5 :           if (got_environment_user_data)
     292             :             {
     293           5 :               reply ("OK - I already got the data from the environment.\n");
     294           5 :               continue;
     295             :             }
     296             : 
     297           0 :           if (log_stream)
     298           0 :             fclose (log_stream);
     299           0 :           log_stream = NULL;
     300           0 :           free (option_user_data);
     301           0 :           option_user_data = args = strdup (buffer + strlen (OPT_USER_DATA));
     302           0 :           goto restart;
     303             :         }
     304             : 
     305         280 :       reply ("OK\n");
     306             :     }
     307             : 
     308             : #undef OPT_USER_DATA
     309             : 
     310          13 :   reply ("# Connection terminated.\n");
     311          13 :   if (log_stream)
     312           1 :     fclose (log_stream);
     313             : 
     314          13 :   free (option_user_data);
     315          13 :   return 0;
     316             : }

Generated by: LCOV version 1.11