1/************************************************************************ 2 * From_ line routines used by procmail * 3 * * 4 * Copyright (c) 1990-1999, S.R. van den Berg, The Netherlands * 5 * Copyright (c) 2000, Philip Guenther, The United States * 6 * of America * 7 * #include "../README" * 8 ************************************************************************/ 9#ifdef RCS 10static /*const*/char rcsid[]= 11 "$Id: from.c,v 1.2 2000/10/27 20:03:58 guenther Exp $"; 12#endif 13#include "procmail.h" 14#include "robust.h" 15#include "shell.h" 16#include "memblk.h" 17#include "common.h" 18#include "misc.h" /* for nlog */ 19#include "from.h" 20 21static int privs; /* can we change the From_ line */ 22static const char From_[]=FROM,Fakefield[]=FAKE_FIELD, 23 attemptst[]="Attempt to fake stamp by"; 24 25int eqFrom_(a)const char*const a; 26{ return !strncmp(a,From_,STRLEN(From_)); 27} 28 29const char*skipFrom_(startchar,tobesentp)const char*startchar;long*tobesentp; 30{ if(eqFrom_(startchar)) 31 { long tobesent;char c; 32 tobesent= *tobesentp; 33 do 34 while(c= *startchar++,--tobesent&&c!='\n'); 35 while(*startchar=='>'); 36 *tobesentp=tobesent; 37 } 38 return startchar; 39} 40 /* tries to locate the timestamp on the From_ line */ 41static char*findtstamp(start,end)const char*start,*end; 42{ end-=25; 43 if(*start==' '&&(++start==end||*start==' '&&++start==end)) 44 return (char*)start-1; 45 start=skpspace(start);start+=strcspn(start," \t\n"); /* jump over address */ 46 if(skpspace(start)>=end) /* enough space left? */ 47 return (char*)start; /* no, too small for a timestamp, stop here */ 48 while(!(end[13]==':'&&end[16]==':')&&--end>start); /* search for :..: */ 49 ;{ int spc=0; /* found it perhaps */ 50 while(end-->start) /* now skip over the space to the left */ 51 { switch(*end) 52 { case ' ':case '\t':spc=1; 53 continue; 54 } 55 if(!spc) 56 continue; 57 break; 58 } 59 return (char*)end+1; /* this should be right after the address */ 60 } 61} 62 63size_t ctime2buf2 P((void)) 64{ time_t t=time((time_t*)0); /* the current time */ 65 buf2[0]=buf2[1]=' ';strcpy(buf2+2,ctime(&t)); 66 return strlen(buf2); 67} 68 69void makeFrom(from,invoker)const char*from,*const invoker; 70{ static const char mdaemon[]=MAILERDAEMON; 71 const char*fwhom;char*rstart;size_t lfr,linv;int tstamp,extra,r; 72 if(Deliverymode!=2) 73 { tstamp=from&&*from==REFRESH_TIME&&!from[1]; 74 fwhom=from; 75 } 76 else 77 { tstamp=0; 78 fwhom= *from?from:mdaemon; 79 } 80 if(from&&!tstamp) 81 { if(privs!=1&&!strcmp(from,invoker)) 82 privs=1; /* if -f user is the same as the invoker, allow it */ 83 else if(privs==-1&&from) 84 { if(verbose) 85 nlog(insufprivs); /* ignore the bogus -f */ 86 syslog(LOG_ERR,slogstr,attemptst,invoker);from=0; 87 fwhom=invoker; 88 } 89 } 90 else 91 fwhom=invoker; 92 makeblock(&themail,2*linebuf+(lfr=strlen(fwhom))+(linv=strlen(invoker))); 93 private(1); /* we're not yet sharing */ 94 rstart=thebody=themail.p; 95 if(!Deliverymode&&!from) /* need to peek for a leading From_ ? */ 96 return; /* nope */ 97 r=ctime2buf2(); 98 lfr+=STRLEN(From_)+r; /* length of requested From_ line */ 99 if(tstamp) 100 tstamp=r; /* save time stamp length */ 101 if(privs>0) /* privileged user? */ 102 linv=0; /* yes, so no need to insert >From_ */ 103 else 104 linv+=STRLEN(Fakefield)+r; /* length of >From_ line */ 105 extra=0; 106 if(Deliverymode!=2) /* if not LMTP */ 107 { while(1==(r=rread(STDIN,themail.p,1))) /* then read in first line */ 108 if(themail.p[0]!='\n') /* skip leading newlines */ 109 break; 110 if(r>0&&STRLEN(From_)<=(extra=1+rread( /* is it a From_ line? */ 111 STDIN,rstart+1,(int)(linebuf-2-1)))&&eqFrom_(themail.p)) 112 { rstart[extra]='\0'; 113 if(!(rstart=strchr(rstart,'\n'))) 114 { do /* drop long From_ line */ 115 { if((extra=rread(STDIN,themail.p,(int)(linebuf-2)))<=0) 116 break; 117 themail.p[extra]='\0'; /* terminate it for strchr */ 118 } 119 while(!(rstart=strchr(themail.p,'\n'))); 120 extra=rstart?extra-(++rstart-themail.p):0; 121 } 122 else 123 { size_t tfrl= ++rstart-themail.p; /* length of existing From_ line */ 124 extra-=tfrl; /* demarcate it */ 125 if(Deliverymode&&privs<0) 126 { if(verbose) /* discard the bogus From_ */ 127 nlog(insufprivs); 128 syslog(LOG_ERR,slogstr,attemptst,fwhom); 129 } 130 else 131 { if(tstamp) 132 lfr=findtstamp(themail.p+STRLEN(From_),rstart) 133 -themail.p+tstamp; 134 else if(!from) /* leave the From_ line alone */ 135 if(linv) /* fake alert? */ 136 lfr=tfrl; /* yes, so separate From_ from the rest */ 137 else 138 lfr=0,extra+=tfrl; /* no, tack it onto the rest */ 139 goto got_from; 140 } 141 } 142 } 143 } 144 tstamp=0; /* no existing From_, so nothing to stamp */ 145 if(!from) /* no -f ? */ 146 linv=0; /* then it can't be a fake */ 147got_from: 148 filled=lfr+linv+extra; /* From_ + >From_ + rest */ 149 if(lfr||linv) /* move read text beyond our From_ line */ 150 { r= *rstart;tmemmove(themail.p+lfr+linv,rstart,extra); 151 rstart=themail.p+lfr; /* skip the From_ line, if any */ 152 if(!linv) /* no fake alert */ 153 { rstart[-tstamp]='\0'; /* where do we append */ 154 if(!tstamp) /* no timestamp, so generate it all */ 155 strcat(strcpy(themail.p,From_),fwhom); /* From user */ 156 } 157 else 158 { if(lfr) /* did we skip a From_ line? */ 159 if(tstamp) /* copy the timestamp over the tail */ 160 strcpy(rstart-tstamp,buf2); 161 else if(from) /* whole new From_? */ 162 strcat(strcat(strcpy(themail.p,From_),fwhom),buf2); 163 strcat(strcpy(rstart,Fakefield),invoker); /* fake alert */ 164 } /* overwrite the trailing \0 again */ 165 strcat(themail.p,buf2);themail.p[lfr+linv]=r; 166 } 167} 168 169void checkprivFrom_(euid,logname,override)uid_t euid;const char*logname; 170 int override; 171{ static const char*const trusted_ids[]=TRUSTED_IDS; 172 privs=1; /* assume they're privileged */ 173 if(Deliverymode&&*trusted_ids&&uid!=euid) 174 { struct group*grp;const char*const*kp; 175 if(logname) /* check out the invoker's uid */ 176 for(kp=trusted_ids;*kp;kp++) 177 if(!strcmp(logname,*kp)) /* is it amongst the privileged? */ 178 goto privileged; 179 if(grp=getgrgid(gid)) /* check out the invoker's gid */ 180 for(logname=grp->gr_name,kp=trusted_ids;*kp;kp++) 181 if(!strcmp(logname,*kp)) /* is it among the privileged? */ 182 goto privileged; 183 privs= -override; /* override only matters when not privileged */ 184 } 185privileged: 186 endgrent(); 187} 188