smtpp.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. /*
  2. 3APA3A simpliest proxy server
  3. (c) 2002-2016 by Vladimir Dubrovin <3proxy@3proxy.ru>
  4. please read License Agreement
  5. */
  6. #include "proxy.h"
  7. #define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
  8. char ehlo[] = "250-Proxy\r\n"
  9. "250-AUTH PLAIN LOGIN\r\n"
  10. "250-8BITMIME\r\n"
  11. "250 DSN\r\n";
  12. int readreply (struct clientparam* param) {
  13. unsigned char * buf;
  14. int res, i, bufsize = 640;
  15. if(!(buf = myalloc(bufsize))) return 0;
  16. do {
  17. i = sockgetlinebuf(param, SERVER, buf, bufsize-1, '\n', conf.timeouts[STRING_L]);
  18. if(i < 1) break;
  19. #ifndef WITHMAIN
  20. res = handlehdrfilterssrv(param, &buf, &bufsize, 0, &i);
  21. if(res != PASS) {
  22. myfree(buf);
  23. return -1;
  24. }
  25. #endif
  26. socksend(param->clisock, buf, i, conf.timeouts[STRING_S]);
  27. } while (i > 3 && buf[3] == '-');
  28. if(i < 3) {
  29. myfree(buf);
  30. return 0;
  31. }
  32. buf[i] = 0;
  33. res = atoi((char *)buf);
  34. myfree(buf);
  35. return res;
  36. }
  37. int readcommand (struct clientparam* param) {
  38. unsigned char * buf;
  39. int res, i, bufsize = 320;
  40. int ret = 1;
  41. if(!(buf = myalloc(bufsize))) return 0;
  42. i = sockgetlinebuf(param, CLIENT, buf, bufsize-1, '\n', conf.timeouts[STRING_L]);
  43. if(i < 4) return 0;
  44. #ifndef WITHMAIN
  45. if(!strncasecmp((char *)buf, "MAIL", 4) || !strncasecmp((char *)buf, "RCPT", 4) || !strncasecmp((char *)buf, "STARTTLS", 8) || !strncasecmp((char *)buf, "TURN", 4)){
  46. res = handlehdrfilterscli(param, &buf, &bufsize, 0, &i);
  47. if(res != PASS) {
  48. myfree(buf);
  49. if(res == HANDLED) return 2;
  50. return -1;
  51. }
  52. }
  53. #endif
  54. socksend(param->remsock, buf, i, conf.timeouts[STRING_S]);
  55. myfree(buf);
  56. if(!strncasecmp((char *)buf, "STARTTLS", 8) || !strncasecmp((char *)buf, "TURN", 4)){
  57. ret = 22;
  58. }
  59. return ret;
  60. }
  61. int readdata (struct clientparam* param) {
  62. unsigned char * buf;
  63. int res, i, bufsize = 4096;
  64. if(!(buf = myalloc(bufsize))) return 0;
  65. while ((i = sockgetlinebuf(param, CLIENT, buf, bufsize-1, '\n', conf.timeouts[STRING_L])) > 0 && !(i==3 && buf[0] == '.')){
  66. #ifndef WITHMAIN
  67. res = handledatfltcli(param, &buf, &bufsize, 0, &i);
  68. if(res != PASS) {
  69. myfree(buf);
  70. if(res == HANDLED) return 1;
  71. return -1;
  72. }
  73. #endif
  74. socksendto(param->remsock, (struct sockaddr *)&param->sinsr, buf, i, conf.timeouts[STRING_S]);
  75. }
  76. if(i < 1) {
  77. myfree(buf);
  78. return 0;
  79. }
  80. socksend(param->remsock, buf, i, conf.timeouts[STRING_S]);
  81. myfree(buf);
  82. return 1;
  83. }
  84. void * smtppchild(struct clientparam* param) {
  85. int i=0, res;
  86. unsigned char buf[320];
  87. unsigned char username[256];
  88. char * command = NULL;
  89. int login = 0;
  90. if(socksend(param->clisock, (unsigned char *)"220 Proxy\r\n", 11, conf.timeouts[STRING_S])!=11) {RETURN (611);}
  91. i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]);
  92. while(i > 4 && (strncasecmp((char *)buf, "AUTH PLAIN", 10) || !(login = 2)) && (strncasecmp((char *)buf, "AUTH LOGIN", 10) || !(login = 1))){
  93. if(!strncasecmp((char *)buf, "QUIT", 4)){
  94. socksend(param->clisock, (unsigned char *)"221 Proxy\r\n", 11,conf.timeouts[STRING_S]);
  95. RETURN(0);
  96. }
  97. else if(!strncasecmp((char *)buf, "HELO ", 5)){
  98. socksend(param->clisock, (unsigned char *)"250 Proxy\r\n", 11,conf.timeouts[STRING_S]);
  99. }
  100. else if(!strncasecmp((char *)buf, "EHLO ", 5)){
  101. socksend(param->clisock, (unsigned char *)ehlo, sizeof(ehlo) - 1,conf.timeouts[STRING_S]);
  102. }
  103. else if(!param->hostname) socksend(param->clisock, (unsigned char *)"571 need AUTH first\r\n", 22, conf.timeouts[STRING_S]);
  104. else {
  105. login = -1;
  106. buf[i] = 0;
  107. command = mystrdup((char *)buf);
  108. break;
  109. }
  110. i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]);
  111. }
  112. if(!login) {RETURN(662);}
  113. if(login == 1){
  114. socksend(param->clisock, (unsigned char *)"334 VXNlcm5hbWU6\r\n", 18,conf.timeouts[STRING_S]);
  115. i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]);
  116. if(i < 3) {RETURN(663);}
  117. buf[i-2] = 0;
  118. i = de64(buf,username,255);
  119. if(i < 1) {RETURN(664);}
  120. username[i] = 0;
  121. parseconnusername((char *)username, param, 0, 25);
  122. socksend(param->clisock, (unsigned char *)"334 UGFzc3dvcmQ6\r\n", 18,conf.timeouts[STRING_S]);
  123. i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]);
  124. if(i < 2) {RETURN(665);}
  125. buf[i-2] = 0;
  126. i = de64(buf,username,255);
  127. if(i < 0) {RETURN(666);}
  128. username[i] = 0;
  129. if(param->extpassword) myfree(param->extpassword);
  130. param->extpassword = (unsigned char *)mystrdup((char *)username);
  131. }
  132. else if(login == 2){
  133. if(i > 13) {
  134. buf[i-2] = 0;
  135. i = de64(buf+11,username,255);
  136. }
  137. else {
  138. socksend(param->clisock, (unsigned char *)"334\r\n", 5,conf.timeouts[STRING_S]);
  139. i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]);
  140. if(i < 3) {RETURN(667);}
  141. buf[i-2] = 0;
  142. i = de64(buf,username,255);
  143. }
  144. if(i < 3 || *username) {RETURN(668);}
  145. username[i] = 0;
  146. parseconnusername((char *)username+1, param, 0, 25);
  147. res = (int)strlen((char *)username+1) + 2;
  148. if(res < i){
  149. if(param->extpassword) myfree(param->extpassword);
  150. param->extpassword = (unsigned char *)mystrdup((char *)username + res);
  151. }
  152. }
  153. #ifndef WITHMAIN
  154. {
  155. int action, reqbufsize, reqsize;
  156. reqbufsize = reqsize = (int)strlen((char *)param->hostname) + 1;
  157. action = handlereqfilters(param, &param->hostname, &reqbufsize, 0, &reqsize);
  158. if(action == HANDLED){
  159. RETURN(0);
  160. }
  161. if(action != PASS) RETURN(617);
  162. }
  163. #endif
  164. param->operation = CONNECT;
  165. res = (*param->srv->authfunc)(param);
  166. if(res) {RETURN(res);}
  167. do {
  168. i = sockgetlinebuf(param, SERVER, buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L]);
  169. } while (i > 3 && buf[3] == '-');
  170. if( i < 3 ) {RETURN(671);}
  171. buf[i] = 0;
  172. if(strncasecmp((char *)buf, "220", 3)||!strncasecmp((char *)buf+4, "PROXY", 5)){RETURN(672);}
  173. i = sprintf((char *)buf, "EHLO [");
  174. i += myinet_ntop(*SAFAMILY(&param->sinsl), SAADDR(&param->sinsl), (char *)buf+strlen((char *)buf), 64);
  175. i += sprintf((char *)buf+strlen((char *)buf), "]\r\n");
  176. if(socksend(param->remsock, buf, i, conf.timeouts[STRING_S])!= i) {RETURN(673);}
  177. param->statscli64+=i;
  178. param->nwrites++;
  179. login = 0;
  180. do {
  181. i = sockgetlinebuf(param, SERVER, buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L]);
  182. if(i < 1) break;
  183. buf[i] = 0;
  184. if(strstr((char *)buf, "LOGIN")) login |= 1;
  185. if(strstr((char *)buf, "PLAIN")) login |= 2;
  186. } while (i > 3 && buf[3] == '-');
  187. if(i<3) {RETURN(672);}
  188. if(!command || (param->extusername && param->extpassword)){
  189. if(!param->extusername || !*param->extusername || !param->extpassword || !*param->extpassword || !login){
  190. socksend(param->clisock, (unsigned char *)"235 auth required\r\n", 19,conf.timeouts[STRING_S]);
  191. }
  192. if ((login & 1)) {
  193. socksend(param->remsock, (unsigned char *)"AUTH LOGIN\r\n", 12, conf.timeouts[STRING_S]);
  194. param->statscli64+=12;
  195. param->nwrites++;
  196. i = sockgetlinebuf(param, SERVER, buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L]);
  197. if(i<4 || strncasecmp((char *)buf, "334", 3)) {RETURN(680);}
  198. en64(param->extusername, buf, (int)strlen((char *)param->extusername));
  199. socksend(param->remsock, buf, (int)strlen((char *)buf), conf.timeouts[STRING_S]);
  200. socksend(param->remsock, (unsigned char *)"\r\n", 2, conf.timeouts[STRING_S]);
  201. param->statscli64+=(i+2);
  202. param->nwrites+=2;
  203. i = sockgetlinebuf(param, SERVER, buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L]);
  204. if(i<4 || strncasecmp((char *)buf, "334", 3)) {RETURN(681);}
  205. en64(param->extpassword, buf, (int)strlen((char *)param->extpassword));
  206. socksend(param->remsock, buf, (int)strlen((char *)buf), conf.timeouts[STRING_S]);
  207. socksend(param->remsock, (unsigned char *)"\r\n", 2, conf.timeouts[STRING_S]);
  208. param->statscli64+=(i+2);
  209. param->nwrites+=2;
  210. }
  211. else if((login & 2)){
  212. socksend(param->remsock, (unsigned char *)"AUTH PLAIN\r\n", 12, conf.timeouts[STRING_S]);
  213. param->statscli64+=(12);
  214. param->nwrites++;
  215. i = sockgetlinebuf(param, SERVER, buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L]);
  216. if(i<4 || strncasecmp((char *)buf, "334", 3)) {RETURN(682);}
  217. *username = 0;
  218. i = (int)strlen((char *)param->extusername) + 1;
  219. memcpy(username+1, param->extusername, i);
  220. i++;
  221. res = (int)strlen((char *)param->extpassword);
  222. memcpy(username + i, param->extpassword, res);
  223. i+=res;
  224. en64(username, buf, i);
  225. i = (int)strlen((char *)buf);
  226. socksend(param->remsock, buf, i, conf.timeouts[STRING_S]);
  227. socksend(param->remsock, (unsigned char *)"\r\n", 2, conf.timeouts[STRING_S]);
  228. param->statscli64+=(i+2);
  229. param->nwrites+=2;
  230. }
  231. if(command) {
  232. i = sockgetlinebuf(param, SERVER, buf, sizeof(buf) - 1, '\n', conf.timeouts[STRING_L]);
  233. }
  234. res = 1;
  235. }
  236. if(command) {
  237. res = 1;
  238. #ifndef WITHMAIN
  239. if(!strncasecmp(command, "MAIL", 4) || !strncasecmp(command, "RCPT", 4) || !strncasecmp(command, "STARTTLS", 8) || !strncasecmp(command, "TURN", 4)){
  240. res = (int)strlen(command);
  241. command[res] = 0;
  242. res = handlehdrfilterscli(param, (unsigned char **)&command, &res, 0, &res);
  243. if(res != PASS) {
  244. if(res == HANDLED) res = 2;
  245. else RETURN(677);
  246. }
  247. else if(!strncasecmp(command, "STARTTLS", 8) || !strncasecmp(command, "TURN", 4))
  248. res = 22;
  249. }
  250. #endif
  251. i = (int)strlen(command);
  252. if(res != 2) socksend(param->remsock, (unsigned char *)command, i, conf.timeouts[STRING_S]);
  253. }
  254. #ifndef WITHMAIN
  255. if(param->nhdrfilterscli || param->nhdrfilterssrv || param->ndatfilterscli || param->ndatfilterssrv){
  256. do {
  257. if(res == 22) RETURN (mapsocket(param, 180));
  258. if(res != 2 && (res = readreply(param)) <= 0) break;
  259. if(res == 221) RETURN(0);
  260. if(res == 354) res = readdata(param);
  261. else res = readcommand(param);
  262. } while(res > 0);
  263. if(res == 22)
  264. if(res >= 0) RETURN(0);
  265. RETURN(676);
  266. }
  267. else
  268. #endif
  269. RETURN (mapsocket(param, 180));
  270. CLEANRET:
  271. if(param->hostname&&param->extusername) {
  272. sprintf((char *)buf, "%.128s@%.128s%c%hu", param->extusername, param->hostname, *SAPORT(&param->sinsr)==25?0:':',ntohs(*SAPORT(&param->sinsr)));
  273. (*param->srv->logfunc)(param, buf);
  274. }
  275. else (*param->srv->logfunc)(param, NULL);
  276. if(param->clisock != INVALID_SOCKET) {
  277. if ((param->res > 0 && param->res < 100) || (param->res > 661 && param->res <700)) socksend(param->clisock, (unsigned char *)"571 \r\n", 6,conf.timeouts[STRING_S]);
  278. }
  279. if(command) myfree(command);
  280. freeparam(param);
  281. return (NULL);
  282. }
  283. #ifdef WITHMAIN
  284. struct proxydef childdef = {
  285. smtppchild,
  286. 25,
  287. 0,
  288. S_SMTPP,
  289. " -hdefault_host[:port] - use this host and port as default if no host specified\n"
  290. };
  291. #include "proxymain.c"
  292. #endif