home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / pgpfk004.zip / PGPFAKE.C < prev    next >
C/C++ Source or Header  |  1999-06-10  |  18KB  |  619 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <errno.h>
  5.  
  6. #define VERSION "0.04"
  7. #define SIGFILE "signok.txt"
  8. #define LOGFILE "pgpfake.log"
  9. #define dprintf if (debug) fprintf
  10.  
  11.  
  12. /* Note. Encript to Self uses the UserID supplied by PMMail */
  13. /* If not called by PMMail, no Encript to Self is performed */
  14. /* To always encript to a particular ID, edit pgp.cfg */
  15. /* Encript_self = 1 only useful if you have multiple accounts, */
  16. /* each with their own pgp key */
  17.  
  18. int  debug=0,encript_self=0;
  19. char cmdline[256], sigfile[256], logfile[256], line[256];
  20.  
  21.  
  22. int convert_signature(char *sigfile)
  23. {
  24.   char dummy[80], answer[6], date[12], name[80];
  25.   FILE *sig;
  26.   int  cnt_parsed;
  27.  
  28.   /* read result of signature check */
  29.   sig = fopen(sigfile, "r");
  30.   while (!feof(sig))
  31.   {
  32.     fgets(line, 256, sig);
  33.     /* handle good and bad signatures */
  34.     if (strstr(line,"signature") != NULL)
  35.     {
  36.       sscanf(line, "%s", answer);
  37.       cnt_parsed = sscanf(line, "%[^0-9]%s", dummy, date);
  38.       if (cnt_parsed != 2)
  39.         strcpy(date, "unknown");
  40.  
  41.       fgets(line, 256, sig);   /* read dummy line */
  42.       fgets(line, 256, sig);   /* read name */
  43.       cnt_parsed = sscanf(line, " \"%[^\"]", name);
  44.       if (cnt_parsed != 1)
  45.         strcpy(name, "unknown");
  46.  
  47.       if (stricmp(answer,"GOOD") == 0)
  48.         fprintf(stderr, "Good signature from user \"%s\".\nSignature made %s\n", name, date);
  49.       else
  50.         fprintf(stderr, "Bad signature from user \"%s\".\nSignature made %s\n", name, date);
  51.       break;
  52.     }
  53.  
  54.     /* handle unknown signatures */
  55.     if (strstr(line,"unknown keyid") != NULL)
  56.     {
  57.       fprintf(stderr, "not found\n");
  58.       break;
  59.     }
  60.   }
  61.   fclose(sig);
  62.   if (!debug) remove(sigfile);
  63.   return (0);
  64. }
  65.  
  66.  
  67. int feed_pgp(FILE *log, char *pgpcmdline)
  68. {
  69.   FILE *pgpcmd;
  70.   int  i, rc;
  71.  
  72.   pgpcmd = popen(pgpcmdline, "wb");
  73.   if (pgpcmd == NULL)
  74.   {
  75.     dprintf(log, "\npopen failed with %d!\n", errno);
  76.     return(-1);
  77.   }
  78.  
  79.   i=0;
  80.   while (!feof(stdin))
  81.   {
  82.     fgets(line, 256, stdin);
  83.     if (feof(stdin)) continue;
  84.        // dprintf(log,"Line %d: %s\n", i, line); 
  85.     fputs(line, pgpcmd);
  86.     i++;
  87.   }
  88.   dprintf(log,"\n%d lines processed\n",i-1);
  89.   return(pclose(pgpcmd));
  90. }
  91.  
  92.  
  93. int pgp_check_signature(FILE *log, char *pgppath, char *sigfile)
  94. {
  95.   int rc;
  96.  
  97.   sprintf(cmdline, "%s\\pgp5.exe v --batchmode -fq 2>%s", pgppath, sigfile);
  98.  
  99.   rc = feed_pgp(log, cmdline);
  100.   if (rc < 0) return(rc);
  101.  
  102.   convert_signature(sigfile);
  103.   return(rc);
  104. }
  105.  
  106.  
  107. int pgp_encrypt(FILE *log, char *pgppath, char *to, char *from)
  108. {
  109.   if(encript_self)
  110.   {
  111.      sprintf(cmdline, "%s\\pgp5.exe e --batchmode -faqr %s -faqr %s", pgppath, to, from);
  112.   }
  113.   else
  114.   {
  115.      sprintf(cmdline, "%s\\pgp5.exe e --batchmode -faqr %s", pgppath, to);
  116.   }
  117.  
  118.   return(feed_pgp(log, cmdline));
  119. }
  120.  
  121.  
  122. int pgp_sign(FILE *log, char *pgppath, char *passphrase, char *userid)
  123. {
  124.   /* Added -t switch for clear text signature as proposed by Dieter Werner <e8726172@student.tuwien.ac.at> */
  125.   sprintf(cmdline, "%s\\pgp5.exe s --batchmode -ftaq -z\"%s\" -u %s", pgppath, passphrase, userid);
  126.  
  127.   return(feed_pgp(log, cmdline));
  128. }
  129.  
  130.  
  131. /* Added by Dieter Werner <e8726172@student.tuwien.ac.at> */
  132. int pgp_signencr(FILE *log, char *pgppath, char *passphrase, char *to, char *userid)
  133. {
  134.   /* Added --batchmode switch to avoid blocking of PGP (tv) */
  135.   if(encript_self)
  136.   {
  137.      sprintf(cmdline, "%s\\pgp5.exe e --batchmode -safq -z\"%s\" -r %s -r %s -u %s", pgppath, passphrase, to, userid, userid);
  138.   }
  139.   else
  140.   {
  141.      sprintf(cmdline, "%s\\pgp5.exe e --batchmode -safq -z\"%s\" -r %s -u %s", pgppath, passphrase, to, userid);
  142.   }
  143.   
  144.   return(feed_pgp(log, cmdline));
  145. }
  146.  
  147.  
  148. int pgp_decrypt(FILE *log, char *pgppath, char *sigfile, char *passphrase)
  149. {
  150.   int rc;
  151.  
  152.   sprintf(cmdline, "%s\\pgp5.exe v --batchmode -fq -z\"%s\" 2>%s", pgppath, passphrase, sigfile);
  153.  
  154.   rc = feed_pgp(log, cmdline);
  155.   if (rc < 0) return(rc);
  156.  
  157.   convert_signature(sigfile);
  158.   return(rc);
  159. }
  160.  
  161.  
  162. int pgp_extract_my_key(char *pgppath, char *userid)
  163. {
  164.   int rc;
  165.  
  166.   sprintf(cmdline, "%s\\pgpk.exe --batchmode -xa %s", pgppath, userid);
  167.   rc = system(cmdline);
  168.  
  169.   return(0);
  170. }
  171.  
  172.  
  173. /* Added by Nick Burch <Nick@Horton-Vineyard.com> */
  174. int pgp_call_no_args(char *pgppath)
  175. {
  176.   int rc;
  177.   
  178.   /* Simply calls PGP, and gets it to display some help */
  179.  
  180.   sprintf(cmdline, "%s\\pgp5.exe", pgppath);
  181.   rc = system(cmdline);
  182.  
  183.   return(0);
  184. }
  185.  
  186.  
  187. int pgp_add_new_key(FILE *log, char *pgppath, char *sigfile)
  188. {
  189.   FILE *pgpkey;
  190.   int  i, rc;
  191.  
  192.   pgpkey = fopen(sigfile, "wb");
  193.   if (pgpkey == NULL)
  194.   {
  195.     dprintf(log, "\nfopen failed with %d!\n", errno);
  196.     return(-1);
  197.   }
  198.  
  199.   i=0;
  200.   while (!feof(stdin))
  201.   {
  202.     fgets(line, 256, stdin);
  203.     if (feof(stdin)) continue;
  204. /*    dprintf(log,"Line %d: %s\n", i, line); */
  205.     fputs(line, pgpkey);
  206.     i++;
  207.   }
  208.   dprintf(log,"\n%d lines processed\n",i-1);
  209.   fclose(pgpkey);
  210.  
  211.   sprintf(cmdline, "%s\\pgpk.exe -a %s --batchmode", pgppath, sigfile);
  212.   rc = system(cmdline);
  213.   remove(sigfile);
  214.  
  215.   return(rc);
  216. }
  217.  
  218.  
  219. /* Added by Nick Burch <Nick@Horton-Vineyard.com> */
  220. char *get_cmd_line(FILE *log, char *args[], int start, int end)
  221. {
  222.    /* Converts the supplied command line to a string */
  223.    
  224.    int i,rc,len_args,relpos;
  225.    char *cmd_line, *blank;
  226.    blank = " ";
  227.    
  228.       // Cycle through args[], summing the length (add 1 for the trailing space)
  229.    for(i = start;i<end;i++)
  230.       len_args = strlen(args[i]) + 1;
  231.       
  232.    // Pointer to enough memory to store the whole string
  233.    cmd_line = malloc( len_args );
  234.    relpos = 0;
  235.    
  236.    for(i = start;i<end;i++)
  237.    {
  238.       // Copy current args[] to the next bit of the string
  239.       memmove(cmd_line + relpos,args[i],strlen(args[i]));
  240.       relpos = relpos + strlen(args[i]);
  241.       
  242.       if(i != end - 1 )
  243.       {
  244.         // If not the last args[], add a space
  245.         memmove(cmd_line + relpos,blank,1);
  246.         ++relpos;
  247.       }  
  248.    }
  249.    // Add null to end
  250.    memmove(cmd_line + relpos,"\0",1);
  251.    
  252.    dprintf( log, "\nCommand Line is:%s\n",cmd_line);
  253.    
  254.    return (cmd_line);
  255. }
  256.  
  257.  
  258. /* Added by Nick Burch <Nick@Horton-Vineyard.com> */
  259. int call_pgp(FILE *log, char *pgppath, char *args[], int start, int end )
  260. {
  261.    /* Calls PGP5.EXE */
  262.    
  263.    int rc;
  264.    char *opts;
  265.    
  266.    // Get Command Line from args[]
  267.    opts = get_cmd_line( log,args,start,end );
  268.    
  269.    sprintf(cmdline, "%s\\pgp5.exe %s", pgppath, opts);
  270.    rc = system(cmdline);
  271.    
  272.    dprintf( log, "Called PGP5.EXE, with RC=%d",rc);
  273.    
  274.    return(rc);    
  275. }
  276.  
  277.  
  278. /* Added by Nick Burch <Nick@Horton-Vineyard.com> */
  279. int call_pgpk(FILE *log, char *pgppath, char *args[], int start, int end )
  280. {
  281.    /* Calls PGPK.EXE */
  282.    
  283.    int rc;
  284.    char *opts;
  285.    
  286.    // Get command line from args[]
  287.    opts = get_cmd_line( log,args,start,end );
  288.    
  289.    sprintf(cmdline, "%s\\pgpk.exe %s", pgppath, opts);
  290.    rc = system(cmdline);
  291.    
  292.    dprintf( log, "Called PGPK.EXE, with RC=%d",rc);
  293.    
  294.    return(rc);    
  295. }
  296.  
  297.  
  298. /* Added by Nick Burch <Nick@Horton-Vineyard.com> */
  299. int pgp_check_command_line(FILE *log, int num_args, char *args[], char *pgppath )
  300. {
  301.   /* If the command line isn't from PMMail, */
  302.   /* Then this anylises it very simply, */
  303.   /* And calls PGP as needed */
  304.   
  305.   int rc,i,len_args;
  306.   char *temp;
  307.   
  308.   rc = 0;
  309.  
  310.   /* Call simply made to PGP assuming PGP.EXE is PGP5.EXE */
  311.   if(strcmp(strlwr(args[1]),"e") == 0)
  312.   {
  313.        /* PGP 5 Encript */
  314.           rc = call_pgp( log, pgppath, args, 1, num_args );
  315.   }
  316.   if(strcmp(strlwr(args[1]),"v") == 0)
  317.   {
  318.        /* PGP 5 Verify/Decript */
  319.           rc = call_pgp( log, pgppath, args, 1, num_args );
  320.   }
  321.   if(strcmp(strlwr(args[1]),"s") == 0)
  322.   {
  323.        /* PGP 5 Sign */
  324.           rc = call_pgp( log, pgppath, args, 1, num_args );
  325.   }
  326.   
  327.   /* Legacy 2.6 Decript support - assume cypertext ends in .pgp or .asc */
  328.   if(strstr(strlwr(args[1]),".asc") == args[1] + strlen(args[1]) - 4)
  329.   {
  330.      temp = malloc(strlen(args[1]) + 2);
  331.      memmove( temp, "v ",2);
  332.      memmove( temp + 2, args[1], strlen(args[1]) );
  333.      args[1] = temp;
  334.      rc = call_pgp( log, pgppath, args, 1, num_args );
  335.   }   
  336.   if(strstr(strlwr(args[1]),".pgp") == args[1] + strlen(args[1]) - 4)
  337.   {
  338.      temp = malloc(strlen(args[1]) + 2);
  339.      memmove( temp, "v ",2);
  340.      memmove( temp + 2, args[1],strlen(args[1]) );
  341.      args[1] = temp;
  342.      rc = call_pgp( log, pgppath, args, 1, num_args );
  343.   }   
  344.  
  345.   /* Check the first character */
  346.   /* If the pointer the the first occurance of a character */
  347.   /* Is the pointer of the start of the string, then that */
  348.   /* Character is first found at the start of the string */
  349.   if(strstr(args[1],"-") == args[1])
  350.   {
  351.        /* Legacy PGP 2.6 structure */
  352.        fprintf(stderr,"\nLegacy 2.6.x Command Line Detected\n");
  353.        
  354.        /* Keys (-k) */
  355.        if( strstr( args[1], "-k" ) == args[1] )
  356.        {
  357.           /* All we want to do is remove the 'k' and pass to PGPK */
  358.           /* Making any changes as needed - for kv & kvv */
  359.           len_args = strlen(args[1]);
  360.           
  361.           if( strcmp(args[1]+2,"v") == 0 ) 
  362.           {
  363.              memmove(args[1]+2,"l",1);
  364.           }   
  365.           if( strcmp(args[1] + 2,"vv") == 0 ) 
  366.           {            
  367.              memmove(args[1]+2,"ll",2);
  368.           }  
  369.           
  370.           // Shift everything 1 byte to the left, to replace "k"
  371.           memmove( args[1]+1,args[1]+2,len_args - 2);
  372.           // Null terminate string 1 character earlier than before
  373.           memmove( args[1] + len_args - 1, "\0",1);
  374.           
  375.           rc = call_pgpk( log, pgppath, args, 1, num_args );
  376.        }   
  377.        
  378.        /* Encript  (-e) */
  379.        if( strstr( args[1], "-e" ) == args[1] )
  380.        {
  381.           /* We just need to replace -e for e */
  382.            /* unless -es, in which case e -s */
  383.            if( strstr( args[1], "-es") == args[1])
  384.               args[1] = "e -s";
  385.            else   
  386.               args[1] = args[1] + 1;
  387.               
  388.           rc = call_pgp( log, pgppath, args, 1, num_args );
  389.        }
  390.        
  391.        /* Simple Encript  (-c) (No Key, only a message Passphrase) */
  392.        if( strstr( args[1], "-c" ) == args[1] )
  393.        {
  394.           /* We just need to replace -c for e -c */
  395.           args[1] = "e -c";
  396.           
  397.           rc = call_pgp( log, pgppath, args, 1, num_args );
  398.        }
  399.        
  400.        /* Sign  (-s) */
  401.        if( strstr( args[1], "-s" ) == args[1])
  402.        {
  403.           /* instead of file -u USERID needs to be -u USERID file */
  404.             // Change -s to s
  405.           temp = args[1] + 1;
  406.           if( num_args > 3 )
  407.           {
  408.             // Supplied -u
  409.               // Save file name
  410.              args[1] = args[2];
  411.               // Move -u
  412.              args[2] = args[3];
  413.               // Move username
  414.              args[3] = args[4];
  415.               // Put file name back
  416.              args[4] = args[1];
  417.               // Put back in PGP command line
  418.              args[1] = temp;
  419.            }
  420.            else
  421.            {
  422.               // Nothing else to change
  423.               args[1] = temp;
  424.            }   
  425.           
  426.           rc = call_pgp( log, pgppath, args, 1, num_args );
  427.        }
  428.   }
  429.   
  430.   return(rc);
  431. }
  432.  
  433.  
  434. int main(int argc, char *argv[])
  435. {
  436.   int i, j, k, rc;
  437.   FILE *log;
  438.   char *pgppath, *tmppath, *temp;
  439.  
  440.   rc = 0;
  441.  
  442.   tmppath = getenv("TMP");
  443.   if (tmppath == NULL)
  444.   {
  445.     tmppath=".";
  446.   }
  447.   sprintf(sigfile,"%s\\%s",tmppath,SIGFILE);
  448.   sprintf(logfile,"%s\\%s",tmppath,LOGFILE);
  449.  
  450.   debug = (getenv("PGPFAKE_DEBUG") != NULL);
  451.   encript_self = (getenv("PGPFAKE_ENCRIPT_TO_SELF") != NULL);
  452.  
  453.   /* switch on debug mode manually */
  454.   /* debug = 1; */
  455.   
  456.   /* switch on self encript manually */
  457.   /* encript_self = 1; */
  458.  
  459.   if (debug)
  460.   {
  461.     debug = 1;
  462.     log = fopen(logfile,"w");
  463.     for (i=1; i<argc; i++)
  464.       fprintf(log, "%d: %s\n",i,argv[i]);
  465.     fprintf(log, "Num of Args: %d\n",argc);  
  466.   }
  467.  
  468.   pgppath = getenv("PGPPATH");
  469.   if (pgppath == NULL)
  470.   {
  471.     dprintf(log, "\nPGP not installed correctly!\n");
  472.     if (debug) fclose(log);
  473.     return(-1);
  474.   }
  475.   
  476.          // As you can see, PGPFake decides what it's being called to do
  477.          // Based on the number of arguments. This is due to it originally
  478.          // Only being a shell for PMMail. This can lead to a few odd 
  479.          // Problems (see Bugs section of readme), but I can't see the
  480.          // Point of re-doing it, so if you can be bothered, go ahead!
  481.          // I'd recomend doing it in a similar way to the new bit above
  482.          // (The bit I wrote)
  483.          //                             Nick Burch <Nick@Horton-Vineyard.com>
  484.   
  485.   switch (argc)
  486.   {
  487.     case 1:  /* no arguments, print version then PGP Help*/
  488.              fprintf(stderr,"\nPGPfake, Version %s, (C) 1998 by Thomas Vandahl, 1999 by Nick Burch ",VERSION);
  489.              
  490.              rc = pgp_call_no_args( pgppath );
  491.  
  492.              break;
  493.  
  494.     case 9:  /* called to verify signature */
  495.              dprintf(log, "check signature\n");
  496.              rc = pgp_check_signature(log, pgppath, sigfile);
  497.              break;
  498.  
  499.     case 11: /* called to extract public key */
  500.              /*
  501.                 argv[10]: my userid
  502.              */
  503.              
  504.              /* Check We're not being asked to Fingerprint */
  505.              if( strcmp(argv[9],"-fkvcat") == 0)
  506.              { 
  507.                 // Fingerprint not supported: Needs a passphrase with pgp 5.0
  508.                 // Do nothing except log the problem
  509.                 dprintf(log, "Fingerprint key: not supported\n");
  510.              }
  511.              else
  512.              {
  513.                 // Extract, which we can do
  514.                 dprintf(log, "extract key\n");
  515.                 rc = pgp_extract_my_key(pgppath, argv[10]);
  516.              }   
  517.              break;
  518.  
  519.     case 12: /* called to decrypt or to add key information */
  520.              /*
  521.                 decrypt: argv[9] -> passphrase
  522.                 addkey:  argv[9] = "-a"
  523.              */
  524.              if (argv[9][1] == 'a') /* called to add public key */
  525.              {
  526.                dprintf(log, "addkey\n");
  527.                rc = pgp_add_new_key(log, pgppath, sigfile);
  528.              }
  529.              else                   /* called to decrypt */
  530.              {
  531.                dprintf(log, "decrypt\n");
  532.                rc = pgp_decrypt(log, pgppath, sigfile, argv[9]+2);
  533.              }
  534.              break;
  535.  
  536.     case 13: /* called to encrypt */
  537.              /*
  538.                 argv[11]: userid to encrypt to
  539.                 argv[12]: my userid
  540.              */
  541.              dprintf(log, "encrypt\n");
  542.              rc = pgp_encrypt(log, pgppath, argv[11], argv[12]);
  543.              break;
  544.  
  545.     case 14: /* called to sign */
  546.              /*
  547.                 argv[11]: passphrase
  548.                 argv[13]: my userid
  549.              */
  550.              dprintf(log, "sign\n");
  551.              rc = pgp_sign(log, pgppath, argv[11]+2, argv[13]);
  552.              break;
  553.  
  554.     /* Added by Dieter Werner <e8726172@student.tuwien.ac.at> */
  555.     case 16: /* called to sign & encrypt */
  556.              /*
  557.                 argv[11]: passphrase
  558.                 argv[12]: userid to encrypt to
  559.                 argv[13]: my userid
  560.              */
  561.              dprintf(log, "encrypt and sign\n");
  562.              rc = pgp_signencr(log, pgppath, argv[11]+2, argv[12]+2, argv[13]);
  563.              break;
  564.  
  565.     /* Based on case 16, coded by Nick Burch <Nick@Horton-Vineyard.com> */
  566.     case 17: /* called to sign & encrypt to 2 people */
  567.              /*
  568.                 argv[11]: passphrase
  569.                 argv[12]: userid to encrypt to
  570.                 argv[13]: other userid to encript to
  571.                 argv[14]: my userid
  572.              */
  573.              
  574.              i = strlen(argv[12]);
  575.              j = strlen(argv[13]);
  576.              
  577.              temp = malloc( i + j + 4 );
  578.              memmove( temp, argv[12], i);
  579.              memmove(temp + i , " -r ",4);
  580.              memmove( temp + i + 4, argv[13], j);
  581.              
  582.              dprintf(log, "encrypt and sign, 2 recipients\n");
  583.              rc = pgp_signencr(log, pgppath, argv[11]+2, temp, argv[14]);
  584.              break;
  585.  
  586.     /* Based on case 16, coded by Nick Burch <Nick@Horton-Vineyard.com> */
  587.     case 18: /* called to sign & encrypt to 3 people */
  588.              /*
  589.                 argv[11]: passphrase
  590.                 argv[12]: userid to encrypt to
  591.                 argv[13]: other userid to encript to
  592.                 argv[14]: final userid to encript to
  593.                 argv[15]: my userid
  594.              */
  595.              
  596.              i = strlen(argv[12]);
  597.              j = strlen(argv[13]);
  598.              k = strlen(argv[14]);
  599.              
  600.              temp = malloc( i + j + k + 8 );
  601.              memmove( temp, argv[12] ,i);
  602.              memmove( temp + i, " -r ", 4 );
  603.              memmove( temp + i + 4, argv[13], j);
  604.              memmove( temp + i + j + 4, " -r ",4 );
  605.              memmove( temp + i + j + 8, argv[14],k);
  606.              
  607.              dprintf(log, "encrypt and sign, 3 recipients\n");
  608.              rc = pgp_signencr(log, pgppath, argv[11]+2, temp, argv[15]);
  609.              break;
  610.  
  611.     default: /* unknown call */
  612.        /* Anylise command line, and call as needed */
  613.        rc = pgp_check_command_line( log, argc, argv, pgppath );
  614.   }
  615.   
  616.   dprintf(log,"\nreturn code: %d\n",rc);
  617.   if (debug) fclose(log);
  618.   return(rc);
  619. }