PageRenderTime 23ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/cone-0.84/tcpd/starttls.c

#
C | 802 lines | 652 code | 144 blank | 6 comment | 149 complexity | a9aa47462d7bc0c6300f4eff27c06ec8 MD5 | raw file
Possible License(s): GPL-3.0
  1. /*
  2. ** Copyright 2000-2008 Double Precision, Inc.
  3. ** See COPYING for distribution information.
  4. */
  5. #include "config.h"
  6. #include "argparse.h"
  7. #include "spipe.h"
  8. #include "libcouriertls.h"
  9. #include "tlscache.h"
  10. #include "rfc1035/rfc1035.h"
  11. #include "soxwrap/soxwrap.h"
  12. #ifdef getc
  13. #undef getc
  14. #endif
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <stdlib.h>
  18. #include <ctype.h>
  19. #include <netdb.h>
  20. #if HAVE_DIRENT_H
  21. #include <dirent.h>
  22. #define NAMLEN(dirent) strlen((dirent)->d_name)
  23. #else
  24. #define dirent direct
  25. #define NAMLEN(dirent) (dirent)->d_namlen
  26. #if HAVE_SYS_NDIR_H
  27. #include <sys/ndir.h>
  28. #endif
  29. #if HAVE_SYS_DIR_H
  30. #include <sys/dir.h>
  31. #endif
  32. #if HAVE_NDIR_H
  33. #include <ndir.h>
  34. #endif
  35. #endif
  36. #if HAVE_UNISTD_H
  37. #include <unistd.h>
  38. #endif
  39. #if HAVE_FCNTL_H
  40. #include <fcntl.h>
  41. #endif
  42. #include <errno.h>
  43. #if HAVE_SYS_TYPES_H
  44. #include <sys/types.h>
  45. #endif
  46. #if HAVE_SYS_STAT_H
  47. #include <sys/stat.h>
  48. #endif
  49. #include <sys/socket.h>
  50. #include <arpa/inet.h>
  51. #if TIME_WITH_SYS_TIME
  52. #include <sys/time.h>
  53. #include <time.h>
  54. #else
  55. #if HAVE_SYS_TIME_H
  56. #include <sys/time.h>
  57. #else
  58. #include <time.h>
  59. #endif
  60. #endif
  61. #include <locale.h>
  62. static const char rcsid[]="$Id: starttls.c,v 1.44 2009/06/27 16:32:38 mrsam Exp $";
  63. /* Command-line options: */
  64. const char *clienthost=0;
  65. const char *clientport=0;
  66. const char *server=0;
  67. const char *localfd=0;
  68. const char *remotefd=0;
  69. const char *statusfd=0;
  70. const char *tcpd=0;
  71. const char *peer_verify_domain=0;
  72. const char *fdprotocol=0;
  73. static FILE *errfp;
  74. static FILE *statusfp;
  75. const char *printx509=0;
  76. static void ssl_errmsg(const char *errmsg, void *dummy)
  77. {
  78. fprintf(errfp, "%s\n", errmsg);
  79. }
  80. static void nonsslerror(const char *pfix)
  81. {
  82. fprintf(errfp, "%s: %s\n", pfix, strerror(errno));
  83. }
  84. void docopy(ssl_handle ssl, int sslfd, int stdinfd, int stdoutfd)
  85. {
  86. struct tls_transfer_info transfer_info;
  87. char from_ssl_buf[BUFSIZ], to_ssl_buf[BUFSIZ];
  88. char *fromptr;
  89. int rc;
  90. fd_set fdr, fdw;
  91. int maxfd=sslfd;
  92. if (fcntl(stdinfd, F_SETFL, O_NONBLOCK)
  93. || fcntl(stdoutfd, F_SETFL, O_NONBLOCK)
  94. )
  95. {
  96. nonsslerror("fcntl");
  97. return;
  98. }
  99. if (maxfd < stdinfd) maxfd=stdinfd;
  100. if (maxfd < stdoutfd) maxfd=stdoutfd;
  101. tls_transfer_init(&transfer_info);
  102. transfer_info.readptr=fromptr=from_ssl_buf;
  103. for (;;)
  104. {
  105. if (transfer_info.readptr == fromptr)
  106. {
  107. transfer_info.readptr=fromptr=from_ssl_buf;
  108. transfer_info.readleft=sizeof(from_ssl_buf);
  109. }
  110. else
  111. transfer_info.readleft=0;
  112. FD_ZERO(&fdr);
  113. FD_ZERO(&fdw);
  114. rc=tls_transfer(&transfer_info, ssl, sslfd, &fdr, &fdw);
  115. if (rc == 0)
  116. continue;
  117. if (rc < 0)
  118. break;
  119. if (!tls_inprogress(&transfer_info))
  120. {
  121. if (transfer_info.readptr > fromptr)
  122. FD_SET(stdoutfd, &fdw);
  123. if (transfer_info.writeleft == 0)
  124. FD_SET(stdinfd, &fdr);
  125. }
  126. if (select(maxfd+1, &fdr, &fdw, 0, 0) <= 0)
  127. {
  128. if (errno != EINTR)
  129. {
  130. nonsslerror("select");
  131. break;
  132. }
  133. continue;
  134. }
  135. if (FD_ISSET(stdoutfd, &fdw) &&
  136. transfer_info.readptr > fromptr)
  137. {
  138. rc=write(stdoutfd, fromptr,
  139. transfer_info.readptr - fromptr);
  140. if (rc <= 0)
  141. break;
  142. fromptr += rc;
  143. }
  144. if (FD_ISSET(stdinfd, &fdr) && transfer_info.writeleft == 0)
  145. {
  146. rc=read(stdinfd, to_ssl_buf, sizeof(to_ssl_buf));
  147. if (rc <= 0)
  148. break;
  149. transfer_info.writeptr=to_ssl_buf;
  150. transfer_info.writeleft=rc;
  151. }
  152. }
  153. tls_closing(&transfer_info);
  154. for (;;)
  155. {
  156. FD_ZERO(&fdr);
  157. FD_ZERO(&fdw);
  158. if (tls_transfer(&transfer_info, ssl, sslfd, &fdr, &fdw) < 0)
  159. break;
  160. if (select(maxfd+1, &fdr, &fdw, 0, 0) <= 0)
  161. {
  162. if (errno != EINTR)
  163. {
  164. nonsslerror("select");
  165. break;
  166. }
  167. continue;
  168. }
  169. }
  170. }
  171. struct dump_capture_subject {
  172. char line[1024];
  173. int line_size;
  174. int set_subject;
  175. int seen_subject;
  176. int in_subject;
  177. FILE *fp;
  178. };
  179. static void dump_to_fp(const char *p, int cnt, void *arg)
  180. {
  181. struct dump_capture_subject *dcs=(struct dump_capture_subject *)arg;
  182. char *n, *v;
  183. char namebuf[64];
  184. if (cnt < 0)
  185. cnt=strlen(p);
  186. if (dcs->fp && fwrite(p, cnt, 1, dcs->fp) != 1)
  187. ; /* NOOP */
  188. while (cnt)
  189. {
  190. if (*p != '\n')
  191. {
  192. if (dcs->line_size < sizeof(dcs->line)-1)
  193. dcs->line[dcs->line_size++]=*p;
  194. ++p;
  195. --cnt;
  196. continue;
  197. }
  198. dcs->line[dcs->line_size]=0;
  199. ++p;
  200. --cnt;
  201. dcs->line_size=0;
  202. if (strncmp(dcs->line, "Subject:", 8) == 0)
  203. {
  204. if (dcs->seen_subject)
  205. continue;
  206. dcs->seen_subject=1;
  207. dcs->in_subject=1;
  208. continue;
  209. }
  210. if (!dcs->in_subject)
  211. continue;
  212. if (dcs->line[0] != ' ')
  213. {
  214. dcs->in_subject=0;
  215. continue;
  216. }
  217. for (n=dcs->line; *n; n++)
  218. if (*n != ' ')
  219. break;
  220. for (v=n; *v; v++)
  221. {
  222. *v=toupper(*v);
  223. if (*v == '=')
  224. {
  225. *v++=0;
  226. break;
  227. }
  228. }
  229. namebuf[snprintf(namebuf, sizeof(namebuf)-1,
  230. "TLS_SUBJECT_%s", n)]=0;
  231. if (dcs->set_subject)
  232. setenv(namebuf, v, 1);
  233. }
  234. }
  235. static int verify_connection(ssl_handle ssl, void *dummy)
  236. {
  237. FILE *printx509_fp=NULL;
  238. int printx509_fd=0;
  239. char *buf;
  240. struct dump_capture_subject dcs;
  241. memset(&dcs, 0, sizeof(dcs));
  242. if (printx509)
  243. {
  244. printx509_fd=atoi(printx509);
  245. printx509_fp=fdopen(printx509_fd, "w");
  246. if (!printx509_fp)
  247. nonsslerror("fdopen");
  248. }
  249. dcs.fp=printx509_fp;
  250. dcs.set_subject=0;
  251. if (tls_certificate_verified(ssl))
  252. dcs.set_subject=1;
  253. tls_dump_connection_info(ssl, server ? 1:0, dump_to_fp, &dcs);
  254. if (printx509_fp)
  255. {
  256. fclose(printx509_fp);
  257. }
  258. if (statusfp)
  259. {
  260. fclose(statusfp);
  261. statusfp=NULL;
  262. errfp=stderr;
  263. }
  264. buf=tls_get_encryption_desc(ssl);
  265. setenv("TLS_CONNECTED_PROTOCOL",
  266. buf ? buf:"(unknown)", 1);
  267. if (buf)
  268. free(buf);
  269. return 1;
  270. }
  271. /* ----------------------------------------------------------------------- */
  272. static void startclient(int argn, int argc, char **argv, int fd,
  273. int *stdin_fd, int *stdout_fd)
  274. {
  275. pid_t p;
  276. int streampipe[2];
  277. if (localfd)
  278. {
  279. *stdin_fd= *stdout_fd= atoi(localfd);
  280. return;
  281. }
  282. if (argn >= argc) return; /* Interactive */
  283. if (libmail_streampipe(streampipe))
  284. {
  285. nonsslerror("libmail_streampipe");
  286. exit(1);
  287. }
  288. if ((p=fork()) == -1)
  289. {
  290. nonsslerror("fork");
  291. close(streampipe[0]);
  292. close(streampipe[1]);
  293. exit(1);
  294. }
  295. if (p == 0)
  296. {
  297. char **argvec;
  298. int n;
  299. close(fd); /* Child process doesn't need it */
  300. dup2(streampipe[1], 0);
  301. dup2(streampipe[1], 1);
  302. close(streampipe[0]);
  303. close(streampipe[1]);
  304. argvec=malloc(sizeof(char *)*(argc-argn+1));
  305. if (!argvec)
  306. {
  307. nonsslerror("malloc");
  308. exit(1);
  309. }
  310. for (n=0; n<argc-argn; n++)
  311. argvec[n]=argv[argn+n];
  312. argvec[n]=0;
  313. execvp(argvec[0], argvec);
  314. nonsslerror(argvec[0]);
  315. exit(1);
  316. }
  317. close(streampipe[1]);
  318. *stdin_fd= *stdout_fd= streampipe[0];
  319. }
  320. static int connectremote(const char *host, const char *port)
  321. {
  322. int fd;
  323. RFC1035_ADDR addr;
  324. int af;
  325. RFC1035_ADDR *addrs;
  326. unsigned naddrs, n;
  327. RFC1035_NETADDR addrbuf;
  328. const struct sockaddr *saddr;
  329. int saddrlen;
  330. int port_num;
  331. port_num=atoi(port);
  332. if (port_num <= 0)
  333. {
  334. struct servent *servent;
  335. servent=getservbyname(port, "tcp");
  336. if (!servent)
  337. {
  338. fprintf(errfp, "%s: invalid port.\n", port);
  339. return (-1);
  340. }
  341. port_num=servent->s_port;
  342. }
  343. else
  344. port_num=htons(port_num);
  345. if (rfc1035_aton(host, &addr) == 0) /* An explicit IP addr */
  346. {
  347. if ((addrs=malloc(sizeof(addr))) == 0)
  348. {
  349. nonsslerror("malloc");
  350. return (-1);
  351. }
  352. memcpy(addrs, &addr, sizeof(addr));
  353. naddrs=1;
  354. }
  355. else
  356. {
  357. if (rfc1035_a(&rfc1035_default_resolver, host, &addrs,
  358. &naddrs))
  359. {
  360. fprintf(errfp, "%s: not found.\n", host);
  361. return (-1);
  362. }
  363. }
  364. if ((fd=rfc1035_mksocket(SOCK_STREAM, 0, &af)) < 0)
  365. {
  366. nonsslerror("socket");
  367. return (-1);
  368. }
  369. for (n=0; n<naddrs; n++)
  370. {
  371. if (rfc1035_mkaddress(af, &addrbuf, addrs+n, port_num,
  372. &saddr, &saddrlen)) continue;
  373. if (sox_connect(fd, saddr, saddrlen) == 0)
  374. break;
  375. }
  376. free(addrs);
  377. if (n >= naddrs)
  378. {
  379. close(fd);
  380. nonsslerror("connect");
  381. return (-1);
  382. }
  383. return (fd);
  384. }
  385. static int connect_completed(ssl_handle ssl, int fd)
  386. {
  387. struct tls_transfer_info transfer_info;
  388. tls_transfer_init(&transfer_info);
  389. while (tls_connecting(ssl))
  390. {
  391. fd_set fdr, fdw;
  392. FD_ZERO(&fdr);
  393. FD_ZERO(&fdw);
  394. if (tls_transfer(&transfer_info, ssl,
  395. fd, &fdr, &fdw) < 0)
  396. return (0);
  397. if (!tls_connecting(ssl))
  398. break;
  399. if (select(fd+1, &fdr, &fdw, 0, 0) <= 0)
  400. {
  401. if (errno != EINTR)
  402. {
  403. nonsslerror("select");
  404. return (0);
  405. }
  406. }
  407. }
  408. return (1);
  409. }
  410. static int dossl(int fd, int argn, int argc, char **argv)
  411. {
  412. ssl_context ctx;
  413. ssl_handle ssl;
  414. int stdin_fd, stdout_fd;
  415. struct tls_info info= *tls_get_default_info();
  416. info.peer_verify_domain=peer_verify_domain;
  417. info.tls_err_msg=ssl_errmsg;
  418. info.connect_callback= &verify_connection;
  419. info.app_data=NULL;
  420. ctx=tls_create(server ? 1:0, &info);
  421. if (ctx == 0) return (1);
  422. ssl=tls_connect(ctx, fd);
  423. if (!ssl)
  424. {
  425. close(fd);
  426. return (1);
  427. }
  428. if (!connect_completed(ssl, fd))
  429. {
  430. tls_disconnect(ssl, fd);
  431. close(fd);
  432. tls_destroy(ctx);
  433. return 1;
  434. }
  435. stdin_fd=0;
  436. stdout_fd=1;
  437. startclient(argn, argc, argv, fd, &stdin_fd, &stdout_fd);
  438. docopy(ssl, fd, stdin_fd, stdout_fd);
  439. tls_disconnect(ssl, fd);
  440. close(fd);
  441. tls_destroy(ctx);
  442. return (0);
  443. }
  444. struct protoreadbuf {
  445. char buffer[512];
  446. char *bufptr;
  447. int bufleft;
  448. char line[256];
  449. } ;
  450. #define PRB_INIT(p) ( (p)->bufptr=0, (p)->bufleft=0)
  451. static char protoread(int fd, struct protoreadbuf *prb)
  452. {
  453. fd_set fds;
  454. struct timeval tv;
  455. FD_ZERO(&fds);
  456. FD_SET(fd, &fds);
  457. tv.tv_sec=60;
  458. tv.tv_usec=0;
  459. if (select(fd+1, &fds, NULL, NULL, &tv) <= 0)
  460. {
  461. nonsslerror("select");
  462. exit(1);
  463. }
  464. if ( (prb->bufleft=read(fd, prb->buffer, sizeof(prb->buffer))) <= 0)
  465. {
  466. errno=ECONNRESET;
  467. nonsslerror("read");
  468. exit(1);
  469. }
  470. prb->bufptr= prb->buffer;
  471. --prb->bufleft;
  472. return (*prb->bufptr++);
  473. }
  474. #define PRB_GETCH(fd,prb) ( (prb)->bufleft-- > 0 ? *(prb)->bufptr++:\
  475. protoread( (fd), (prb)))
  476. static const char *prb_getline(int fd, struct protoreadbuf *prb)
  477. {
  478. int i=0;
  479. char c;
  480. while ((c=PRB_GETCH(fd, prb)) != '\n')
  481. {
  482. if ( i < sizeof (prb->line)-1)
  483. prb->line[i++]=c;
  484. }
  485. prb->line[i]=0;
  486. return (prb->line);
  487. }
  488. static void prb_write(int fd, struct protoreadbuf *prb, const char *p)
  489. {
  490. printf("%s", p);
  491. while (*p)
  492. {
  493. int l=write(fd, p, strlen(p));
  494. if (l <= 0)
  495. {
  496. nonsslerror("write");
  497. exit(1);
  498. }
  499. p += l;
  500. }
  501. }
  502. static int goodimap(const char *p)
  503. {
  504. if (*p == 'x' && p[1] && isspace((int)(unsigned char)p[1]))
  505. ++p;
  506. else
  507. {
  508. if (*p != '*')
  509. return (0);
  510. ++p;
  511. }
  512. while (*p && isspace((int)(unsigned char)*p))
  513. ++p;
  514. if (strncasecmp(p, "BAD", 3) == 0)
  515. {
  516. exit(1);
  517. }
  518. if (strncasecmp(p, "BYE", 3) == 0)
  519. {
  520. exit(1);
  521. }
  522. if (strncasecmp(p, "NO", 2) == 0)
  523. {
  524. exit(1);
  525. }
  526. return (strncasecmp(p, "OK", 2) == 0);
  527. }
  528. static void imap_proto(int fd)
  529. {
  530. struct protoreadbuf prb;
  531. const char *p;
  532. PRB_INIT(&prb);
  533. do
  534. {
  535. p=prb_getline(fd, &prb);
  536. printf("%s\n", p);
  537. } while (!goodimap(p));
  538. prb_write(fd, &prb, "x STARTTLS\r\n");
  539. do
  540. {
  541. p=prb_getline(fd, &prb);
  542. printf("%s\n", p);
  543. } while (!goodimap(p));
  544. }
  545. static void pop3_proto(int fd)
  546. {
  547. struct protoreadbuf prb;
  548. const char *p;
  549. PRB_INIT(&prb);
  550. p=prb_getline(fd, &prb);
  551. printf("%s\n", p);
  552. prb_write(fd, &prb, "STLS\r\n");
  553. p=prb_getline(fd, &prb);
  554. printf("%s\n", p);
  555. }
  556. static void smtp_proto(int fd)
  557. {
  558. struct protoreadbuf prb;
  559. const char *p;
  560. char hostname[1024];
  561. PRB_INIT(&prb);
  562. do
  563. {
  564. p=prb_getline(fd, &prb);
  565. printf("%s\n", p);
  566. } while ( ! ( isdigit((int)(unsigned char)p[0]) &&
  567. isdigit((int)(unsigned char)p[1]) &&
  568. isdigit((int)(unsigned char)p[2]) &&
  569. (p[3] == 0 || isspace((int)(unsigned char)p[3]))));
  570. if (strchr("123", *p) == 0)
  571. exit(1);
  572. hostname[sizeof(hostname)-1]=0;
  573. if (gethostname(hostname, sizeof(hostname)-1) < 0)
  574. strcpy(hostname, "localhost");
  575. prb_write(fd, &prb, "EHLO ");
  576. prb_write(fd, &prb, hostname);
  577. prb_write(fd, &prb, "\r\n");
  578. do
  579. {
  580. p=prb_getline(fd, &prb);
  581. printf("%s\n", p);
  582. } while ( ! ( isdigit((int)(unsigned char)p[0]) &&
  583. isdigit((int)(unsigned char)p[1]) &&
  584. isdigit((int)(unsigned char)p[2]) &&
  585. (p[3] == 0 || isspace((int)(unsigned char)p[3]))));
  586. if (strchr("123", *p) == 0)
  587. exit(1);
  588. prb_write(fd, &prb, "STARTTLS\r\n");
  589. do
  590. {
  591. p=prb_getline(fd, &prb);
  592. printf("%s\n", p);
  593. } while ( ! ( isdigit((int)(unsigned char)p[0]) &&
  594. isdigit((int)(unsigned char)p[1]) &&
  595. isdigit((int)(unsigned char)p[2]) &&
  596. (p[3] == 0 || isspace((int)(unsigned char)p[3]))));
  597. if (strchr("123", *p) == 0)
  598. exit(1);
  599. }
  600. int main(int argc, char **argv)
  601. {
  602. int argn;
  603. int fd;
  604. static struct args arginfo[] = {
  605. { "host", &clienthost },
  606. { "localfd", &localfd},
  607. { "port", &clientport },
  608. { "printx509", &printx509},
  609. { "remotefd", &remotefd},
  610. { "server", &server},
  611. { "tcpd", &tcpd},
  612. { "verify", &peer_verify_domain},
  613. { "statusfd", &statusfd},
  614. { "protocol", &fdprotocol},
  615. {0}};
  616. void (*protocol_func)(int)=0;
  617. setlocale(LC_ALL, "");
  618. errfp=stderr;
  619. argn=argparse(argc, argv, arginfo);
  620. if (statusfd)
  621. statusfp=fdopen(atoi(statusfd), "w");
  622. if (statusfp)
  623. errfp=statusfp;
  624. if (fdprotocol)
  625. {
  626. if (strcmp(fdprotocol, "smtp") == 0)
  627. protocol_func= &smtp_proto;
  628. else if (strcmp(fdprotocol, "imap") == 0)
  629. protocol_func= &imap_proto;
  630. else if (strcmp(fdprotocol, "pop3") == 0)
  631. protocol_func= &pop3_proto;
  632. else
  633. {
  634. fprintf(stderr, "--protocol=%s - unknown protocol.\n",
  635. fdprotocol);
  636. exit(1);
  637. }
  638. }
  639. if (tcpd)
  640. {
  641. dup2(2, 1);
  642. fd=0;
  643. }
  644. else if (remotefd)
  645. fd=atoi(remotefd);
  646. else if (clienthost && clientport)
  647. fd=connectremote(clienthost, clientport);
  648. else
  649. {
  650. fprintf(errfp, "%s: specify remote location.\n",
  651. argv[0]);
  652. return (1);
  653. }
  654. if (fd < 0) return (1);
  655. if (protocol_func)
  656. (*protocol_func)(fd);
  657. return (dossl(fd, argn, argc, argv));
  658. }