/*************************************************************************** * * Copyright 2008 by Sean Conner. * * * 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 3 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, see . * * Comments, questions and criticisms can be sent to: sean@conman.org * *************************************************************************/ /**************************************************************** * * Wrapper program for sendmail for PHP under Apache (may work * on other webservers, but untested). * * To compile: * * You'll need to install my cgilib, available at * http://www.conman.org/software/cgilib/cgilib.tar.gz * * Then: * * gcc -Wall -ansi -pedantic -o wrapper wrapper.c -lcgi5 * * Copy the wrapper program somewhere where Apache can execute it, * then modify /etc/php.ini: * * ; For Unix only. You may supply arguments as well (default: "sendmail -t -i"). * ; sendmail_path = /usr/sbin/sendmail -t -i * sendmail_path = /path/to/wrapper -t -i * * Restart Apache, and Bob's your uncle. * * The wrapper logs information to syslog using the LOG_LOCAL4 facility, * so you may want to check /etc/syslog.conf to make sure you're * logging local4.info (at least) somewhere. * ******************************************************************/ /******************************************************************** * * This program was brought to you by a grant from Pick Internet [1], and * by a grant from HarmonyLogic [2]. Also, by the number 10. * * [1] http://www.pickint.net/ * [2] http://www.harmonylogic.com/ * ********************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*******************************************************/ int main(int argc,char *argv[],char *envp[]) { List headers; Stream tmp; char *hostname; char *workdir; char *to; char *cc; char *bcc; int rc; pid_t child; char tmpfile[BUFSIZ]; int fhin; MemInit(); DdtInit(); StreamInit(); openlog("smw",0,LOG_LOCAL4); /*--------------------------------------------------------- ; copy STDIN to a file. This copy is used twice, once ; to read the headers, then again when we fork() to ; sendmail. ;--------------------------------------------------------*/ sprintf(tmpfile,"/tmp/wrapper.%lu",(unsigned long)getpid()); tmp = FileStreamWrite(tmpfile,FILE_CREATE | FILE_TRUNCATE); StreamCopy(tmp,StdinStream); StreamFree(tmp); /*---------------------------------------------------- ; read in the headers from the email we're sending ;----------------------------------------------------*/ tmp = FileStreamRead(tmpfile); ListInit(&headers); RFC822HeadersRead(tmp,&headers); StreamFree(tmp); hostname = spc_getenv("HOSTNAME"); workdir = spc_getenv("PWD"); to = PairListGetValue(&headers,"TO"); cc = PairListGetValue(&headers,"CC"); bcc = PairListGetValue(&headers,"BCC"); syslog( LOG_INFO, "H: %s W: %s To: %s Cc: %s Bcc: %s", hostname, workdir, to, cc, bcc ); /*-------------------------------------------------- ; we open the file for read mode---this file then ; becomes STDIN for sendmail when we fork()/exec() it ;----------------------------------------------------*/ fhin = open(tmpfile,O_RDONLY); if (fhin == -1) { syslog(LOG_CRIT,"open(%s,READ) = %s",tmpfile,strerror(errno)); exit(EXIT_FAILURE); } child = fork(); if (child == (pid_t)-1) { syslog(LOG_CRIT,"fork() = %s",strerror(errno)); exit(EXIT_FAILURE); } if (child == 0) /* child process */ { char **newargv; int i; /*-------------------------------------------------- ; while argv[] is writable on Linux, it may not be ; on other systems, so just in case, we copy the ; array, so we can swap out the name of the program ; in argv[0] ;-------------------------------------------------*/ newargv = MemAlloc(sizeof(char *) * (argc + 1)); newargv[0] = "sendmail"; for (i = 1 ; i < argc ; i++) newargv[i] = argv[i]; newargv[i] = NULL; /*----------------------------------------------- ; set STDIN to our file, then fork() away ;-----------------------------------------------*/ dup2(fhin,STDIN_FILENO); rc = execve("/usr/sbin/sendmail",newargv,envp); syslog(LOG_CRIT,"execve() = %s",strerror(errno)); exit(EXIT_FAILURE); } else /* parent process */ { pid_t cstat; int status; cstat = waitpid(child,&status,0); if (WIFEXITED(status)) rc = WEXITSTATUS(status); else rc = EXIT_FAILURE; unlink(tmpfile); /* make sure we clean up after ourselves */ exit(rc); } }