免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 11779 | 回复: 11
打印 上一主题 下一主题

[Mail] qmail-smtpd.c拒收垃圾邮件修改(原创) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2003-09-12 18:16 |只看该作者 |倒序浏览
在这里学习了很多,贡献一点我自己的东西,我不会写patch,
所以就这样写出来了,大家将就一下!
     修改qmail-smtpd.c使其支持以下功能,注意此处的qmail-smtpd.c是在打了
        qmail-smtpd-auth-0.31补丁或者是qmail-smtpd-auth-0.30补丁以后的程序
        功能列表:
        (a)发信人和收信人的地址只能由字母、数字、下划线、减号和点号组成,
                且@符号只能有一个,并且地址长度必须大于5,小于97.
        (b)检查在使用认证的smtp向本服务器发信时,认证的用户必须和
                 mail from:<XXXX@XXXX>;的邮件地址相同,不同,则不发信
        (c)在使用非认证的smtp向本机发信时(邮件服务器之间送信,使用非认证的smtp协议),
                检查是否有此用户,若没有此用户,则拒收.
        (d)对本邮件服务器上的用户采用每日发信次数的限制,超过,则不允许
                在当天再发信,这样即便是有人破解了你的用户,也不大能发送
                大量的垃圾邮件
        安装:先确保smtp服务器是由用户vpopmail来运行的
        开始安装:
        (1)在qmail-smtpd.c的所有include 之后,加入以下代码
        /*******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******/

        (2)在int timeout和函数int safewrite之间加入以下代码:
        /************************* 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        = filename[i-len+1];
                path        = '\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*********************************/
        (3)在函数int err_input()和stralloc greeting = {0}之间加入以下代码:
        /************************* Added by Jizhao*********************************/
        void outsafe(stralloc *sa)
        {
                int i;

                char ch[200];
                for (i = 0;i < sa->;len;++i)
                {
                        ch = sa->;s; if (ch < 33) ch = '?'; if (ch >; 126) ch = '?';
                }
                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 == '@')
                        {
                                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**************************/
        (4)在函数int addrparse(arg)中所有变量的定义之后,即int flagquoted之后,加入以下
                代码:
                  /********Added by Jizhao****/
                  char error[150];
                  /********Added by Jizhao****/
        (5)在函数addrparse中注释掉if (addr.len >; 900) return 0;这一行,并在此行和return 1之间
        加入以下代码:
          /**********************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**********/
        (6)在函数smtp_ehlo的最后,加入如下代码:
         /*************Added by jizhao**********/
         ehlo = 1;
          /*************Added by jizhao**********/
        (7)在函数smtp_mail的一开始加入以下代码:
        /*******Added by Jizhao*****/
        char dir[PATH_MAX];
          short        result;
          /*******Added by Jizhao*****/
        (在函数smtp_mail的out("250 ok\r\n";行,即最后一行前,加入以下代码:
          /*****************************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**********************/
        (9)在函数smtp_rcpt的一开始加入如下代码:
        /*************Added by Jizhao******/
          char dir[PATH_MAX];
          short        result;
        /*************Added by Jizhao******/
        (10)在函数smtp_rcpt的out("250 ok\r\n");行,即最后一行前,加入以下代码:
          /*****************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****************************/
        (11)在函数authenticate的return一行之前加入如下代码:
        /***************Added by Jizhao******************/
        /*将用户名存入全局变量 authusername*/
        if(!stralloc_copy(&authusername,&user)) return 1;
          /***************Added by Jizhao******************/
ximeng 该用户已被删除
2 [报告]
发表于 2003-09-13 00:23 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
3 [报告]
发表于 2003-09-13 09:37 |只看该作者

qmail-smtpd.c拒收垃圾邮件修改(原创)

最好用code标签包一下,顺便关掉表情符号
carolson 该用户已被删除
4 [报告]
发表于 2003-09-14 09:50 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
5 [报告]
发表于 2003-09-14 12:56 |只看该作者

qmail-smtpd.c拒收垃圾邮件修改(原创)

我发现在qmail-smtp认证那里还有bug,等我修改完了一并穿上来,不过怎么用code标签,能有人说一下吗?
另外上传附件呢?

论坛徽章:
0
6 [报告]
发表于 2003-09-14 12:58 |只看该作者

qmail-smtpd.c拒收垃圾邮件修改(原创)

我把它贴出来吧,大家看着也比较方便.我也试了一下,不错,多谢楼主.大家也帮忙测试一下

  1. #include "sig.h"
  2. #include "readwrite.h"
  3. #include "stralloc.h"
  4. #include "substdio.h"
  5. #include "alloc.h"
  6. #include "auto_qmail.h"
  7. #include "control.h"
  8. #include "received.h"
  9. #include "constmap.h"
  10. #include "error.h"
  11. #include "ipme.h"
  12. #include "ip.h"
  13. #include "qmail.h"
  14. #include "str.h"
  15. #include "fmt.h"
  16. #include "scan.h"
  17. #include "byte.h"
  18. #include "case.h"
  19. #include "env.h"
  20. #include "now.h"
  21. #include "exit.h"
  22. #include "rcpthosts.h"
  23. #include "timeoutread.h"
  24. #include "timeoutwrite.h"
  25. #include "commands.h"
  26. #include "wait.h"
  27. #include "fd.h"

  28. /*******Added by Jizhao******/
  29. #include <stdio.h>;
  30. #include <regex.h>;
  31. #include <unistd.h>;
  32. #include <sys/types.h>;
  33. #include <limits.h>;
  34. #include <sys/stat.h>;
  35. #include <fcntl.h>;
  36. #include <time.h>;
  37. #include <string.h>;
  38. /*******Added by Jizhao******/

  39. #define AUTHCRAM
  40. #define MAXHOPS 100
  41. unsigned int databytes = 0;
  42. int timeout = 1200;

  43. /************************* Added by Jizhao*********************************/
  44. /*
  45. 全局变量用于记录认证的email地址
  46. 如果是虚拟域的用户则是邮件地址
  47. 如果是主域用户则在函数authenticate
  48. 里面赋值后,需加上defaultdomain里面的内容
  49. */
  50. stralloc authusername={0};
  51. stralloc completeusername={0};
  52. /*
  53. 如果是远程邮件服务器连接本地的
  54. smtp,则远程主机使用的是不带认证
  55. 的连接方式,即在连接建立以后,
  56. 远程主机使用的是helo命令,这样
  57. 远程主机就只能向本机发送本地域
  58. 的用户,因为如果用ehlo的话,远程
  59. 主机不可能知道每个帐户的密码
  60. ehlo 记录,smtp连接使用的是
  61. helo还是ehlo
  62. 0:helo 1:ehlo
  63. */
  64. int ehlo = 0;
  65. /*
  66. 检查邮件地址只能由字母、数字、下划线、减号
  67. 和点组成,其余均视为为非法地址
  68. */
  69. #define SUBSLEN 20
  70. #define EBUFLEN 128 /* error buffer length */

  71. int CheckMailAddress(char * mail, char * msg)
  72. {
  73. size_t len; /* store error message length */
  74. regex_t re; /* store compilned regular expression */
  75. regmatch_t subs[SUBSLEN]; /* store matched string position */
  76. char errbuf[EBUFLEN]; /* store error message */
  77. int err, i;
  78. char pattern[] = "([a-zA-Z\\.0-9_-])+@([a-zA-Z\\.0-9_-])+";

  79. /* compile regular expression */
  80. err = regcomp (&re, pattern, REG_EXTENDED);
  81. if (err)
  82. {
  83. len = regerror (err, &re, errbuf, sizeof (errbuf));
  84. sprintf(msg, "error: regcomp: %s\r\n", errbuf);
  85. return 0;
  86. }

  87. /* execute pattern match */
  88. err = regexec (&re, mail, (size_t)SUBSLEN, subs, 0);
  89. if (err == REG_NOMATCH)
  90. {
  91. sprintf (msg, "Invalid mail address\r\n");
  92. regfree (&re);
  93. return 0;
  94. }
  95. else if (err)
  96. {
  97. len = regerror (err, &re, errbuf, sizeof (errbuf));
  98. sprintf(msg, "error: regexec: %s\r\n", errbuf);
  99. return 0;
  100. }
  101. regfree(&re);
  102. if (subs[0].rm_so == 0 && subs[0].rm_eo == strlen(mail))
  103. {
  104. return 1;
  105. }
  106. sprintf (msg, "Invalid mail address\r\n");
  107. return 0;
  108. }
  109. /*
  110. 初始设置:每天最多可发送的邮件数
  111. 具体每个那个用户每天可发信的数量
  112. 限制可在该用户目录下的mailsperday
  113. 文件中的第二个域修改
  114. */
  115. #define MAX_MAILS_PERDAY 30
  116. /*
  117. user: 用户完整mail地址
  118. dir : 返回用户的目录,如果用户存在
  119. 返回值:如果发生错误返回 -1,
  120. 无此用户返回 -2,
  121. 否则返回0
  122. */
  123. int getuserdir(const char *user, char * dir)
  124. {
  125. FILE * fp = NULL;
  126. char command[150];
  127. int len;

  128. if (strlen(user) >; 97) return 0;
  129. sprintf(command, "/home/vpopmail/bin/vuserinfo %s -d", user);
  130. fp = popen(command, "r");
  131. if (fp ==NULL) return -1;
  132. len = read(fileno(fp),dir,PATH_MAX);
  133. if (len == -1) return -1;
  134. if (strstr(dir, "no such user") != 0) return -2; //无此帐户
  135. if (fp != NULL) pclose(fp);
  136. return 0;
  137. }
  138. /*
  139. 在每个用户的目录下有一个文件mailsperday记录
  140. 当天该用户利用smtp和web mail发信的情况,该文
  141. 件只有一行,分为4个域,每个域宽度为10个字符,
  142. 域之间用一个空格分开,所以改行总长度为43

  143. 记录日期(10个字符)
  144. 每天最多可发送邮件的数目
  145. 记录当天通过smtp已发信的数目
  146. 记录当天通过webmail已发送邮件的数目

  147. 函数返回值:
  148. 0: 通过发信次数检查
  149. -1: 内存分配失败
  150. -2: 文件操作失败
  151. -3: 发信次数已达限制,不能发信
  152. */

  153. int checkmaxmailsperday(const char* dir/*要检查的用户的目录*/)
  154. {
  155. int fd, len;
  156. char info[50];
  157. char temp[50];
  158. short year, month, day;
  159. short limit, smtp, webmail;
  160. char *path;
  161. time_t cur_time;
  162. struct tm *cur_tm;
  163. char filename[]="/mailsperday";
  164. int i=0;

  165. /*给path分配空间,并将path置为有完整路径的文件名*/
  166. len = strlen(dir);
  167. path = (char*)calloc(strlen(dir)+13, 1);
  168. if (path == 0) return -1;
  169. strcpy(path, dir);
  170. /*在这里不知道为什么strcat不好用*/
  171. for(i=len-1;i<len+11;i++)
  172. path[i] = filename[i-len+1];
  173. path[i] = '\0';

  174. if ((fd = open(path,O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) == -1) return -2;
  175. if ((len = read(fd, info, 43)) == -1) return -2;


  176. cur_time = time(NULL);
  177. cur_tm = localtime(&cur_time);
  178. year = cur_tm->;tm_year + 1900;
  179. month = cur_tm->;tm_mon + 1;
  180. day = cur_tm->;tm_mday;
  181. limit = MAX_MAILS_PERDAY;
  182. smtp = 0;
  183. webmail = 0;

  184. /*如果读到了43个字符,说明文件已存在,
  185. 不是刚刚创建出来的,那么提取文件中的
  186. 数据
  187. */
  188. if (len >;= 43)
  189. {
  190. strncpy(temp, info, 4);
  191. year = atoi(temp);

  192. memset(temp, 0, 50);
  193. strncpy(temp, info+5, 2);
  194. month = atoi(temp);

  195. memset(temp, 0, 50);
  196. strncpy(temp, info+8, 2);
  197. day = atoi(temp);

  198. memset(temp, 0, 50);
  199. strncpy(temp, info+11, 10);
  200. limit = atoi(temp);

  201. memset(temp, 0, 50);
  202. strncpy(temp, info+22, 10);
  203. smtp = atoi(temp);

  204. memset(temp, 0, 50);
  205. strncpy(temp, info+33, 10);
  206. webmail = atoi(temp);

  207. /*
  208. 如果文件中记录的时间不是今天,
  209. 则置smtp和webmail的值为0,
  210. 时间置为今天
  211. */
  212. if (!(year == cur_tm->;tm_year+1900 && month == cur_tm->;tm_mon+1
  213. && day == cur_tm->;tm_mday))
  214. {
  215. year = cur_tm->;tm_year + 1900;
  216. month = cur_tm->;tm_mon + 1;
  217. day = cur_tm->;tm_mday;
  218. smtp = 0;
  219. webmail = 0;
  220. }
  221. }

  222. /*判断发信是否超出次数限制*/
  223. if (smtp + webmail + 1 >; limit)
  224. {
  225. return -3; /*发信次数超过限制*/
  226. }
  227. else
  228. {
  229. smtp += 1;
  230. memset(temp, 0, 50);
  231. sprintf(temp, "%4d/%2d/%2d %10d %10d %10d\n",
  232. year, month, day, limit, smtp, webmail);
  233. lseek(fd, 0, SEEK_SET);
  234. len = write(fd, temp, 44);
  235. if (len != 44) return -2;
  236. }
  237. close(fd);
  238. if (path != 0 ) free(path);
  239. return 0;
  240. }

  241. /************************* Added by Jizhao*********************************/


  242. int safewrite(fd,buf,len) int fd; char *buf; int len;
  243. {
  244.   int r;
  245.   r = timeoutwrite(timeout,fd,buf,len);
  246.   if (r <= 0) _exit(1);
  247.   return r;
  248. }

  249. char ssoutbuf[512];
  250. substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);

  251. void flush() { substdio_flush(&ssout); }
  252. void out(s) char *s; { substdio_puts(&ssout,s); }

  253. void die_read() { _exit(1); }
  254. void die_alarm() { out("451 timeout (#4.4.2)\r\n"); flush(); _exit(1); }
  255. void die_nomem() { out("421 out of memory (#4.3.0)\r\n"); flush(); _exit(1); }
  256. void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); flush(); _exit(1); }
  257. void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); }
  258. void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }

  259. void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
  260. void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
  261. void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); }
  262. void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }
  263. void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); }
  264. void err_wantrcpt() { out("503 RCPT first (#5.5.1)\r\n"); }
  265. void err_noop() { out("250 ok\r\n"); }
  266. void err_vrfy() { out("252 send some mail, i'll try my best\r\n"); }
  267. void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }

  268. int err_child() { out("454 oops, problem with child and I can't auth (#4.3.0)\r\n"); return -1; }
  269. int err_fork() { out("454 oops, child won't start and I can't auth (#4.3.0)\r\n"); return -1; }
  270. int err_pipe() { out("454 oops, unable to open pipe and I can't auth (#4.3.0)\r\n"); return -1; }
  271. int err_write() { out("454 oops, unable to write pipe and I can't auth (#4.3.0)\r\n"); return -1; }
  272. void err_authd() { out("503 you're already authenticated (#5.5.0)\r\n"); }
  273. void err_authmail() { out("503 no auth during mail transaction (#5.5.0)\r\n"); }
  274. int err_noauth() { out("504 auth type unimplemented (#5.5.1)\r\n"); return -1; }
  275. int err_authabrt() { out("501 auth exchange cancelled (#5.0.0)\r\n"); return -1; }
  276. int err_input() { out("501 malformed auth input (#5.5.4)\r\n"); return -1; }

  277. /************************* Added by Jizhao*********************************/
  278. void outsafe(stralloc *sa)
  279. {
  280. int i;

  281. char ch[200];
  282. for (i = 0;i < sa->;len;++i)
  283. {
  284. ch[i] = sa->;s[i]; if (ch[i] < 33) ch[i] = '?'; if (ch[i] >; 126) ch[i] = '?';
  285. }
  286. ch[i-1]='\0';
  287. out(ch);
  288. }

  289. /*
  290. 处理用户认证的用户名为完整形式,即
  291. username@domain
  292. */
  293. void complete_authusername()
  294. {
  295. stralloc temp = {0}, mydefaultdomain={0};
  296. int isaddress = 0; /*如果为0,说明需要加上defaultdomain,否则不需要加*/
  297. int len = 0, i = 0;

  298. len = authusername.len;
  299. for (i = 0; i < len; i++)
  300. {
  301. if (authusername.s[i] == '@')
  302. {
  303. isaddress = 1;
  304. break;
  305. }
  306. }

  307. if (isaddress == 0)
  308. {
  309. if (control_readfile(&mydefaultdomain,"/var/qmail/control/defaultdomain",1) != 1)
  310. {
  311. die_nomem();
  312. }
  313. /*
  314. 由于从defaultdomain中读出的字符串末尾有
  315. 一个特殊字符,所以要先去掉它,再放到放到
  316. mydefaultdomain里面去
  317. */
  318. if (!stralloc_copyb(&completeusername, authusername.s, authusername.len-1))
  319. {
  320. die_nomem();
  321. }
  322. if (!stralloc_cats(&completeusername, "@") )
  323. {
  324. die_nomem();
  325. }
  326. if (!stralloc_cat(&completeusername, &mydefaultdomain))
  327. {
  328. die_nomem();
  329. }
  330. }
  331. else
  332. {
  333. if (!stralloc_cat(&completeusername, &authusername))
  334. {
  335. die_nomem();
  336. }
  337. }
  338. }

  339. /*********************************Added by jizhao**************************/


  340. stralloc greeting = {0};

  341. void smtp_greet(code) char *code;
  342. {
  343.   substdio_puts(&ssout,code);
  344.   substdio_put(&ssout,greeting.s,greeting.len);
  345. }
  346. void smtp_help()
  347. {
  348.   out("214 qmail home page: http://pobox.com/~djb/qmail.html\r\n");
  349. }
  350. void smtp_quit()
  351. {
  352.   smtp_greet("221 "); out("\r\n"); flush(); _exit(0);
  353. }

  354. char *remoteip;
  355. char *remotehost;
  356. char *remoteinfo;
  357. char *local;
  358. char *relayclient;

  359. stralloc helohost = {0};
  360. char *fakehelo; /* pointer into helohost, or 0 */

  361. void dohelo(arg) char *arg; {
  362.   if (!stralloc_copys(&helohost,arg)) die_nomem();
  363.   if (!stralloc_0(&helohost)) die_nomem();
  364.   fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0;
  365. }

  366. int liphostok = 0;
  367. stralloc liphost = {0};
  368. int bmfok = 0;
  369. stralloc bmf = {0};
  370. struct constmap mapbmf;

  371. void setup()
  372. {
  373.   char *x;
  374.   unsigned long u;

  375.   if (control_init() == -1) die_control();
  376.   if (control_rldef(&greeting,"control/smtpgreeting",1,(char *) 0) != 1)
  377.     die_control();
  378.   liphostok = control_rldef(&liphost,"control/localiphost",1,(char *) 0);
  379.   if (liphostok == -1) die_control();
  380.   if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control();
  381.   if (timeout <= 0) timeout = 1;

  382.   if (rcpthosts_init() == -1) die_control();

  383.   bmfok = control_readfile(&bmf,"control/badmailfrom",0);
  384.   if (bmfok == -1) die_control();
  385.   if (bmfok)
  386.     if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem();

  387.   if (control_readint(&databytes,"control/databytes") == -1) die_control();
  388.   x = env_get("DATABYTES");
  389.   if (x) { scan_ulong(x,&u); databytes = u; }
  390.   if (!(databytes + 1)) --databytes;

  391.   remoteip = env_get("TCPREMOTEIP");
  392.   if (!remoteip) remoteip = "unknown";
  393.   local = env_get("TCPLOCALHOST");
  394.   if (!local) local = env_get("TCPLOCALIP");
  395.   if (!local) local = "unknown";
  396.   remotehost = env_get("TCPREMOTEHOST");
  397.   if (!remotehost) remotehost = "unknown";
  398.   remoteinfo = env_get("TCPREMOTEINFO");
  399.   relayclient = env_get("RELAYCLIENT");
  400.   dohelo(remotehost);
  401. }


  402. stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */

  403. int addrparse(arg)
  404. char *arg;
  405. {
  406.   int i;
  407.   char ch;
  408.   char terminator;
  409.   struct ip_address ip;
  410.   int flagesc;
  411.   int flagquoted;
  412.   
  413. /********Added by Jizhao****/
  414. char error[150];
  415. /********Added by Jizhao****/
  416.   

  417.   terminator = '>;';
  418.   i = str_chr(arg,'<');
  419.   if (arg[i])
  420.     arg += i + 1;
  421.   else { /* partner should go read rfc 821 */
  422.     terminator = ' ';
  423.     arg += str_chr(arg,':');
  424.     if (*arg == ':') ++arg;
  425.     while (*arg == ' ') ++arg;
  426.   }

  427.   /* strip source route */
  428.   if (*arg == '@') while (*arg) if (*arg++ == ':') break;

  429.   if (!stralloc_copys(&addr,"")) die_nomem();
  430.   flagesc = 0;
  431.   flagquoted = 0;
  432.   for (i = 0;ch = arg[i];++i) { /* copy arg to addr, stripping quotes */
  433.     if (flagesc) {
  434.       if (!stralloc_append(&addr,&ch)) die_nomem();
  435.       flagesc = 0;
  436.     }
  437.     else {
  438.       if (!flagquoted && (ch == terminator)) break;
  439.       switch(ch) {
  440.         case '\\': flagesc = 1; break;
  441.         case '"': flagquoted = !flagquoted; break;
  442.         default: if (!stralloc_append(&addr,&ch)) die_nomem();
  443.       }
  444.     }
  445.   }
  446.   /* could check for termination failure here, but why bother? */
  447.   if (!stralloc_append(&addr,"")) die_nomem();

  448.   if (liphostok) {
  449.     i = byte_rchr(addr.s,addr.len,'@');
  450.     if (i < addr.len) /* if not, partner should go read rfc 821 */
  451.       if (addr.s[i + 1] == '[')
  452.         if (!addr.s[i + 1 + ip_scanbracket(addr.s + i + 1,&ip)])
  453.           if (ipme_is(&ip)) {
  454.             addr.len = i + 1;
  455.             if (!stralloc_cat(&addr,&liphost)) die_nomem();
  456.             if (!stralloc_0(&addr)) die_nomem();
  457.           }
  458.   }

  459.   //if (addr.len >; 900) return 0;
  460.   
  461. /**********************Added by Jizhao***********/
  462. /*Qmail判断大于900才出错,我觉得小于6或者大于
  463. 97的都非法*/
  464. if (addr.len < 7 || addr.len >; 97) return 0;
  465. if(!CheckMailAddress(addr.s,error))
  466. {
  467. out(error);
  468. return 0;
  469. }

  470. /**********************Added by Jizhao**********/

  471.   
  472.   return 1;
  473. }

  474. int bmfcheck()
  475. {
  476.   int j;
  477.   if (!bmfok) return 0;
  478.   if (constmap(&mapbmf,addr.s,addr.len - 1)) return 1;
  479.   j = byte_rchr(addr.s,addr.len,'@');
  480.   if (j < addr.len)
  481.     if (constmap(&mapbmf,addr.s + j,addr.len - j - 1)) return 1;
  482.   return 0;
  483. }

  484. int addrallowed()
  485. {
  486.   int r;
  487.   r = rcpthosts(addr.s,str_len(addr.s));
  488.   if (r == -1) die_control();
  489.   return r;
  490. }


  491. int seenmail = 0;
  492. int flagbarf; /* defined if seenmail */
  493. stralloc mailfrom = {0};
  494. stralloc rcptto = {0};

  495. void smtp_helo(arg) char *arg;
  496. {
  497.   smtp_greet("250 "); out("\r\n");
  498.   seenmail = 0; dohelo(arg);
  499. }
  500. void smtp_ehlo(arg) char *arg;
  501. {
  502.   smtp_greet("250-");
  503. #ifdef AUTHCRAM
  504.   out("\r\n250-AUTH LOGIN CRAM-MD5 PLAIN");
  505.   out("\r\n250-AUTH=LOGIN CRAM-MD5 PLAIN");
  506. #else
  507.   out("\r\n250-AUTH LOGIN PLAIN");
  508.   out("\r\n250-AUTH=LOGIN PLAIN");
  509. #endif
  510.   out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
  511.   seenmail = 0; dohelo(arg);
  512.   
  513. /*************Added by jizhao**********/
  514. ehlo = 1;
  515. /*************Added by jizhao**********/
  516.   
  517. }
  518. void smtp_rset()
  519. {
  520.   seenmail = 0;
  521.   out("250 flushed\r\n");
  522. }
  523. void smtp_mail(arg) char *arg;
  524. {
  525. /*******Added by Jizhao*****/
  526. char dir[PATH_MAX];
  527. short result;
  528. /*******Added by Jizhao*****/


  529.   if (!addrparse(arg)) { err_syntax(); return; }
  530.   flagbarf = bmfcheck();
  531.   seenmail = 1;
  532.   if (!stralloc_copys(&rcptto,"")) die_nomem();
  533.   if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
  534.   if (!stralloc_0(&mailfrom)) die_nomem();
  535.   
  536. /*****************************Added by jizhao***********************/
  537. if (ehlo == 1) /*如果是通过认证发信*/
  538. {
  539. complete_authusername();

  540. /*检查发信次数是否超出限制*/
  541. result = getuserdir(completeusername.s, dir);
  542. if (result != 0)
  543. {
  544. out("Unable to get user's info\r\n");
  545. flush();
  546. _exit(1);
  547. }
  548. result = checkmaxmailsperday(dir);
  549. if (result == -1)
  550. {
  551. die_nomem();
  552. }
  553. else if (result == -2)
  554. {
  555. out("Unable to access user's mailsperday file!\r\n");
  556. flush();
  557. _exit(1);
  558. }
  559. else if (result == -3)
  560. {
  561. out("The times of your sending mails are too much today!\r\n");
  562. flush();
  563. _exit(1);
  564. }

  565. /*检查发信人跟mailfrom是否一致*/
  566. if(case_diffs(completeusername.s,mailfrom.s)) /*如果不同,返回false*/
  567. {
  568. /*outsafe(&completeusername);*/
  569. out("username does't equal mailfrom\r\n"); /*认证用户名与mailfrom中的地址不符*/
  570. flush();
  571. _exit(1); //出错返回
  572. }
  573. }
  574. /*****************************Added by jizhao**********************/   
  575.   out("250 ok\r\n");
  576. }
  577. void smtp_rcpt(arg) char *arg; {

  578. /*************Added by Jizhao******/
  579. char dir[PATH_MAX];
  580. short result;
  581. /*************Added by Jizhao******/

  582.   if (!seenmail) { err_wantmail(); return; }
  583.   if (!addrparse(arg)) { err_syntax(); return; }
  584.   if (flagbarf) { err_bmf(); return; }
  585.   if (relayclient) {
  586.     --addr.len;
  587.     if (!stralloc_cats(&addr,relayclient)) die_nomem();
  588.     if (!stralloc_0(&addr)) die_nomem();
  589.   }
  590.   else
  591.     if (!addrallowed()) { err_nogateway(); return; }
  592.   if (!stralloc_cats(&rcptto,"T")) die_nomem();
  593.   if (!stralloc_cats(&rcptto,addr.s)) die_nomem();
  594.   if (!stralloc_0(&rcptto)) die_nomem();

  595. /*****************Added by Jizhao****************************/
  596. /*如果不通过认证发信,或者是别的邮件服务器发信过来
  597. 检查是否有该用户存在
  598. */
  599. if (ehlo != 1)
  600. {
  601. result = getuserdir(addr.s, dir);
  602. if (result == -1)
  603. {
  604. out("Unable to get user's info!\r\n");
  605. flush();
  606. _exit(1);
  607. }
  608. else if (result == -2)
  609. {
  610. out("No this user in our mail server!\r\n");
  611. flush();
  612. _exit(1);
  613. }
  614. }
  615. /*****************Added by Jizhao****************************/
  616.   
  617.   out("250 ok\r\n");
  618. }


  619. int saferead(fd,buf,len) int fd; char *buf; int len;
  620. {
  621.   int r;
  622.   flush();
  623.   r = timeoutread(timeout,fd,buf,len);
  624.   if (r == -1) if (errno == error_timeout) die_alarm();
  625.   if (r <= 0) die_read();
  626.   return r;
  627. }

  628. char ssinbuf[1024];
  629. substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);

  630. struct qmail qqt;
  631. unsigned int bytestooverflow = 0;

  632. void put(ch)
  633. char *ch;
  634. {
  635.   if (bytestooverflow)
  636.     if (!--bytestooverflow)
  637.       qmail_fail(&qqt);
  638.   qmail_put(&qqt,ch,1);
  639. }

  640. void blast(hops)
  641. int *hops;
  642. {
  643.   char ch;
  644.   int state;
  645.   int flaginheader;
  646.   int pos; /* number of bytes since most recent \n, if fih */
  647.   int flagmaybex; /* 1 if this line might match RECEIVED, if fih */
  648.   int flagmaybey; /* 1 if this line might match \r\n, if fih */
  649.   int flagmaybez; /* 1 if this line might match DELIVERED, if fih */

  650.   state = 1;
  651.   *hops = 0;
  652.   flaginheader = 1;
  653.   pos = 0; flagmaybex = flagmaybey = flagmaybez = 1;
  654.   for (;;) {
  655.     substdio_get(&ssin,&ch,1);
  656.     if (flaginheader) {
  657.       if (pos < 9) {
  658.         if (ch != "delivered"[pos]) if (ch != "DELIVERED"[pos]) flagmaybez = 0;
  659.         if (flagmaybez) if (pos == 8) ++*hops;
  660.         if (pos < 8)
  661.           if (ch != "received"[pos]) if (ch != "RECEIVED"[pos]) flagmaybex = 0;
  662.         if (flagmaybex) if (pos == 7) ++*hops;
  663.         if (pos < 2) if (ch != "\r\n"[pos]) flagmaybey = 0;
  664.         if (flagmaybey) if (pos == 1) flaginheader = 0;
  665.       }
  666.       ++pos;
  667.       if (ch == '\n') { pos = 0; flagmaybex = flagmaybey = flagmaybez = 1; }
  668.     }
  669.     switch(state) {
  670.       case 0:
  671.         if (ch == '\n') straynewline();
  672.         if (ch == '\r') { state = 4; continue; }
  673.         break;
  674.       case 1: /* \r\n */
  675.         if (ch == '\n') straynewline();
  676.         if (ch == '.') { state = 2; continue; }
  677.         if (ch == '\r') { state = 4; continue; }
  678.         state = 0;
  679.         break;
  680.       case 2: /* \r\n + . */
  681.         if (ch == '\n') straynewline();
  682.         if (ch == '\r') { state = 3; continue; }
  683.         state = 0;
  684.         break;
  685.       case 3: /* \r\n + .\r */
  686.         if (ch == '\n') return;
  687.         put(".");
  688.         put("\r");
  689.         if (ch == '\r') { state = 4; continue; }
  690.         state = 0;
  691.         break;
  692.       case 4: /* + \r */
  693.         if (ch == '\n') { state = 1; break; }
  694.         if (ch != '\r') { put("\r"); state = 0; }
  695.     }
  696.     put(&ch);
  697.   }
  698. }

  699. char accept_buf[FMT_ULONG];
  700. void acceptmessage(qp) unsigned long qp;
  701. {
  702.   datetime_sec when;
  703.   when = now();
  704.   out("250 ok ");
  705.   accept_buf[fmt_ulong(accept_buf,(unsigned long) when)] = 0;
  706.   out(accept_buf);
  707.   out(" qp ");
  708.   accept_buf[fmt_ulong(accept_buf,qp)] = 0;
  709.   out(accept_buf);
  710.   out("\r\n");
  711. }

  712. void smtp_data() {
  713.   int hops;
  714.   unsigned long qp;
  715.   char *qqx;

  716.   if (!seenmail) { err_wantmail(); return; }
  717.   if (!rcptto.len) { err_wantrcpt(); return; }
  718.   seenmail = 0;
  719.   if (databytes) bytestooverflow = databytes + 1;
  720.   if (qmail_open(&qqt) == -1) { err_qqt(); return; }
  721.   qp = qmail_qp(&qqt);
  722.   out("354 go ahead\r\n");

  723.   received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo);
  724.   blast(&hops);
  725.   hops = (hops >;= MAXHOPS);
  726.   if (hops) qmail_fail(&qqt);
  727.   qmail_from(&qqt,mailfrom.s);
  728.   qmail_put(&qqt,rcptto.s,rcptto.len);

  729.   qqx = qmail_close(&qqt);
  730.   if (!*qqx) { acceptmessage(qp); return; }
  731.   if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; }
  732.   if (databytes) if (!bytestooverflow) { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return; }
  733.   if (*qqx == 'D') out("554 "); else out("451 ");
  734.   out(qqx + 1);
  735.   out("\r\n");
  736. }


  737. char unique[FMT_ULONG + FMT_ULONG + 3];
  738. static stralloc authin = {0};
  739. static stralloc user = {0};
  740. static stralloc pass = {0};
  741. static stralloc resp = {0};
  742. static stralloc slop = {0};
  743. char *hostname;
  744. char **childargs;
  745. substdio ssup;
  746. char upbuf[128];
  747. int authd = 0;

  748. int authgetl(void) {
  749.   int i;

  750.   if (!stralloc_copys(&authin, "")) die_nomem();

  751.   for (;;) {
  752.     if (!stralloc_readyplus(&authin,1)) die_nomem(); /* XXX */
  753.     i = substdio_get(&ssin,authin.s + authin.len,1);
  754.     if (i != 1) die_read();
  755.     if (authin.s[authin.len] == '\n') break;
  756.     ++authin.len;
  757.   }

  758.   if (authin.len >; 0) if (authin.s[authin.len - 1] == '\r') --authin.len;
  759.   authin.s[authin.len] = 0;

  760.   if (*authin.s == '*' && *(authin.s + 1) == 0) { return err_authabrt(); }
  761.   if (authin.len == 0) { return err_input(); }
  762.   return authin.len;
  763. }

  764. int authenticate(void)
  765. {
  766.   int child;
  767.   int wstat;
  768.   int pi[2];

  769.   if (!stralloc_0(&user)) die_nomem();
  770.   if (!stralloc_0(&pass)) die_nomem();
  771.   if (!stralloc_0(&resp)) die_nomem();

  772.   if (fd_copy(2,1) == -1) return err_pipe();
  773.   close(3);
  774.   if (pipe(pi) == -1) return err_pipe();
  775.   if (pi[0] != 3) return err_pipe();
  776.   switch(child = fork()) {
  777.     case -1:
  778.       return err_fork();
  779.     case 0:
  780.       close(pi[1]);
  781.       sig_pipedefault();
  782.       execvp(*childargs, childargs);
  783.       _exit(1);
  784.   }
  785.   close(pi[0]);

  786.   substdio_fdbuf(&ssup,write,pi[1],upbuf,sizeof upbuf);
  787.   if (substdio_put(&ssup,user.s,user.len) == -1) return err_write();
  788.   if (substdio_put(&ssup,pass.s,pass.len) == -1) return err_write();
  789.   if (substdio_put(&ssup,resp.s,resp.len) == -1) return err_write();
  790.   if (substdio_flush(&ssup) == -1) return err_write();

  791.   close(pi[1]);
  792.   byte_zero(pass.s,pass.len);
  793.   byte_zero(upbuf,sizeof upbuf);
  794.   if (wait_pid(&wstat,child) == -1) return err_child();
  795.   if (wait_crashed(wstat)) return err_child();
  796.   if (wait_exitcode(wstat)) { sleep(5); return 1; } /* no */
  797.   
  798. /***************Added by Jizhao******************/
  799. /*将用户名存入全局变量 authusername*/
  800. if(!stralloc_copy(&authusername,&user)) return 1;
  801. /***************Added by Jizhao******************/

  802.   
  803.   return 0; /* yes */
  804. }

  805. int auth_login(arg) char *arg;
  806. {
  807.   int r;

  808.   if (*arg) {
  809.     if (r = b64decode(arg,str_len(arg),&user) == 1) return err_input();
  810.   }
  811.   else {
  812.     out("334 VXNlcm5hbWU6\r\n"); flush(); /* Username: */
  813.     if (authgetl() < 0) return -1;
  814.     if (r = b64decode(authin.s,authin.len,&user) == 1) return err_input();
  815.   }
  816.   if (r == -1) die_nomem();

  817.   out("334 UGFzc3dvcmQ6\r\n"); flush(); /* Password: */

  818.   if (authgetl() < 0) return -1;
  819.   if (r = b64decode(authin.s,authin.len,&pass) == 1) return err_input();
  820.   if (r == -1) die_nomem();

  821.   if (!user.len || !pass.len) return err_input();
  822.   return authenticate();  
  823. }

  824. int auth_plain(arg) char *arg;
  825. {
  826.   int r, id = 0;

  827.   if (*arg) {
  828.     if (r = b64decode(arg,str_len(arg),&slop) == 1) return err_input();
  829.   }
  830.   else {
  831.     out("334 \r\n"); flush();
  832.     if (authgetl() < 0) return -1;
  833.     if (r = b64decode(authin.s,authin.len,&slop) == 1) return err_input();
  834.   }
  835.   if (r == -1 || !stralloc_0(&slop)) die_nomem();
  836.   while (slop.s[id]) id++; /* ignore authorize-id */

  837.   if (slop.len >; id + 1)
  838.     if (!stralloc_copys(&user,slop.s + id + 1)) die_nomem();
  839.   if (slop.len >; id + user.len + 2)
  840.     if (!stralloc_copys(&pass,slop.s + id + user.len + 2)) die_nomem();

  841.   if (!user.len || !pass.len) return err_input();
  842.   return authenticate();
  843. }

  844. #ifdef AUTHCRAM
  845. int auth_cram()
  846. {
  847.   int i, r;
  848.   char *s;

  849.   s = unique;
  850.   s += fmt_uint(s,getpid());
  851.   *s++ = '.';
  852.   s += fmt_ulong(s,(unsigned long) now());
  853.   *s++ = '@';
  854.   *s++ = 0;

  855.   if (!stralloc_copys(&pass,"<")) die_nomem();
  856.   if (!stralloc_cats(&pass,unique)) die_nomem();
  857.   if (!stralloc_cats(&pass,hostname)) die_nomem();
  858.   if (!stralloc_cats(&pass,">;")) die_nomem();
  859.   if (b64encode(&pass,&slop) < 0) die_nomem();
  860.   if (!stralloc_0(&slop)) die_nomem();

  861.   out("334 ");
  862.   out(slop.s);
  863.   out("\r\n");
  864.   flush();

  865.   if (authgetl() < 0) return -1;
  866.   if (r = b64decode(authin.s,authin.len,&slop) == 1) return err_input();
  867.   if (r == -1 || !stralloc_0(&slop)) die_nomem();

  868.   i = str_chr(slop.s,' ');
  869.   s = slop.s + i;
  870.   while (*s == ' ') ++s;
  871.   slop.s[i] = 0;
  872.   if (!stralloc_copys(&user,slop.s)) die_nomem();
  873.   if (!stralloc_copys(&resp,s)) die_nomem();

  874.   if (!user.len || !resp.len) return err_input();
  875.   return authenticate();
  876. }
  877. #endif

  878. struct authcmd {
  879.   char *text;
  880.   int (*fun)();
  881. } authcmds[] = {
  882.   { "login", auth_login }
  883. , { "plain", auth_plain }
  884. #ifdef AUTHCRAM
  885. , { "cram-md5", auth_cram }
  886. #endif
  887. , { 0, err_noauth }
  888. };

  889. void smtp_auth(arg)
  890. char *arg;
  891. {
  892.   int i;
  893.   char *cmd = arg;

  894.   if (!hostname || !*childargs)
  895.   {
  896.     out("503 auth not available (#5.3.3)\r\n");
  897.     return;
  898.   }
  899.   if (authd) { err_authd(); return; }
  900.   if (seenmail) { err_authmail(); return; }

  901.   if (!stralloc_copys(&user,"")) die_nomem();
  902.   if (!stralloc_copys(&pass,"")) die_nomem();
  903.   if (!stralloc_copys(&resp,"")) die_nomem();

  904.   i = str_chr(cmd,' ');   
  905.   arg = cmd + i;
  906.   while (*arg == ' ') ++arg;
  907.   cmd[i] = 0;

  908.   for (i = 0;authcmds[i].text;++i)
  909.     if (case_equals(authcmds[i].text,cmd)) break;

  910.   switch (authcmds[i].fun(arg)) {
  911.     case 0:
  912.       authd = 1;
  913.       relayclient = "";
  914.       remoteinfo = user.s;
  915.       if (!env_unset("TCPREMOTEINFO")) die_read();
  916.       if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem();
  917.       out("235 ok, go ahead (#2.0.0)\r\n");
  918.       break;
  919.     case 1:
  920.       out("535 authorization failed (#5.7.0)\r\n");
  921.   }
  922. }

  923. struct commands smtpcommands[] = {
  924.   { "rcpt", smtp_rcpt, 0 }
  925. , { "mail", smtp_mail, 0 }
  926. , { "data", smtp_data, flush }
  927. , { "auth", smtp_auth, flush }
  928. , { "quit", smtp_quit, flush }
  929. , { "helo", smtp_helo, flush }
  930. , { "ehlo", smtp_ehlo, flush }
  931. , { "rset", smtp_rset, 0 }
  932. , { "help", smtp_help, flush }
  933. , { "noop", err_noop, flush }
  934. , { "vrfy", err_vrfy, flush }
  935. , { 0, err_unimpl, flush }
  936. } ;

  937. void main(argc,argv)
  938. int argc;
  939. char **argv;
  940. {
  941.   hostname = argv[1];
  942.   childargs = argv + 2;

  943.   sig_pipeignore();
  944.   if (chdir(auto_qmail) == -1) die_control();
  945.   setup();
  946.   if (ipme_init() != 1) die_ipme();
  947.   smtp_greet("220 ");
  948.   out(" ESMTP\r\n");
  949.   if (commands(&ssin,&smtpcommands) == 0) die_read();
  950.   die_nomem();
  951. }
复制代码

论坛徽章:
0
7 [报告]
发表于 2003-10-20 21:30 |只看该作者

qmail-smtpd.c拒收垃圾邮件修改(原创)

你的头文件怎么没有给出来???

论坛徽章:
0
8 [报告]
发表于 2003-10-21 07:51 |只看该作者

qmail-smtpd.c拒收垃圾邮件修改(原创)

社会上的好人真多………………

论坛徽章:
0
9 [报告]
发表于 2003-10-21 09:59 |只看该作者

qmail-smtpd.c拒收垃圾邮件修改(原创)

打qmail-103.patch补丁程序的qmail怎么改, 5......

论坛徽章:
0
10 [报告]
发表于 2003-10-21 10:02 |只看该作者

qmail-smtpd.c拒收垃圾邮件修改(原创)

这么多代码,往哪加呀?不明白!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP