summaryrefslogtreecommitdiffstats
path: root/imap/pop3login.c
diff options
context:
space:
mode:
authorSam Varshavchik2013-08-19 16:39:41 -0400
committerSam Varshavchik2013-08-25 14:43:51 -0400
commit9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch)
tree7a81a04cb51efb078ee350859a64be2ebc6b8813 /imap/pop3login.c
parenta9520698b770168d1f33d6301463bb70a19655ec (diff)
downloadcourier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2
Initial checkin
Imported from subversion report, converted to git. Updated all paths in scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'imap/pop3login.c')
-rw-r--r--imap/pop3login.c529
1 files changed, 529 insertions, 0 deletions
diff --git a/imap/pop3login.c b/imap/pop3login.c
new file mode 100644
index 0000000..2c6e599
--- /dev/null
+++ b/imap/pop3login.c
@@ -0,0 +1,529 @@
+/*
+** Copyright 1998 - 2008 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#if HAVE_CONFIG_H
+#undef PACKAGE
+#undef VERSION
+#include "config.h"
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <ctype.h>
+#include <fcntl.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <netinet/in.h>
+#include <netdb.h>
+#include "waitlib/waitlib.h"
+#include "proxy.h"
+
+#include <courierauth.h>
+#include <courierauthdebug.h>
+#include <courierauthsasl.h>
+#include "tcpd/spipe.h"
+#include "numlib/numlib.h"
+#include "tcpd/tlsclient.h"
+
+
+extern void pop3dcapa();
+extern int have_starttls();
+extern int tls_required();
+extern const char *pop3_externalauth();
+
+static const char *pop3d;
+static const char *defaultmaildir;
+
+static int starttls()
+{
+ char *argvec[4];
+
+ char localfd_buf[NUMBUFSIZE+40];
+ char buf2[NUMBUFSIZE];
+ struct couriertls_info cinfo;
+ int pipefd[2];
+
+ if (libmail_streampipe(pipefd))
+ {
+ printf("-ERR libmail_streampipe() failed.\r\n");
+ return (-1);
+ }
+
+ couriertls_init(&cinfo);
+ fcntl(pipefd[0], F_SETFD, FD_CLOEXEC);
+
+ strcat(strcpy(localfd_buf, "-localfd="),
+ libmail_str_size_t(pipefd[1], buf2));
+
+ argvec[0]=localfd_buf;
+ argvec[1]="-tcpd";
+ argvec[2]="-server";
+ argvec[3]=NULL;
+
+ printf("+OK Begin SSL/TLS negotiation now.\r\n");
+ fflush(stdout);
+
+ if (couriertls_start(argvec, &cinfo))
+ {
+ close(pipefd[0]);
+ close(pipefd[1]);
+ printf("-ERR STARTTLS failed: %s\r\n",
+ cinfo.errmsg);
+ couriertls_destroy(&cinfo);
+ return (-1);
+ }
+
+ couriertls_export_subject_environment(&cinfo);
+ couriertls_destroy(&cinfo);
+
+ close(pipefd[1]);
+ close(0);
+ close(1);
+ if (dup(pipefd[0]) != 0 || dup(pipefd[0]) != 1)
+ {
+ perror("dup");
+ exit(1);
+ }
+ close(pipefd[0]);
+
+ putenv("POP3_STARTTLS=NO");
+ putenv("POP3_TLS_REQUIRED=0");
+ putenv("POP3_TLS=1");
+ return (0);
+}
+
+static char *authresp(const char *s, void *dummy)
+{
+char *p;
+char buf[BUFSIZ];
+
+ printf("+ %s\r\n", s);
+ fflush(stdout);
+
+ if (fgets(buf, sizeof(buf), stdin) == 0) return (0);
+ if ((p=strchr(buf, '\n')) == 0) return (0);
+ if (p > buf && p[-1] == '\r') --p;
+ *p=0;
+
+ p=strdup(buf);
+ if (!p)
+ {
+ perror("malloc");
+ return (0);
+ }
+ return (p);
+}
+
+struct pop3proxyinfo {
+ const char *uid;
+ const char *pwd;
+};
+
+static int login_pop3(int, const char *, void *);
+
+static int login_callback(struct authinfo *ainfo, void *dummy)
+{
+ int rc;
+ char *p;
+
+ p=getenv("POP3_PROXY");
+
+ if (p && atoi(p))
+ {
+ if (ainfo->options == NULL ||
+ (p=auth_getoption(ainfo->options,
+ "mailhost")) == NULL)
+ {
+ fprintf(stderr,"WARN: proxy enabled, but no proxy"
+ " host defined for %s\n",
+ ainfo->address);
+
+ /* Fallthru to account login */
+
+ }
+ else if (ainfo->clearpasswd == NULL)
+ {
+ free(p);
+ fprintf(stderr, "WARN: proxy enabled, but no password"
+ " for %s\n", ainfo->address);
+ return -1;
+ }
+ else
+ {
+ struct proxyinfo pi;
+ struct pop3proxyinfo ppi;
+ struct servent *se;
+ int fd;
+
+ se=getservbyname("pop3", NULL);
+
+ pi.host=p;
+ pi.port=se ? ntohs(se->s_port):110;
+
+ ppi.uid=ainfo->address;
+ ppi.pwd=ainfo->clearpasswd;
+
+ pi.connected_func=login_pop3;
+ pi.void_arg=&ppi;
+
+ if ((fd=connect_proxy(&pi)) < 0)
+ {
+ free(p);
+ return -1;
+ }
+ free(p);
+ if (fd > 0)
+ {
+ alarm(0);
+ proxyloop(fd);
+ exit(0);
+ }
+
+ /* FALLTHRU */
+ }
+ }
+
+ rc=auth_callback_default(ainfo);
+
+ if (rc == 0)
+ {
+ char *p=malloc(sizeof("OPTIONS=") + strlen(ainfo->options ?
+ ainfo->options:""));
+
+ if (p)
+ {
+ strcat(strcpy(p, "OPTIONS="),
+ ainfo->options ? ainfo->options:"");
+ putenv(p);
+
+ p=malloc(sizeof("AUTHENTICATED=")+
+ strlen(ainfo->address));
+ if (p)
+ {
+ strcat(strcpy(p, "AUTHENTICATED="),
+ ainfo->address);
+ putenv(p);
+
+ alarm(0);
+ execl(pop3d, pop3d,
+ ainfo->maildir ?
+ ainfo->maildir:defaultmaildir,
+ NULL);
+ fprintf(stderr, "ERR: exec(%s) failed!!\n",
+ pop3d);
+ }
+ }
+ }
+
+ return (rc);
+}
+
+int main(int argc, char **argv)
+{
+char *user=0;
+char *p;
+char buf[BUFSIZ];
+int c;
+const char *ip=getenv("TCPREMOTEIP");
+char authservice[40];
+char *q ;
+
+#ifdef HAVE_SETVBUF_IOLBF
+ setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
+#endif
+
+ if (!ip || !*ip)
+ {
+ ip="127.0.0.1";
+ }
+
+ if (argc != 3)
+ {
+ printf("-ERR pop3login requires exactly two arguments.\r\n");
+ fflush(stdout);
+ exit(1);
+ }
+
+ pop3d=argv[1];
+ defaultmaildir=argv[2];
+
+ courier_authdebug_login_init();
+
+ fprintf(stderr, "DEBUG: Connection, ip=[%s]\n", ip);
+ printf("+OK Hello there.\r\n");
+
+ fflush(stdout);
+ fflush(stderr);
+ alarm(60);
+ while (fgets(buf, sizeof(buf), stdin))
+ {
+ c=1;
+ for (p=buf; *p; p++)
+ {
+ if (*p == '\n')
+ break;
+
+ if (*p == ' ' || *p == '\t') c=0;
+ if (c)
+ *p=toupper((int)(unsigned char)*p);
+ }
+
+ if (*p)
+ *p=0;
+ else while ((c=getchar()) != EOF && c != '\n')
+ ;
+ p=strtok(buf, " \t\r");
+ if (p)
+ {
+ courier_authdebug_login( 1, "command=%s", p );
+
+ if ( strcmp(p, "QUIT") == 0)
+ {
+ fprintf(stderr, "INFO: LOGOUT, ip=[%s]\n",
+ ip);
+ fflush(stderr);
+ printf("+OK Better luck next time.\r\n");
+ fflush(stdout);
+ break;
+ }
+
+ if ( strcmp(p, "USER") == 0)
+ {
+ if (tls_required())
+ {
+ printf("-ERR TLS required to log in.\r\n");
+ fflush(stdout);
+ continue;
+ }
+
+ p=strtok(0, "\r\n");
+ if (p)
+ {
+ if (user) free(user);
+ if ((user=malloc(strlen(p)+1)) == 0)
+ {
+ printf("-ERR Server out of memory, aborting connection.\r\n");
+ fflush(stdout);
+ perror("malloc");
+ exit(1);
+ }
+ strcpy(user, p);
+ printf("+OK Password required.\r\n");
+ fflush(stdout);
+ continue;
+ }
+ } else if (strcmp(p, "CAPA") == 0)
+ {
+ pop3dcapa();
+ continue;
+ } else if (strcmp(p, "STLS") == 0)
+ {
+ if (!have_starttls())
+ {
+ printf("-ERR TLS support not available.\r\n");
+ fflush(stdout);
+ continue;
+ }
+ starttls();
+ fflush(stdout);
+ continue;
+ } else if (strcmp(p, "AUTH") == 0)
+ {
+ char *authtype, *authdata;
+ char *method=strtok(0, " \t\r");
+
+ if (tls_required())
+ {
+ printf("-ERR TLS required to log in.\r\n");
+ fflush(stdout);
+ continue;
+ }
+
+ if (method)
+ {
+ char *initreply=strtok(0, " \t\r");
+ int rc;
+ char *p;
+
+ for (p=method; *p; p++)
+ *p=toupper(*p);
+
+ if (initreply &&
+ strcmp(initreply, "=") == 0)
+ initreply="";
+
+ rc=auth_sasl_ex(method, initreply,
+ pop3_externalauth(),
+ authresp,
+ NULL,
+ &authtype,
+ &authdata);
+
+ if (rc == 0)
+ {
+ strcat(strcpy(authservice, "AUTHSERVICE"),getenv("TCPLOCALPORT"));
+ q=getenv(authservice);
+ if (!q || !*q)
+ q="pop3";
+
+ rc=auth_generic(q,
+ authtype,
+ authdata,
+ login_callback,
+ NULL);
+ free(authtype);
+ free(authdata);
+ }
+
+ courier_safe_printf("INFO: LOGIN "
+ "FAILED, method=%s, ip=[%s]",
+ method, ip);
+ if (rc == AUTHSASL_ABORTED)
+ printf("-ERR Authentication aborted.\r\n");
+ else if (rc > 0)
+ {
+ perror("ERR: authentication error");
+ printf("-ERR Temporary problem, please try again later\r\n");
+ fflush(stdout);
+ exit(1);
+ }
+ else
+ {
+ sleep(5);
+ printf("-ERR Authentication failed.\r\n");
+ }
+
+ fflush(stdout);
+ continue;
+ }
+ } else if (strcmp(p, "PASS") == 0)
+ {
+ int rc;
+
+ p=strtok(0, "\r\n");
+
+ if (!user || p == 0)
+ {
+ printf("-ERR USER/PASS required.\r\n");
+ fflush(stdout);
+ continue;
+ }
+
+ strcat(strcpy(authservice, "AUTHSERVICE"),getenv("TCPLOCALPORT"));
+ q=getenv(authservice);
+ if (!q || !*q)
+ q="pop3";
+
+ rc=auth_login(q, user, p, login_callback, NULL);
+ courier_safe_printf("INFO: LOGIN "
+ "FAILED, user=%s, ip=[%s]",
+ user, ip);
+ if (rc > 0)
+ {
+ perror("ERR: authentication error");
+ printf("-ERR Temporary problem, please try again later\r\n");
+ fflush(stdout);
+ exit(1);
+ }
+ sleep(5);
+ printf("-ERR Login failed.\r\n");
+ fflush(stdout);
+ continue;
+ }
+ }
+ printf("-ERR Invalid command.\r\n");
+ fflush(stdout);
+ }
+ fprintf(stderr, "DEBUG: Disconnected, ip=[%s]\n", ip);
+ exit(0);
+ return (0);
+}
+
+static int login_pop3(int fd, const char *hostname, void *void_arg)
+{
+ struct pop3proxyinfo *ppi=(struct pop3proxyinfo *)void_arg;
+ struct proxybuf pb;
+ char linebuf[256];
+ char *cmd;
+
+ DPRINTF("Proxy connected to %s", hostname);
+
+ memset(&pb, 0, sizeof(pb));
+
+ if (proxy_readline(fd, &pb, linebuf, sizeof(linebuf), 1) < 0)
+ return -1;
+
+ DPRINTF("%s: %s", hostname, linebuf);
+
+ if (linebuf[0] != '+')
+ {
+ fprintf(stderr, "WARN: Did not receive greeting from %s\n",
+ hostname);
+ return -1;
+ }
+
+ cmd=malloc(strlen(ppi->uid) + strlen(ppi->pwd)+100);
+ /* Should be enough */
+
+ if (!cmd)
+ return -1;
+
+ sprintf(cmd, "USER %s\r\n", ppi->uid);
+
+ if (proxy_write(fd, hostname, cmd, strlen(cmd)))
+ {
+ free(cmd);
+ return -1;
+ }
+
+ if (proxy_readline(fd, &pb, linebuf, sizeof(linebuf), 1) < 0)
+ {
+ free(cmd);
+ return -1;
+ }
+
+ DPRINTF("%s: %s", hostname, linebuf);
+
+ if (linebuf[0] != '+')
+ {
+ free(cmd);
+ fprintf(stderr, "WARN: Login userid rejected by %s\n",
+ hostname);
+ return -1;
+ }
+
+ sprintf(cmd, "PASS %s\r\n", ppi->pwd);
+
+ if (proxy_write(fd, hostname, cmd, strlen(cmd)))
+ {
+ free(cmd);
+ return -1;
+ }
+
+ if (proxy_readline(fd, &pb, linebuf, sizeof(linebuf), 1) < 0)
+ {
+ free(cmd);
+ return -1;
+ }
+
+ DPRINTF("%s: %s", hostname, linebuf);
+
+ if (linebuf[0] != '+')
+ {
+ free(cmd);
+ fprintf(stderr, "WARN: Login password rejected by %s\n",
+ hostname);
+ return -1;
+ }
+
+ free(cmd);
+ if (fcntl(1, F_SETFL, 0) < 0 ||
+ (printf("+OK Connected to proxy server.\r\n"), fflush(stdout)) < 0)
+ return -1;
+
+ return 0;
+}