diff options
| author | Sam Varshavchik | 2013-08-19 16:39:41 -0400 | 
|---|---|---|
| committer | Sam Varshavchik | 2013-08-25 14:43:51 -0400 | 
| commit | 9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch) | |
| tree | 7a81a04cb51efb078ee350859a64be2ebc6b8813 /imap/pop3login.c | |
| parent | a9520698b770168d1f33d6301463bb70a19655ec (diff) | |
| download | courier-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.c | 529 | 
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; +} | 
