smtpap.c 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420
  1. /**
  2. * smtpap.c
  3. * SMTP Application Proxy for Onion Routing
  4. *
  5. * Matej Pfajfar <mp292@cam.ac.uk>
  6. */
  7. /*
  8. * Changes :
  9. * $Log$
  10. * Revision 1.6 2002/09/10 13:32:27 nickm
  11. * "You got BSD in my MacOS!" "You got MacOS in my BSD!" Anyway, MacOS works again.
  12. *
  13. * Revision 1.5 2002/09/09 04:10:58 arma
  14. * port to actual BSD
  15. *
  16. * (hey nick, does this break the os x build?)
  17. *
  18. * you still need to add some stuff to the ./configure commandline...
  19. * anybody know a better solution?
  20. *
  21. * Revision 1.4 2002/09/03 18:44:24 nickm
  22. * Port to MacOS X
  23. *
  24. * Revision 1.3 2002/08/24 07:56:34 arma
  25. * proxies send port in host order as ascii string
  26. *
  27. * Revision 1.2 2002/07/12 18:14:17 montrose
  28. * removed loglevel from global namespace. severity level is set using log() with a NULL format argument now. example: log(LOG_ERR,NULL);
  29. *
  30. * Revision 1.1.1.1 2002/06/26 22:45:50 arma
  31. * initial commit: current code
  32. *
  33. * Revision 1.32 2002/04/02 14:29:49 badbytes
  34. * Final finishes.
  35. *
  36. * Revision 1.31 2002/03/25 08:03:17 badbytes
  37. * Added header sanitization.
  38. *
  39. * Revision 1.30 2002/03/02 23:54:06 mp292
  40. * Fixed missing CRLFs at the end of error messages.
  41. *
  42. * Revision 1.29 2002/01/29 01:00:10 mp292
  43. * All network operations are now timeoutable.
  44. *
  45. * Revision 1.28 2002/01/28 21:38:18 mp292
  46. * Fixed bugs in RSET handling. Added Anonimize option which signifies whether
  47. * the router should falsify the identity of the sender or not.
  48. *
  49. * Revision 1.27 2002/01/26 22:45:02 mp292
  50. * Now handles SS_ERROR_INVALID_PORT.
  51. *
  52. * Revision 1.26 2002/01/26 22:33:21 mp292
  53. * Removed hard-coded values for onion proxy return codes. Also fixed a bug in
  54. * parameter checking.
  55. *
  56. * Revision 1.25 2002/01/26 21:58:27 mp292
  57. * Added some missing parameter checking.
  58. *
  59. * Revision 1.24 2002/01/26 21:50:17 mp292
  60. * Reviewed according to Secure-Programs-HOWTO. Still need to deal with network
  61. * timeouts.
  62. *
  63. * Revision 1.23 2002/01/18 21:07:02 mp292
  64. * (a) THe form of HELO is now HELO Anonymous.Smtp.Daemon rather than the real
  65. * address. (b) The user *can* now specify a default SMTP daemon to route through
  66. * although this is insecure and not recommended.
  67. *
  68. * Revision 1.22 2002/01/16 23:01:58 mp292
  69. * First phase of system testing completed (main functionality).
  70. *
  71. * Revision 1.21 2002/01/16 17:04:01 mp292
  72. * Bug in checking whether incoming connection is local or not.
  73. *
  74. * Revision 1.20 2002/01/09 09:18:22 badbytes
  75. * Now handles EINTR error from accept().
  76. *
  77. * Revision 1.19 2001/12/19 11:15:27 badbytes
  78. * Corrected AF_INET to PF_INET in socket() calls.
  79. *
  80. * Revision 1.18 2001/12/19 08:36:04 badbytes
  81. * Incorrect error checking in recv() calls caused zombies ... fixed
  82. *
  83. * Revision 1.17 2001/12/18 14:42:46 badbytes
  84. * Variable name op_port_str was incorrectly named, changed to dest_port_str
  85. *
  86. * Revision 1.16 2001/12/18 13:20:16 badbytes
  87. * Some error messages did not include a terminating <CRLF>
  88. *
  89. * Revision 1.15 2001/12/18 12:37:23 badbytes
  90. * Found an overflow bug ...
  91. *
  92. * Revision 1.14 2001/12/18 09:17:31 badbytes
  93. * Corrected a spelling mistake in print_usage()
  94. *
  95. * Revision 1.13 2001/12/14 13:13:24 badbytes
  96. * Changed types.h references to ss.h
  97. *
  98. * Revision 1.12 2001/12/14 09:17:25 badbytes
  99. * Moved function stolower(char *str) from smtpap.c to common/utils.c
  100. *
  101. * Revision 1.11 2001/12/13 13:51:05 badbytes
  102. * Fixed a bug in processing command-line parameters.
  103. *
  104. * Revision 1.10 2001/12/13 13:36:44 badbytes
  105. * Now accepts the -l command-line option which specifies the logging threshold.
  106. *
  107. * Revision 1.9 2001/12/12 16:02:29 badbytes
  108. * Testing completed.
  109. *
  110. * Revision 1.8 2001/12/11 16:30:20 badbytes
  111. * Some bugs removed, still testing though.
  112. *
  113. * Revision 1.7 2001/12/11 14:12:20 badbytes
  114. * Onion Proxy connection setup completed. Proceeding to test.
  115. *
  116. * Revision 1.6 2001/12/11 10:43:21 badbytes
  117. * MAIL and RCPT handling completed. Still coding connection to Onion Proxy.
  118. *
  119. * Revision 1.5 2001/12/10 16:10:35 badbytes
  120. * Wrote a tokenize() function to help with parsing input from SMTP clients.
  121. *
  122. * Revision 1.4 2001/12/07 15:02:43 badbytes
  123. * Server setup code completed.
  124. *
  125. */
  126. #include "orconfig.h"
  127. #undef VERSION
  128. #include <sys/types.h>
  129. #include <sys/socket.h>
  130. #include <sys/time.h>
  131. #include <sys/wait.h>
  132. #include <netinet/in.h>
  133. #include <netdb.h>
  134. #include <arpa/inet.h>
  135. #include <errno.h>
  136. #include <ctype.h>
  137. #include <stdio.h>
  138. #include <unistd.h>
  139. #include <signal.h>
  140. #include <stdarg.h>
  141. #include <ctype.h>
  142. #include <limits.h>
  143. #include <string.h>
  144. #include <stdlib.h>
  145. #include <time.h>
  146. #ifdef HAVE_STDINT_H
  147. #include <stdint.h>
  148. #endif
  149. #include "../common/log.h"
  150. #include "../common/config.h"
  151. #include "../common/ss.h"
  152. #include "../common/utils.h"
  153. #include "../common/version.h"
  154. #include "smtpap.h"
  155. #include "io.h"
  156. struct timeval conn_tout;
  157. struct timeval *conn_toutp = &conn_tout;
  158. /* valid command-line options */
  159. static const char *args = "hf:p:l:";
  160. /* valid config file options */
  161. static config_opt_t options[] =
  162. {
  163. {"OnionProxy", CONFIG_TYPE_INT, {0}, 0},
  164. {"MaxConn", CONFIG_TYPE_INT, {0}, 0},
  165. {"Anonimize", CONFIG_TYPE_INT, {0}, 0},
  166. {"ConnTimeout", CONFIG_TYPE_INT, {0}, 0},
  167. {0}
  168. };
  169. enum opts {
  170. OnionProxy=0,MaxConn, Anonimize, ConnTimeout
  171. };
  172. /* number of open connections */
  173. int connections=0;
  174. /* prints help on using smtpap */
  175. void print_usage()
  176. {
  177. char *program = "smtpap";
  178. printf("\n%s - SMTP application proxy for Onion Routing.\nUsage : %s -f config [-p port -l loglevel -h]\n-h : display this help\n-f config : config file\n-p port : port number which %s should bind to\n-l loglevel : logging threshold; one of alert|crit|err|warning|notice|info|debug\n\n", program,program,program);
  179. }
  180. /* used for reaping zombie processes */
  181. void sigchld_handler(int s)
  182. {
  183. while (wait(NULL) > 0);
  184. connections--;
  185. }
  186. /* takes the contents of a RCPT command in a null-terminated string and retrieves the address
  187. * of the corresponding recipient domain*/
  188. char *extract_smtp_dest(char *rcptbuf)
  189. {
  190. char *dest_smtp=NULL;
  191. char *pos1, *pos2;
  192. if (!rcptbuf)
  193. return NULL;
  194. pos1 = (char *)strchr(rcptbuf,'@');
  195. if (pos1 == NULL)
  196. return NULL;
  197. pos2 = (char *)strpbrk(pos1,SMTPAP_PATH_SEPCHARS);
  198. if (pos2 == NULL)
  199. return NULL;
  200. else
  201. {
  202. dest_smtp = (char *)malloc((size_t)(pos2-pos1));
  203. if (!dest_smtp)
  204. {
  205. log(LOG_ERR,"Could not allocate memory.");
  206. return NULL;
  207. }
  208. else
  209. {
  210. strncpy(dest_smtp,pos1+1,(size_t)(pos2-pos1-1));
  211. dest_smtp[pos2-pos1-1] = 0;
  212. }
  213. }
  214. return dest_smtp;
  215. }
  216. /* process a DATA stream and remove any e-mail headers */
  217. int sanitize_data(unsigned char **buf, int *buflen)
  218. {
  219. unsigned char *offset; /* offset to data after the last header */
  220. unsigned char *crlf = NULL;
  221. unsigned char *colon = NULL;
  222. unsigned char *line;
  223. unsigned char *newbuf;
  224. int newbuflen;
  225. if ((!buf) || (!buflen)) /* invalid parameters */
  226. return -1;
  227. offset = *buf;
  228. line = *buf;
  229. /* process the data line by line and discard anything that looks like a header */
  230. while(1)
  231. {
  232. /* find the end of line */
  233. crlf = strstr(line, SMTPAP_CRLF);
  234. if (crlf)
  235. {
  236. colon = (unsigned char *)memchr((void *)line,(int)':',crlf-line);
  237. if (!colon)
  238. break; /* this doesn't seem to be a header, can stop */
  239. else
  240. offset = crlf + 2; /* discard this line */
  241. line = crlf + 2; /* move on to the next line */
  242. }
  243. else /* no more CRLFs found, end of data */
  244. /* NB : there is no need to check the current line at this stage as this will be of the form <CRLF>.<CRLF> */
  245. /* we should never reach this point in the code anyway, the '.' will be trapped as a non-header line in the above code */
  246. break;
  247. }
  248. if (offset != *buf) /* data changed */
  249. {
  250. newbuflen = *buflen - (offset - *buf);
  251. newbuf = (unsigned char *)malloc(newbuflen+1); /* leave space for a terminating NULL character */
  252. if (!newbuf) /* malloc() error */
  253. return -1;
  254. else
  255. {
  256. /* copy into the new buffer */
  257. memcpy((void *)newbuf, (void *)offset, newbuflen);
  258. newbuf[newbuflen] = 0;
  259. /* replace the old buffer with the new one */
  260. free((void *)*buf);
  261. *buf = newbuf;
  262. *buflen = newbuflen;
  263. }
  264. }
  265. return 0;
  266. }
  267. /* main logic of smtpap */
  268. int handle_connection(int s, struct hostent *local, struct sockaddr_in remote, u_short op_port)
  269. {
  270. int retval = 0;
  271. int state = 0; /* 0 - start / RSET received
  272. * 1 - connection not local, waiting for QUIT
  273. * 2 - connection local, waiting for HELO/EHLO
  274. * 3 - HELO/EHLO received, waiting for MAIL
  275. * 4 - MAIL received, waiting for RCPT
  276. * 5 - waiting for DATA
  277. * 6 - DATA received, accepting data
  278. * - data accepted, back to state 3
  279. */
  280. int islocal = 0;
  281. char *cp;
  282. int i=0;
  283. char message[512]; /* for storing outgoing messages */
  284. char *inbuf = NULL; /* for storing incoming messages */
  285. char *token = NULL; /* next token in the incoming message */
  286. char *tmpbuf = NULL; /* temporary buffer for copying data */
  287. char *mailbuf = NULL; /* storing the MAIL command */
  288. char **rcptarray = NULL; /* storing a NULL-terminated array of RCPT commands */
  289. char *rcptbuf = NULL; /* storing a single RCPT command */
  290. int tmpbuflen = 0; /* length of tmpbuflen in bytes */
  291. int inbuflen = 0; /* length of inbuf in bytes */
  292. int inputlen = 0; /* length of actual input in bytes */
  293. int mailbuflen=0; /* etc ... */
  294. int rcptbuflen=0;
  295. int inputerror=0; /* error occured when receiving data from the client */
  296. /* the following is used for conecting to the SMTP host through the OR network */
  297. char *dest_addr_str = NULL; /* for storing the ASCII address of the destination SMTP */
  298. int sop=-1; /* socket for connecting to the onion proxy */
  299. struct sockaddr_in op_addr; /* stores the address of the onion proxy */
  300. ss_t ss; /* standard structure */
  301. char dest_port_str[6]; /* ascii representation of the destination port */
  302. /* input and output buffers for talking to the onion proxy */
  303. char *op_out = NULL;
  304. char *op_in = NULL;
  305. int op_outlen = 0;
  306. int op_inlen = 0;
  307. int partial_dataend = 0; /* used for recognising the <CRLF>.<CRLF> sequence that ends the DATA segment */
  308. if (!local)
  309. return -1;
  310. log(LOG_DEBUG, "handle_connection() : Local address = %s.", inet_ntoa(*(struct in_addr *)local->h_addr));
  311. log(LOG_DEBUG, "handle_connection() : Remote address = %s.", inet_ntoa(remote.sin_addr));
  312. /* first check that the connection is from the local host, otherwise reject */
  313. if (*(uint32_t *)&remote.sin_addr == inet_addr("127.0.0.1"))
  314. islocal = 1;
  315. for (i=0; (local->h_addr_list[i] != NULL) && (!islocal); i++)
  316. {
  317. cp = local->h_addr_list[i];
  318. log(LOG_DEBUG,"handle_connection() : Checking if connection is from address %s.",inet_ntoa(*(struct in_addr *)cp));
  319. if (!memcmp(&remote.sin_addr, cp, sizeof(struct in_addr)))
  320. islocal = 1;
  321. }
  322. if (islocal)
  323. {
  324. log(LOG_DEBUG,"handle_connection() : Connection seems to be local. Will accept.");
  325. state = 2;
  326. sendmessage(s, (char *)message, (size_t)512, "220 This is smtpap v1.0 running on %s.%s",local->h_name,SMTPAP_CRLF);
  327. }
  328. else
  329. {
  330. log(LOG_DEBUG,"handle_connection() : Connection doesn't seem to be local. Will reject.");
  331. state = 1;
  332. sendmessage(s,(char *)message, (size_t)512,"554 smtpap v1.0 Connection refused. Only local connections allowed.%s",SMTPAP_CRLF);
  333. }
  334. /* initially allocate 512 bytes for incoming message buffer */
  335. inbuf = (char *)malloc((size_t)512);
  336. if (!inbuf)
  337. {
  338. log(LOG_ERR,"Could not allocate memory.");
  339. return -1;
  340. }
  341. inbuflen = 512;
  342. /* initially allocate 512 bytes for the temporary buffer */
  343. tmpbuf = (char *)malloc((size_t)512);
  344. if (!tmpbuf)
  345. {
  346. log(LOG_ERR,"Could not allocate memory.");
  347. free(inbuf);
  348. return -1;
  349. }
  350. tmpbuflen = 512;
  351. while(1)
  352. {
  353. inputlen = 0;
  354. do
  355. {
  356. if (inputlen == inbuflen-1) /* we need to increase the buffer size */
  357. {
  358. /* increase the size of the buffers */
  359. inbuflen += 512;
  360. tmpbuflen += 512;
  361. inbuf = (char *)realloc(inbuf,(size_t)inbuflen);
  362. if (!inbuf)
  363. {
  364. log(LOG_ERR,"Could not allocate memory.");
  365. inputerror = 1;
  366. break;
  367. }
  368. tmpbuf = (char *)realloc(tmpbuf,(size_t)tmpbuflen);
  369. if (!tmpbuf)
  370. {
  371. log(LOG_ERR,"Could not allocate memory.");
  372. free(inbuf);
  373. inputerror = 1;
  374. break;
  375. }
  376. }
  377. retval=read_tout(s,inbuf+inputlen,(size_t)(inbuflen-inputlen-1),0, conn_toutp); /* subtract 1 from inbuflen to leave space for \0 */
  378. if (retval <= 0)
  379. {
  380. log(LOG_ERR,"Error occured while receiving data.");
  381. inputerror = 1;
  382. break;
  383. }
  384. else
  385. {
  386. inputerror = 0;
  387. inputlen += retval;
  388. /* exit clause if we have received CRLF or SMTPAP_ENDDATA, otherwise we need to keep reading*/
  389. if ( (state == 6) && (inputlen >= SMTPAP_ENDDATA_LEN) )
  390. {
  391. if (!strncmp(inbuf+inputlen-SMTPAP_ENDDATA_LEN,SMTPAP_ENDDATA,SMTPAP_ENDDATA_LEN))
  392. break;
  393. }
  394. else if ( (state != 6) && (inputlen >= SMTPAP_CRLF_LEN) )
  395. {
  396. if (!strncmp(inbuf+inputlen-SMTPAP_CRLF_LEN,SMTPAP_CRLF,SMTPAP_CRLF_LEN))
  397. break;
  398. }
  399. }
  400. } while(1);
  401. if (inputerror != 0)
  402. break;
  403. if (*inbuf == EOF)
  404. {
  405. log(LOG_DEBUG,"handle_connection() : Received EOF. Exiting.");
  406. break;
  407. }
  408. inbuf[inputlen]=0; /* add the terminating NULL character */
  409. log(LOG_DEBUG, "Received this from client : %s",inbuf);
  410. /* save a copy of inbuf into tmpbuf, because calls to strtok() will change it */
  411. strcpy(tmpbuf,inbuf);
  412. /* now handle input depending on the state */
  413. /* first check for a quit */
  414. token = stolower((char *)strtok(inbuf,SMTPAP_SEPCHARS));
  415. log(LOG_DEBUG,"handle_connection() : First token is %s.",token);
  416. if ((!strcmp(token,SMTPAP_QUIT)) && (state != 6)) /* QUIT command - but doesn't count in state 6
  417. * That's when we are receiving DATA input
  418. */
  419. {
  420. sendmessage(s,(char *)message, (size_t)512,"221 %s closing connection. Goodbye.%s",local->h_name,SMTPAP_CRLF);
  421. break;
  422. }
  423. /* check for a RSET */
  424. if ((!strcmp(token,SMTPAP_RSET)) && (state !=6)) /* RSET command - again, doesn't count in state 6 */
  425. {
  426. sendmessage(s,(char *)message,(size_t)512,"250 RSET received.%s",SMTPAP_CRLF);
  427. /* clean up message state */
  428. if (mailbuf != NULL)
  429. {
  430. free(mailbuf);
  431. mailbuf = NULL;
  432. }
  433. if (rcptarray != NULL)
  434. {
  435. free(rcptarray);
  436. rcptarray = NULL;
  437. }
  438. if (rcptbuf != NULL)
  439. {
  440. free(rcptbuf);
  441. rcptbuf=NULL;
  442. }
  443. close(sop);
  444. /* set state to 2/3 (depending on wether we have recieved HELO yet) and loop back and start again */
  445. if (state != 2)
  446. state=3;
  447. continue;
  448. }
  449. if (state == 1)
  450. {
  451. sendmessage(s,(char *)message, (size_t)512,"503 Connection refused. Please QUIT.%s",SMTPAP_CRLF);
  452. }
  453. else if (state == 2)
  454. {
  455. if ((!strcmp(token,SMTPAP_HELO)) || (!strcmp(token,SMTPAP_EHLO)))
  456. {
  457. token = (char *)strtok(NULL,SMTPAP_SEPCHARS);
  458. if (!token) /* no more tokens in inbuf */
  459. {
  460. log(LOG_DEBUG,"handle_connection() : handle_connection : Received HELO/EHLO without arguments.");
  461. sendmessage(s,(char *)message,(size_t)512,"500 HELO/EHLO requires domain address.%s",SMTPAP_CRLF);
  462. }
  463. else
  464. {
  465. log(LOG_DEBUG,"handle_connection() : handle_connection : Received HELO/EHLO with the following domain address : %s.",token);
  466. state =3;
  467. sendmessage(s,(char *)message,(size_t)512,"250 Hello user at %s. Pleased to meet you.%s",inet_ntoa(remote.sin_addr),SMTPAP_CRLF);
  468. }
  469. }
  470. else
  471. sendmessage(s,(char *)message,(size_t)512,"503 Expecting either HELO/EHLO or QUIT.%s",SMTPAP_CRLF);
  472. }
  473. else if (state == 3)
  474. {
  475. int further_check=0;
  476. if ((!strncmp(token,SMTPAP_MAIL,SMTPAP_MAIL_LEN)))
  477. {
  478. token = (char *)strtok(NULL,SMTPAP_SEPCHARS);
  479. if (!token)
  480. {
  481. sendmessage(s,(char *)message,(size_t)512,"500 MAIL requires From:<sender@address> .%s",SMTPAP_CRLF);
  482. }
  483. else
  484. {
  485. stolower(token);
  486. if (!strcmp(token,"from:")) /* from: separate from the address */
  487. {
  488. token = (char *)strtok(NULL,SMTPAP_SEPCHARS);
  489. if (token == NULL) /* expected another parameter but it's not there */
  490. {
  491. log(LOG_DEBUG,"handle_connection() : Received MAIL From: without an address.");
  492. sendmessage(s,(char *)message,(size_t)512,"500 MAIL From: requires sender address.%s",SMTPAP_CRLF);
  493. further_check = 0;
  494. }
  495. else /* continue further checking */
  496. further_check = 1;
  497. }
  498. else if (!strcmp(token,"from")) /* probably from : address */
  499. {
  500. token = (char *)strtok(NULL,SMTPAP_SEPCHARS);
  501. if (token == NULL) /* not enough parameters */
  502. {
  503. log(LOG_DEBUG,"handle_connection() : Received Mail From with no other parameters.");
  504. sendmessage(s,(char *)message,(size_t)512, "500 MAIL From: requires sender address.%s",SMTPAP_CRLF);
  505. further_check=0;
  506. }
  507. else if ( (token[0] == ':') && (token[1]!='\0') ) /* contains :address */
  508. {
  509. token++;
  510. further_check=1;
  511. }
  512. else if ( (token[0] == ':') && (token[1]=='\0') )/* the address is in the next token */
  513. {
  514. token = (char *)strtok(NULL,SMTPAP_SEPCHARS);
  515. if (token == NULL) /* not enough parameters */
  516. {
  517. log(LOG_DEBUG,"handle_connection() : Received Mail From : with no other parameters.");
  518. sendmessage(s,(char *)message,(size_t)512,"500 MAIL From: requires sender address.%s",SMTPAP_CRLF);
  519. further_check = 0;
  520. }
  521. else /* continue further checking */
  522. further_check =1;
  523. }
  524. else /* couldn't find a colon (:) */
  525. {
  526. log(LOG_DEBUG,"handle_connection() : Couldn't find a colon in the received MAIL command.");
  527. sendmessage(s,(char *)message,(size_t)512,"500 There is a colon (:) missing in that command.%s",SMTPAP_CRLF);
  528. further_check = 1;
  529. }
  530. }
  531. else /* probably from:address */
  532. {
  533. if (!strncmp(token,"from:",5)) /* string starts with from: */
  534. {
  535. token += 5; /* skip the from: bit */
  536. further_check = 1; /* continue further checking */
  537. }
  538. else /* error */
  539. {
  540. log(LOG_DEBUG,"handle_connection() : MAIL parameters don't start with from: .");
  541. sendmessage(s,(char *)message,(size_t)512,"500 MAIL requires From:<sender@address>.%s",SMTPAP_CRLF);
  542. further_check=0;
  543. }
  544. }
  545. if (further_check == 1) /* check that this is in the correct, format - we can't handle anything else
  546. * but straightforward <user@host> representation, <> optional
  547. */
  548. {
  549. if (((cp = (char *)strchr(token,',')) != NULL) || ((cp = (char *)strchr(token,':')) != NULL)) /* path contains , or : - can't cope with that */
  550. {
  551. log(LOG_DEBUG,"handle_connection() : The client is probably trying to specify a reverse path, which I can't handle.");
  552. sendmessage(s,(char *)message,(size_t)512,"500 I can only handle a simple return address.%s",SMTPAP_CRLF);
  553. }
  554. else if ((cp = (char *)strchr(token,'@')) == NULL) /* no @, that is most likely a problem :-) */
  555. {
  556. log(LOG_DEBUG,"handle_connection() : The client specified a sender address with no @.");
  557. sendmessage(s,(char *)message,(size_t)512,"500 Domain name required.%s",SMTPAP_CRLF);
  558. }
  559. else /* the mail command seems to be OK, save it */
  560. {
  561. if (mailbuf != NULL)
  562. free(mailbuf);
  563. mailbuflen = strlen(tmpbuf) + 1;
  564. mailbuf = (char *)malloc(mailbuflen);
  565. if (!mailbuf)
  566. {
  567. log(LOG_ERR,"Could not allocate memory.");
  568. sendmessage(s,(char *)message,(size_t)512,"451 Insufficient memory.%s",SMTPAP_CRLF);
  569. }
  570. else
  571. {
  572. strncpy(mailbuf,tmpbuf,mailbuflen);
  573. mailbuf[mailbuflen-1] = '\0'; /* add the terminating NULL character */
  574. log(LOG_DEBUG,"handle_connection() : MAIL command saved as %s.",mailbuf);
  575. /* send an OK response to the client */
  576. sendmessage(s,(char *)message,(size_t)512,"250 Sender address OK.%s",SMTPAP_CRLF);
  577. state=4;
  578. }
  579. }
  580. }
  581. }
  582. }
  583. else
  584. sendmessage(s,(char *)message, (size_t)512,"503 Need MAIL first.%s",SMTPAP_CRLF);
  585. }
  586. else if(state == 4)
  587. {
  588. int further_check=0;
  589. if ((!strcmp(token,SMTPAP_RCPT)))
  590. {
  591. token = (char *)strtok(NULL,SMTPAP_SEPCHARS);
  592. if (!token)
  593. {
  594. sendmessage(s,(char *)message,(size_t)512,"500 RCPT requires To:<recipient@address> .%s",SMTPAP_CRLF);
  595. }
  596. else
  597. {
  598. stolower(token);
  599. if (!strcmp(token,"to:")) /* to: separate from the address */
  600. {
  601. token = (char *)strtok(NULL,SMTPAP_SEPCHARS);
  602. if (token == NULL) /* expected another parameter but it's not there */
  603. {
  604. log(LOG_DEBUG,"handle_connection() : Received RCPT To: without an address.");
  605. sendmessage(s,(char *)message,(size_t)512,"500 RCPT To: requires recipient address.%s",SMTPAP_CRLF);
  606. further_check = 0;
  607. }
  608. else /* continue further checking */
  609. further_check = 1;
  610. }
  611. else if (!strcmp(token,"to")) /* probably to : address or to :address */
  612. {
  613. token = (char *)strtok(NULL,SMTPAP_SEPCHARS);
  614. if (token == NULL) /* not enough parameters */
  615. {
  616. log(LOG_DEBUG,"handle_connection() : Received RCPT To with no other parameters.");
  617. sendmessage(s,(char *)message,(size_t)512, "500 RCPT To: requires recipient address.%s",SMTPAP_CRLF);
  618. further_check=0;
  619. }
  620. else if ( (token[0] == ':') && (token[1]!='\0') ) /* contains :address */
  621. {
  622. token++;
  623. further_check=1;
  624. }
  625. else if ( (token[0] == ':') && (token[1]=='\0') )/* the address is in the next token */
  626. {
  627. token = (char *)strtok(NULL,SMTPAP_SEPCHARS);
  628. if (token == NULL) /* not enough parameters */
  629. {
  630. log(LOG_DEBUG,"handle_connection() : Received RCPT To : with no other parameters.");
  631. sendmessage(s,(char *)message,(size_t)512,"500 RCPT To: requires recipient address.%s",SMTPAP_CRLF);
  632. further_check = 0;
  633. }
  634. else /* continue further checking */
  635. further_check =1;
  636. }
  637. else /* couldn't find a colon (:) */
  638. {
  639. log(LOG_DEBUG,"handle_connection() : Couldn't find a colon in the received RCPT command.");
  640. sendmessage(s,(char *)message,(size_t)512,"500 There is a colon (:) missing in that command.%s",SMTPAP_CRLF);
  641. further_check = 1;
  642. }
  643. }
  644. else /* probably to:address */
  645. {
  646. if (!strncmp(token,"to:",3)) /* string starts with from: */
  647. {
  648. token += 3; /* skip the to: bit */
  649. further_check = 1; /* continue further checking */
  650. }
  651. else /* error */
  652. {
  653. log(LOG_DEBUG,"handle_connection() : RCPT parameters don't start with to: .");
  654. sendmessage(s,(char *)message,(size_t)512,"500 RCPT requires To:<recipient@address>.%s",SMTPAP_CRLF);
  655. further_check=0;
  656. }
  657. }
  658. if (further_check == 1) /* check that this is in the correct, format - we can't handle anything else
  659. * but straightforward <user@host> representation, <> optional
  660. */
  661. {
  662. if (((cp = (char *)strchr(token,',')) != NULL) || ((cp = (char *)strchr(token,':')) != NULL)) /* path contains , or : - can't cope with that */
  663. {
  664. log(LOG_DEBUG,"handle_connection() : The client is probably trying to specify a forward path, which I can't handle.");
  665. sendmessage(s,(char *)message,(size_t)512,"500 I can only handle a simple recipient address.%s",SMTPAP_CRLF);
  666. }
  667. else if ((cp = (char *)strchr(token,'@')) == NULL) /* no @, that is most likely a problem :-) */
  668. {
  669. log(LOG_DEBUG,"handle_connection() : The client specified a recipient address with no @.");
  670. sendmessage(s,(char *)message,(size_t)512,"500 Domain name required.%s",SMTPAP_CRLF);
  671. }
  672. else /* the rcpt command seems to be OK, save it */
  673. {
  674. if (rcptbuf != NULL)
  675. {
  676. free(rcptbuf);
  677. rcptbuf = NULL;
  678. }
  679. rcptbuflen = strlen(tmpbuf) + 1;
  680. rcptbuf = (char *)malloc(rcptbuflen);
  681. if (!rcptbuf)
  682. {
  683. log(LOG_ERR,"Could not allocate memory.");
  684. sendmessage(s,(char *)message,(size_t)512,"451 Insufficient memory.%s",SMTPAP_CRLF);
  685. }
  686. else
  687. {
  688. strncpy(rcptbuf,tmpbuf,rcptbuflen);
  689. rcptbuf[rcptbuflen-1] = '\0'; /* add the terminating NULL character */
  690. log(LOG_DEBUG,"handle_connection() : handle_connection : RCPT command saved.");
  691. /* attempt to connect to the destination SMTP server through the OR network */
  692. /* first extract the destination address */
  693. dest_addr_str = extract_smtp_dest(rcptbuf);
  694. log(LOG_DEBUG,"handle_connection() : handle_connection : called extract_smtp_dest()");
  695. if (!dest_addr_str)
  696. {
  697. log(LOG_DEBUG,"handle_connection() : Could not extract a destination SMTP address from the specified recipient address.");
  698. sendmessage(s,(char *)message,(size_t)512,"550 Could not extract destination domain.%s",SMTPAP_CRLF);
  699. }
  700. else
  701. {
  702. /* fill in the standard structure */
  703. ss.version = VERSION;
  704. ss.protocol= SS_PROTOCOL_SMTP;
  705. ss.retry_count = 0;
  706. ss.addr_fmt = SS_ADDR_FMT_ASCII_HOST_PORT;
  707. /* open a socket for connecting to the proxy */
  708. sop = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
  709. if (sop < 0)
  710. {
  711. log(LOG_DEBUG,"handle_connection() : handle_connection : Error opening socket.");
  712. sendmessage(s,(char *)message,(size_t)512,"451 Could not connect to the onion proxy.%s",SMTPAP_CRLF);
  713. if (dest_addr_str != NULL) {
  714. free(dest_addr_str);
  715. dest_addr_str = NULL;
  716. }
  717. }
  718. else
  719. {
  720. log(LOG_DEBUG,"handle_connection() : handle_connection : Socket opened.");
  721. memset((void *)&op_addr,0,sizeof(op_addr)); /* clear the structure first */
  722. /* set up the sockaddr_in structure */
  723. op_addr.sin_family=AF_INET;
  724. op_addr.sin_port=htons(op_port);
  725. memcpy((void *)&op_addr.sin_addr,local->h_addr,local->h_length);
  726. log(LOG_DEBUG,"handle_connection() : Trying to connect to %s at port %u.",inet_ntoa(*((struct in_addr *)local->h_addr)),op_port);
  727. /* try to connect */
  728. retval = connect(sop,(struct sockaddr *)&op_addr,sizeof(op_addr));
  729. if (retval == -1)
  730. {
  731. sendmessage(s,(char *)message,(size_t)512,"451 Could not connect to the onion proxy.%s",SMTPAP_CRLF);
  732. close(sop);
  733. if (dest_addr_str != NULL)
  734. {
  735. free(dest_addr_str);
  736. dest_addr_str = NULL;
  737. }
  738. }
  739. else /* connection established, now send the standard structure + address and wait for a response */
  740. {
  741. /* write the message to the op_out buffer */
  742. snprintf(dest_port_str,6,"%u",SMTPAP_DEFAULT_SMTP_PORT);
  743. if (op_out != NULL)
  744. {
  745. free(op_out);
  746. op_out = NULL;
  747. }
  748. op_outlen = sizeof(ss) /* standard structure */
  749. + strlen(dest_addr_str) /* destination address */
  750. + 1 /* terminating NULL character */
  751. + strlen(dest_port_str)
  752. + 1; /* terminating NULL character */
  753. op_out = (char *)malloc(op_outlen);
  754. if (!op_out) /* error */
  755. {
  756. log(LOG_DEBUG,"handle_connection() : handle_connection : Could not allocate memory.");
  757. sendmessage(s,(char *)message,(size_t)512,"451 Insufficient memory.%s",SMTPAP_CRLF);
  758. close(sop);
  759. if (dest_addr_str != NULL)
  760. {
  761. free(dest_addr_str);
  762. dest_addr_str = NULL;
  763. }
  764. }
  765. else
  766. {
  767. memcpy(op_out,(void *)&ss,sizeof(ss));
  768. strcpy(op_out+sizeof(ss), dest_addr_str);
  769. strcpy(op_out+sizeof(ss)+strlen(dest_addr_str)+1,dest_port_str);
  770. /* now send the message */
  771. retval = write_tout(sop,op_out,op_outlen,conn_toutp);
  772. /* now clean up the buffers */
  773. op_outlen = 0;
  774. free(op_out);
  775. free(dest_addr_str);
  776. if (retval == -1) /* send failed */
  777. {
  778. log(LOG_DEBUG,"handle_connection() : handle_connection : send() failed.");
  779. sendmessage(s,(char *)message,(size_t)512,"451 Could not send to onion proxy.%s",SMTPAP_CRLF);
  780. close(sop);
  781. }
  782. else /* send seemed to have succeeded */
  783. {
  784. /* wait for the return code */
  785. op_inlen = 1;
  786. op_in = (char *)malloc(op_inlen);
  787. if (!op_in) /* memory allocation failed */
  788. {
  789. log(LOG_DEBUG,"handle_connection() : handle_conection : Could not allocate memory.");
  790. sendmessage(s,(char *)message,(size_t)512,"451 Insufficient memory.%s",SMTPAP_CRLF);
  791. close(sop);
  792. }
  793. else
  794. {
  795. retval = read_tout(sop,op_in,1,0, conn_toutp);
  796. if (retval <= 0) /* recv() failed */
  797. {
  798. log(LOG_DEBUG,"handle_connection() : handle_connection : recv() failed.");
  799. sendmessage(s,(char *)message,(size_t)512,"451 Could not receive data from the onion proxy.%s",SMTPAP_CRLF);
  800. close(sop);
  801. }
  802. else
  803. {
  804. if (!(*op_in)) /* onion proxy says OK */
  805. {
  806. log(LOG_DEBUG,"handle_connection() : handle_connection : received E_SUCCESS from onion proxy");
  807. /* clean up */
  808. free(op_in);
  809. op_inlen=0;
  810. /* allocate both op_in and op_out 512 bytes, the maximum size of an SMTP line */
  811. op_outlen=512;
  812. op_inlen=512;
  813. op_out = (char *)malloc(512);
  814. op_in = (char *)malloc(512);
  815. if ((!op_out) || (!op_in))
  816. {
  817. log(LOG_DEBUG,"handle_connection() : handle_connection : Could not allocate memory.");
  818. sendmessage(s,(char *)message,(size_t)512,"451 Insufficient memory.%s",SMTPAP_CRLF);
  819. close(sop);
  820. }
  821. else
  822. {
  823. /* receive the greeting message from the recipient */
  824. retval = receive(sop,&op_in,(size_t *)&op_inlen,0);
  825. if (retval == -1) /* could not receive greeting */
  826. {
  827. log(LOG_DEBUG,"handle_connection() : handle_connection : error receiving greeting from recipient.");
  828. sendmessage(s,(char *)message,(size_t)512,"451 Error receiving data from the recipient.%s",SMTPAP_CRLF);
  829. }
  830. else /* received greeting */
  831. {
  832. /* send HELO command */
  833. retval = sendmessage(sop,(char *)op_out,(size_t)op_outlen,"HELO ANONYMOUS.smtp.daemon%s",SMTPAP_CRLF);
  834. if (retval == -1)
  835. {
  836. sendmessage(s,(char *)message,(size_t)512,"451 Error sending HELO to the recipient.");
  837. close(sop);
  838. }
  839. else
  840. {
  841. retval = receive(sop,&op_in,(size_t *)&op_inlen,0);
  842. if (retval == -1)
  843. {
  844. log(LOG_DEBUG,"handle_connection() : handle_connection : error receiving HELO response from recipient");
  845. sendmessage(s,(char *)message,(size_t)512,"451 Error receiving data from the recipient.%s",SMTPAP_CRLF);
  846. close(sop);
  847. }
  848. else
  849. {
  850. op_in[retval]=0;
  851. log(LOG_DEBUG,"handle_connection() : handle_connection : Received this from recipient : %s.",op_in);
  852. if (op_in[0] == '2') /* success */
  853. {
  854. /* send MAIL */
  855. if (options[Anonimize].r.i)
  856. retval = sendmessage(sop,(char *)op_out,(size_t)op_outlen,"MAIL From:anonymous@anon.net%s",SMTPAP_CRLF);
  857. else
  858. retval = write_tout(sop,mailbuf,mailbuflen-1,conn_toutp);
  859. if (retval == -1)
  860. {
  861. log(LOG_DEBUG,"handle_connection() : handle_connection : error sending MAIL to recipient");
  862. sendmessage(s,(char *)message,(size_t)512,"451 Error sending MAIL to the recipient.%s",SMTPAP_CRLF);
  863. sendmessage(sop,(char *)op_out,(size_t)op_outlen,"%s%s",SMTPAP_QUIT,SMTPAP_CRLF);
  864. close(sop);
  865. }
  866. else
  867. {
  868. retval = receive(sop,&op_in,(size_t *)&op_inlen,0);
  869. if (retval == -1)
  870. {
  871. log(LOG_DEBUG,"handle_connection() : handle_connection : error receiving MAIL response from recipient");
  872. sendmessage(s,(char *)message,(size_t)512,"451 Error receiving data from the recipient.%s",SMTPAP_CRLF);
  873. close(sop);
  874. }
  875. else
  876. {
  877. op_in[retval]=0;
  878. log(LOG_DEBUG,"handle_connection() : handle_connection : Received this from recipient : %s.",op_in);
  879. if (op_in[0] == '2') /* success */
  880. {
  881. /* send RCPT */
  882. retval = write_tout(sop,rcptbuf,rcptbuflen-1,conn_toutp); /* rcptbuflen includes the terminating NULL character but we don't want to send that */
  883. if (retval == -1)
  884. {
  885. log(LOG_DEBUG,"handle_connection() : handle_connection : error sending RCPT to recipient");
  886. sendmessage(s,(char *)message,(size_t)512,"451 Error sending RCPT to the recipient.%s",SMTPAP_CRLF);
  887. sendmessage(sop,(char *)op_out,(size_t)op_outlen,"%s%s",SMTPAP_QUIT,SMTPAP_CRLF);
  888. close(sop);
  889. }
  890. else
  891. {
  892. retval = receive(sop,&op_in,(size_t *)&op_inlen,0);
  893. if (retval == -1)
  894. {
  895. log(LOG_DEBUG,"handle_connection() : handle_connection : error receiving RCPT response from recipient");
  896. sendmessage(s,(char *)message,(size_t)512,"451 Error receiving data from the recipient.%s",SMTPAP_CRLF);
  897. close(sop);
  898. }
  899. else
  900. {
  901. op_in[retval]=0;
  902. log(LOG_DEBUG,"handle_connection() : handle_connection : Received this from recipient : %s.",op_in);
  903. if (op_in[0] == '2') /* success */
  904. {
  905. sendmessage(s,(char *)message,(size_t)512,"250 Recipient OK.%s",SMTPAP_CRLF);
  906. state = 5;
  907. }
  908. else /* didn't like my RCPT */
  909. {
  910. log(LOG_DEBUG,"handle_connection() : handle_connection : RCPT unsuccessful");
  911. sendmessage(sop,(char *)op_out,(size_t)op_outlen,"%s%s",SMTPAP_QUIT,SMTPAP_CRLF);
  912. close(sop);
  913. sendmessage(s,(char *)message,(size_t)512,"500 Recipient SMTP daemon rejected my RCPT.%s",SMTPAP_CRLF);
  914. }
  915. }
  916. }
  917. }
  918. else /* didn't like my MAIL */
  919. {
  920. log(LOG_DEBUG,"handle_connection() : handle_connection : MAIL unsuccessful");
  921. sendmessage(sop,(char *)op_out,(size_t)op_outlen,"%s%s",SMTPAP_QUIT,SMTPAP_CRLF);
  922. close(sop);
  923. sendmessage(s,(char *)message,(size_t)512,"500 Recipient SMTP daemon rejected my MAIL.%s",SMTPAP_CRLF);
  924. }
  925. }
  926. }
  927. }
  928. else
  929. {
  930. log(LOG_DEBUG,"handle_connection() : handle_connection : HELO unsuccessful");
  931. sendmessage(sop,(char *)op_out,(size_t)op_outlen,"%s%s",SMTPAP_QUIT,SMTPAP_CRLF);
  932. close(sop);
  933. sendmessage(s,(char *)message,(size_t)512,"500 Recipient SMTP daemon rejected my HELO.%s",SMTPAP_CRLF);
  934. }
  935. }
  936. }
  937. }
  938. }
  939. }
  940. else
  941. {
  942. log(LOG_DEBUG,"handle_connection() : handle_connection : onion proxy returned non-zero error code %d.",*op_in);
  943. close(sop);
  944. switch(*op_in)
  945. {
  946. case SS_ERROR_VERSION_UNSUPPORTED :
  947. sendmessage(s,(char *)message,(size_t)512,"500 Onion proxy returned an error (Protocol version not supported).%s",SMTPAP_CRLF);
  948. break;
  949. case SS_ERROR_ADDR_FMT_UNSUPPORTED:
  950. sendmessage(s,(char *)message,(size_t)512,"500 Onion proxy returned an error (Address format not recognised).%s",SMTPAP_CRLF);
  951. break;
  952. case SS_ERROR_INVALID_ADDRESS:
  953. sendmessage(s,(char *)message,(size_t)512,"500 Onion proxy returned an error (Invalid destination address).%s",SMTPAP_CRLF);
  954. break;
  955. case SS_ERROR_INVALID_PORT:
  956. sendmessage(s,(char *)message,(size_t)512,"500 Onion proxy returned an error (Invalid destination port).%s",SMTPAP_CRLF);
  957. break;
  958. default :
  959. sendmessage(s,(char *)message,(size_t)512,"500 Onion proxy returned unexpected error code %d.%s",*op_in,SMTPAP_CRLF);
  960. break;
  961. }
  962. /* clean up */
  963. free(op_in);
  964. op_inlen=0;
  965. }
  966. }
  967. }
  968. }
  969. }
  970. }
  971. }
  972. }
  973. }
  974. }
  975. }
  976. }
  977. }
  978. else
  979. sendmessage(s,(char *)message, (size_t)512,"503 Need RCPT first.%s",SMTPAP_CRLF);
  980. }
  981. else if (state == 5)
  982. {
  983. if ((!strcmp(token,SMTPAP_DATA))) /* received data */
  984. {
  985. partial_dataend = 0;
  986. retval = write_tout(sop, tmpbuf, strlen(tmpbuf), conn_toutp); /* send DATA */
  987. if (retval == -1) /* send(0) failed */
  988. {
  989. log(LOG_DEBUG,"handle_connection() : handle_connection : Failed to send DATA to recipient.");
  990. sendmessage(s,(char *)message,(size_t)512,"451 Error sending DATA to the recipient.%s",SMTPAP_CRLF);
  991. }
  992. else /* get response from the recipient */
  993. {
  994. retval = receive(sop,&op_in,(size_t *)&op_inlen,0);
  995. if (retval == -1)
  996. {
  997. log(LOG_DEBUG,"handle_connection() : handle_connection : error receiving DATA response from recipient");
  998. sendmessage(s,(char *)message,(size_t)512,"451 Error receiving data from the recipient.%s",SMTPAP_CRLF);
  999. }
  1000. else
  1001. {
  1002. op_in[retval]=0;
  1003. log(LOG_DEBUG,"handle_connection() : handle_connection : Received this from recipient : %s.",op_in);
  1004. if (op_in[0] == '3') /* success */
  1005. {
  1006. sendmessage(s,(char *)message,(size_t)512,"354 Enter mail, end with \".\" on a line by itself%s",SMTPAP_CRLF);
  1007. state = 6;
  1008. }
  1009. else /* didn't like my DATA */
  1010. {
  1011. log(LOG_DEBUG,"handle_connection() : handle_connection : DATA unsuccessful");
  1012. sendmessage(s,(char *)message,(size_t)512,"500 Recipient SMTP daemon rejected my DATA.%s",SMTPAP_CRLF);
  1013. }
  1014. }
  1015. }
  1016. }
  1017. else
  1018. sendmessage(s,(char *)message, (size_t)512,"503 Expecting DATA.%s",SMTPAP_CRLF);
  1019. }
  1020. else if (state == 6)
  1021. {
  1022. /* sanitize the data stream if necessary */
  1023. if (options[Anonimize].r.i == 1)
  1024. {
  1025. log(LOG_DEBUG,"handle_connection() : Sanitizing headers ...");
  1026. retval = sanitize_data((unsigned char **)&tmpbuf, &inputlen);
  1027. }
  1028. if ((!retval) || (!options[Anonimize].r.i)) /* sanitization successsful (or wasn't necessary)? */
  1029. {
  1030. log(LOG_DEBUG,"handle_connection() : Attempting to send ...");
  1031. /* forward to recipient */
  1032. retval = write_tout(sop,tmpbuf, inputlen, conn_toutp);
  1033. if (retval == -1)
  1034. {
  1035. log(LOG_DEBUG,"handle_connection() : handle_connection : Failed to forward data to recipient.");
  1036. sendmessage(sop, (char *)op_out, (size_t)op_outlen,"451 Failed to forward data to the recipient.%s",SMTPAP_CRLF);
  1037. }
  1038. else
  1039. {
  1040. /* get the response */
  1041. retval = receive(sop,&op_in,(size_t *)&op_inlen,0);
  1042. if (retval == -1)
  1043. {
  1044. log(LOG_DEBUG,"handle_connection() : handle_connection : error receiving response from recipient");
  1045. sendmessage(s,(char *)message,(size_t)512,"451 Data sent but did not receive a response from the recipient%s.",SMTPAP_CRLF);
  1046. }
  1047. else
  1048. {
  1049. op_in[retval]=0;
  1050. log(LOG_DEBUG,"handle_connection() : handle_connection : Received this from recipient : %s.",op_in);
  1051. if (op_in[0] == '2') /* success */
  1052. {
  1053. sendmessage(s,(char *)message,(size_t)512,"250 Message accepted for delivery.%s",SMTPAP_CRLF);
  1054. sendmessage(sop, (char *)op_out, (size_t)op_outlen,"QUIT%s",SMTPAP_CRLF);
  1055. }
  1056. else /* didn't like my DATA */
  1057. {
  1058. log(LOG_DEBUG,"handle_connection() : handle_connection : DATA unsuccessful");
  1059. sendmessage(s,(char *)message,(size_t)512,"500 Recipient SMTP daemon rejected my DATA.%s",SMTPAP_CRLF);
  1060. }
  1061. }
  1062. }
  1063. }
  1064. else /* sanitization error */
  1065. {
  1066. log(LOG_ERR,"Unable to sanitize an incoming message. Will reject.");
  1067. sendmessage(sop,(char *)op_out, (size_t)op_outlen,"400 Failed to sanitize the data stream.%s", SMTPAP_CRLF);
  1068. }
  1069. /* after state 6 we go back to state 3, regardless of wether the transfer was succesful or not */
  1070. state = 3;
  1071. close(sop);
  1072. free(op_in);op_in=NULL;
  1073. free(op_out);op_out=NULL;
  1074. }
  1075. else /* unexpected state */
  1076. {
  1077. log(LOG_DEBUG,"handle_connection() : handle_connection : Unexpected state!");
  1078. log(LOG_ERR,"An unexpected error has occured. Closing connection.");
  1079. sendmessage(s,(char *)message,(size_t)512,"500 An unexpected error has ocurred. Closing connection.%s",SMTPAP_CRLF);
  1080. break;
  1081. }
  1082. }
  1083. /* clean up */
  1084. if (inbuf != NULL)
  1085. free(inbuf);
  1086. if (tmpbuf != NULL)
  1087. free(tmpbuf);
  1088. if (mailbuf != NULL)
  1089. free(mailbuf);
  1090. if (rcptbuf != NULL)
  1091. free(rcptbuf);
  1092. if (rcptarray != NULL)
  1093. free(rcptarray);
  1094. if (dest_addr_str != NULL)
  1095. free(dest_addr_str);
  1096. if (op_in != NULL)
  1097. free(op_in);
  1098. if (op_out != NULL)
  1099. free(op_out);
  1100. close(sop);
  1101. close(s);
  1102. return retval;
  1103. }
  1104. int main(int argc, char *argv[])
  1105. {
  1106. int loglevel = LOG_DEBUG;
  1107. int retval = 0;
  1108. char c; /* command-line option */
  1109. /* configuration file */
  1110. char *conf_filename = NULL;
  1111. FILE *cf = NULL;
  1112. struct hostent *local_host;
  1113. char local_hostname[512];
  1114. struct sockaddr_in local, remote; /* local and remote address info */
  1115. int request_sock; /* where we listen for connections */
  1116. int new_sock; /* for accepted connections */
  1117. size_t sin_size; /* for accept() calls */
  1118. u_short p; /* smtp proxy port */
  1119. u_short op_port; /* onion proxy port */
  1120. /* used for reaping zombie processes */
  1121. struct sigaction sa;
  1122. char *errtest = NULL; /* for detecting strtoul() errors */
  1123. /* set default listening port */
  1124. p = htons(SMTPAP_LISTEN_PORT);
  1125. /* deal with program arguments */
  1126. if ((argc < 2) && (argc > 5)) /* to few or too many arguments*/
  1127. {
  1128. print_usage();
  1129. return -1;
  1130. }
  1131. opterr = 0;
  1132. while ((c = getopt(argc,argv,args)) != -1)
  1133. {
  1134. switch(c)
  1135. {
  1136. case 'f': /* config file */
  1137. conf_filename = optarg;
  1138. break;
  1139. case 'p':
  1140. p = htons((u_short)strtoul(optarg,&errtest,0));
  1141. if (errtest == optarg) /* error */
  1142. {
  1143. log(LOG_ERR,"Error : -p must be followed by an unsigned positive integer value.");
  1144. print_usage();
  1145. return -1;
  1146. }
  1147. break;
  1148. case 'h':
  1149. print_usage();
  1150. return 0;
  1151. break;
  1152. case 'l':
  1153. if (!strcmp(optarg,"emerg"))
  1154. loglevel = LOG_EMERG;
  1155. else if (!strcmp(optarg,"alert"))
  1156. loglevel = LOG_ALERT;
  1157. else if (!strcmp(optarg,"crit"))
  1158. loglevel = LOG_CRIT;
  1159. else if (!strcmp(optarg,"err"))
  1160. loglevel = LOG_ERR;
  1161. else if (!strcmp(optarg,"warning"))
  1162. loglevel = LOG_WARNING;
  1163. else if (!strcmp(optarg,"notice"))
  1164. loglevel = LOG_NOTICE;
  1165. else if (!strcmp(optarg,"info"))
  1166. loglevel = LOG_INFO;
  1167. else if (!strcmp(optarg,"debug"))
  1168. loglevel = LOG_DEBUG;
  1169. else
  1170. {
  1171. log(LOG_ERR,"Error : argument to -l must be one of alert|crit|err|warning|notice|info|debug.");
  1172. print_usage();
  1173. return -1;
  1174. }
  1175. break;
  1176. case '?':
  1177. if (isprint(c))
  1178. log(LOG_ERR,"Missing argument or unknown option '-%c'.",optopt);
  1179. else
  1180. log(LOG_ERR,"Unknown option character 'x%x'.",optopt);
  1181. print_usage();
  1182. return -1;
  1183. break;
  1184. default:
  1185. abort();
  1186. }
  1187. }
  1188. log(loglevel,NULL); /* assign severity level for logger */
  1189. /* the -f option is mandatory */
  1190. if (conf_filename == NULL)
  1191. {
  1192. log(LOG_ERR,"You must specify a config file with the -f option. See help (-h).");
  1193. return -1;
  1194. }
  1195. /* load config file */
  1196. cf = open_config(conf_filename);
  1197. if (!cf)
  1198. {
  1199. log(LOG_ERR,"Could not open configuration file %s.",conf_filename);
  1200. return -1;
  1201. }
  1202. retval = parse_config(cf,options);
  1203. if (retval)
  1204. return -1;
  1205. if (options[OnionProxy].err != 1)
  1206. {
  1207. log(LOG_ERR,"The OnionProxy option is mandatory.");
  1208. return -1;
  1209. }
  1210. if (options[MaxConn].err != 1)
  1211. {
  1212. log(LOG_ERR,"The MaxConn option is mandatory.");
  1213. return -1;
  1214. }
  1215. if (options[Anonimize].err != 1)
  1216. {
  1217. log(LOG_ERR,"The Anonimize option is mandatory.");
  1218. return -1;
  1219. }
  1220. else if ((options[Anonimize].r.i != 0) && (options[Anonimize].r.i != 1))
  1221. {
  1222. log(LOG_ERR,"The Anonimize option takes the values 1 or 0.");
  1223. return -1;
  1224. }
  1225. if (options[ConnTimeout].err != 1)
  1226. {
  1227. conn_tout.tv_sec = SMTPAP_DEFAULT_CONN_TIMEOUT;
  1228. }
  1229. else
  1230. {
  1231. if (!options[ConnTimeout].r.i)
  1232. conn_toutp = NULL;
  1233. else
  1234. conn_tout.tv_sec = options[ConnTimeout].r.i;
  1235. }
  1236. conn_tout.tv_usec = 0;
  1237. op_port = (u_short)options[OnionProxy].r.i;
  1238. /* get local address so that we know where to get the onion proxy when we need it */
  1239. retval = gethostname(local_hostname, (size_t)512);
  1240. if (retval < 0)
  1241. {
  1242. log(LOG_ERR,"Error getting local hostname");
  1243. return -1;
  1244. }
  1245. local_host = gethostbyname(local_hostname);
  1246. if (!local_host)
  1247. {
  1248. log(LOG_ERR,"Error getting local address.");
  1249. return -1;
  1250. }
  1251. log(LOG_DEBUG,"main() : Got local address : %s.",local_hostname);
  1252. /* get the server up and running */
  1253. request_sock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
  1254. if (request_sock < 0)
  1255. {
  1256. log(LOG_ERR,"Error opening socket.");
  1257. return -1;
  1258. }
  1259. log(LOG_DEBUG,"Socket opened.");
  1260. memset((void *)&local,0,sizeof(local)); /* clear the structure first */
  1261. /* set up the sockaddr_in structure */
  1262. local.sin_family=AF_INET;
  1263. local.sin_addr.s_addr = INADDR_ANY;
  1264. local.sin_port=p;
  1265. /* bind it to the socket */
  1266. retval = bind(request_sock,(struct sockaddr *)&local, sizeof(local));
  1267. if (retval < 0)
  1268. {
  1269. log(LOG_ERR,"Error binding socket to local port %d.",ntohs(p));
  1270. return retval;
  1271. }
  1272. log(LOG_DEBUG,"Socket bound to port %d.",ntohs(p));
  1273. /* listen for connections */
  1274. retval = listen(request_sock,SOMAXCONN);
  1275. if (retval < 0)
  1276. {
  1277. log(LOG_ERR,"Could not listen for connections.");
  1278. return retval;
  1279. }
  1280. log(LOG_DEBUG,"Listening for connections.");
  1281. /* server should now be up and running */
  1282. /* install the signal handler for making sure zombie processes are killed */
  1283. sa.sa_handler = sigchld_handler;
  1284. sigemptyset(&sa.sa_mask);
  1285. sa.sa_flags = SA_RESTART;
  1286. retval = sigaction(SIGCHLD,&sa,NULL);
  1287. if (retval < 0)
  1288. {
  1289. log(LOG_ERR,"Could not install a signal handler.");
  1290. return -1;
  1291. }
  1292. /* main server loop */
  1293. /* I use a forking server technique - this isn't the most efficient way to do it,
  1294. * but it is simpler. */
  1295. while(1)
  1296. {
  1297. sin_size = sizeof(struct sockaddr_in);
  1298. new_sock = accept(request_sock,(struct sockaddr *)&remote,&sin_size);
  1299. if (new_sock == -1)
  1300. {
  1301. if (errno != EINTR)
  1302. log(LOG_ERR,"Could not accept socket connection.");
  1303. else
  1304. log(LOG_DEBUG,"Interrupt received.");
  1305. continue;
  1306. }
  1307. if (connections >= options[MaxConn].r.i)
  1308. {
  1309. log(LOG_NOTICE,"Number of maximum connections reached. Rejecting incoming request.");
  1310. close(new_sock);
  1311. continue;
  1312. }
  1313. log(LOG_DEBUG,"Accepted a connection from %s.",inet_ntoa(remote.sin_addr));
  1314. connections++;
  1315. if (!fork()) /* this is the child process */
  1316. {
  1317. close(request_sock); /* the child doesn't need the request socket anymore */
  1318. /* Main logic of smtpap. */
  1319. retval = handle_connection(new_sock, local_host, remote, op_port);
  1320. /* End main logic */
  1321. exit(retval); /* done, exit */
  1322. }
  1323. close(new_sock); /* don't need this anymore */
  1324. }
  1325. return retval;
  1326. }