#ifdef RCS
static char rcsid[]=
"$Id: foldinfo.c,v 1.11 2001/08/04 07:07:42 guenther Exp $";
#endif
#include "procmail.h"
#include "misc.h"
#include "lastdirsep.h"
#include "robust.h"
#include "exopen.h"
#include "goodies.h"
#include "locking.h"
#include "foldinfo.h"
static const char
maildirtmp[]=MAILDIRtmp,maildircur[]=MAILDIRcur;
const char
maildirnew[]=MAILDIRnew;
int accspooldir;
static int folderparse P((void))
{ char*chp;int type;
type=ft_FILE;chp=strchr(buf,'\0');
switch(chp-buf)
{ case 2:
if(chp[-1]==*MCDIRSEP_)
chp--,type=ft_MAILDIR;
case 0:case 1:
goto ret;
}
if(chp[-1]==chCURDIR&&chp[-2]==*MCDIRSEP_)
chp-=2,type=ft_MH;
else if(chp[-1]==*MCDIRSEP_)
chp--,type=ft_MAILDIR;
else
goto ret;
while(chp-1>buf&&strchr(dirsep,chp[-1]))
chp--;
ret:
*chp='\0';
return type;
}
int rnmbogus(name,stbuf,i,dolog)const char*const name;
const struct stat*const stbuf;const int i,dolog;
{ static const char renbogus[]="Renamed bogus \"%s\" into \"%s\"",
renfbogus[]="Couldn't rename bogus \"%s\" into \"%s\"",
bogusprefix[]=BOGUSprefix;char*p;
p=strchr(strcpy(strcpy(buf2+i,bogusprefix)+STRLEN(bogusprefix),
getenv(lgname)),'\0');
*p++='.';ultoan((unsigned long)stbuf->st_ino,p);
if(dolog)
{ nlog("Renaming bogus mailbox \"");elog(name);elog("\" info");
logqnl(buf2);
}
if(rename(name,buf2))
{ syslog(LOG_ALERT,renfbogus,name,buf2);
return 1;
}
syslog(LOG_CRIT,renbogus,name,buf2);
return 0;
}
static mode_t trymkdir(dir,paranoid,i)const char*const dir;
const int paranoid,i;
{ struct stat stbuf;int tries=3-1;
do
{ if(!(paranoid?lstat(dir,&stbuf):stat(dir,&stbuf)))
{ if(!paranoid||
(S_ISDIR(stbuf.st_mode)&&
(stbuf.st_uid==uid||
!stbuf.st_uid&&!chown(dir,uid,sgid))))
return stbuf.st_mode;
else if(rnmbogus(dir,&stbuf,i,1))
break;
}
else if(errno!=ENOENT)
break;
else if(!mkdir(dir,NORMdirperm))
{ if(!paranoid)
return S_IFDIR|NORMdirperm&~cumask;
tries++;
}
}while(tries-->0);
return 0;
}
static int mkmaildir(buffer,chp,paranoid)char*const buffer,*const chp;
const int paranoid;
{ mode_t mode;int i;
if(paranoid)
memcpy(buf2,buffer,i=chp-buffer+1),buf2[i-1]= *MCDIRSEP_,buf2[i]='\0';
return
(strcpy(chp,maildirnew),mode=trymkdir(buffer,paranoid,i),S_ISDIR(mode))&&
(strcpy(chp,maildircur),mode=trymkdir(buffer,paranoid,i),S_ISDIR(mode))&&
(strcpy(chp,maildirtmp),mode=trymkdir(buffer,paranoid,i),S_ISDIR(mode));
}
int foldertype(type,forcedir,modep,paranoid)int type,forcedir;
mode_t*const modep;struct stat*const paranoid;
{ struct stat stbuf;mode_t mode;int i;char*chp;
if(!type)
type=folderparse();
switch(type)
{ case ft_MAILDIR:i=MAILDIRLEN;break;
case ft_MH:i=0;break;
case ft_FILE:
i=0;
if(!forcedir)
{ if(paranoid?lstat(buf,&stbuf):stat(buf,&stbuf))
{ if(paranoid)
{ type=ft_NOTYET;
goto ret;
}
goto newfile;
}
else if(mode=stbuf.st_mode,!S_ISDIR(mode))
goto file;
}
type=ft_DIR;
break;
default:
nlog("Internal error: improper type (");
ltstr(0,type,buf2);elog(buf2);
elog(") passed to foldertype for folder ");logqnl(buf);
Terminate();
}
chp=strchr(buf,'\0');
if((chp-buf)+UNIQnamelen+1+i>linebuf)
{ type=ft_TOOLONG;
goto ret;
}
if(type==ft_DIR&&!forcedir)
goto done;
if(paranoid)
memcpy(buf2,buf,i=lastdirsep(buf)-buf),buf2[i]='\0';
mode=trymkdir(buf,paranoid!=0,i);
if(!S_ISDIR(mode)||(type==ft_MAILDIR&&
(forcedir=1,!mkmaildir(buf,chp,paranoid!=0))))
{ nlog("Unable to treat as directory");logqnl(buf);
if(forcedir)
{ *chp='\0';skipped(buf);type=ft_CANTCREATE;
goto ret;
}
if(!mode)
newfile:mode=S_IFREG|NORMperm&~cumask;
file:type=ft_FILE;
}
done:
if(paranoid)
*paranoid=stbuf;
else
*modep=mode;
ret:
return type;
}
int screenmailbox(chp,egid,Deliverymode)
char*chp;const gid_t egid;const int Deliverymode;
{ char ch;struct stat stbuf;int basetype,type;
accspooldir=3;
sgid=gid;
strcpy(buf,chp);
basetype=folderparse();
if(buf[0]=='\0')
return 0;
ch= *(chp=lastdirsep(buf));
if(chp>buf)
*chp='\0';
if(!stat(buf,&stbuf))
{ unsigned wwsdir;
accspooldir=(wwsdir=
((S_IWGRP|S_IXGRP|S_IWOTH|S_IXOTH)&stbuf.st_mode)==
(S_IWGRP|S_IXGRP|S_IWOTH|S_IXOTH)
<<1|
uid==stbuf.st_uid);
if((CAN_toggle_sgid||accspooldir)&&privileged)
privileged=priv_DONTNEED;
if(uid!=stbuf.st_uid&&
(stbuf.st_mode&S_ISGID||!wwsdir))
{ if(stbuf.st_gid==egid)
doumask(GROUPW_UMASK);
goto keepgid;
}
else if(stbuf.st_mode&S_ISGID)
keepgid:
if((sgid=stbuf.st_gid)!=egid&&
setgid(sgid))
checkroot('g',(unsigned long)sgid);
}
else
{ setids();mkdir(buf,NORMdirperm);
}
*chp=ch;
chp=strchr(buf,'\0')-1;
for(;;)
{ type=foldertype(basetype,0,0,&stbuf);
if(type==ft_NOTYET)
{ if(errno!=EACCES||(setids(),lstat(buf,&stbuf)))
goto nobox;
}
else if(!ft_checkcloser(type))
{ setids();
if(type<0)
goto fishy;
goto nl;
}
;{ int checkiter=1;
for(;;)
{ if(stbuf.st_uid!=uid||
!(stbuf.st_mode&S_IWUSR)||
S_ISLNK(stbuf.st_mode)||
(S_ISDIR(stbuf.st_mode)?
!(stbuf.st_mode&S_IXUSR):stbuf.st_nlink!=1))
if(checkiter--)
suspend();
else
{ int i=lastdirsep(buf)-buf;
memcpy(buf2,buf,i);buf2[i]='\0';
if(rnmbogus(buf,&stbuf,i,1))
goto fishy;
goto nobox;
}
else
break;
if(lstat(buf,&stbuf))
goto nobox;
}
if(Deliverymode&&(stbuf.st_mode&S_ISUID||
!S_ISDIR(stbuf.st_mode)&&stbuf.st_mode&S_ISGID))
{ nlog("Autoforwarding mailbox found\n");
exit(EX_NOUSER);
}
else
{ if(!(stbuf.st_mode&OVERRIDE_MASK)&&
stbuf.st_mode&cumask&
(accspooldir?~(mode_t)0:~(S_IRGRP|S_IWGRP)))
{ static const char enfperm[]=
"Enforcing stricter permissions on";
nlog(enfperm);logqnl(buf);
syslog(LOG_NOTICE,slogstr,enfperm,buf);setids();
chmod(buf,stbuf.st_mode&=~cumask);
}
break;
}
}
nobox:
if(!(accspooldir&1))
{ if(!xcreat(buf,NORMperm,(time_t*)0,doCHOWN|doCHECK))
break;
if(!lstat(buf,&stbuf))
continue;
}
setids();
if(!xcreat(buf,NORMperm,(time_t*)0,doCHECK))
break;
if(lstat(buf,&stbuf))
fishy:
{ nlog("Couldn't create");logqnl(buf);
return 0;
}
}
if(!S_ISDIR(stbuf.st_mode))
{ int isgrpwrite=stbuf.st_mode&S_IWGRP;
strcpy(chp=strchr(buf,'\0'),lockext);
defdeflock=tstrdup(buf);
if(!isgrpwrite&&!lstat(defdeflock,&stbuf)&&stbuf.st_uid!=uid&&
stbuf.st_uid!=ROOT_uid)
{ int i=lastdirsep(buf)-buf;
memcpy(buf2,buf,i);buf2[i]='\0';
rnmbogus(defdeflock,&stbuf,i,0);
}
*chp='\0';
}
else
nl: defdeflock=empty;
return 1;
}