/* * File: receive.c * * Author: Ulli Horlacher (framstag@rus.uni-stuttgart.de) * * Contrib.: Christian Recktenwald (chris@yeti.faveve.uni-stuttgart.de) * Rainer Bawidamann (widi@sol.wohnheim.uni-ulm.de) * Beate Herrmann (beate@juhu.lake.de) * Stefan Zehl (sec@42.org) * * History: * * 1995-08-11 Framstag initial version * 1995-08-14 Framstag corrected bug when receiving archives * 1995-09-10 Framstag extracted functions to spool.c * 1995-10-31 Framstag fixed security problems * 1995-11-05 Framstag added NeXT support * 1995-11-07 Framstag corrected bug when receiving to * a non-writable directory * 1995-12-02 Framstag added rename option * 1996-01-15 Framstag better error handling * 1996-02-06 Framstag added ATTRIBUTE=EXE * 1996-02-07 Chris better Convex-OS support * 1996-02-21 widi better Solaris-2 support * 1996-02-22 Framstag added bounce (forward) option * 1996-03-06 Framstag moved time stamp setting to get_date * 1996-03-17 Framstag some bug fixes * 1996-03-27 Framstag added quiet mode: no questions asked * 1996-03-28 Framstag extended search for support programs * 1996-04-01 Framstag corrected forking bug * 1996-04-02 Framstag added verbose bouncing * 1996-04-04 Framstag added check for dangerous file names in archives * 1996-04-05 Framstag correction: 1 KB is now 1024 bytes * 1996-04-08 Framstag added question for renaming better dangerous * file name checking * 1996-04-12 Framstag added pgp support * 1996-04-13 Framstag added -f from option * 1996-04-13 Beate added -s list option * 1996-04-18 Framstag delete empty file when pgp fails * 1996-04-20 Framstag added preserve option for pgp and tar * added -k keep option * 1996-04-22 Framstag some code cleanup * 1996-04-23 Framstag moved fcopy to io.c * 1996-04-24 Framstag changed bouncing option syntax * 1996-05-02 Framstag better tar error checking * 1996-05-12 Framstag better checking of not complete files * 1996-05-23 Framstag added check for writeable tmp-files * 1996-05-26 Framstag fixed bug with overwriting links * fixed bug with returning from fork * 1996-06-24 Framstag added -P to stdout option * 1996-09-13 Framstag added rename option to "."-file checking * 1996-11-26 Framstag substituted all gets() with fgets() * 1996-11-27 Framstag corrected bug when receiving file is not * writable * 1996-12-01 Framstag better file name questioning * 1996-12-20 Framstag don't ask for directory overwriting * 1997-01-20 GNUish modified to reflect the GNUs needs * 1997-02-12 Framstag fixed boolean bugs in receive_sf * 1997-02-20 GNUish renamed error to error_log to support glibc * 1997-02-23 Framstag modified str_* function names * extended with TYPE=MIME * 1997-02-24 Framstag sprintf() -> snprintf() * 1997-06-23 Framstag added readline support * 1997-08-01 Framstag added -S secure option (signature check) * 1997-08-07 Framstag no tar-file checking with quiet-mode * 1997-08-27 Framstag ignore symlink errors when extracting tar files * 1997-09-21 Framstag added multi-spool support and -Z option * 1997-09-30 Framstag corrected list bug * 1997-10-06 Framstag corrected bug with -n -b options together * 1997-11-14 Framstag better verbose mode for system() calls * 1997-12-02 Framstag fixed -b -a conjunction bug * 1997-12-11 Framstag added bzip2 support * 1997-12-16 Sec better xhoppel support for BSD * 1998-03-11 Framstag added -H option to display the headers * 1998-05-10 Framstag added -R option to renumber the spool files * 1999-02-15 Framstag added check for dangerous symbolic links in * archive files * 1999-02-19 Framstag option -L with selecting arguments * 2001-01-10 Framstag fopen() ==> rfopen() * 2001-02-04 Framstag added secure mktmpdir() * * The receive client of the sendfile package. * Receives, lists and deletes files from the sendfile spool. * * Copyright © 1995-2001 Ulli Horlacher * This file is covered by the GNU General Public License */ #include "config.h" /* various #defines */ #ifdef ULTRIX #define S_IFMT 0170000 /* type of file */ #define S_IFDIR 0040000 /* directory */ #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "message.h" /* information, warning and error messages */ #include "utf7.h" /* UTF-7 coding */ #include "io.h" /* read/write routines */ #include "string.h" /* extended string functions */ #include "spool.h" /* operations on files in the sendfile spool */ #include "getline.h" /* get a line of text from stdin */ #include "lock.h" /* file locking */ #if defined(HAVE_GETOPT_H) #include #else int getopt(int, char * const *, const char *); extern int opterr; extern int optind; extern int optopt; extern char *optarg; #endif #ifndef AIX #ifndef CONVEXOS FILE *popen(const char *, const char *); #endif int pclose(FILE *); #endif /* global variables */ char *lll, /* last list line */ *prg, /* name of the game */ *pgpvm, /* pgp verbose mode string */ *verbose, /* verbose mode on bouncing files */ *tmpdir, /* directory for temporary files */ error_log[MAXLEN], /* error log file */ tartmp[MAXLEN], /* tar temporary file */ userspool[MAXLEN], /* user spool directory */ pgp_bin[MAXLEN], /* the pgp binary */ tar_bin[MAXLEN], /* the tar binary */ gzip_bin[MAXLEN], /* the gzip binary */ bzip2_bin[MAXLEN], /* the bzip2 binary */ recode_bin[MAXLEN], /* the recode binary */ metamail_bin[MAXLEN]; /* the metamail binary */ int keep=0, /* flag for keeping files in spool */ pipeout=0, /* flag for receiving to stdout (via pipe) */ quiet=0, /* quiet mode: no questions asked */ client=1, /* flag to determine client or server */ ren=0, /* flag for renaming files */ pgppass=0, /* flag if the pgp password is set as an env variable */ preserve=0, /* preserve pgp and tar attributes */ nometamail=0; /* metamail-usage flag */ mode_t cmask; /* umask value */ /* clean termination routine */ void cleanexit(); /* delete tmp-file */ void cleanup(); /* print short help usage text */ int usage(void); /* list all spool files */ int list(struct senderlist *, int, char *, char *, int, int, char **); /* receive a spool file */ void receive_sf(struct filelist *, char *, int); /* check what to do when file with same name already exists */ int checkfile(int, char *, char *, char *, char *); /* create detached pgp signature file */ int create_sigfile(const char *, const char *, const char *, char *); /* translate NVT format file to Unix text format file */ void crlf2lf(FILE *, FILE *, const char *, const char *); /* spawn a subprocess and direct output to a file */ int spawn(char **, const char *, mode_t); /* shameless plug from GNU fileutils (getdate.c) :-) */ time_t get_date(char *, void *); /* check or print pgp signature */ int check_signature(struct filelist *, char *, int); /* renumber spool files */ void renumber(struct senderlist *); int main(int argc, char *argv[]) { int i, /* simple loop count */ number, /* flag for specifying a spool file number */ listformat, /* format of listing */ del, /* flag for deleting */ all, /* flag for receiving all */ header, /* flag for receiving only the header (to stdout) */ id, /* spool id */ found, /* flag for found spool id */ opt; /* option to test for */ char *cp, /* a simple string pointer */ bounce[FLEN], /* bounce address */ from[FLEN], /* from which sender */ pgpring[FLEN], /* flag for receiveing only signed files */ tmp[3*MAXLEN], /* temporary string */ fname[MAXLEN], /* displayble file name */ bouncelist[MAXLEN], /* list of spool files to bounce */ pattern[MAXLEN]; /* file name pattern to search for */ struct stat finfo; /* information about a file */ struct passwd *pwe; /* password entry */ struct filelist *flp; /* file list pointer */ struct senderlist *sls, /* sender list start */ *slp; /* sender list pointer */ FILE *inf; del=0; all=0; found=0; number=0; header=0; listformat=0; lll=""; verbose=""; *bounce=0; *pgpring=0; *userspool=0; *bouncelist=0; strcpy(from,"*"); cmask=umask(0); umask(cmask); /* get program name */ prg=argv[0]; if ((cp=strrchr(prg,'/'))) prg=cp+1; /* get pgp password environment variable */ if (getenv("PGPPASS")) { pgppass=1; pgpvm="+verbose=0"; } else { pgppass=0; pgpvm="+verbose=1"; } /* get metamail usage environment variable */ if (getenv("NOMETAMAIL")) nometamail=1; /* scan the command line */ while ((opt=getopt(argc,argv,"h?lLsndarRVvqpkHPS:f:Z:b:")) > 0) { switch (opt) { case ':': case 'h': case '?': exit(usage()); case 's': listformat=1; break; case 'l': listformat=2; break; case 'L': listformat=3; break; case 'n': number=1; break; case 'r': ren=1; break; case 'R': ren=2; break; case 'd': del=1; break; case 'a': all=1; break; case 'P': pipeout=1; break; case 'k': keep=1; break; case 'q': quiet=1; break; case 'p': preserve=1; break; case 'H': header=1; break; case 'S': snprintf(MAXS(pgpring),"%s",optarg); break; case 'v': verbose="-v"; break; case 'f': snprintf(MAXS(from),"%s",optarg); break; case 'b': snprintf(MAXS(bounce),"%s",optarg); break; case 'Z': snprintf(MAXS(userspool),"%s",optarg); break; case 'V': message(prg,'I',"version "VERSION" revision "REVISION""); exit(0); } } /* no arguments? */ if (optind==argc && !all && !listformat) { listformat=2; lll="Type \"receive -a\" to receive all files or \"receive -h\" " "for a short help.\n\n"; } /* too few arguments? */ if ((argc-optind==0 && !all && ren<2 && (ren || del || (!str_eq(from,"*") && !listformat))) || (argc-optind>0 && ((*bounce && all) || ren==2)) || (argc-optind<1 && *bounce && !all)) exit(usage()); /* get the own user name */ if ((pwe=getpwuid(getuid())) == NULL) message(prg,'F',"cannot determine own user name"); /* determine the spool directory */ if (!*userspool) { if ((cp=getenv("SF_SPOOL"))) { snprintf(MAXS(userspool),"%s",cp); } else { snprintf(MAXS(userspool),"%s/.sfspool",pwe->pw_dir); if (stat(userspool,&finfo)<0 || !(finfo.st_mode&S_IFDIR)) snprintf(MAXS(userspool),SPOOL"/%s",pwe->pw_name); } } if (*userspool=='Z') snprintf(MAXS(userspool),SPOOL"/%s",pwe->pw_name); /* does the spool directory exist? */ if (stat(userspool,&finfo)<0 || (finfo.st_mode&S_IFMT)!=S_IFDIR) { snprintf(MAXS(tmp),"spool directory %s does not exist",userspool); errno=0; message(prg,'E',tmp); exit(1); } /* correct permissions for the spool directory? */ if (!(finfo.st_mode&S_IRWXU) || finfo.st_uid!=getuid()) { snprintf(MAXS(tmp), "no access to spool directory %s (wrong permissions)", userspool); errno=0; message(prg,'F',tmp); exit(1); } /* are there any files to receive? */ sls=scanspool(from); if (sls==NULL) { snprintf(MAXS(tmp),"no files found in spool directory %s",userspool); message(prg,'W',tmp); exit(1); } if (ren==2) { renumber(sls); sls=scanspool(""); } /* set log file read status (st_atime) for xhoppel */ snprintf(MAXS(tmp),"%s/log",userspool); inf=rfopen(tmp,"r"); if (inf) { fgetl(tmp,inf); fclose(inf); } /* incompatible options? */ if (*bounce) { if (listformat||ren||del||preserve) message(prg,'W',"you cannot use any other option " "when bouncing a file - ignored"); listformat=ren=del=0; } if (!str_eq(from,"*") && number) message(prg,'W',"ignoring -f option when specifying a spool number"); if (del&&keep) message(prg,'F',"you cannot delete and keep a file at the same time"); /* support programs defaults */ strcpy(pgp_bin,PGP); strcpy(tar_bin,TAR); strcpy(gzip_bin,GZIP); strcpy(bzip2_bin,BZIP2); strcpy(recode_bin,RECODE); strcpy(metamail_bin,RECODE); /* look for environment variables */ if ((cp=getenv("SF_PGP"))) strcpy(pgp_bin,cp); if ((cp=getenv("SF_TAR"))) strcpy(tar_bin,cp); if ((cp=getenv("SF_GZIP"))) strcpy(gzip_bin,cp); if ((cp=getenv("SF_BZIP2"))) strcpy(bzip2_bin,cp); if ((cp=getenv("SF_RECODE"))) strcpy(recode_bin,cp); if ((cp=getenv("SF_METAMAIL"))) strcpy(metamail_bin,cp); /* do the support programs really exist? */ if (access(pgp_bin,X_OK)<0) strcpy(pgp_bin,"pgp"); if (access(tar_bin,X_OK)<0) strcpy(tar_bin,"tar"); if (access(gzip_bin,X_OK)<0) strcpy(gzip_bin,"gzip"); if (access(bzip2_bin,X_OK)<0) strcpy(bzip2_bin,"bzip2"); if (access(recode_bin,X_OK)<0) strcpy(recode_bin,"recode"); if (access(metamail_bin,X_OK)<0) strcpy(metamail_bin,"metamail"); /* enable simple interrupt handler */ signal(SIGTERM,cleanexit); signal(SIGABRT,cleanexit); signal(SIGQUIT,cleanexit); signal(SIGHUP,cleanexit); signal(SIGINT,cleanexit); /* set tmp file names */ tmpdir=mktmpdir(strlen(verbose)); snprintf(MAXS(tartmp),"%s/receive.tar",tmpdir); snprintf(MAXS(error_log),"%s/error.log",tmpdir); /* list files? */ if (listformat) { if (list(sls,listformat,from,pgpring,number,argc,argv)<0) { snprintf(MAXS(tmp),"no files in spool directory %s",userspool); message(prg,'W',tmp); } cleanup(); exit(0); } /* number specified? */ if (number) { /* loop over all args */ for (i=optind; inext) { /* loop over files list */ for (flp=slp->flist; flp!=NULL && found==0; flp=flp->next) { /* spool id found and spool file complete? */ if (flp->id==id && flp->csize==flp->tsize) { /* delete, bounce or receive spool file? */ if (del) delete_sf(flp,1); else if (*bounce) { if (*bouncelist) { snprintf(MAXS(tmp),"%s %d",bouncelist,id); strcpy(bouncelist,tmp); } else snprintf(MAXS(bouncelist),"%d",id); } else receive_sf(flp,pgpring,header); found=1; } } } /* not found? */ if (!found && id) { snprintf(MAXS(tmp),"spool file #%d not found",id); message(prg,'W',tmp); } } } else /* file name specified */ { /* loop over all args */ for (i=optind; inext) { /* loop over files list */ for (flp=slp->flist; flp!=NULL; flp=flp->next) { /* spool file incomplete? */ if (flp->csize!=flp->tsize) continue; /* translate UTF-7 name to the displayable file name */ utf2iso(1,NULL,fname,NULL,flp->fname); /* match? */ if (simplematch(fname,pattern,0)==1) { /* delete, bounce or receive spool file? */ if (del) delete_sf(flp,1); else if (*bounce) { if (*bouncelist) { snprintf(MAXS(tmp),"%s %d",bouncelist,flp->id); strcpy(bouncelist,tmp); } else snprintf(MAXS(bouncelist),"%d",flp->id); } else receive_sf(flp,pgpring,header); found=1; } } } /* not found? */ if (!found && !all) { snprintf(MAXS(tmp),"file %s not found",pattern); message(prg,'W',tmp); } all=0; } } /* files to bounce? */ if (*bounce && *bouncelist) { if (keep) snprintf(MAXS(tmp), "sendfile -bk=y %s %s %s",verbose,bouncelist,bounce); else snprintf(MAXS(tmp), "sendfile -bk=n %s %s %s",verbose,bouncelist,bounce); if (*verbose) printf("call: %s\n",tmp); system(tmp); } cleanup(); exit(0); } /* * list - list spool files with attributes * * INPUT: sls - sender list start * format - format of listing * from - select from user * pgpring - pgp ring file * number - getopt number flag * argc - from main() * argv - from main() * * RETURN: 0 if files found, -1 if no files to list */ int list(struct senderlist *sls, int format, char *from, char *pgpring, int number, int argc, char *argv[]) { int i, /* simple loop counter */ found, /* flag for files found */ mff, /* matching file flag */ fff; /* first file flag */ char *cp1,*cp2, /* simple character pointer */ line[MAXLEN], /* line to read in */ showtar[MAXLEN], /* shell command to look inside tar archive */ show_fname[MAXLEN]; /* file name to display */ struct senderlist *slp; /* sender list pointer */ struct filelist *flp; /* file list pointer */ FILE *pp; /* pipe input stream */ found=0; /* loop over sender list */ for (slp=sls; slp!=NULL; slp=slp->next) { /* match this sender? */ if (simplematch(slp->from,from,1)==1) { /* loop over files list */ for (flp=slp->flist,fff=1; flp!=NULL; flp=flp->next) { /* file not completly transfered? */ if (flp->csize!=flp->tsize) continue; /* wanted by CLI options? */ if (optindid) { mff = 1; break; } } else { if (simplematch(flp->fname,argv[i],0)==1) { mff = 1; break; } } } /* file is not selected by the user, try next one */ if (!mff) continue; } if (!found && format>1) printf("\nFiles in spool directory %s :\n",userspool); found=1; /* first file from this sender? */ if (fff) { fff=0; /* print from header */ printf("\nFrom %s\n",slp->from); for (i=1; i<80 && i<=strlen(slp->from)+5; i++) printf("-"); printf("\n"); } /* print spool file informations */ utf2iso(1,NULL,show_fname,NULL,flp->fname); printf("%3d) %s %8lu kB %s", flp->id,flp->rdate,(flp->osize+1023)/1024,show_fname); if (format>1) { /* tar archive, MIME file or encrypted? */ if (flp->flags&F_TAR && flp->flags&F_CRYPT) printf(" (archive,encrypted)"); else if (flp->flags&F_MIME && flp->flags&F_CRYPT) printf(" (MIME,encrypted)"); else if (flp->flags&F_MIME) printf(" (MIME)"); else if (flp->flags&F_TAR) printf(" (archive)"); else if (flp->flags&F_CRYPT) printf(" (encrypted)"); } printf("\n"); /* check signature */ if (*(flp->sign) && format>1) check_signature(flp,pgpring,1); /* comment available? */ cp1=flp->comment; if (*cp1 && format>1) { while ((cp2=strchr(cp1,'\n'))) { *cp2=0; printf(" \"%s\"\n",cp1); cp1=cp2+1; } printf(" \"%s\"\n",cp1); } /* on verbose mode look inside tar */ if (flp->flags&F_TAR && format==3 && !(flp->flags&F_CRYPT && (quiet || preserve) && !pgppass)) { /* encrypted, compressed or normal tar file? */ if (flp->flags&F_CRYPT) snprintf(MAXS(showtar),"%s %s -f < %s/%d.d | %s tvf -", pgp_bin,pgpvm,userspool,flp->id,tar_bin); else if (flp->flags&F_COMPRESS) { if (str_eq(flp->compress,S_BZIP2)) snprintf(MAXS(showtar),"%s -d < %s/%d.d | %s tvf -", bzip2_bin,userspool,flp->id,tar_bin); else snprintf(MAXS(showtar),"%s -d < %s/%d.d | %s tvf -", gzip_bin,userspool,flp->id,tar_bin); } else snprintf(MAXS(showtar),"%s tvf %s/%d.d",tar_bin,userspool,flp->id); /* sneak inside... */ if (*verbose) printf("call: %s\n",showtar); if ((pp=popen(showtar,"r")) == NULL) message(prg,'E',"contents of archive is not accessible"); else { if (flp->flags&F_CRYPT && !pgppass && fgetl(line,pp)) printf("\n\n %s",line); while (fgetl(line,pp)) printf(" %s",line); if (flp->flags&F_CRYPT && !pgppass) printf("\n"); } pclose(pp); } } } } if (found) { printf("\n%s",lll); return(0); } else return(-1); } /* * receive_sf - receive a spool file * * INPUT: flp - file list element * pgpring - pgp ring file (force pgp signature checking) * header - flag for receiving onnly the header to stdout */ void receive_sf(struct filelist *flp, char *pgpring, int header) { int utf, /* return code from utf2iso */ terr, /* tar error flag */ tom; /* tar overwrite message flag */ char *cp, /* simple character pointer */ *sad[10], /* spawn argument descriptor */ answer[FLEN], /* answer string */ line[MAXLEN], /* one line of text */ tmp[2*MAXLEN], /* temporary string */ tmpfile[MAXLEN], /* temporary file name */ cmd[2*MAXLEN], /* command string for system() */ sfile[MAXLEN], /* spool data file */ danger[OVERSIZE], /* dangerous file names */ fname[MAXLEN], /* file name to write */ nname[MAXLEN], /* file name in display format */ sname[MAXLEN]; /* file name in shell handling format */ static char overwrite='n'; /* overwrite mode */ struct stat finfo; /* information about a file */ struct utimbuf utb; /* binary time */ time_t dummy; /* dummy arg for localtime() */ FILE *pp, /* pipe input stream */ *inf, /* spool data file to read */ *outf; /* file to create */ tom=0; terr=0; *danger=0; *answer=0; /* oops? */ if (flp==NULL) return; /* translate UTF-7 file name */ utf=utf2iso(1,fname,nname,sname,flp->fname); fname[FLEN-1]=nname[FLEN-1]=sname[FLEN-1]=0; if (*pgpring) { switch (check_signature(flp,pgpring,0)) { case 1: break; case 0: snprintf(MAXS(tmp),"no signature found for '%s'",nname); errno=0; message(prg,'E',tmp); return; case -1: snprintf(MAXS(tmp),"no public key found to check " "signature for '%s'",nname); errno=0; message(prg,'E',tmp); return; case -2: snprintf(MAXS(tmp),"bad signature for '%s'",nname); errno=0; message(prg,'E',tmp); return; default: return; } } /* determine overwrite mode */ if (quiet) overwrite='Y'; if (!strchr("YNS",overwrite)) overwrite='n'; (void) localtime(&dummy); /* show only the header? */ if (header) { snprintf(MAXS(tmp),"%s/%d.h",userspool,flp->id); printf("%d) %s\n",flp->id,nname); inf=rfopen(tmp,"r"); while (fgetl(line,inf)) printf("%s",line); printf("\n"); fclose(inf); return; } /* pipe to stdout? */ if (pipeout) { /* encrypted spool file? */ if (flp->flags&F_CRYPT) { snprintf(MAXS(cmd),"%s %s -f < %s/%d.d",pgp_bin,pgpvm,userspool,flp->id); if (*verbose) printf("call: %s\n",cmd); if (system(cmd)!=0) { errno=0; snprintf(MAXS(tmp),"cannot decrypt '%s' :",nname); message(prg,'E',tmp); return; } } /* compressed spool file? */ else if (flp->flags&F_COMPRESS) { if (str_eq(flp->compress,S_BZIP2)) snprintf(MAXS(cmd),"%s -d < %s/%d.d",bzip2_bin,userspool,flp->id); else snprintf(MAXS(cmd),"%s -d < %s/%d.d",gzip_bin,userspool,flp->id); if (*verbose) printf("call: %s\n",cmd); if (system(cmd)!=0 && !(flp->flags&F_TAR)) { errno=0; snprintf(MAXS(tmp),"cannot decompress '%s' :",nname); message(prg,'E',tmp); return; } } else /* copy spool file to stdout */ { /* copy file */ snprintf(MAXS(tmp),"%s/%d.d",userspool,flp->id); if (fcopy(tmp,"",0)<0) { errno=0; snprintf(MAXS(tmp),"cannot read '%s'",nname); message(prg,'E',tmp); return; } } /* delete tar spool file if required */ if (!keep) delete_sf(flp,0); return; } /* tar file to receive? */ if (flp->flags&F_TAR) { /* save file in transfer shape? */ if (preserve) { /* set new file name */ fname[FLEN-12]=nname[FLEN-12]=sname[FLEN-12]=0; strcat(fname,".tar"); strcat(nname,".tar"); strcat(sname,".tar"); if (flp->flags&F_COMPRESS) { strcat(fname,".gz"); strcat(nname,".gz"); strcat(sname,".gz"); } if (flp->flags&F_CRYPT) { strcat(fname,".pgp"); strcat(nname,".pgp"); strcat(sname,".pgp"); } /* if file with same name already exists check what to do */ if (!quiet && checkfile(utf,fname,nname,sname,&overwrite)) return; /* copy file */ snprintf(MAXS(tmp),"%s/%d.d",userspool,flp->id); if (fcopy(tmp,fname,0666&~cmask)<0) { snprintf(MAXS(tmp),"cannot receive '%s'",nname); errno=0; message(prg,'E',tmp); return; } /* pgp signature to save? */ create_sigfile(flp->sign,fname,nname,&overwrite); if (!keep) delete_sf(flp,0); snprintf(MAXS(tmp),"'%s' received",nname); message(prg,'I',tmp); return; } /* encrypted tar spool file? */ if (flp->flags&F_CRYPT) { snprintf(MAXS(cmd),"%s %s -f < %s/%d.d > %s", pgp_bin,pgpvm,userspool,flp->id,tartmp); /* create temporary decrypted tar file */ if (*verbose) printf("call: %s\n",cmd); system(cmd); if (stat(tartmp,&finfo)<0 || finfo.st_size==0) { errno=0; snprintf(MAXS(tmp),"cannot decrypt '%s' :",nname); message(prg,'E',tmp); return; } if (!pgppass) printf("\n\n"); } /* test on (dangerous) symbolic links in tar file */ /* compressed, encrypted or normal tar file? */ if (flp->flags&F_COMPRESS) { if (str_eq(flp->compress,S_BZIP2)) snprintf(MAXS(cmd),"%s -d < %s/%d.d | %s tvf -", bzip2_bin,userspool,flp->id,tar_bin); else snprintf(MAXS(cmd),"%s -d < %s/%d.d | %s tvf -", gzip_bin,userspool,flp->id,tar_bin); } else if (flp->flags&F_CRYPT) { snprintf(MAXS(cmd),"%s tvf %s",tar_bin,tartmp); } else { snprintf(MAXS(cmd),"%s tvf %s/%d.d",tar_bin,userspool,flp->id); } /* open pipe to read tar file-info */ if (*verbose) printf("call: %s\n",cmd); if ((pp=popen(cmd,"r")) == NULL) { message(prg,'E',"cannot open spool file for reading"); return; } /* loop over all files in tar archive */ while (fgetl(line,pp)) { if ((cp=strchr(line,'\n'))) *cp=0; /* is it a (dangerous) symbolic link? */ if (*line == 'l') { if (strlen(danger)+strlen(line)+4 > sizeof(danger)) { snprintf(MAXS(tmp), "archive %s has too many dangerous file names inside", nname); message(prg,'F',tmp); } strcat(danger,"\n "); strcat(danger,line); } } pclose(pp); /* test on dangerous file namess in tar file */ /* compressed, encrypted or normal tar file? */ if (flp->flags&F_COMPRESS) { if (str_eq(flp->compress,S_BZIP2)) snprintf(MAXS(cmd),"%s -d < %s/%d.d | %s tf -", bzip2_bin,userspool,flp->id,tar_bin); else snprintf(MAXS(cmd),"%s -d < %s/%d.d | %s tf -", gzip_bin,userspool,flp->id,tar_bin); } else if (flp->flags&F_CRYPT) { snprintf(MAXS(cmd),"%s tf %s",tar_bin,tartmp); } else { snprintf(MAXS(cmd),"%s tf %s/%d.d",tar_bin,userspool,flp->id); } /* open pipe to read tar file-info */ if (*verbose) printf("call: %s\n",cmd); if ((pp=popen(cmd,"r")) == NULL) { message(prg,'E',"cannot open spool file for reading"); return; } /* loop over all files in tar archive */ while (fgetl(fname,pp)) { /* does the file already exist? */ if ((cp=strchr(fname,'\n'))) *cp=0; if (overwrite!='Y' && stat(fname,&finfo)==0 && !S_ISDIR(finfo.st_mode)) { if (!tom) printf("Archive '%s' will overwrite:\n",nname); tom=1; printf(" %s\n",fname); } /* is it a dangerous file name? */ if (strstr(fname,"../") || strstr(fname,"/.") || fname[0]=='/' || (fname[0]=='.' && fname[1]!='/')) { if (strlen(danger)+strlen(fname)+4 > sizeof(danger)) { snprintf(MAXS(tmp), "archive %s has too many dangerous file names inside", nname); message(prg,'F',tmp); } strcat(danger,"\n "); strcat(danger,fname); } } pclose(pp); /* ask user for overwriting */ if (tom && overwrite!='Y') { printf("Overwrite (yYnN)? "); fgetl(answer,stdin); overwrite=answer[0]; if (toupper(overwrite)!='Y') return; } /* ask user for extracting dangerous files */ if (*danger && overwrite!='Y') { printf("Archive contains files with dangerous names:%s\n",danger); printf("Continue with receiving (yYnN)? "); fgetl(tmp,stdin); overwrite=tmp[0]; if (toupper(overwrite)!='Y') return; } /* receive from tar file */ snprintf(MAXS(tmp),"receiving from archive '%s' :",nname); message(prg,'I',tmp); /* compressed, encrypted or normal tar file? */ if (flp->flags&F_COMPRESS) { if (str_eq(flp->compress,S_BZIP2)) snprintf(MAXS(cmd),"%s -d < %s/%d.d | %s xvf - 2>%s", bzip2_bin,userspool,flp->id,tar_bin,error_log); else snprintf(MAXS(cmd),"%s -d < %s/%d.d | %s xvf - 2>%s", gzip_bin,userspool,flp->id,tar_bin,error_log); } else if (flp->flags&F_CRYPT) snprintf(MAXS(cmd),"%s xvf %s 2>%s",tar_bin,tartmp,error_log); else snprintf(MAXS(cmd),"%s xvf %s/%d.d 2>%s", tar_bin,userspool,flp->id,error_log); /* receive tar archive and check for errors */ terr=0; if (*verbose) printf("call: %s\n",cmd); system(cmd); if (stat(error_log,&finfo)==0 && finfo.st_size>10) { errno=0; inf=rfopen(error_log,"r"); while (fgetl(line,inf)) { if (str_beq(TAR": ",line) && !simplematch(line,TAR": Could not create symlink*File exists*",1)) { if (!terr) { terr=1; snprintf(MAXS(tmp),"errors while receive '%s' :",nname); message(prg,'E',tmp); } printf("%s",line); } } fclose(inf); } /* was there an error with tar? */ if (terr) { snprintf(MAXS(tmp),"leaving '%s' in spool intact",nname); message(prg,'I',tmp); } else { /* delete tar spool file */ if (!keep) delete_sf(flp,0); } cleanup(); return; } /* receive non-tar file */ /* save file in transfer shape? */ if (preserve && flp->flags&F_CRYPT) { fname[FLEN-5]=nname[FLEN-5]=sname[FLEN-5]=0; strcat(fname,".pgp"); strcat(nname,".pgp"); strcat(sname,".pgp"); } /* if file with same name already exists check what to do */ if (!quiet && checkfile(utf,fname,nname,sname,&overwrite)) return; /* leading . in file name? */ if (!strchr("yYr",overwrite) && fname[0]=='.') { /* skipping? */ if (overwrite=='S' || overwrite=='N') return; /* ask user what to do */ printf("'%s' starts with a '.' which may be dangerous\n",nname); printf("Receive it anyway (yY), rename (r) or skip (sS) it? "); fgetl(answer,stdin); overwrite=answer[0]; /* skipping this file? */ if (toupper(overwrite)=='S') return; /* request for renaming? */ if (overwrite=='r') { sprintf(fname,"Rename '%s' to? ",nname); if (getpromptline(fname,MAXLEN-1)==NULL || *fname=='\n' || *fname==0) strcpy(fname,nname); if ((cp=strrchr(fname,'\n'))) *cp=0; strcpy(nname,fname); } } /* safety fallback: try to delete an old file with the same name */ unlink(fname); if (stat(fname,&finfo)==0) { snprintf(MAXS(tmp),"cannot create '%s' : " "file does already exist and is not deletable",fname); errno=0; message(prg,'E',tmp); return; } /* save file encrypted? */ if (preserve && flp->flags&F_CRYPT) { /* copy file */ snprintf(MAXS(tmp),"%s/%d.d",userspool,flp->id); if (fcopy(tmp,fname,0666&~cmask)<0) { snprintf(MAXS(tmp),"cannot receive '%s'",nname); errno=0; message(prg,'E',tmp); return; } if ((flp->flags&F_SOURCE || flp->flags&F_TEXT) && !quiet) { snprintf(MAXS(tmp), "'%s' has a SOURCE or TEXT attribute, you have to decode it " "after pgp-decrypting with: recode %s:"CHARSET" '%s'", nname,flp->charset,nname); message(prg,'W',tmp); } if (flp->flags&F_MIME && !quiet) { snprintf(MAXS(tmp), "'%s' has the MIME attribute, you have to run it through" "metamail after pgp-decrypting",nname); message(prg,'W',tmp); } /* pgp signature to save? */ create_sigfile(flp->sign,fname,nname,&overwrite); if (!keep) delete_sf(flp,0); snprintf(MAXS(tmp),"'%s' received",nname); message(prg,'I',tmp); return; } /* spool file compressed or encrypted? */ if (flp->flags&F_COMPRESS || flp->flags&F_CRYPT) { /* source, text or MIME format? */ if ((flp->flags&F_SOURCE) || (flp->flags&F_TEXT) || (flp->flags&F_MIME)) { /* open pipe to uncompress or decrypt spool file */ if (flp->flags&F_COMPRESS) { if (str_eq(flp->compress,S_BZIP2)) snprintf(MAXS(cmd),"%s -d < %s/%d.d",bzip2_bin,userspool,flp->id); else snprintf(MAXS(cmd),"%s -d < %s/%d.d",gzip_bin,userspool,flp->id); } else if (flp->flags&F_CRYPT) snprintf(MAXS(cmd), "%s %s -f < %s/%d.d",pgp_bin,pgpvm,userspool,flp->id); if (*verbose) printf("call: %s\n",cmd); if ((pp=popen(cmd,"r")) == NULL) { message(prg,'E',"cannot open spool file for reading"); return; } /* open output file */ if (!(outf=rfopen(fname,"w"))) { pclose(pp); printf("\n"); snprintf(MAXS(tmp),"cannot open '%s' for writing",nname); message(prg,'E',tmp); return; } /* translate CR LF to LF and write to output file */ crlf2lf(pp,outf,fname,nname); /* ready */ pclose(pp); fclose(outf); if (flp->flags&F_CRYPT && !pgppass) printf("\n\n"); } else /* binary format */ { snprintf(MAXS(sfile),"%s/%d.d",userspool,flp->id); /* try to create destination file */ /* open output file */ if (!(outf=rfopen(fname,"w"))) { snprintf(MAXS(tmp),"cannot open '%s' for writing",nname); message(prg,'E',tmp); return; } fclose(outf); /* compressed spool file? */ if (flp->flags&F_COMPRESS) { /* uncompress and receive binary file */ /* stupid bzip2 NEEDS file from stdin */ if (str_eq(flp->compress,S_BZIP2)) { strcpy(tmp,fname); if ((cp=strrchr(tmp,'/'))) *++cp=0; else *tmp=0; snprintf(MAXS(tmpfile),"%sreceive-%d.tmp",tmp,(int)getpid()); snprintf(MAXS(tmp),"%s -d < %s > %s",bzip2_bin,sfile,tmpfile); if (system(tmp)) { snprintf(MAXS(tmp),"call to %s failed, cannot receive '%s'", bzip2_bin,nname); message(prg,'E',tmp); return; } if (rename(tmpfile,fname)<0) { snprintf(MAXS(tmp),"cannot write to '%s'",nname); message(prg,'E',tmp); unlink(tmpfile); return; } } else { /* gzip format */ sad[0]=gzip_bin; sad[1]="-dc"; sad[2]=sfile; sad[3]=NULL; if (spawn(sad,fname,cmask)<0) { errno=0; snprintf(MAXS(tmp), "call to %s failed, cannot receive '%s'",sad[0],nname); message(prg,'E',tmp); return; } } } /* encrypted spool file? */ if (flp->flags&F_CRYPT) { snprintf(MAXS(cmd),"%s %s -f < %s > '%s'",pgp_bin,pgpvm,sfile,fname); if (*verbose) printf("call: %s\n",cmd); if (system(cmd)!=0) { errno=0; snprintf(MAXS(tmp),"cannot receive '%s', pgp failed",nname); message(prg,'E',tmp); unlink(fname); return; } if (!pgppass) printf("\n\n"); } } } else /* not compressed and not encrypted or keep encryption */ { /* source, text or MIME format? */ if (((flp->flags&F_SOURCE) || (flp->flags&F_TEXT) || (flp->flags&F_MIME)) && !(flp->flags&F_CRYPT)) { /* open input file */ snprintf(MAXS(sfile),"%s/%d.d",userspool,flp->id); if ((inf=rfopen(sfile,"r")) == NULL) { message(prg,'E',"cannot open spool file for reading"); return; } /* open output file */ if ((outf=rfopen(fname,"w")) == NULL) { snprintf(MAXS(tmp),"cannot open '%s' for writing",nname); message(prg,'E',tmp); fclose(inf); return; } /* translate CR LF to LF and write to output file */ crlf2lf(inf,outf,fname,nname); /* ready */ fclose(inf); fclose(outf); } else /* binary file */ { /* copy file */ snprintf(MAXS(tmp),"%s/%d.d",userspool,flp->id); if (fcopy(tmp,fname,0666&~cmask)<0) { snprintf(MAXS(tmp),"cannot receive '%s'",nname); errno=0; message(prg,'E',tmp); return; } } } /* pgp signature to save? */ /* no more needed, because already saved in transfer shape! if (preserve) create_sigfile(flp->sign,fname,nname,&overwrite); */ /* executable flag set? */ if (flp->flags&F_EXE) chmod(fname,(S_IRWXU|S_IRWXG|S_IRWXO)&~cmask); snprintf(MAXS(tmp),"'%s' received",nname); message(prg,'I',tmp); /* foreign character set in text file? */ if ((flp->flags&F_TEXT) && !str_eq(flp->charset,CHARSET)) { /* call GNU recode */ snprintf(MAXS(tmp),"%s:"CHARSET,flp->charset); sad[0]=recode_bin; sad[1]=tmp; sad[2]=fname; sad[3]=NULL; if (spawn(sad,NULL,cmask)<0) { snprintf(MAXS(tmp), "call to %s failed, cannot translate character set in '%s'", recode_bin,nname); message(prg,'E',tmp); } } /* set the original date */ if (*(flp->date)) { if (!strstr(flp->date,"UTC")) strcat(flp->date," UTC"); utb.actime=utb.modtime=get_date(flp->date,NULL); utime(fname,&utb); } /* MIME? */ if (flp->flags&F_MIME) { /* metamail call allowed? */ if (nometamail) { snprintf(MAXS(tmp), "'%s' is a MIME file, you have to run it through metamail", nname); message(prg,'I',tmp); if (!keep) delete_sf(flp,0); } else { /* call metamail */ sad[0]=metamail_bin; sad[1]=fname; sad[2]=NULL; if (spawn(sad,NULL,cmask)<0) { snprintf(MAXS(tmp), "call to %s failed, keeping local file '%s'", metamail_bin,nname); message(prg,'E',tmp); } else { /* delete spool file and received MIME-file*/ if (!keep) delete_sf(flp,0); if (!nometamail) unlink(fname); } } } else /* delete spool file */ if (!keep) delete_sf(flp,0); } /* * crlf2lf - translate NVT format file to Unix text format file * * INPUT: inf - file to read from * outf - file to write to * fname - file name to write */ void crlf2lf(FILE *inf, FILE *outf, const char *fname, const char *nname) { int c1,c2; /* characters to read in */ char tmp[MAXLEN]; /* temporary string */ /* read first char */ c1=fgetc(inf); /* loop until EOF */ while ((c2=fgetc(inf)) != EOF) { /* crlf? */ if (c1=='\r' && c2=='\n') { /* write lf */ if(fputc(c2,outf)==EOF) { snprintf(MAXS(tmp),"cannot write to %s",nname); message(prg,'E',tmp); return; } /* read next char */ if ((c2=fgetc(inf)) == EOF) return; } else { /* write char */ if(fputc(c1,outf)==EOF) { snprintf(MAXS(tmp),"cannot write to %s",nname); message(prg,'E',tmp); return; } } c1=c2; } /* write last char */ if(fputc(c1,outf)==EOF) { snprintf(MAXS(tmp),"cannot write to %s",nname); message(prg,'E',tmp); return; } } /* * spawn - spawn a subprocess and direct output to a file * * INPUT: sad - spawn argument descriptor * output - output file * cmask - protection mask * * RETURN: 0 on success, -1 on failure * */ int spawn(char **sad, const char *output, mode_t cmask) { int status, /* fork status */ fd; /* output file descriptor */ pid_t pid; /* process id */ /* spawn subprocess */ pid=fork(); /* failed? */ if (pid<0) { message(prg,'E',"cannot fork subprocess"); return(-1); } /* is this the subprocess? */ if (pid==0) { /* redirect stdout? */ if (output) { /* close stdout */ close(1); /* open output file as stdout */ fd=creat(output,0666&~cmask); if (fd!=1) { errno=0; message(prg,'E',"file descriptor mismatch"); cleanup(); exit(1); } } /* execute program */ execvp(sad[0],sad); /* oops - failed */ message(prg,'F',"execvp() failed!"); cleanup(); exit(2); } /* wait for termination of subprocess */ #ifdef NEXT wait(&status); #else waitpid(pid,&status,0); #endif /* error in subprocess? */ if (status) return(-1); return(0); } /* * cleanexit - clean termination routine (only called by signal handler) */ void cleanexit() { printf("\r\n"); cleanup(); exit(4); } /* * cleanup - delete tmp files */ void cleanup() { /* ignore all relevant signals */ signal(SIGTERM,SIG_IGN); signal(SIGABRT,SIG_IGN); signal(SIGQUIT,SIG_IGN); signal(SIGHUP,SIG_IGN); signal(SIGINT,SIG_IGN); #ifndef DEBUG rmtmpdir(tmpdir); #endif } /* * checkfile - check file name before writing * * INPUT: fname - real file name * nname - normal file name to display * sname - file name for shell usage * overwrite - overwriting, renaming or skipping * * OUTPUT: fname - new real file name * nname - new normal name to display * sname - file name for shell usage * overwrite - overwriting, renaming or skipping * * RETURN: 0 if renaming or overwriting * 1 if skipping */ int checkfile(int utf, char *fname, char *nname, char *sname, char *overwrite) { char *cp, /* a simple string pointer */ tmp[MAXLEN], /* temporary string */ answer[FLEN]; /* answer string */ static char storeformat='c'; /* file name storing format */ struct stat finfo; /* information about a file */ if (quiet) storeformat='C'; /* rename files before receiving? */ if (ren) { sprintf(fname,"Rename '%s' to? ",nname); if (getpromptline(fname,MAXLEN-1)==NULL || *fname=='\n' || *fname==0) strcpy(fname,nname); if ((cp=strrchr(fname,'\n'))) *cp=0; strcpy(nname,fname); } else { /* need user request? */ if (!strchr("CNS",storeformat)) { /* found Unicode or 0x0? */ if (utf==1) { printf("The next file name contains characters which are not allowed " "in Unix.\nThese characters have been substituted with '_'.\n"); } /* found control or meta characters? */ if (utf&2) { printf("The next file name contains characters which may cause " "problems with your shell\n or may do strange things with " "your terminal.\n" "These characters have been substituted with '_'.\n"); if (utf&1) printf("Non-valid characters for Unix file names have been substituted" ", too.\n"); /* let user choose file name format */ /*if (strcmp(nname,sname)!=0) */ printf("Save the next file as:\n"); printf(" (c)omplete file name with control code characters " "(not displayable)\n"); printf(" (n)ormal file name: '%s'\n",nname); printf(" (u)ntainted file name: '%s'\n",sname); printf(" (s)kip it\n"); printf(" (r)ename it\n"); do { printf("c or n may cause severe security problems " "(Kids, don't try this at home!) !\n"); printf("Select one of c n u s r (or C N U S R for no more questions): "); fgetl(tmp,stdin); storeformat=tmp[0]; } while (strchr("cnusrCNUSR",storeformat)==NULL); } } /* set file name */ switch (toupper(storeformat)) { case 'S': return(1); case 'N': strcpy(fname,nname); break; case 'U': strcpy(fname,sname); strcpy(nname,sname); break; case 'R': sprintf(fname,"Rename '%s' to? ",nname); if (getpromptline(fname,MAXLEN-1)==NULL || *fname=='\n' || *fname==0) strcpy(fname,nname); if ((cp=strrchr(fname,'\n'))) *cp=0; strcpy(nname,fname); } } /* does the file already exist? */ while (stat(fname,&finfo)==0 && (*overwrite!='Y')) { /* skipping? */ if (*overwrite=='S' || *overwrite=='N') return(1); /* ask user what to do */ printf("'%s' already exists.\n" "Overwrite (yY), rename (r) or skip (sS) it? ",nname); fgetl(answer,stdin); *overwrite=answer[0]; /* request for renaming? */ if (*overwrite=='r') { sprintf(fname,"Rename '%s' to? ",nname); if (getpromptline(fname,MAXLEN-1)==NULL || *fname=='\n' || *fname==0) strcpy(fname,nname); if ((cp=strrchr(fname,'\n'))) *cp=0; strcpy(nname,fname); continue; } /* overwriting or leaving? */ if (toupper(*overwrite)=='Y') break; else return(1); } return(0); } /* * create_sigfile - create detached pgp signature file * * INPUT: sign - signature * fname - original file name * overwrite - overwriting, renaming or skipping * * RETURN: 0 if ok, -1 if failed */ int create_sigfile(const char *sign, const char *fname, const char *nname, char *overwrite) { char *cp, /* a simple string pointer */ tmp[MAXLEN], /* temporary string */ sigfile[MAXLEN], /* signature file */ nsigfile[MAXLEN], /* normal displayable signature file name */ answer[FLEN]; /* answer string */ struct stat finfo; /* information about a file */ FILE *outf; /* file to create */ /* no pgp signature to save? */ if (!*sign) return(0); snprintf(MAXS(sigfile),"%s.sig",fname); snprintf(MAXS(nsigfile),"%s.sig",nname); /* signature file does already exist? */ while (stat(sigfile,&finfo)==0 && (*overwrite!='Y')) { /* skipping? */ if (*overwrite=='S' || *overwrite=='N') return(-1); /* ask user what to do */ printf("'%s' already exists.\n" "Overwrite (yY), rename (r) or skip (sS) it? ",nsigfile); fgetl(answer,stdin); *overwrite=answer[0]; /* request for renaming? */ if (*overwrite=='r') { sprintf(nsigfile,"Rename to? "); if (getpromptline(nsigfile,MAXLEN-1)==NULL || *nsigfile=='\n' || *nsigfile==0) strcpy(nsigfile,sigfile); if ((cp=strrchr(nsigfile,'\n'))) *cp=0; strcpy(sigfile,nsigfile); continue; } /* overwriting or leaving? */ if (toupper(*overwrite)=='Y') break; else return(-1); } /* safety fallback: try to delete an old file with the same name */ unlink(fname); if (stat(sigfile,&finfo)==0) { snprintf(MAXS(tmp),"cannot create '%s' : " "file does already exist and is not deletable",sigfile); errno=0; message(prg,'E',tmp); return(-1); } if (!(outf=rfopen(sigfile,"w"))) { snprintf(MAXS(tmp),"cannot create signature file '%s' ",nsigfile); message(prg,'E',tmp); return(-1); } fprintf(outf,"%s",sign); fclose(outf); snprintf(MAXS(tmp),"signature file '%s' created",nsigfile); message(prg,'I',tmp); return(0); } /* * check_signature - check or print pgp signature * * INPUT: flp - file list pointer to spool file * pgpring - pgp ring file name * print - flag for printing signature status * * RETURN: 1 if good signature * 0 if no signature * -1 if signature not found in pgp key ring * -2 if bad signature * -3 if other error * */ int check_signature(struct filelist *flp, char *pgpring, int print) { int status; /* return status */ char *cp; /* simple character pointer */ char sigfile[FLEN], /* pgp signature file */ pgpopt[FLEN], /* pgp options */ tmp[MAXLEN], /* temp-string */ line[MAXLEN]; /* line to read in */ FILE *outf, /* output file */ *pp; /* pipe input stream */ status=0; if (!(*(flp->sign))) return(0); if (str_eq(pgpring,".")) *pgpring=0; /* write signature file */ snprintf(MAXS(sigfile),"%s/%d.d.sig",userspool,flp->id); if (!(outf=rfopen(sigfile,"w"))) { snprintf(MAXS(tmp),"cannot write signature file %s",sigfile); message(prg,'E',tmp); return(-2); } fprintf(outf,"%s",flp->sign); fclose(outf); /* build pgp options */ if (*pgpring) { if (access(pgpring,R_OK)<0) { snprintf(MAXS(tmp),"cannot read pgp pub ring file %s",pgpring); message(prg,'F',tmp); } snprintf(MAXS(pgpopt),"+batchmode=on +language=en +pubring=%s",pgpring); } else snprintf(MAXS(pgpopt),"+batchmode=on +language=en"); /* check signature file with pgp */ snprintf(MAXS(tmp),"%s %s %s 2>/dev/null",pgp_bin,pgpopt,sigfile); if (*verbose) printf("call: %s\n",tmp); if (!(pp=popen(tmp,"r"))) { message(prg,'E',"cannot call pgp"); unlink(sigfile); return(-2); } /* print or check only result */ if (print) { while (fgetl(line,pp)) { if ((cp=strchr(line,'\n'))) *cp=0; if ((cp=strrchr(line,'.'))) *cp=0; if (strstr(line,"Good signature from user") || strstr(line,"Bad signature from user")) { printf(" (%s)\n",line); break; } if (strstr(line,"Key matching expected")) { printf(" (No matching signature found in pgp key file)\n"); break; } } } else { /* check only result */ while (fgetl(line,pp)) { if (strstr(line,"Good signature from user")) { status=1; break; } if (strstr(line,"Key matching expected")) { status=-1; break; } if (strstr(line,"Could not read key")) { status=-1; break; } if (strstr(line,"Bad signature from user")) { status=-2; break; } } } /* close pipe and delete signature file */ pclose(pp); unlink(sigfile); return(status); } /* * renumber - renumber spool files */ void renumber (struct senderlist *sls) { int i, /* actual spool file number */ nextfree, /* next free spool file number */ lastused, /* last used spool file number */ min, /* smallest spool file number */ max; /* biggest spool file number */ char tmp[MAXLEN], /* temporary string */ ofile[FLEN], /* old filename */ nfile[FLEN]; /* new filename */ struct filelist *flp; /* file list pointer */ struct senderlist *slp; /* sender list pointer */ struct stat finfo; /* information about a file */ FILE *lockf; /* lock file */ min = lastused = 0; nextfree = max = nextfree = 1; if (chdir(userspool)<0) { snprintf(MAXS(tmp),"cannot change to %s",userspool); message(prg,'F',tmp); } /* create lock file */ lockf=rfopen("renumber","a+"); if (!lockf) message(prg,'F',"cannot open renumber file"); if (wlock_file(fileno(lockf))<0) { message(prg,'E',"spool is locked - try again later"); return; } /* loop over all spool files to find max spool file number */ for (slp=sls; slp; slp=slp->next) { for (flp=slp->flist; flp; flp=flp->next) { fprintf(lockf,"%d\n",flp->id); if (flp->id > max) max=flp->id; } } /* renumber loop */ while (minlastused && i>nextfree) min=i; } snprintf(MAXS(ofile),"%d.h",min); for (i=nextfree; i