免费注册 查看新帖 |

Chinaunix

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

[Mail] jizhao的qmail-smtpd.c修改版(增加本地域之间的验证) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2004-02-14 09:30 |只看该作者 |倒序浏览
jizhao的qmail-smtpd.c,很多人说没有本地域之间验证的问题,我之前叫大家从gadfly的补丁里找出本地验证的部分加上就行了.可大家好象还是有问题.那我自己来把它加上吧.大家试一下,效果如何.

  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 150
  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. /**********************Added by ARTXING***********/   
  490.   if (!localauthd()) return 0; //本地用户之间互相发信也需要认证
  491. /**********************Added by ARTXING***********/
  492.   return r;
  493. }


  494. int seenmail = 0;
  495. int flagbarf; /* defined if seenmail */
  496. stralloc mailfrom = {0};
  497. stralloc rcptto = {0};

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


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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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


  736. char unique[FMT_ULONG + FMT_ULONG + 3];
  737. static stralloc authin = {0};
  738. static stralloc user = {0};
  739. static stralloc pass = {0};
  740. static stralloc resp = {0};
  741. static stralloc slop = {0};
  742. char *hostname;
  743. char **childargs;
  744. substdio ssup;
  745. char upbuf[128];
  746. int authd = 0;
  747. /**********************Added by ARTXING***********/
  748. /*本地用户互相发信也需要认证*/
  749. int localauthd() {

  750.   if (rcpthosts(mailfrom.s, strlen(mailfrom.s)) && !authd) return 0;
  751.   return 1;
  752. }
  753. /**********************Added by ARTXING***********/

  754. int authgetl(void) {
  755.   int i;

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

  757.   for (;;) {
  758.     if (!stralloc_readyplus(&authin,1)) die_nomem(); /* XXX */
  759.     i = substdio_get(&ssin,authin.s + authin.len,1);
  760.     if (i != 1) die_read();
  761.     if (authin.s[authin.len] == '\n') break;
  762.     ++authin.len;
  763.   }

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

  766.   if (*authin.s == '*' && *(authin.s + 1) == 0) { return err_authabrt(); }
  767.   if (authin.len == 0) { return err_input(); }
  768.   return authin.len;
  769. }

  770. int authenticate(void)
  771. {
  772.   int child;
  773.   int wstat;
  774.   int pi[2];

  775.   if (!stralloc_0(&user)) die_nomem();
  776.   if (!stralloc_0(&pass)) die_nomem();
  777.   if (!stralloc_0(&resp)) die_nomem();

  778.   if (fd_copy(2,1) == -1) return err_pipe();
  779.   close(3);
  780.   if (pipe(pi) == -1) return err_pipe();
  781.   if (pi[0] != 3) return err_pipe();
  782.   switch(child = fork()) {
  783.     case -1:
  784.       return err_fork();
  785.     case 0:
  786.       close(pi[1]);
  787.       sig_pipedefault();
  788.       execvp(*childargs, childargs);
  789.       _exit(1);
  790.   }
  791.   close(pi[0]);

  792.   substdio_fdbuf(&ssup,write,pi[1],upbuf,sizeof upbuf);
  793.   if (substdio_put(&ssup,user.s,user.len) == -1) return err_write();
  794.   if (substdio_put(&ssup,pass.s,pass.len) == -1) return err_write();
  795.   if (substdio_put(&ssup,resp.s,resp.len) == -1) return err_write();
  796.   if (substdio_flush(&ssup) == -1) return err_write();

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

  809.   
  810.   return 0; /* yes */
  811. }

  812. int auth_login(arg) char *arg;
  813. {
  814.   int r;

  815.   if (*arg) {
  816.     if (r = b64decode(arg,str_len(arg),&user) == 1) return err_input();
  817.   }
  818.   else {
  819.     out("334 VXNlcm5hbWU6\r\n"); flush(); /* Username: */
  820.     if (authgetl() < 0) return -1;
  821.     if (r = b64decode(authin.s,authin.len,&user) == 1) return err_input();
  822.   }
  823.   if (r == -1) die_nomem();

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

  825.   if (authgetl() < 0) return -1;
  826.   if (r = b64decode(authin.s,authin.len,&pass) == 1) return err_input();
  827.   if (r == -1) die_nomem();

  828.   if (!user.len || !pass.len) return err_input();
  829.   return authenticate();  
  830. }

  831. int auth_plain(arg) char *arg;
  832. {
  833.   int r, id = 0;

  834.   if (*arg) {
  835.     if (r = b64decode(arg,str_len(arg),&slop) == 1) return err_input();
  836.   }
  837.   else {
  838.     out("334 \r\n"); flush();
  839.     if (authgetl() < 0) return -1;
  840.     if (r = b64decode(authin.s,authin.len,&slop) == 1) return err_input();
  841.   }
  842.   if (r == -1 || !stralloc_0(&slop)) die_nomem();
  843.   while (slop.s[id]) id++; /* ignore authorize-id */

  844.   if (slop.len >; id + 1)
  845.     if (!stralloc_copys(&user,slop.s + id + 1)) die_nomem();
  846.   if (slop.len >; id + user.len + 2)
  847.     if (!stralloc_copys(&pass,slop.s + id + user.len + 2)) die_nomem();

  848.   if (!user.len || !pass.len) return err_input();
  849.   return authenticate();
  850. }

  851. #ifdef AUTHCRAM
  852. int auth_cram()
  853. {
  854.   int i, r;
  855.   char *s;

  856.   s = unique;
  857.   s += fmt_uint(s,getpid());
  858.   *s++ = '.';
  859.   s += fmt_ulong(s,(unsigned long) now());
  860.   *s++ = '@';
  861.   *s++ = 0;

  862.   if (!stralloc_copys(&pass,"<")) die_nomem();
  863.   if (!stralloc_cats(&pass,unique)) die_nomem();
  864.   if (!stralloc_cats(&pass,hostname)) die_nomem();
  865.   if (!stralloc_cats(&pass,">;")) die_nomem();
  866.   if (b64encode(&pass,&slop) < 0) die_nomem();
  867.   if (!stralloc_0(&slop)) die_nomem();

  868.   out("334 ");
  869.   out(slop.s);
  870.   out("\r\n");
  871.   flush();

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

  875.   i = str_chr(slop.s,' ');
  876.   s = slop.s + i;
  877.   while (*s == ' ') ++s;
  878.   slop.s[i] = 0;
  879.   if (!stralloc_copys(&user,slop.s)) die_nomem();
  880.   if (!stralloc_copys(&resp,s)) die_nomem();

  881.   if (!user.len || !resp.len) return err_input();
  882.   return authenticate();
  883. }
  884. #endif

  885. struct authcmd {
  886.   char *text;
  887.   int (*fun)();
  888. } authcmds[] = {
  889.   { "login", auth_login }
  890. , { "plain", auth_plain }
  891. #ifdef AUTHCRAM
  892. , { "cram-md5", auth_cram }
  893. #endif
  894. , { 0, err_noauth }
  895. };

  896. void smtp_auth(arg)
  897. char *arg;
  898. {
  899.   int i;
  900.   char *cmd = arg;

  901.   if (!hostname || !*childargs)
  902.   {
  903.     out("503 auth not available (#5.3.3)\r\n");
  904.     return;
  905.   }
  906.   if (authd) { err_authd(); return; }
  907.   if (seenmail) { err_authmail(); return; }

  908.   if (!stralloc_copys(&user,"")) die_nomem();
  909.   if (!stralloc_copys(&pass,"")) die_nomem();
  910.   if (!stralloc_copys(&resp,"")) die_nomem();

  911.   i = str_chr(cmd,' ');   
  912.   arg = cmd + i;
  913.   while (*arg == ' ') ++arg;
  914.   cmd[i] = 0;

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

  917.   switch (authcmds[i].fun(arg)) {
  918.     case 0:
  919.       authd = 1;
  920.       relayclient = "";
  921.       remoteinfo = user.s;
  922.       if (!env_unset("TCPREMOTEINFO")) die_read();
  923.       if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem();
  924.       out("235 ok, go ahead (#2.0.0)\r\n");
  925.       break;
  926.     case 1:
  927.       out("535 authorization failed (#5.7.0)\r\n");
  928.   }
  929. }

  930. struct commands smtpcommands[] = {
  931.   { "rcpt", smtp_rcpt, 0 }
  932. , { "mail", smtp_mail, 0 }
  933. , { "data", smtp_data, flush }
  934. , { "auth", smtp_auth, flush }
  935. , { "quit", smtp_quit, flush }
  936. , { "helo", smtp_helo, flush }
  937. , { "ehlo", smtp_ehlo, flush }
  938. , { "rset", smtp_rset, 0 }
  939. , { "help", smtp_help, flush }
  940. , { "noop", err_noop, flush }
  941. , { "vrfy", err_vrfy, flush }
  942. , { 0, err_unimpl, flush }
  943. } ;

  944. void main(argc,argv)
  945. int argc;
  946. char **argv;
  947. {
  948.   hostname = argv[1];
  949.   childargs = argv + 2;

  950.   sig_pipeignore();
  951.   if (chdir(auto_qmail) == -1) die_control();
  952.   setup();
  953.   if (ipme_init() != 1) die_ipme();
  954.   smtp_greet("220 ");
  955.   out(" ESMTP\r\n");
  956.   if (commands(&ssin,&smtpcommands) == 0) die_read();
  957.   die_nomem();
  958. }
复制代码

论坛徽章:
0
2 [报告]
发表于 2004-02-14 09:37 |只看该作者

jizhao的qmail-smtpd.c修改版(增加本地域之间的验证)

谢谢大哥,更希望你能帮我解答一些问题,内容见帖子!!!急盼!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP