/* * $Filename: pgpsendmail.c $ * $Revision: 1.45 $ * $Date: 1994/03/21 14:54:52 $ * * Copyright (C) 1993 by Peter Simons * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: pgpsendmail.c,v 1.45 1994/03/21 14:54:52 simons Exp simons $ * */ /************************************************************************** * * * Section: Macros, Definitions, Includes, Structures * * * **************************************************************************/ /************************************* Includes ***********/ #include #include #include #include #include #include #include "pgpsendmail.h" /* standard defines */ #include "protos.h" /* protoypes of all available routines */ #include "pgpsendmail_rev.h" /* bumprevision stuff (AmigaOS only) */ /************************************* Prototypes *********/ void my_exit(void); void sendmail(void); /************************************* Defines ************/ #define PGP "PGP -fesa <%s >%s %s +batchmode" #define PGPKEYLIST "UULib:PGPKeys.lst" #define BODY_ID "Automatically encrypted message-body follows:\n\n" /************************************* global Variables ***/ static const char __OSVer[] = VERSTAG; static const char __RCSId[] = "$Id: pgpsendmail.c,v 1.45 1994/03/21 14:54:52 simons Exp simons $"; char PRGNAME[] = "PGPSendmail"; struct NetSupportLibrary *NetSupportBase; FILE *mailfh, *tmpfh; char mailfilename[L_tmpnam], tmpfilename[L_tmpnam], encryptedfilename[L_tmpnam], *argline, *tmpbuf; int exitPipe = 1; /************************************************************************** * * * Section: main program * * * **************************************************************************/ int main(int argc, char **argv) { extern struct ExecBase *SysBase; BPTR pipe, tmp_pipe; char **receipients, *cmdbuf, *header, *tmp, *ptr; int rc; /* * Initialize the requires resources and return if something fails! */ if (SysBase->LibNode.lib_Version < 37) { fprintf(stderr, "%s: Kickstart 2.04 or later is required!", PRGNAME); return 20; } if (atexit(my_exit)) { fprintf(stderr, "%s: Could not install my exit handler!\n", PRGNAME); return 20; } if (!(NetSupportBase = (struct NetSupportLibrary *) OpenLibrary("netsupport.library", 0L))) { fprintf(stderr, "%s: Failed opening NetSupport.Library!", PRGNAME); return 20; } if (!(cmdbuf = malloc(MAX_CMDLINELEN)) || (!(tmpbuf = malloc(MY_BUFLEN)))) { MakeLogEntry(PRGNAME, MLE_FATAL_ERROR, "Failed allocating my buffers!"); return 20; } tmpnam(mailfilename); tmpnam(tmpfilename); tmpnam(encryptedfilename); argline = GetOriginalCmdLine(argc, argv); /* Re-build the original commandline, because * the real sendmail will need it later. */ /* * Copy standard input to a temporary file for security reasons. */ if (!(mailfh = fopen(mailfilename, "w"))) { MakeLogEntry(PRGNAME, MLE_FATAL_ERROR, "Failed opening %s!", mailfilename); return 20; } while (fgets(tmpbuf, MY_BUFLEN, stdin)) { if (fputs(tmpbuf, mailfh) == EOF) { MakeLogEntry(PRGNAME, MLE_FATAL_ERROR, "Can't write to %s!", mailfilename); return 20; } } fclose(mailfh); mailfh = NULL; MakeLogEntry(PRGNAME, MLE_DEBUG2, "original mail is now in '%s'.", mailfilename); /* * Now that the mail is safe, install an exit handler that pipes the * file to sendmail when we exit, to make sure the mail will not be * lost under error condition. */ if (atexit(sendmail)) { fprintf(stderr, "%s: Could not install my exit handler!\n", PRGNAME); return 20; } /* * Load the mail header for RFC routines. */ if (!(header = malloc(10*1024))) { /* allocate 10k for the mail header */ MakeLogEntry(PRGNAME, MLE_ERROR, "Failed allocating my buffers!"); return 10; } if (!(mailfh = fopen(mailfilename, "r"))) { MakeLogEntry(PRGNAME, MLE_ERROR, "Failed opening %s!", mailfilename); return 10; } tmp = header; while (fgets(tmp, MY_BUFLEN, mailfh)) { if (strlen(tmp) == 1) /* Have we reached the mail body? */ break; tmp += strlen(tmp); } /* * Determine receipients to decide whom to encrypt to. */ receipients = FindReceipients(header); free(header); /* Header isn't needed anymore. */ if (!receipients || (!*receipients)) { MakeLogEntry(PRGNAME, MLE_ERROR, "Can't determine receipient of message."); return 10; } else MakeLogEntry(PRGNAME, MLE_DEBUG2, "receipients (including aliases): %s", ArrayToLine(receipients)); receipients = ExpandAliases(receipients); if (!receipients || (!*receipients)) { MakeLogEntry(PRGNAME, MLE_ERROR, "Can't determine receipient of message."); return 10; } else MakeLogEntry(PRGNAME, MLE_DEBUG2, "receipients (aliases expanded): %s", ArrayToLine(receipients)); MakeDomainAddress(receipients); /* * Check wether all keys are available or not. */ if ((CheckKeyAvailability(receipients)) == 0) { MakeLogEntry(PRGNAME, MLE_DEBUG2, "Not all receipients have a valid public key."); return 0; } /* * Ask user wether this mail should be encrypted or not. */ ptr = GetConfig(NULL, CONFIRMENCRYPTION, NULL, "y"); if (ptr[0] == 'y' || ptr[0] == 'Y') if (!ConfirmEncryption()) { MakeLogEntry(PRGNAME, MLE_INFO, "Encryption denied by user."); return 0; } /* * Copy messagebody for encryption. */ if (!(tmpfh = fopen(tmpfilename, "w"))) { MakeLogEntry(PRGNAME, MLE_ERROR, "Failed opening %s!", tmpfilename); return 5; } while (fgets(tmpbuf, MY_BUFLEN, mailfh)) { /* The fileposition is at the begin of the * mailbody because we read the header earlier. */ if (fputs(tmpbuf, tmpfh) == EOF) { MakeLogEntry(PRGNAME, MLE_ERROR, "Can't write to %s!", tmpfilename); return 5; } } fclose(mailfh); mailfh = NULL; fclose(tmpfh); tmpfh = NULL; /* * Encrypt message body. */ sprintf(tmpbuf, "PGP -ftea <%s >%s %s", tmpfilename, encryptedfilename, ArrayToLine(receipients)); MakeLogEntry(PRGNAME, MLE_DEBUG1, "calling '%s'", tmpbuf); if (rc = system(tmpbuf)) { MakeLogEntry(PRGNAME, MLE_ERROR, "PGP returned error code %ld", rc); return 5; } else MakeLogEntry(PRGNAME, MLE_INFO, "succesfully encrypted the mail for %s", ArrayToLine(receipients)); remove(tmpfilename); /* isn't required anymore */ /* * Call SendMail to handle the message. */ sprintf(tmpbuf, "%s %s", FindConfig(SENDMAIL), argline); MakeLogEntry(PRGNAME, MLE_DEBUG1, "Calling '%s'", tmpbuf); /* * PORT NOTE: Sorry, but I need POpen() again. To make this stuff work on * another platform, you'll have to re-write it completely. */ if (pipe = POpen(tmpbuf, MODE_PIPETO)) { /* Pipe the mail header to sendmail. */ if (tmp_pipe = Open(mailfilename, MODE_OLDFILE)) { while (FGets(tmp_pipe, tmpbuf, MY_BUFLEN)) { FPuts(pipe, tmpbuf); if (strlen(tmpbuf) == 1) /* header is copied completely */ break; } Close(tmp_pipe); /* Pipe the encrypted mail body to sendmail. */ FPuts(pipe, BODY_ID); if (tmp_pipe = Open(encryptedfilename, MODE_OLDFILE)) { while (FGets(tmp_pipe, tmpbuf, MY_BUFLEN)) FPuts(pipe, tmpbuf); Close(tmp_pipe); } exitPipe = 0; /* The mail is sent already, we don't need the sendmail() * exit handler anymore. */ } rc = PClose(pipe); } else { MakeLogEntry(PRGNAME, MLE_ERROR, "Can't send the encrypted mail!"); return 5; } return rc; } /************************************************************************** * * * SECTION: Subroutines * * * **************************************************************************/ /* * This exit handler will free all resources allocated by the program * when we exit to make sure nothing is wasted under error condition. * * PORT NOTE: Contains system-dependant stuff! */ void my_exit(void) { /* Close all open files and delete them afterwards. */ if (mailfh) fclose(mailfh); if (tmpfh) fclose(tmpfh); remove(mailfilename); remove(tmpfilename); remove(encryptedfilename); /* Free all locked files and close the netsupport.library. */ if (NetSupportBase) { UnLockFiles(); CloseLibrary((struct Library *) NetSupportBase); } } /* * Pipe the mailfile to sendmail when we exit. * * PORT NOTE: Because the AmigaOS doen't know popen(), we have to use * the routine from the netsupport.library. For other operating systems * it will be necessary to replace the whole routine! */ void sendmail(void) { BPTR pipe, fh; int len; if (!exitPipe) return; sprintf(tmpbuf, "%s %s", FindConfig(SENDMAIL), argline); MakeLogEntry(PRGNAME, MLE_DEBUG1, "Calling '%s'", tmpbuf); if (pipe = POpen(tmpbuf, MODE_PIPETO)) { /* If the file holding the mail is still open, close it first * to make sure we can access it. */ if (mailfh) { fclose(mailfh); mailfh = NULL; } /* Pipe the whole file to sendmail. */ if (fh = Open(mailfilename, MODE_OLDFILE)) { while (len = Read(fh, tmpbuf, MY_BUFLEN-1)) { if (len == -1L) break; /* Read() failed */ if (Write(pipe, tmpbuf, len) == -1L) break; /* Write() failed */ } Close(fh); } else MakeLogEntry(PRGNAME, MLE_FATAL_ERROR, "Couldn't open mailfile! Mail is lost!!"); PClose(pipe); } else MakeLogEntry(PRGNAME, MLE_FATAL_ERROR, "Couldn't open pipe to sendmail! Mail is lost!!"); } char *ArrayToLine(char *array[]) { char *line; if (!(line = malloc(MY_BUFLEN))) return NULL; line[0] = '\0'; while (*array != NULL) { strcat(line, *array); strcat(line, " "); array++; } return line; } int CheckKeyAvailability(char *receipients[]) { FILE *fh; char *keylist; int filelength; if (*receipients == NULL) return 0; /* No receipient found! */ LockFile(PGPKEYLIST); if ((fh = fopen(PGPKEYLIST, "r")) == NULL) { UnLockFile(PGPKEYLIST); return 0; /* Couldn't open keylist! */ } fseek(fh, 0L, SEEK_END); filelength = ftell(fh); /* Determine filelength. */ /* Allocate buffer and read keylist. */ if (keylist = malloc(filelength+1)) { lseek(fileno(fh), 0, 0); if ((read(fileno(fh), keylist, filelength)) == -1) { fclose(fh); /* Couldn't read keylist. */ UnLockFile(PGPKEYLIST); free(keylist); return 0; } else { /* Read went fine. */ fclose(fh); UnLockFile(PGPKEYLIST); keylist[filelength] = '\0'; while (*receipients != NULL) { if (FindKey(*receipients, keylist) == 0) { free(keylist); MakeLogEntry(PRGNAME, MLE_DEBUG1, "No key available for <%s>.", *receipients); return 0; /* Key is not in keylist. */ } receipients++; } } } free(keylist); return 1; /* Everything is fine. */ } int FindKey(char *key, char *keylist) { char line[MY_BUFLEN]; int i; while (*keylist != '\0') { /* Is this a valid key-line? */ if (!strnicmp(keylist, "pub ", strlen("pub ")) || !strnicmp(keylist, " ", strlen(" "))) { for(i = 0; keylist[i] != '\n'; i++) line[i] = keylist[i]; line[i] = '\0'; if (stristr(line, key)) return 1; } /* Find end of line or end of buffer. */ while (*keylist != '\n' && *keylist != '\0') keylist++; keylist++; } return 0; } char *stristr(char *line, char *key) { int i, cmplen = strlen(key), end = strlen(line)-cmplen; for (i = 0; i <= end; i++) if (strnicmp(&line[i], key, cmplen) == NULL) return &line[i]; return NULL; }