- 论坛徽章:
- 0
|
qmail-smtpd.c拒收垃圾邮件修改(原创)
我把它贴出来吧,大家看着也比较方便.我也试了一下,不错,多谢楼主.大家也帮忙测试一下
- #include "sig.h"
- #include "readwrite.h"
- #include "stralloc.h"
- #include "substdio.h"
- #include "alloc.h"
- #include "auto_qmail.h"
- #include "control.h"
- #include "received.h"
- #include "constmap.h"
- #include "error.h"
- #include "ipme.h"
- #include "ip.h"
- #include "qmail.h"
- #include "str.h"
- #include "fmt.h"
- #include "scan.h"
- #include "byte.h"
- #include "case.h"
- #include "env.h"
- #include "now.h"
- #include "exit.h"
- #include "rcpthosts.h"
- #include "timeoutread.h"
- #include "timeoutwrite.h"
- #include "commands.h"
- #include "wait.h"
- #include "fd.h"
- /*******Added by Jizhao******/
- #include <stdio.h>;
- #include <regex.h>;
- #include <unistd.h>;
- #include <sys/types.h>;
- #include <limits.h>;
- #include <sys/stat.h>;
- #include <fcntl.h>;
- #include <time.h>;
- #include <string.h>;
- /*******Added by Jizhao******/
- #define AUTHCRAM
- #define MAXHOPS 100
- unsigned int databytes = 0;
- int timeout = 1200;
- /************************* Added by Jizhao*********************************/
- /*
- 全局变量用于记录认证的email地址
- 如果是虚拟域的用户则是邮件地址
- 如果是主域用户则在函数authenticate
- 里面赋值后,需加上defaultdomain里面的内容
- */
- stralloc authusername={0};
- stralloc completeusername={0};
- /*
- 如果是远程邮件服务器连接本地的
- smtp,则远程主机使用的是不带认证
- 的连接方式,即在连接建立以后,
- 远程主机使用的是helo命令,这样
- 远程主机就只能向本机发送本地域
- 的用户,因为如果用ehlo的话,远程
- 主机不可能知道每个帐户的密码
- ehlo 记录,smtp连接使用的是
- helo还是ehlo
- 0:helo 1:ehlo
- */
- int ehlo = 0;
- /*
- 检查邮件地址只能由字母、数字、下划线、减号
- 和点组成,其余均视为为非法地址
- */
- #define SUBSLEN 20
- #define EBUFLEN 128 /* error buffer length */
- int CheckMailAddress(char * mail, char * msg)
- {
- size_t len; /* store error message length */
- regex_t re; /* store compilned regular expression */
- regmatch_t subs[SUBSLEN]; /* store matched string position */
- char errbuf[EBUFLEN]; /* store error message */
- int err, i;
- char pattern[] = "([a-zA-Z\\.0-9_-])+@([a-zA-Z\\.0-9_-])+";
- /* compile regular expression */
- err = regcomp (&re, pattern, REG_EXTENDED);
- if (err)
- {
- len = regerror (err, &re, errbuf, sizeof (errbuf));
- sprintf(msg, "error: regcomp: %s\r\n", errbuf);
- return 0;
- }
- /* execute pattern match */
- err = regexec (&re, mail, (size_t)SUBSLEN, subs, 0);
- if (err == REG_NOMATCH)
- {
- sprintf (msg, "Invalid mail address\r\n");
- regfree (&re);
- return 0;
- }
- else if (err)
- {
- len = regerror (err, &re, errbuf, sizeof (errbuf));
- sprintf(msg, "error: regexec: %s\r\n", errbuf);
- return 0;
- }
- regfree(&re);
- if (subs[0].rm_so == 0 && subs[0].rm_eo == strlen(mail))
- {
- return 1;
- }
- sprintf (msg, "Invalid mail address\r\n");
- return 0;
- }
- /*
- 初始设置:每天最多可发送的邮件数
- 具体每个那个用户每天可发信的数量
- 限制可在该用户目录下的mailsperday
- 文件中的第二个域修改
- */
- #define MAX_MAILS_PERDAY 30
- /*
- user: 用户完整mail地址
- dir : 返回用户的目录,如果用户存在
- 返回值:如果发生错误返回 -1,
- 无此用户返回 -2,
- 否则返回0
- */
- int getuserdir(const char *user, char * dir)
- {
- FILE * fp = NULL;
- char command[150];
- int len;
- if (strlen(user) >; 97) return 0;
- sprintf(command, "/home/vpopmail/bin/vuserinfo %s -d", user);
- fp = popen(command, "r");
- if (fp ==NULL) return -1;
- len = read(fileno(fp),dir,PATH_MAX);
- if (len == -1) return -1;
- if (strstr(dir, "no such user") != 0) return -2; //无此帐户
- if (fp != NULL) pclose(fp);
- return 0;
- }
- /*
- 在每个用户的目录下有一个文件mailsperday记录
- 当天该用户利用smtp和web mail发信的情况,该文
- 件只有一行,分为4个域,每个域宽度为10个字符,
- 域之间用一个空格分开,所以改行总长度为43
- 记录日期(10个字符)
- 每天最多可发送邮件的数目
- 记录当天通过smtp已发信的数目
- 记录当天通过webmail已发送邮件的数目
- 函数返回值:
- 0: 通过发信次数检查
- -1: 内存分配失败
- -2: 文件操作失败
- -3: 发信次数已达限制,不能发信
- */
- int checkmaxmailsperday(const char* dir/*要检查的用户的目录*/)
- {
- int fd, len;
- char info[50];
- char temp[50];
- short year, month, day;
- short limit, smtp, webmail;
- char *path;
- time_t cur_time;
- struct tm *cur_tm;
- char filename[]="/mailsperday";
- int i=0;
- /*给path分配空间,并将path置为有完整路径的文件名*/
- len = strlen(dir);
- path = (char*)calloc(strlen(dir)+13, 1);
- if (path == 0) return -1;
- strcpy(path, dir);
- /*在这里不知道为什么strcat不好用*/
- for(i=len-1;i<len+11;i++)
- path[i] = filename[i-len+1];
- path[i] = '\0';
- if ((fd = open(path,O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) == -1) return -2;
- if ((len = read(fd, info, 43)) == -1) return -2;
- cur_time = time(NULL);
- cur_tm = localtime(&cur_time);
- year = cur_tm->;tm_year + 1900;
- month = cur_tm->;tm_mon + 1;
- day = cur_tm->;tm_mday;
- limit = MAX_MAILS_PERDAY;
- smtp = 0;
- webmail = 0;
- /*如果读到了43个字符,说明文件已存在,
- 不是刚刚创建出来的,那么提取文件中的
- 数据
- */
- if (len >;= 43)
- {
- strncpy(temp, info, 4);
- year = atoi(temp);
- memset(temp, 0, 50);
- strncpy(temp, info+5, 2);
- month = atoi(temp);
- memset(temp, 0, 50);
- strncpy(temp, info+8, 2);
- day = atoi(temp);
- memset(temp, 0, 50);
- strncpy(temp, info+11, 10);
- limit = atoi(temp);
- memset(temp, 0, 50);
- strncpy(temp, info+22, 10);
- smtp = atoi(temp);
- memset(temp, 0, 50);
- strncpy(temp, info+33, 10);
- webmail = atoi(temp);
- /*
- 如果文件中记录的时间不是今天,
- 则置smtp和webmail的值为0,
- 时间置为今天
- */
- if (!(year == cur_tm->;tm_year+1900 && month == cur_tm->;tm_mon+1
- && day == cur_tm->;tm_mday))
- {
- year = cur_tm->;tm_year + 1900;
- month = cur_tm->;tm_mon + 1;
- day = cur_tm->;tm_mday;
- smtp = 0;
- webmail = 0;
- }
- }
- /*判断发信是否超出次数限制*/
- if (smtp + webmail + 1 >; limit)
- {
- return -3; /*发信次数超过限制*/
- }
- else
- {
- smtp += 1;
- memset(temp, 0, 50);
- sprintf(temp, "%4d/%2d/%2d %10d %10d %10d\n",
- year, month, day, limit, smtp, webmail);
- lseek(fd, 0, SEEK_SET);
- len = write(fd, temp, 44);
- if (len != 44) return -2;
- }
- close(fd);
- if (path != 0 ) free(path);
- return 0;
- }
- /************************* Added by Jizhao*********************************/
- int safewrite(fd,buf,len) int fd; char *buf; int len;
- {
- int r;
- r = timeoutwrite(timeout,fd,buf,len);
- if (r <= 0) _exit(1);
- return r;
- }
- char ssoutbuf[512];
- substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);
- void flush() { substdio_flush(&ssout); }
- void out(s) char *s; { substdio_puts(&ssout,s); }
- void die_read() { _exit(1); }
- void die_alarm() { out("451 timeout (#4.4.2)\r\n"); flush(); _exit(1); }
- void die_nomem() { out("421 out of memory (#4.3.0)\r\n"); flush(); _exit(1); }
- void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); flush(); _exit(1); }
- void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); }
- void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }
- void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
- void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
- void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); }
- void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }
- void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); }
- void err_wantrcpt() { out("503 RCPT first (#5.5.1)\r\n"); }
- void err_noop() { out("250 ok\r\n"); }
- void err_vrfy() { out("252 send some mail, i'll try my best\r\n"); }
- void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }
- int err_child() { out("454 oops, problem with child and I can't auth (#4.3.0)\r\n"); return -1; }
- int err_fork() { out("454 oops, child won't start and I can't auth (#4.3.0)\r\n"); return -1; }
- int err_pipe() { out("454 oops, unable to open pipe and I can't auth (#4.3.0)\r\n"); return -1; }
- int err_write() { out("454 oops, unable to write pipe and I can't auth (#4.3.0)\r\n"); return -1; }
- void err_authd() { out("503 you're already authenticated (#5.5.0)\r\n"); }
- void err_authmail() { out("503 no auth during mail transaction (#5.5.0)\r\n"); }
- int err_noauth() { out("504 auth type unimplemented (#5.5.1)\r\n"); return -1; }
- int err_authabrt() { out("501 auth exchange cancelled (#5.0.0)\r\n"); return -1; }
- int err_input() { out("501 malformed auth input (#5.5.4)\r\n"); return -1; }
- /************************* Added by Jizhao*********************************/
- void outsafe(stralloc *sa)
- {
- int i;
- char ch[200];
- for (i = 0;i < sa->;len;++i)
- {
- ch[i] = sa->;s[i]; if (ch[i] < 33) ch[i] = '?'; if (ch[i] >; 126) ch[i] = '?';
- }
- ch[i-1]='\0';
- out(ch);
- }
- /*
- 处理用户认证的用户名为完整形式,即
- username@domain
- */
- void complete_authusername()
- {
- stralloc temp = {0}, mydefaultdomain={0};
- int isaddress = 0; /*如果为0,说明需要加上defaultdomain,否则不需要加*/
- int len = 0, i = 0;
- len = authusername.len;
- for (i = 0; i < len; i++)
- {
- if (authusername.s[i] == '@')
- {
- isaddress = 1;
- break;
- }
- }
- if (isaddress == 0)
- {
- if (control_readfile(&mydefaultdomain,"/var/qmail/control/defaultdomain",1) != 1)
- {
- die_nomem();
- }
- /*
- 由于从defaultdomain中读出的字符串末尾有
- 一个特殊字符,所以要先去掉它,再放到放到
- mydefaultdomain里面去
- */
- if (!stralloc_copyb(&completeusername, authusername.s, authusername.len-1))
- {
- die_nomem();
- }
- if (!stralloc_cats(&completeusername, "@") )
- {
- die_nomem();
- }
- if (!stralloc_cat(&completeusername, &mydefaultdomain))
- {
- die_nomem();
- }
- }
- else
- {
- if (!stralloc_cat(&completeusername, &authusername))
- {
- die_nomem();
- }
- }
- }
- /*********************************Added by jizhao**************************/
- stralloc greeting = {0};
- void smtp_greet(code) char *code;
- {
- substdio_puts(&ssout,code);
- substdio_put(&ssout,greeting.s,greeting.len);
- }
- void smtp_help()
- {
- out("214 qmail home page: http://pobox.com/~djb/qmail.html\r\n");
- }
- void smtp_quit()
- {
- smtp_greet("221 "); out("\r\n"); flush(); _exit(0);
- }
- char *remoteip;
- char *remotehost;
- char *remoteinfo;
- char *local;
- char *relayclient;
- stralloc helohost = {0};
- char *fakehelo; /* pointer into helohost, or 0 */
- void dohelo(arg) char *arg; {
- if (!stralloc_copys(&helohost,arg)) die_nomem();
- if (!stralloc_0(&helohost)) die_nomem();
- fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0;
- }
- int liphostok = 0;
- stralloc liphost = {0};
- int bmfok = 0;
- stralloc bmf = {0};
- struct constmap mapbmf;
- void setup()
- {
- char *x;
- unsigned long u;
-
- if (control_init() == -1) die_control();
- if (control_rldef(&greeting,"control/smtpgreeting",1,(char *) 0) != 1)
- die_control();
- liphostok = control_rldef(&liphost,"control/localiphost",1,(char *) 0);
- if (liphostok == -1) die_control();
- if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control();
- if (timeout <= 0) timeout = 1;
- if (rcpthosts_init() == -1) die_control();
- bmfok = control_readfile(&bmf,"control/badmailfrom",0);
- if (bmfok == -1) die_control();
- if (bmfok)
- if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem();
-
- if (control_readint(&databytes,"control/databytes") == -1) die_control();
- x = env_get("DATABYTES");
- if (x) { scan_ulong(x,&u); databytes = u; }
- if (!(databytes + 1)) --databytes;
-
- remoteip = env_get("TCPREMOTEIP");
- if (!remoteip) remoteip = "unknown";
- local = env_get("TCPLOCALHOST");
- if (!local) local = env_get("TCPLOCALIP");
- if (!local) local = "unknown";
- remotehost = env_get("TCPREMOTEHOST");
- if (!remotehost) remotehost = "unknown";
- remoteinfo = env_get("TCPREMOTEINFO");
- relayclient = env_get("RELAYCLIENT");
- dohelo(remotehost);
- }
- stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
- int addrparse(arg)
- char *arg;
- {
- int i;
- char ch;
- char terminator;
- struct ip_address ip;
- int flagesc;
- int flagquoted;
-
- /********Added by Jizhao****/
- char error[150];
- /********Added by Jizhao****/
-
-
- terminator = '>;';
- i = str_chr(arg,'<');
- if (arg[i])
- arg += i + 1;
- else { /* partner should go read rfc 821 */
- terminator = ' ';
- arg += str_chr(arg,':');
- if (*arg == ':') ++arg;
- while (*arg == ' ') ++arg;
- }
- /* strip source route */
- if (*arg == '@') while (*arg) if (*arg++ == ':') break;
- if (!stralloc_copys(&addr,"")) die_nomem();
- flagesc = 0;
- flagquoted = 0;
- for (i = 0;ch = arg[i];++i) { /* copy arg to addr, stripping quotes */
- if (flagesc) {
- if (!stralloc_append(&addr,&ch)) die_nomem();
- flagesc = 0;
- }
- else {
- if (!flagquoted && (ch == terminator)) break;
- switch(ch) {
- case '\\': flagesc = 1; break;
- case '"': flagquoted = !flagquoted; break;
- default: if (!stralloc_append(&addr,&ch)) die_nomem();
- }
- }
- }
- /* could check for termination failure here, but why bother? */
- if (!stralloc_append(&addr,"")) die_nomem();
- if (liphostok) {
- i = byte_rchr(addr.s,addr.len,'@');
- if (i < addr.len) /* if not, partner should go read rfc 821 */
- if (addr.s[i + 1] == '[')
- if (!addr.s[i + 1 + ip_scanbracket(addr.s + i + 1,&ip)])
- if (ipme_is(&ip)) {
- addr.len = i + 1;
- if (!stralloc_cat(&addr,&liphost)) die_nomem();
- if (!stralloc_0(&addr)) die_nomem();
- }
- }
- //if (addr.len >; 900) return 0;
-
- /**********************Added by Jizhao***********/
- /*Qmail判断大于900才出错,我觉得小于6或者大于
- 97的都非法*/
- if (addr.len < 7 || addr.len >; 97) return 0;
- if(!CheckMailAddress(addr.s,error))
- {
- out(error);
- return 0;
- }
- /**********************Added by Jizhao**********/
-
- return 1;
- }
- int bmfcheck()
- {
- int j;
- if (!bmfok) return 0;
- if (constmap(&mapbmf,addr.s,addr.len - 1)) return 1;
- j = byte_rchr(addr.s,addr.len,'@');
- if (j < addr.len)
- if (constmap(&mapbmf,addr.s + j,addr.len - j - 1)) return 1;
- return 0;
- }
- int addrallowed()
- {
- int r;
- r = rcpthosts(addr.s,str_len(addr.s));
- if (r == -1) die_control();
- return r;
- }
- int seenmail = 0;
- int flagbarf; /* defined if seenmail */
- stralloc mailfrom = {0};
- stralloc rcptto = {0};
- void smtp_helo(arg) char *arg;
- {
- smtp_greet("250 "); out("\r\n");
- seenmail = 0; dohelo(arg);
- }
- void smtp_ehlo(arg) char *arg;
- {
- smtp_greet("250-");
- #ifdef AUTHCRAM
- out("\r\n250-AUTH LOGIN CRAM-MD5 PLAIN");
- out("\r\n250-AUTH=LOGIN CRAM-MD5 PLAIN");
- #else
- out("\r\n250-AUTH LOGIN PLAIN");
- out("\r\n250-AUTH=LOGIN PLAIN");
- #endif
- out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
- seenmail = 0; dohelo(arg);
-
- /*************Added by jizhao**********/
- ehlo = 1;
- /*************Added by jizhao**********/
-
- }
- void smtp_rset()
- {
- seenmail = 0;
- out("250 flushed\r\n");
- }
- void smtp_mail(arg) char *arg;
- {
- /*******Added by Jizhao*****/
- char dir[PATH_MAX];
- short result;
- /*******Added by Jizhao*****/
- if (!addrparse(arg)) { err_syntax(); return; }
- flagbarf = bmfcheck();
- seenmail = 1;
- if (!stralloc_copys(&rcptto,"")) die_nomem();
- if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
- if (!stralloc_0(&mailfrom)) die_nomem();
-
- /*****************************Added by jizhao***********************/
- if (ehlo == 1) /*如果是通过认证发信*/
- {
- complete_authusername();
- /*检查发信次数是否超出限制*/
- result = getuserdir(completeusername.s, dir);
- if (result != 0)
- {
- out("Unable to get user's info\r\n");
- flush();
- _exit(1);
- }
- result = checkmaxmailsperday(dir);
- if (result == -1)
- {
- die_nomem();
- }
- else if (result == -2)
- {
- out("Unable to access user's mailsperday file!\r\n");
- flush();
- _exit(1);
- }
- else if (result == -3)
- {
- out("The times of your sending mails are too much today!\r\n");
- flush();
- _exit(1);
- }
- /*检查发信人跟mailfrom是否一致*/
- if(case_diffs(completeusername.s,mailfrom.s)) /*如果不同,返回false*/
- {
- /*outsafe(&completeusername);*/
- out("username does't equal mailfrom\r\n"); /*认证用户名与mailfrom中的地址不符*/
- flush();
- _exit(1); //出错返回
- }
- }
- /*****************************Added by jizhao**********************/
- out("250 ok\r\n");
- }
- void smtp_rcpt(arg) char *arg; {
- /*************Added by Jizhao******/
- char dir[PATH_MAX];
- short result;
- /*************Added by Jizhao******/
- if (!seenmail) { err_wantmail(); return; }
- if (!addrparse(arg)) { err_syntax(); return; }
- if (flagbarf) { err_bmf(); return; }
- if (relayclient) {
- --addr.len;
- if (!stralloc_cats(&addr,relayclient)) die_nomem();
- if (!stralloc_0(&addr)) die_nomem();
- }
- else
- if (!addrallowed()) { err_nogateway(); return; }
- if (!stralloc_cats(&rcptto,"T")) die_nomem();
- if (!stralloc_cats(&rcptto,addr.s)) die_nomem();
- if (!stralloc_0(&rcptto)) die_nomem();
- /*****************Added by Jizhao****************************/
- /*如果不通过认证发信,或者是别的邮件服务器发信过来
- 检查是否有该用户存在
- */
- if (ehlo != 1)
- {
- result = getuserdir(addr.s, dir);
- if (result == -1)
- {
- out("Unable to get user's info!\r\n");
- flush();
- _exit(1);
- }
- else if (result == -2)
- {
- out("No this user in our mail server!\r\n");
- flush();
- _exit(1);
- }
- }
- /*****************Added by Jizhao****************************/
-
- out("250 ok\r\n");
- }
- int saferead(fd,buf,len) int fd; char *buf; int len;
- {
- int r;
- flush();
- r = timeoutread(timeout,fd,buf,len);
- if (r == -1) if (errno == error_timeout) die_alarm();
- if (r <= 0) die_read();
- return r;
- }
- char ssinbuf[1024];
- substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);
- struct qmail qqt;
- unsigned int bytestooverflow = 0;
- void put(ch)
- char *ch;
- {
- if (bytestooverflow)
- if (!--bytestooverflow)
- qmail_fail(&qqt);
- qmail_put(&qqt,ch,1);
- }
- void blast(hops)
- int *hops;
- {
- char ch;
- int state;
- int flaginheader;
- int pos; /* number of bytes since most recent \n, if fih */
- int flagmaybex; /* 1 if this line might match RECEIVED, if fih */
- int flagmaybey; /* 1 if this line might match \r\n, if fih */
- int flagmaybez; /* 1 if this line might match DELIVERED, if fih */
-
- state = 1;
- *hops = 0;
- flaginheader = 1;
- pos = 0; flagmaybex = flagmaybey = flagmaybez = 1;
- for (;;) {
- substdio_get(&ssin,&ch,1);
- if (flaginheader) {
- if (pos < 9) {
- if (ch != "delivered"[pos]) if (ch != "DELIVERED"[pos]) flagmaybez = 0;
- if (flagmaybez) if (pos == 8) ++*hops;
- if (pos < 8)
- if (ch != "received"[pos]) if (ch != "RECEIVED"[pos]) flagmaybex = 0;
- if (flagmaybex) if (pos == 7) ++*hops;
- if (pos < 2) if (ch != "\r\n"[pos]) flagmaybey = 0;
- if (flagmaybey) if (pos == 1) flaginheader = 0;
- }
- ++pos;
- if (ch == '\n') { pos = 0; flagmaybex = flagmaybey = flagmaybez = 1; }
- }
- switch(state) {
- case 0:
- if (ch == '\n') straynewline();
- if (ch == '\r') { state = 4; continue; }
- break;
- case 1: /* \r\n */
- if (ch == '\n') straynewline();
- if (ch == '.') { state = 2; continue; }
- if (ch == '\r') { state = 4; continue; }
- state = 0;
- break;
- case 2: /* \r\n + . */
- if (ch == '\n') straynewline();
- if (ch == '\r') { state = 3; continue; }
- state = 0;
- break;
- case 3: /* \r\n + .\r */
- if (ch == '\n') return;
- put(".");
- put("\r");
- if (ch == '\r') { state = 4; continue; }
- state = 0;
- break;
- case 4: /* + \r */
- if (ch == '\n') { state = 1; break; }
- if (ch != '\r') { put("\r"); state = 0; }
- }
- put(&ch);
- }
- }
- char accept_buf[FMT_ULONG];
- void acceptmessage(qp) unsigned long qp;
- {
- datetime_sec when;
- when = now();
- out("250 ok ");
- accept_buf[fmt_ulong(accept_buf,(unsigned long) when)] = 0;
- out(accept_buf);
- out(" qp ");
- accept_buf[fmt_ulong(accept_buf,qp)] = 0;
- out(accept_buf);
- out("\r\n");
- }
- void smtp_data() {
- int hops;
- unsigned long qp;
- char *qqx;
-
- if (!seenmail) { err_wantmail(); return; }
- if (!rcptto.len) { err_wantrcpt(); return; }
- seenmail = 0;
- if (databytes) bytestooverflow = databytes + 1;
- if (qmail_open(&qqt) == -1) { err_qqt(); return; }
- qp = qmail_qp(&qqt);
- out("354 go ahead\r\n");
-
- received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo);
- blast(&hops);
- hops = (hops >;= MAXHOPS);
- if (hops) qmail_fail(&qqt);
- qmail_from(&qqt,mailfrom.s);
- qmail_put(&qqt,rcptto.s,rcptto.len);
-
- qqx = qmail_close(&qqt);
- if (!*qqx) { acceptmessage(qp); return; }
- if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; }
- if (databytes) if (!bytestooverflow) { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return; }
- if (*qqx == 'D') out("554 "); else out("451 ");
- out(qqx + 1);
- out("\r\n");
- }
- char unique[FMT_ULONG + FMT_ULONG + 3];
- static stralloc authin = {0};
- static stralloc user = {0};
- static stralloc pass = {0};
- static stralloc resp = {0};
- static stralloc slop = {0};
- char *hostname;
- char **childargs;
- substdio ssup;
- char upbuf[128];
- int authd = 0;
- int authgetl(void) {
- int i;
- if (!stralloc_copys(&authin, "")) die_nomem();
- for (;;) {
- if (!stralloc_readyplus(&authin,1)) die_nomem(); /* XXX */
- i = substdio_get(&ssin,authin.s + authin.len,1);
- if (i != 1) die_read();
- if (authin.s[authin.len] == '\n') break;
- ++authin.len;
- }
- if (authin.len >; 0) if (authin.s[authin.len - 1] == '\r') --authin.len;
- authin.s[authin.len] = 0;
- if (*authin.s == '*' && *(authin.s + 1) == 0) { return err_authabrt(); }
- if (authin.len == 0) { return err_input(); }
- return authin.len;
- }
- int authenticate(void)
- {
- int child;
- int wstat;
- int pi[2];
- if (!stralloc_0(&user)) die_nomem();
- if (!stralloc_0(&pass)) die_nomem();
- if (!stralloc_0(&resp)) die_nomem();
- if (fd_copy(2,1) == -1) return err_pipe();
- close(3);
- if (pipe(pi) == -1) return err_pipe();
- if (pi[0] != 3) return err_pipe();
- switch(child = fork()) {
- case -1:
- return err_fork();
- case 0:
- close(pi[1]);
- sig_pipedefault();
- execvp(*childargs, childargs);
- _exit(1);
- }
- close(pi[0]);
- substdio_fdbuf(&ssup,write,pi[1],upbuf,sizeof upbuf);
- if (substdio_put(&ssup,user.s,user.len) == -1) return err_write();
- if (substdio_put(&ssup,pass.s,pass.len) == -1) return err_write();
- if (substdio_put(&ssup,resp.s,resp.len) == -1) return err_write();
- if (substdio_flush(&ssup) == -1) return err_write();
- close(pi[1]);
- byte_zero(pass.s,pass.len);
- byte_zero(upbuf,sizeof upbuf);
- if (wait_pid(&wstat,child) == -1) return err_child();
- if (wait_crashed(wstat)) return err_child();
- if (wait_exitcode(wstat)) { sleep(5); return 1; } /* no */
-
- /***************Added by Jizhao******************/
- /*将用户名存入全局变量 authusername*/
- if(!stralloc_copy(&authusername,&user)) return 1;
- /***************Added by Jizhao******************/
-
- return 0; /* yes */
- }
- int auth_login(arg) char *arg;
- {
- int r;
- if (*arg) {
- if (r = b64decode(arg,str_len(arg),&user) == 1) return err_input();
- }
- else {
- out("334 VXNlcm5hbWU6\r\n"); flush(); /* Username: */
- if (authgetl() < 0) return -1;
- if (r = b64decode(authin.s,authin.len,&user) == 1) return err_input();
- }
- if (r == -1) die_nomem();
- out("334 UGFzc3dvcmQ6\r\n"); flush(); /* Password: */
- if (authgetl() < 0) return -1;
- if (r = b64decode(authin.s,authin.len,&pass) == 1) return err_input();
- if (r == -1) die_nomem();
- if (!user.len || !pass.len) return err_input();
- return authenticate();
- }
- int auth_plain(arg) char *arg;
- {
- int r, id = 0;
- if (*arg) {
- if (r = b64decode(arg,str_len(arg),&slop) == 1) return err_input();
- }
- else {
- out("334 \r\n"); flush();
- if (authgetl() < 0) return -1;
- if (r = b64decode(authin.s,authin.len,&slop) == 1) return err_input();
- }
- if (r == -1 || !stralloc_0(&slop)) die_nomem();
- while (slop.s[id]) id++; /* ignore authorize-id */
- if (slop.len >; id + 1)
- if (!stralloc_copys(&user,slop.s + id + 1)) die_nomem();
- if (slop.len >; id + user.len + 2)
- if (!stralloc_copys(&pass,slop.s + id + user.len + 2)) die_nomem();
- if (!user.len || !pass.len) return err_input();
- return authenticate();
- }
- #ifdef AUTHCRAM
- int auth_cram()
- {
- int i, r;
- char *s;
- s = unique;
- s += fmt_uint(s,getpid());
- *s++ = '.';
- s += fmt_ulong(s,(unsigned long) now());
- *s++ = '@';
- *s++ = 0;
- if (!stralloc_copys(&pass,"<")) die_nomem();
- if (!stralloc_cats(&pass,unique)) die_nomem();
- if (!stralloc_cats(&pass,hostname)) die_nomem();
- if (!stralloc_cats(&pass,">;")) die_nomem();
- if (b64encode(&pass,&slop) < 0) die_nomem();
- if (!stralloc_0(&slop)) die_nomem();
- out("334 ");
- out(slop.s);
- out("\r\n");
- flush();
- if (authgetl() < 0) return -1;
- if (r = b64decode(authin.s,authin.len,&slop) == 1) return err_input();
- if (r == -1 || !stralloc_0(&slop)) die_nomem();
- i = str_chr(slop.s,' ');
- s = slop.s + i;
- while (*s == ' ') ++s;
- slop.s[i] = 0;
- if (!stralloc_copys(&user,slop.s)) die_nomem();
- if (!stralloc_copys(&resp,s)) die_nomem();
- if (!user.len || !resp.len) return err_input();
- return authenticate();
- }
- #endif
- struct authcmd {
- char *text;
- int (*fun)();
- } authcmds[] = {
- { "login", auth_login }
- , { "plain", auth_plain }
- #ifdef AUTHCRAM
- , { "cram-md5", auth_cram }
- #endif
- , { 0, err_noauth }
- };
- void smtp_auth(arg)
- char *arg;
- {
- int i;
- char *cmd = arg;
- if (!hostname || !*childargs)
- {
- out("503 auth not available (#5.3.3)\r\n");
- return;
- }
- if (authd) { err_authd(); return; }
- if (seenmail) { err_authmail(); return; }
- if (!stralloc_copys(&user,"")) die_nomem();
- if (!stralloc_copys(&pass,"")) die_nomem();
- if (!stralloc_copys(&resp,"")) die_nomem();
- i = str_chr(cmd,' ');
- arg = cmd + i;
- while (*arg == ' ') ++arg;
- cmd[i] = 0;
- for (i = 0;authcmds[i].text;++i)
- if (case_equals(authcmds[i].text,cmd)) break;
- switch (authcmds[i].fun(arg)) {
- case 0:
- authd = 1;
- relayclient = "";
- remoteinfo = user.s;
- if (!env_unset("TCPREMOTEINFO")) die_read();
- if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem();
- out("235 ok, go ahead (#2.0.0)\r\n");
- break;
- case 1:
- out("535 authorization failed (#5.7.0)\r\n");
- }
- }
- struct commands smtpcommands[] = {
- { "rcpt", smtp_rcpt, 0 }
- , { "mail", smtp_mail, 0 }
- , { "data", smtp_data, flush }
- , { "auth", smtp_auth, flush }
- , { "quit", smtp_quit, flush }
- , { "helo", smtp_helo, flush }
- , { "ehlo", smtp_ehlo, flush }
- , { "rset", smtp_rset, 0 }
- , { "help", smtp_help, flush }
- , { "noop", err_noop, flush }
- , { "vrfy", err_vrfy, flush }
- , { 0, err_unimpl, flush }
- } ;
- void main(argc,argv)
- int argc;
- char **argv;
- {
- hostname = argv[1];
- childargs = argv + 2;
- sig_pipeignore();
- if (chdir(auto_qmail) == -1) die_control();
- setup();
- if (ipme_init() != 1) die_ipme();
- smtp_greet("220 ");
- out(" ESMTP\r\n");
- if (commands(&ssin,&smtpcommands) == 0) die_read();
- die_nomem();
- }
复制代码 |
|