/************************************************************************
* From_ line routines used by procmail *
* *
* Copyright (c) 1990-1999, S.R. van den Berg, The Netherlands *
* Copyright (c) 2000, Philip Guenther, The United States *
* of America *
* #include "../README" *
************************************************************************/
#ifdef RCS
static /*const*/char rcsid[]=
"$Id: from.c,v 1.2 2000/10/27 20:03:58 guenther Exp $";
#endif
#include "procmail.h"
#include "robust.h"
#include "shell.h"
#include "memblk.h"
#include "common.h"
#include "misc.h" /* for nlog */
#include "from.h"
static int privs; /* can we change the From_ line */
static const char From_[]=FROM,Fakefield[]=FAKE_FIELD,
attemptst[]="Attempt to fake stamp by";
int eqFrom_(a)const char*const a;
{ return !strncmp(a,From_,STRLEN(From_));
}
const char*skipFrom_(startchar,tobesentp)const char*startchar;long*tobesentp;
{ if(eqFrom_(startchar))
{ long tobesent;char c;
tobesent= *tobesentp;
do
while(c= *startchar++,--tobesent&&c!='\n');
while(*startchar=='>');
*tobesentp=tobesent;
}
return startchar;
}
/* tries to locate the timestamp on the From_ line */
static char*findtstamp(start,end)const char*start,*end;
{ end-=25;
if(*start==' '&&(++start==end||*start==' '&&++start==end))
return (char*)start-1;
start=skpspace(start);start+=strcspn(start," \t\n"); /* jump over address */
if(skpspace(start)>=end) /* enough space left? */
return (char*)start; /* no, too small for a timestamp, stop here */
while(!(end[13]==':'&&end[16]==':')&&--end>start); /* search for :..: */
;{ int spc=0; /* found it perhaps */
while(end-->start) /* now skip over the space to the left */
{ switch(*end)
{ case ' ':case '\t':spc=1;
continue;
}
if(!spc)
continue;
break;
}
return (char*)end+1; /* this should be right after the address */
}
}
size_t ctime2buf2 P((void))
{ time_t t=time((time_t*)0); /* the current time */
buf2[0]=buf2[1]=' ';strcpy(buf2+2,ctime(&t));
return strlen(buf2);
}
void makeFrom(from,invoker)const char*from,*const invoker;
{ static const char mdaemon[]=MAILERDAEMON;
const char*fwhom;char*rstart;size_t lfr,linv;int tstamp,extra,r;
if(Deliverymode!=2)
{ tstamp=from&&*from==REFRESH_TIME&&!from[1];
fwhom=from;
}
else
{ tstamp=0;
fwhom= *from?from:mdaemon;
}
if(from&&!tstamp)
{ if(privs!=1&&!strcmp(from,invoker))
privs=1; /* if -f user is the same as the invoker, allow it */
else if(privs==-1&&from)
{ if(verbose)
nlog(insufprivs); /* ignore the bogus -f */
syslog(LOG_ERR,slogstr,attemptst,invoker);from=0;
fwhom=invoker;
}
}
else
fwhom=invoker;
makeblock(&themail,2*linebuf+(lfr=strlen(fwhom))+(linv=strlen(invoker)));
private(1); /* we're not yet sharing */
rstart=thebody=themail.p;
if(!Deliverymode&&!from) /* need to peek for a leading From_ ? */
return; /* nope */
r=ctime2buf2();
lfr+=STRLEN(From_)+r; /* length of requested From_ line */
if(tstamp)
tstamp=r; /* save time stamp length */
if(privs>0) /* privileged user? */
linv=0; /* yes, so no need to insert >From_ */
else
linv+=STRLEN(Fakefield)+r; /* length of >From_ line */
extra=0;
if(Deliverymode!=2) /* if not LMTP */
{ while(1==(r=rread(STDIN,themail.p,1))) /* then read in first line */
if(themail.p[0]!='\n') /* skip leading newlines */
break;
if(r>0&&STRLEN(From_)<=(extra=1+rread( /* is it a From_ line? */
STDIN,rstart+1,(int)(linebuf-2-1)))&&eqFrom_(themail.p))
{ rstart[extra]='\0';
if(!(rstart=strchr(rstart,'\n')))
{ do /* drop long From_ line */
{ if((extra=rread(STDIN,themail.p,(int)(linebuf-2)))<=0)
break;
themail.p[extra]='\0'; /* terminate it for strchr */
}
while(!(rstart=strchr(themail.p,'\n')));
extra=rstart?extra-(++rstart-themail.p):0;
}
else
{ size_t tfrl= ++rstart-themail.p; /* length of existing From_ line */
extra-=tfrl; /* demarcate it */
if(Deliverymode&&privs<0)
{ if(verbose) /* discard the bogus From_ */
nlog(insufprivs);
syslog(LOG_ERR,slogstr,attemptst,fwhom);
}
else
{ if(tstamp)
lfr=findtstamp(themail.p+STRLEN(From_),rstart)
-themail.p+tstamp;
else if(!from) /* leave the From_ line alone */
if(linv) /* fake alert? */
lfr=tfrl; /* yes, so separate From_ from the rest */
else
lfr=0,extra+=tfrl; /* no, tack it onto the rest */
goto got_from;
}
}
}
}
tstamp=0; /* no existing From_, so nothing to stamp */
if(!from) /* no -f ? */
linv=0; /* then it can't be a fake */
got_from:
filled=lfr+linv+extra; /* From_ + >From_ + rest */
if(lfr||linv) /* move read text beyond our From_ line */
{ r= *rstart;tmemmove(themail.p+lfr+linv,rstart,extra);
rstart=themail.p+lfr; /* skip the From_ line, if any */
if(!linv) /* no fake alert */
{ rstart[-tstamp]='\0'; /* where do we append */
if(!tstamp) /* no timestamp, so generate it all */
strcat(strcpy(themail.p,From_),fwhom); /* From user */
}
else
{ if(lfr) /* did we skip a From_ line? */
if(tstamp) /* copy the timestamp over the tail */
strcpy(rstart-tstamp,buf2);
else if(from) /* whole new From_? */
strcat(strcat(strcpy(themail.p,From_),fwhom),buf2);
strcat(strcpy(rstart,Fakefield),invoker); /* fake alert */
} /* overwrite the trailing \0 again */
strcat(themail.p,buf2);themail.p[lfr+linv]=r;
}
}
void checkprivFrom_(euid,logname,override)uid_t euid;const char*logname;
int override;
{ static const char*const trusted_ids[]=TRUSTED_IDS;
privs=1; /* assume they're privileged */
if(Deliverymode&&*trusted_ids&&uid!=euid)
{ struct group*grp;const char*const*kp;
if(logname) /* check out the invoker's uid */
for(kp=trusted_ids;*kp;kp++)
if(!strcmp(logname,*kp)) /* is it amongst the privileged? */
goto privileged;
if(grp=getgrgid(gid)) /* check out the invoker's gid */
for(logname=grp->gr_name,kp=trusted_ids;*kp;kp++)
if(!strcmp(logname,*kp)) /* is it among the privileged? */
goto privileged;
privs= -override; /* override only matters when not privileged */
}
privileged:
endgrent();
}
syntax highlighted by Code2HTML, v. 0.9.1