📄 vdelivermail.c
字号:
*/int deliver_mail(char *address, char *quota){ time_t tm; off_t file_count; long unsigned pid; long unsigned inject_pid = 0; int child; int write_fd; FILE *fs; char tmp_file[256]; /* This is a comment, ignore it */ if ( *address == '#' ) return(0); /* 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); } /* Starts with '.' or '/', then it's an mbox or maildir delivery */ else if ((*address == '.') || (*address == '/')) { /* check for mbox delivery and exit accordingly */ if (address[strlen(address)-1] != '/') { printf ("can't handle mbox delivery for %s", address); vexit(111); } /* 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); }#endif /* 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: %s@%s\n", 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; inject_pid = qmail_inject_open(address); write_fd = fdm; /* use the DTLINE variable, but skip past the dash in * domain-user@domain */ 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 = "x-y-z.com-fred@x-y-z.com\n" * dtlen = 25, atpos = dtline+14 * add 25 - 14 - 1 = 10 bytes to dtline, * now points to "fred@x-y-z.com\n". */ 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(-2); } /* 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(-2); } } /* 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(-2); } /* Check if the user is over quota */ if ( errno == EDQUOT ) { return(-1); } else { printf("write failed errno = %d\n", errno); return(-2); } } } if ( inject_pid != 0 ) { close(write_fd); waitpid(inject_pid,&child,0); return(wait_exitcode(child)); } /* 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); /* shouldn't we unlink the file here? */ return(-2); /* 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(-2); } } } /* 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, "%s@%s", 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; /* check for &user@example.com as well */ if ((*qmail_line == '&') && (strcmp (qmail_line + 1, 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -