diff: Breached# diff vdelivermail.c /usr/home/main/public_html/random/vdelivermail.c 475a476
/* quota section removed for the purpose that we dont want it to drop any email at all533a535,537
Close the comments section removing the entire quota */
vdelivermail.c: /* * Copyright (C) 1999-2002 Inter7 Internet Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */
/* include files */ #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/wait.h> #include <fcntl.h> #include <dirent.h> #include <errno.h> #include <time.h> #include <signal.h> #include "config.h" #include "vpopmail.h" #include "vauth.h" #include "maildirquota.h" #ifdef MAKE_SEEKABLE #include "seek.h" #endif
/* Globals */ #define AUTH_SIZE 300 char TheUser[AUTH_SIZE]; char TheUserFull[AUTH_SIZE]; char TheDomain[AUTH_SIZE]; char TheDomainDir[AUTH_SIZE]; uid_t TheDomainUid; gid_t TheDomainGid; char TheDir[AUTH_SIZE]; char CurrentDir[AUTH_SIZE]; char DeliveredTo[AUTH_SIZE]; struct vqpasswd *vpw; off_t message_size = 0; char bounce[AUTH_SIZE]; int CurrentQuotaSizeFd;
#ifdef QMAIL_EXT
/* the User with '-' and following chars out if any */
char TheUserExt[AUTH_SIZE]; #endif
#define FILE_SIZE 156 char hostname[FILE_SIZE]; char loop_buf[FILE_SIZE];
#define MSG_BUF_SIZE 5000 char msgbuf[MSG_BUF_SIZE];
#define BUFF_SIZE 300 int fdm; static char *binqqargs[4]; char *maildir_to_email(char *maildir);
#define QUOTA_WARN_PERCENT 90
/* from qmail's wait.h for run_command() */ #define wait_exitcode(w) ((w) >> 8)
/* Forward declarations */ int process_valias(void); int is_delete(char *deliverto); int is_bounce(char *deliverto); void get_arguments(int argc, char **argv); off_t get_message_size(); int deliver_mail(char *address, char *quota); int check_forward_deliver(char *dir); off_t count_dir(char *dir_name); int is_looping( char *address ); void run_command(char *prog); void checkuser(void); void usernotfound(void); int is_loop_match( char *dt, char *address); int deliver_quota_warning(const char *dir, const char *q);
static char local_file[156]; static char local_file_new[156];
/* * The email message comes in on file descriptor 0 - stanard in
* The user to deliver the email to is in the EXT environment variable
* The domain to deliver the email to is in the HOST environment variable
*/
int main(int argc, char **argv)
{
/* get the arguments to the program and setup things */
get_arguments(argc, argv);
#ifdef VALIAS
/* process valiases if configured */
if ( process_valias() == 1 ) {
printf("vdelivermail: valiases processed\n");
vexit(0); /* if the database is down, deferr */
} else if ( verrori == VA_NO_AUTH_CONNECTION ) {
vexit(111);
}#endif
/* get the user from vpopmail database */
if ((vpw=vauth_getpw(TheUser, TheDomain)) != NULL ) {
checkuser();
}
#ifdef QMAIL_EXT
/* try and find user that matches the QmailEXT address if: no user found,
* and the QmailEXT address is different, meaning there was an extension */
else if ( strncmp(TheUser, TheUserExt, AUTH_SIZE) != 0 ) {
/* get the user from vpopmail database */
if ((vpw=vauth_getpw(TheUserExt, TheDomain)) != NULL ) {
checkuser();
} else {
usernotfound();
}
}
#endif
/* Additions by Steve Fulton - [EMAIL PROTECTED] * - added error code handling for error codes generated by Autoresponder
* 99 = deliver mail
* 100 = bounce mail
*/
else if ( verrori == 100) vexit(100);
else if ( verrori == 99) vexit(0);
/* End of additions by Steve Fulton */
else {
if ( verrori != 0 ) {
vexit(111);
}
usernotfound();
}
/* exit successfully and have qmail delete the email */
return(vexit(0));
}
/* * Get the command line arguments and the environment variables.
* Force addresses to be lower case and set the default domain
*/
void get_arguments(int argc, char **argv)
{
char *tmpstr; int i;
if (argc != 3) {
printf("vdelivermail: invalid syntax in .qmail-default file\n"); /* exit with temporary error */
vexit(111);
}/* get the last parameter in the .qmail-default file */
strncpy(bounce, argv[2], sizeof(bounce));
if ((tmpstr=getenv("EXT")) == NULL ) {
printf("vdelivermail: no EXT environment varilable\n"); /* exit and bounce the email back */
vexit(100);
} else {
for(i=0;*tmpstr!=0&&i<AUTH_SIZE;++i,++tmpstr) {
TheUser[i] = *tmpstr;
}
TheUser[i] = 0;
} if ((tmpstr=getenv("HOST")) == NULL ) {
printf("vdelivermail: no HOST environment varilable\n"); /* exit and bounce the email back */
vexit(100);
} else {
for(i=0;*tmpstr!=0&&i<AUTH_SIZE;++i,++tmpstr) {
TheDomain[i] = *tmpstr;
}
TheDomain[i] = 0;
}lowerit(TheUser); lowerit(TheDomain);
if ( is_username_valid(TheUser) != 0 ) vexit(100); if ( is_domain_valid(TheDomain) != 0 ) vexit(100); strncpy(TheUserFull, TheUser, AUTH_SIZE);
#ifdef QMAIL_EXT /* delete the '-' and following chars if any and store in TheUserExt */
for(i = 0; TheUser[i] != 0; i++) {
if (TheUser[i] == '-' ) {
break;
}
TheUserExt[i] = TheUser[i];
}
TheUserExt[i] = 0;
if ( is_username_valid(TheUserExt) != 0 ) {
vexit(100);
}#endif
vget_assign(TheDomain,TheDomainDir,156,&TheDomainUid,&TheDomainGid);
}
#ifdef VALIAS
/* * Process any valiases for this [EMAIL PROTECTED]
* * This will look up any valiases in vpopmail and
* deliver the email to the entries
*
* Return 1 if aliases found
* Return 0 if no aliases found */
int process_valias(void)
{
int found = 0;
int deliver_err;
char *tmpstr;
char tmpuser[350];
char def[150];
int i;
int j=0;
/* Get the first alias for this [EMAIL PROTECTED] */ tmpstr = valias_select( TheUser, TheDomain );
/* check for wildcard if there's no match */
if(tmpstr == NULL) {
for(i=strlen(TheUser);i >= 0 && j != 1;--i) {
if(TheUser[i-1]=='-') {
tmpuser[0] = '\0';
strncat(tmpuser,TheUser,i); strcat(tmpuser, "default");
tmpstr = valias_select( tmpuser, TheDomain );
if(tmpstr != NULL) {
sprintf(def, "DEFAULT=%s", &TheUser[i]);
putenv(def);
j = 1;
}
}
}
}
/* tmpstr will be NULL if there are no more aliases */
while (tmpstr != NULL ) { /* We found one */
found = 1; /* deliver the mail */
deliver_err = deliver_mail(tmpstr, "NOQUOTA");
if (deliver_err == -2) {
printf("system error\n");
vexit(111);
} else if (deliver_err == -3) {
printf("mail is looping");
vexit(111);
} /* Get the next alias for this [EMAIL PROTECTED] */
tmpstr = valias_select_next();
}#ifdef QMAIL_EXT /* try and find alias that matches the QmailEXT address * if: no alias found, * and the QmailEXT address is different, meaning there was an extension */
if ( (!found) && ( strncmp(TheUser, TheUserExt, AUTH_SIZE) != 0 ) ) {
/* Get the first alias for this [EMAIL PROTECTED] */
tmpstr = valias_select( TheUserExt, TheDomain );
/* tmpstr will be NULL if there are no more aliases */
while (tmpstr != NULL ) { /* We found one */
found = 1; /* deliver the mail */
deliver_err = deliver_mail(tmpstr, "NOQUOTA");
if (deliver_err == -2) {
printf("system error\n");
vexit(111);
} else if (deliver_err == -3) {
printf("mail is looping\n");
vexit(111);
}/* Get the next alias for this [EMAIL PROTECTED] */
tmpstr = valias_select_next();
} } #endif
/* Return whether we found an alias or not */ return(found); } #endif
/* If the .qmail-default file has bounce all in it
* Then return 1
* otherwise return 0
*/
int is_bounce(char *deliverto)
{
if ( strcmp( deliverto, BOUNCE_ALL ) == 0 ) {
return(1);
} else {
return(0);
}
}/* If the .qmail-default file has delete all in it
* Then return 1
* otherwise return 0
*/
int is_delete(char *deliverto)
{
if ( strcmp( deliverto, DELETE_ALL ) == 0 ) {
return(1);
} else {
return(0);
}
}/* cound the directory */
off_t count_dir(char *dir_name)
{
DIR *mydir;
struct dirent *mydirent;
struct stat statbuf;
off_t file_size = 0;
char *tmpstr; if ( dir_name == NULL ) return(0);
if (chdir(dir_name) == -1) return(0);
if ( (mydir = opendir(".")) == NULL ) return(0); while( (mydirent=readdir(mydir)) != NULL ) {
if ( strcmp( mydirent->d_name, "..") == 0 ) continue;
if ( strcmp( mydirent->d_name, ".") == 0 ) continue;if ( (tmpstr=strstr(mydirent->d_name, ",S="))!=NULL) {
tmpstr += 3;
file_size += atoi(tmpstr);
} else if (stat(mydirent->d_name,&statbuf)==0 && (statbuf.st_mode & S_IFDIR) ) {
file_size += count_dir(mydirent->d_name);
}
}
closedir(mydir);
if ( dir_name != NULL && strcmp(dir_name, ".." )!=0 && strcmp(dir_name, "." )!=0) {
chdir("..");
}
return(file_size);
}
long unsigned qmail_inject_open(char *address)
{
int pim[2];
long unsigned pid;
int i=0;
static char *in_address;in_address = malloc(strlen(address)+1); strcpy(in_address, address);
/* skip over an & sign if there */ if (in_address[i] == '&') ++i;
if ( pipe(pim) == -1) return(-1);
switch(pid=vfork()){
case -1:
close(pim[0]);
close(pim[1]);
return(-1);
case 0:
close(pim[1]);
if (vfd_move(0,pim[0]) == -1 ) _exit(-1);
binqqargs[0] = QMAILINJECT;
binqqargs[1] = &in_address[i];
execv(*binqqargs, binqqargs);
}
fdm = pim[1];
close(pim[0]);
free(in_address);
return(pid);
}/* * Deliver an email to an address
* Return 0 on success
* Return less than zero on failure
* * -1 = user is over quota
* -2 and below are system failures
* -3 mail is looping */
int deliver_mail(char *address, char *quota)
{
time_t tm;
off_t file_count;
long unsigned pid;
int write_fd;
int inject = 0;
FILE *fs;
char tmp_file[256];
/* check if the email is looping to this user */
if ( is_looping( address ) == 1 ) {
printf("message is looping %s\n", address );
return(-3);
}
#ifdef MAKE_SEEKABLE
/* at this point we know the message size - if its 0 drop out silently */
if (message_size==0)
return(0);
#endif
/* This is an command */
if ( *address == '|' ) {
/* run the command */ run_command(address);
return(0);
}
/* This is a comment, ignore it */
else if ( *address == '#' ) {
return(0);
}/* Contains /Maildir/ ? Then it must be a full or relative
* path to a Maildir */ else if ( strstr(address, "/Maildir/") != NULL ) {
/* quota section removed for the purpose that we dont want it to drop any email at all
/* if the user has a quota set */
if ( strncmp(quota, "NOQUOTA", 2) != 0 ) { /* If the user is over their quota, return it back
* to the sender.
*/
if (user_over_maildirquota(address,format_maildirquota(quota))==1) { /* check for over quota message in domain */
sprintf(tmp_file, "%s/.over-quota.msg",TheDomainDir);
if ( (fs=fopen(tmp_file, "r")) == NULL ) {
/* if no domain over quota then check in vpopmail dir */
sprintf(tmp_file, "%s/domains/.over-quota.msg",VPOPMAILDIR);
fs=fopen(tmp_file, "r");
} if ( fs == NULL ) {
printf("user is over quota\n");
} else {
while( fgets( tmp_file, 256, fs ) != NULL ) {
fputs(tmp_file, stdout);
}
fclose(fs);
}
deliver_quota_warning(address, format_maildirquota(quota));
return(-1);
}
if (QUOTA_WARN_PERCENT >= 0 &&
vmaildir_readquota(address, format_maildirquota(quota))
>= QUOTA_WARN_PERCENT) {
deliver_quota_warning(address, format_maildirquota(quota));
}
}#ifdef DOMAIN_QUOTAS
/* bk: check domain quota */
if (domain_over_maildirquota(address)==1)
{
/* check for over quota message in domain */
sprintf(tmp_file, "%s/.over-quota.msg",TheDomainDir);
if ( (fs=fopen(tmp_file, "r")) == NULL ) {
/* if no domain over quota then check in vpopmail dir */
sprintf(tmp_file, "%s/domains/.over-quota.msg",VPOPMAILDIR);
fs=fopen(tmp_file, "r");
} if ( fs == NULL ) {
printf("domain is over quota\n");
} else {
while( fgets( tmp_file, 256, fs ) != NULL ) {
fputs(tmp_file, stdout);
}
fclose(fs);
}
deliver_quota_warning(address, format_maildirquota(quota));
return(-1);
}
#endifClose the comments section removing the entire quota */
/* Format the email file name */
gethostname(hostname,sizeof(hostname));
pid=getpid();
time (&tm);
snprintf(local_file, 156, "%stmp/%lu.%lu.%s,S=%lu",
address,(long unsigned)tm,(long unsigned)pid,
hostname, (long unsigned)message_size);
snprintf(local_file_new, 156, "%snew/%lu.%lu.%s,S=%lu",
address,(long unsigned)tm,(long unsigned)pid,hostname, (long unsigned)message_size);
/* open the new email file */
if ((write_fd=open(local_file,O_CREAT|O_RDWR,S_IRUSR|S_IWUSR))== -1) {
printf("can not open new email file errno=%d file=%s\n", errno, local_file);
return(-2);
}
/* Set the Delivered-To: header */
if ( strcmp( address, bounce) == 0 ) {
snprintf(DeliveredTo, sizeof(DeliveredTo), "%sDelivered-To: [EMAIL PROTECTED]", getenv("RPLINE"), TheUser, TheDomain);
} else {
snprintf(DeliveredTo, sizeof(DeliveredTo), "%sDelivered-To: %s\n", getenv("RPLINE"), maildir_to_email(address));
}
/* must be an email address */
} else {
char *dtline;
char *atpos;
int dtlen; qmail_inject_open(address);
write_fd = fdm;
inject = 1;/* use the DTLINE variable, but skip past the dash in * [EMAIL PROTECTED] */
if ( (dtline = getenv("DTLINE")) != NULL ) {
dtlen = strlen(dtline);
/* make sure dtline is at least as long as "Delivered-To: " */
if (dtlen < 15) {
dtline = NULL;
} else {
dtline += 14; /* skip "Delivered-To: " */
dtlen -= 14;
atpos = strchr (dtline, '@');
/* ex: dtline = "[EMAIL PROTECTED]"
* dtlen = 25, atpos = dtline+14
* add 25 - 14 - 1 = 10 bytes to dtline,
* now points to "[EMAIL PROTECTED]".
*/
if (atpos != NULL) {
dtline += (dtlen - (atpos - dtline) - 1);
}
}
}
if (dtline == NULL) {
if (*address=='&') ++address; /* will this case ever happen? */
snprintf(DeliveredTo, sizeof(DeliveredTo), "%sDelivered-To: %s\n", getenv("RPLINE"), address);
} else {
snprintf(DeliveredTo, sizeof(DeliveredTo), "%sDelivered-To: %s", getenv("RPLINE"), dtline);
}
}
#ifdef MAKE_SEEKABLE
if (!Seekable(0))
MakeSeekable(stdin);
#endif if ( lseek(0, 0L, SEEK_SET) < 0 ) {
printf("lseek errno=%d\n", errno);
return(errno);
}/* write the Return-Path: and Delivered-To: headers */
if (write(write_fd,DeliveredTo,strlen(DeliveredTo))!= strlen(DeliveredTo)) {
close(write_fd);
/* Check if the user is over quota */
if ( errno == EDQUOT ) {
return(-1);
} else {
printf("failed to write delivered to line errno=%d\n",errno);
return(errno);
}
}
/* read it in chunks and write it to the new file */ while((file_count=read(0,msgbuf,MSG_BUF_SIZE))>0) { if ( write(write_fd,msgbuf,file_count) == -1 ) { close(write_fd);
/* if the write fails and we are writing to a Maildir
* then unlink the file
*/
if ( unlink(local_file) != 0 ) {
printf("unlink failed %s errno = %d\n", local_file, errno);
return(errno);
} /* Check if the user is over quota */
if ( errno == EDQUOT ) {
return(-1);
} else {
printf("write failed errno = %d\n", errno);
return(errno);
}
}
}
if ( inject == 1 ) {
close(write_fd);
return(0);
} /* if we are writing to a Maildir, move it
* into the new directory
*//* sync the data to disk and close the file */
errno = 0;
if ( #ifdef FILE_SYNC
#ifdef HAVE_FDATASYNC
fdatasync(write_fd) == 0 &&
#else
fsync(write_fd) == 0 &&
#endif
#endif
close(write_fd) == 0 ) {
/* if this succeeds link the file to the new directory */
if ( link( local_file, local_file_new ) == 0 ) {
if ( unlink(local_file) != 0 ) {
printf("unlink failed %s errno = %d\n", local_file, errno);
}
} else { /* coda fs has problems with link, check for that error */
if ( errno==EXDEV ) { /* try to rename the file instead */
if (rename(local_file, local_file_new)!=0) {/* even rename failed, time to give up */
printf("rename failed %s %s errno = %d\n", local_file, local_file_new, errno);
return(errno);
/* rename worked, so we are okay now */
} else {
errno = 0;
}/* link failed and we are not on coda */
} else {
printf("link REALLY failed %s %s errno = %d\n", local_file, local_file_new, errno);
unlink(local_file);
}
}
}
/* return success */ return(0); }
/* Check if the vpopmail user has a .qmail file in thier directory
* and foward to each email address, Maildir or program * that is found there in that file
*
* Return: 1 if we found and delivered email
* : 0 if not found
* : -1 if no user .qmail file *
*/
int check_forward_deliver(char *dir)
{
static char qmail_line[500];
char tmpbuf[500];
FILE *fs;
int i;
int return_value = 0;
int deliver_err;
chdir(dir);
/* format the file name */
if ( (fs = fopen(".qmail","r")) == NULL ) { /* no file, so just return */
return(-1);
}/* format a simple loop checker name */ snprintf(tmpbuf, 500, "[EMAIL PROTECTED]", TheUser, TheDomain);
/* read the file, line by line */
while ( fgets(qmail_line, 500, fs ) != NULL ) {
if (*qmail_line == '#') continue; /* remove the trailing new line */
for(i=0;qmail_line[i]!=0;++i) {
if (qmail_line[i] == '\n') qmail_line[i] = 0;
} /* simple loop check, if they are sending it to themselves
* then skip this line
*/
if ( strcmp( qmail_line, tmpbuf) == 0 ) continue; deliver_err = deliver_mail(qmail_line, "NOQUOTA");
if (deliver_err == -2) {
printf("system error\n");
vexit(111);
} else if (deliver_err == -3) {
printf("mail is looping\n");
vexit(111);
}
return_value = 1;
}/* close the file */ fclose(fs);
/* return if we found one or not */ return(return_value); }
void sig_catch(sig,f)
int sig;
void (*f)();
{
#ifdef HAVE_SIGACTION
struct sigaction sa;
sa.sa_handler = f;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(sig,&sa,(struct sigaction *) 0);
#else
signal(sig,f); /* won't work under System V, even nowadays---dorks */
#endif
}/* open a pipe to a command * return the pid or -1 if error
*/
void run_command(char *prog)
{
int child;
char *(args[4]);
int wstat;
while (*prog==' ') ++prog; while (*prog=='|') ++prog;
#ifdef MAKE_SEEKABLE
if (!Seekable(0))
MakeSeekable(stdin);
#endif if ( lseek(0, 0L, SEEK_SET) < 0 ) {
printf("lseek errno=%d\n", errno);
return;
}switch(child = fork())
{
case -1:
printf("unable to fork\n"); exit(0);
case 0:
args[0] = "/bin/sh"; args[1] = "-c"; args[2] = prog; args[3] = 0;
sig_catch(SIGPIPE,SIG_DFL);
execv(*args,args);
printf("Unable to run /bin/sh: ");
exit(-1);
}
wait(&wstat);
waitpid(wstat,&child,0);
switch(wait_exitcode(wstat))
{
case 64: case 65: case 70: case 76: case 77: case 78: case 100: case 112:
_exit(100);
case 99: _exit(99);
case 0: break;
default: _exit(111);
}}
/* Check for a looping message
* This is done by checking for a matching line
* in the email headers for Delivered-To: which
* we put in each email
* * Return 1 if looping
* Return 0 if not looping
* Return -1 on error */
int is_looping( char *address ) {
int i;
int found;
char *dtline;
/* if we don't know the message size then get it */
if ( message_size == 0 ) {
/* read the message to get the size */
message_size = get_message_size();
}
if (*address=='&') ++address; /* check the DTLINE */
dtline = getenv("DTLINE");
if ( dtline != NULL && is_loop_match(dtline, address) == 1 ) {
return(1);
}#ifdef MAKE_SEEKABLE
if (!Seekable(0))
MakeSeekable(stdin);
#endif lseek(0,0L,SEEK_SET);
while(fgets(loop_buf,sizeof(loop_buf),stdin)!=NULL){/* if we find the line, return error (looping) */
if (strstr(loop_buf, "Delivered-To")!= 0 && is_loop_match(loop_buf, address)==1 ) {
/* return the loop found */
return(1);/* check for the start of the body, we only need
* to check the headers. */
} else {
/* walk through the charaters in the body */
for(i=0,found=0;loop_buf[i]!=0&&found==0;++i){
switch(loop_buf[i]){ /* skip blank spaces and new lines */
case ' ':
case '\n':
case '\t':
case '\r':
break;/* found a non blank, so we are still
* in the headers
*/
default:
/* set the found non blank char flag */
found = 1;
break;
}
}
/* if the line only had blanks, then it is the
* delimiting line between the headers and the
* body. We don't need to check the body for
* the duplicate Delivered-To: line. Hence, we
* are done with our search and can return the
* looping not found value
*/
if ( found == 0 ) {
/* return not found looping message value */
return(0);
}
}
}/* if we get here then the there is either no body * or the logic above failed and we scanned
* the whole email, headers and body. */
return(0);
}
/* * Get the size of the email message * return the size */
off_t get_message_size()
{
ssize_t message_size;
ssize_t bytes;
#ifdef MAKE_SEEKABLE
if (!Seekable(0))
MakeSeekable(stdin);
#endif if ( lseek(0, 0L,SEEK_SET) < 0 ) {
printf("lseek error %d\n", errno);
return(-1);
} message_size = 0;
while((bytes=read(0,msgbuf,MSG_BUF_SIZE))>0) {
message_size += bytes;
}
return(message_size);
}char *maildir_to_email(char *maildir)
{
static char email[256];
int i, j=0;
char *pnt, *last; memset(email, 0, sizeof(email));
for(last=NULL, pnt=maildir; (pnt=strstr(pnt,"/Maildir/"))!=NULL; pnt+=9 ){
last = pnt;
}
if(!last) return ""; /* so now pnt at begin of last Maildir occurence
* going toward start of maildir we can get username
*/
pnt = last;for( i=(pnt-maildir); (i > 1 && *(pnt-1) != '/'); --pnt, --i);
for( ; (*pnt && *pnt != '/' && j < 255); ++pnt) {
email[j++] = *pnt;
}email[j++] = '@';
for (last=NULL, pnt=maildir; (pnt=strstr(pnt, "/" DOMAINS_DIR "/")); pnt+=strlen("/"
DOMAINS_DIR "/")) {
last = pnt;
}if(!last) return "";
pnt = last + strlen(DOMAINS_DIR) + 2;
while ( *(pnt+1) == '/' ) pnt+=2; /* skip over hash directory names */
for( ; (*pnt && *pnt != '/' && j < 255); ++pnt, ++j ) {
email[j] = *pnt;
}email[j] = 0;
return( email ); }
/*
* check for locked account
* deliver to .qmail file if any
* deliver to user if no .qmail file
*/
void checkuser() {
struct stat mystatbuf;
if (vpw->pw_gid & BOUNCE_MAIL ) {
printf("vdelivermail: account is locked email bounced [EMAIL PROTECTED]",
TheUser, TheDomain);
vexit(100);
}/* If thier directory path is empty make them a new one */
if ( vpw->pw_dir == NULL || vpw->pw_dir[0]==0 ) {
if ( make_user_dir(vpw->pw_name, TheDomain, TheDomainUid, TheDomainGid)==NULL){
printf("Auto creation of maildir failed. vpopmail (#5.9.8)\n");
vexit(100);
}
}
/* check if the directory exists and create if needed */
if ( stat(vpw->pw_dir, &mystatbuf ) == -1 ) {
if ( vmake_maildir(TheDomain, vpw->pw_dir )!= VA_SUCCESS ) {
printf("Auto re-creation of maildir failed. vpopmail (#5.9.9)\n");
vexit(100);
}
} /* check for a .qmail file in thier Maildir
* If it exists, then deliver to the contents and exit
*/
if ( check_forward_deliver(vpw->pw_dir) == 1 ) {
vexit(0);
} snprintf(TheDir, AUTH_SIZE, "%s/Maildir/", vpw->pw_dir);
if ( deliver_mail(TheDir, vpw->pw_shell) != 0 ) {
vexit(100);
}
}/*
* the vpopmail user does not exist. Follow the rest of
* the directions in the .qmail-default file
*/
void usernotfound() {
int ret;
/* If they want to delete email for non existant users
* then just exit 0. Qmail will delete the email for us
*/
if ( strcmp(bounce, DELETE_ALL) == 0 ) {
/* just exit 0 and qmail will delete the email from the system */
vexit(0); /* If they want to bounce the email back then
* print a message and exit 100
*/
} else if ( strcmp(bounce, BOUNCE_ALL) == 0 ) {
FILE *fs;
char *tmp_file; tmp_file = malloc(256);
sprintf(tmp_file, "%s/.no-user.msg",TheDomainDir);
if ( (fs=fopen(tmp_file, "r")) == NULL ) {
/* if no domain no user then check in vpopmail dir */
sprintf(tmp_file, "%s/domains/.no-user.msg",VPOPMAILDIR);
fs=fopen(tmp_file, "r");
}
if ( fs == NULL ) {
printf("Sorry, no mailbox here by that name. vpopmail (#5.1.1)\n");
} else {
while( fgets( tmp_file, 256, fs ) != NULL ) {
fputs(tmp_file, stdout);
}
fclose(fs);
}
free(tmp_file); /* exit 100 causes the email to be bounced back */
vexit(100);}
/* check if it is a path add the /Maildir/ for delivery */
if ( bounce[0] == '/' ) {
strcat( bounce, "/");
printf ("user does not exist, but will deliver to %s\n", bounce);
if( check_forward_deliver(bounce) == 1 )
vexit(0);
else
strcat( bounce, "/Maildir/");
}ret = deliver_mail(bounce, "NOQUOTA" );
/* Send the email out, if we get a -1 then the user is over quota */
if ( ret == -1 ) {
printf("user is over quota, mail bounced\n");
vexit(100);
} else if ( ret == -2 ) {
printf("system error\n");
vexit(100);
} else if ( ret != 0 ) {
printf("mail is looping\n");
vexit(100);
}}
/* * Deliver an quota warning message
* Return 0 on success
* Return less than zero on failure
* * -1 = user is over quota
* -2 and below are system failures
* -3 mail is looping */
int deliver_quota_warning(const char *dir, const char *q)
{
time_t tm;
long unsigned pid;
long unsigned wrn_msg_sz;
int write_fd, fdin, fd;
size_t l;
char newdir[400];
char *qname = 0;
struct stat sb;
char buf[4096];
FILE *fs;
char quotawarnmsg[BUFF_SIZE];
/* Look in the domain for a .quotawarn.msg */
sprintf(quotawarnmsg, "%s/.quotawarn.msg", TheDomainDir);
if ( ((fdin=open(quotawarnmsg, O_RDONLY)) < 0) || (stat(quotawarnmsg, &sb)<0)) {
/* if that fails look in vpopmail dir */
sprintf(quotawarnmsg, "%s/domains/.quotawarn.msg", VPOPMAILDIR);
if ( ((fdin=open(quotawarnmsg, O_RDONLY)) < 0) || (stat(quotawarnmsg, &sb)<0)) {
return(0);
}
}
wrn_msg_sz = sb.st_size;
l = strlen(dir)+sizeof("/quotawarn");
if ((qname = malloc(l)) == 0)
{
close(fdin);
perror("malloc");
return(-1);
}strcat(strcpy(qname, dir), "/quotawarn"); time(&tm);
/* Send only one warning every 24 hours */ if (stat(qname, &sb) == 0 && ((sb.st_mtime + 86400) > tm)) { free(qname); close(fdin); return(0); }
fd = open(qname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
if (!fd)
{
free(qname);
close(fdin);
perror("open");
exit(111);
}
write(fd, buf, 0); close(fd);
/* Format the email file name */ gethostname(hostname,sizeof(hostname)); pid=getpid(); time (&tm); snprintf(local_file, 156, "%stmp/%lu.%lu.%s,S=%lu", dir,(long unsigned)tm,pid,hostname, wrn_msg_sz); snprintf(local_file_new, 156, "%snew/%lu.%lu.%s,S=%lu", dir,(long unsigned)tm,pid,hostname,wrn_msg_sz);
/* open the new email file */
if ((write_fd=open(local_file,O_CREAT|O_RDWR,S_IRUSR|S_IWUSR))== -1) {
printf("can not open new email file errno=%d file=%s\n", errno, local_file);
return(-2);
}
if ( strcmp( dir, bounce) == 0 ) {
snprintf(DeliveredTo, sizeof(DeliveredTo), "%s%s%s", getenv("RPLINE"), getenv("DTLINE"), date_header());
} else {
strcpy(newdir, dir);
snprintf(DeliveredTo, sizeof(DeliveredTo), "%sDelivered-To: %s\n%s", getenv("RPLINE"), maildir_to_email(newdir), date_header());
}
/* write the Return-Path: and Delivered-To: headers */ if (write(write_fd,DeliveredTo,strlen(DeliveredTo)) != strlen(DeliveredTo)) { close(write_fd); /* Check if the user is over quota */ if ( errno == EDQUOT ) { return(-1); } else { printf("failed to write delivered to line errno=%d\n",errno); return(errno); } }
/* read the quota message in chunks and write it to the new file */
if((fs=fopen(quotawarnmsg, "ro")) != NULL) {
while(fgets(buf, MSG_BUF_SIZE, fs)) {
if ( write(write_fd,buf,strlen(buf)) == -1 ) {
close(write_fd); /* if the write fails and we are writing to a Maildir
* then unlink the file
*/
if ( unlink(local_file) != 0 ) {
printf("unlink failed %s errno = %d\n", local_file, errno);
return(errno);
} /* Check if the user is over quota */
if ( errno == EDQUOT ) {
return(-1);
} else {
printf("write failed errno = %d\n", errno);
return(errno);
}
}
}
}/* since we are writing to a Maildir, move it * into the new directory */
/* sync the data to disk and close the file */
errno = 0;
if ( #ifdef FILE_SYNC
#ifdef HAVE_FDATASYNC
fdatasync(write_fd) == 0 &&
#else
fsync(write_fd) == 0 &&
#endif
#endif
close(write_fd) == 0 ) {
/* if this succeeds link the file to the new directory */
if ( link( local_file, local_file_new ) == 0 ) {
if ( unlink(local_file) != 0 ) {
printf("unlink failed %s errno = %d\n", local_file, errno);
}
} else { /* coda fs has problems with link, check for that error */
if ( errno==EXDEV ) { /* try to rename the file instead */
if (rename(local_file, local_file_new)!=0) {/* even rename failed, time to give up */
printf("rename failed %s %s errno = %d\n", local_file, local_file_new, errno);
return(errno);
/* rename worked, so we are okay now */
} else {
errno = 0;
}/* link failed and we are not on coda */
} else {
printf("link fucking failed %s %s errno = %d\n", local_file, local_file_new, errno);
}
}
}
/* return success */ add_warningsize_to_quota(dir,q); return(0); }
int is_loop_match( char *dt, char *address)
{
char *startdt;startdt = dt;
/* walk forward in dt line for @ character */ while ( *dt != '@' && *dt != 0 ) ++dt;
/* now walk back to first space */ while ( *dt != ' ' && dt != startdt) --dt;
/* step forward one character */ ++dt;
/* strcmp up to end of line or newline */
while ( *dt != 0 && *dt != '\n' && *dt != '\r' ) { /* if it does not match, then no loop */
if ( *dt != *address ) return(0);
++dt;
++address;
}/* we have a match */ return(1); }
