#include "local_scan.h" #include "macros.h" #include #include #include #include #include #include #include #include #define PARENT_READ readpipe[0] #define CHILD_WRITE readpipe[1] #define CHILD_READ writepipe[0] #define PARENT_WRITE writepipe[1] #define MAX_ARGS 16 int remap_pipe_stdin_stdout(int rpipe, int wpipe); int pipe_stream(char *cmd, FILE *fmsg, uschar **yield); extern uschar *tod_stamp(int); extern uschar *spool_directory; static pid_t pid = 0; static int has_timeout = 0; //------------------------------------------------------------------------- int pipe_message(uschar **yield, int argc, uschar *argv[]) { FILE *fmsg; char mbox_path[512]; if (argc != 1) { *yield = string_copy((uschar *)"Bad number of arguments"); return ERROR; } // get message body stream sprintf(mbox_path, "%s/input/%s-D", spool_directory, message_id); fmsg = fopen(mbox_path,"rb"); if (!fmsg) { *yield = string_copy((uschar *)"Unable to spool message"); return ERROR; } (void)fseek(fmsg, SPOOL_DATA_START_OFFSET, SEEK_SET); return pipe_stream((char *)argv[0],fmsg,yield); } //------------------------------------------------------------------------- void timout_alarm(int a) { if (pid) kill(pid,SIGTERM); } //------------------------------------------------------------------------- int pipe_stream(char *cmd, FILE *fmsg, uschar **yield) { FILE *fout; //, *flog; char buffer[1024],exename[512],*args[MAX_ARGS],*s; int nargs,status,res; int writepipe[2], /* parent -> child */ readpipe [2]; /* child -> parent */ header_line *my_headerlist; uschar *address; if (pipe(readpipe) == -1) { fclose(fmsg); *yield = string_copy((uschar *)"Unable to create read pipe"); return ERROR; } if (pipe(writepipe) == -1) { close(CHILD_READ); close(CHILD_WRITE); fclose(fmsg); *yield = string_copy((uschar *)"Unable to create write pipe"); return ERROR; } pid = fork(); if (pid < 0) { fclose(fmsg); close(CHILD_READ); close(CHILD_WRITE); close(PARENT_READ); close(PARENT_WRITE); *yield = string_copy((uschar *)"Unable to fork"); return ERROR; } // Child process --------------------------------------- if (!pid) { // Close unused streams close(PARENT_READ); close(PARENT_WRITE); // Redirect stdin/stdout if (!remap_pipe_stdin_stdout(CHILD_READ,CHILD_WRITE)) { log_write(0,LOG_MAIN,"PIPE: Cannot remap stdin/stdout (%s)",strerror(errno)); _exit(-2); return 0; } // Prepare args strcpy(exename,cmd); strtok(exename," "); args[0] = exename; for (nargs=1; nargs\n", address); write(PARENT_WRITE,buffer,strlen(buffer)); // fprintf(flog,buffer); } address = expand_string(US"${if def:received_for{$received_for}}"); if (!address || !*address) address = expand_string(US"${local_part}@${domain}"); if (address && *address) { sprintf(buffer, "Envelope-To: %s\n", address); write(PARENT_WRITE,buffer,strlen(buffer)); // fprintf(flog,buffer); } sprintf(buffer, "Delivery-date: %s\n", tod_stamp(tod_full)); write(PARENT_WRITE,buffer,strlen(buffer)); //fprintf(flog,buffer); my_headerlist = header_list; for (my_headerlist = header_list; my_headerlist; my_headerlist = my_headerlist->next) { if (my_headerlist->type == '*') continue; write(PARENT_WRITE,my_headerlist->text,my_headerlist->slen); // fprintf(flog,(char *)my_headerlist->text); } // Write message body to pipe write(PARENT_WRITE,"\n",1); //fprintf(flog,"\n"); while (!feof(fmsg) && fgets(buffer,sizeof(buffer),fmsg)) { write(PARENT_WRITE,buffer,strlen(buffer)); // fprintf(flog,buffer); } // Close unused handlers close(PARENT_WRITE); fclose(fmsg); //fclose(flog); // Read from pipe *yield = string_copy((uschar *)""); while (!feof(fout) && fgets(buffer,sizeof(buffer),fout)) { *yield = string_sprintf("%s%s",*yield,buffer); } // Wait for pipe to finish close(PARENT_READ); waitpid(pid,&status,0); // Disable timeout alarm(0); pid = 0; if (has_timeout) { log_write(0,LOG_MAIN,"Pipe timeout expired"); *yield = string_copy((uschar *)"Pipe timeout expired"); return ERROR; } else if (WIFSIGNALED(status)) { log_write(0,LOG_MAIN,"Pipe exited by signal %d",WTERMSIG(status)); *yield = string_sprintf("Pipe exited by signal %d",WTERMSIG(status)); return ERROR; } /* if (WIFEXITED(status)) { res = WEXITSTATUS(status); } */ return OK; } //------------------------------------------------------------------------- int remap_pipe_stdin_stdout(int rpipe, int wpipe) { if (dup2(rpipe, 0) == -1) return 0; close(rpipe); if (dup2(wpipe, 1) == -1) return 0; close(wpipe); return 1; }