mirror of
				https://gitlab.alpinelinux.org/alpine/aports.git
				synced 2025-10-26 05:51:40 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			821 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			821 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| diff -Naur maildrop-2.3.0/maildrop/dovecotauth.c maildrop-2.3.0-dovecotauth/maildrop/dovecotauth.c
 | |
| --- maildrop-2.3.0/maildrop/dovecotauth.c	1970-01-01 01:00:00.000000000 +0100
 | |
| +++ maildrop-2.3.0-dovecotauth/maildrop/dovecotauth.c	2010-01-31 15:01:38.000000000 +0100
 | |
| @@ -0,0 +1,480 @@
 | |
| +/*
 | |
| +** Copyright 2009 Marko Njezic
 | |
| +** Licensed under the same terms as Courier Authlib AND/OR Courier Maildrop.
 | |
| +**
 | |
| +** Partially based on authdaemonlib.c from Courier Authlib, which had the following statement:
 | |
| +**
 | |
| +** Copyright 2000-2006 Double Precision, Inc.  See COPYING for
 | |
| +** distribution information.
 | |
| +**
 | |
| +** Code that was taken from authdaemonlib.c is as follows:
 | |
| +**  - s_connect() function
 | |
| +**  - opensock() function with modification to accept socket address
 | |
| +**  - writeauth() function
 | |
| +**  - readline() function with related support functions (with modification 
 | |
| +**    to time-out after TIMEOUT_READ seconds)
 | |
| +*/
 | |
| +
 | |
| +#include	"dovecotauth.h"
 | |
| +#include	<stdio.h>
 | |
| +#include	<stdlib.h>
 | |
| +#include	<string.h>
 | |
| +#include	<errno.h>
 | |
| +#include	<fcntl.h>
 | |
| +#include	<pwd.h>
 | |
| +#include	<time.h>
 | |
| +#include	<unistd.h>
 | |
| +#include	<sys/types.h>
 | |
| +#include	<sys/socket.h>
 | |
| +#include	<sys/un.h>
 | |
| +#include	<sys/select.h>
 | |
| +
 | |
| +static const char rcsid[]="$Id$";
 | |
| +
 | |
| +static int TIMEOUT_SOCK=10,
 | |
| +	TIMEOUT_WRITE=10,
 | |
| +	TIMEOUT_READ=30; 
 | |
| +
 | |
| +static int s_connect(int sockfd,
 | |
| +		     const struct sockaddr *addr,
 | |
| +		     size_t addr_s,
 | |
| +		     time_t connect_timeout)
 | |
| +{
 | |
| +	fd_set fdr;
 | |
| +	struct timeval tv;
 | |
| +	int	rc;
 | |
| +
 | |
| +#ifdef SOL_KEEPALIVE
 | |
| +	setsockopt(sockfd, SOL_SOCKET, SOL_KEEPALIVE,
 | |
| +		   (const char *)&dummy, sizeof(dummy));
 | |
| +#endif
 | |
| +
 | |
| +#ifdef  SOL_LINGER
 | |
| +        {
 | |
| +		struct linger l;
 | |
| +
 | |
| +                l.l_onoff=0;
 | |
| +                l.l_linger=0;
 | |
| +
 | |
| +                setsockopt(sockfd, SOL_SOCKET, SOL_LINGER,
 | |
| +			   (const char *)&l, sizeof(l));
 | |
| +        }
 | |
| +#endif
 | |
| +
 | |
| +        /*
 | |
| +        ** If configuration says to use the kernel's timeout settings,
 | |
| +        ** just call connect, and be done with it.
 | |
| +        */
 | |
| +
 | |
| +        if (connect_timeout == 0)
 | |
| +                return ( connect(sockfd, addr, addr_s));
 | |
| +
 | |
| +        /* Asynchronous connect with timeout. */
 | |
| +
 | |
| +        if (fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0)     return (-1);
 | |
| +
 | |
| +        if ( connect(sockfd, addr, addr_s) == 0)
 | |
| +        {
 | |
| +                /* That was easy, we're done. */
 | |
| +
 | |
| +                if (fcntl(sockfd, F_SETFL, 0) < 0)      return (-1);
 | |
| +                return (0);
 | |
| +        }
 | |
| +
 | |
| +	if (errno != EINPROGRESS)
 | |
| +		return -1;
 | |
| +
 | |
| +	/* Wait for the connection to go through, until the timeout expires */
 | |
| +
 | |
| +        FD_ZERO(&fdr);
 | |
| +        FD_SET(sockfd, &fdr);
 | |
| +        tv.tv_sec=connect_timeout;
 | |
| +        tv.tv_usec=0;
 | |
| +
 | |
| +        rc=select(sockfd+1, 0, &fdr, 0, &tv);
 | |
| +        if (rc < 0)     return (-1);
 | |
| +
 | |
| +        if (!FD_ISSET(sockfd, &fdr))
 | |
| +        {
 | |
| +                errno=ETIMEDOUT;
 | |
| +                return (-1);
 | |
| +        }
 | |
| +
 | |
| +	{
 | |
| +		int     gserr;
 | |
| +		socklen_t gslen = sizeof(gserr);
 | |
| +
 | |
| +		if (getsockopt(sockfd, SOL_SOCKET,
 | |
| +			       SO_ERROR,
 | |
| +			       (char *)&gserr, &gslen)==0)
 | |
| +		{
 | |
| +			if (gserr == 0)
 | |
| +				return 0;
 | |
| +
 | |
| +			errno=gserr;
 | |
| +		}
 | |
| +	}
 | |
| +	return (-1);
 | |
| +}
 | |
| +
 | |
| +static int opensock(const char *addr)
 | |
| +{
 | |
| +	int	s=socket(PF_UNIX, SOCK_STREAM, 0);
 | |
| +	struct  sockaddr_un skun;
 | |
| +
 | |
| +	skun.sun_family=AF_UNIX;
 | |
| +	strncpy(skun.sun_path, addr, sizeof(skun.sun_path));
 | |
| +
 | |
| +	if (s < 0)
 | |
| +	{
 | |
| +		perror("CRIT: dovecotauth: socket() failed");
 | |
| +		return (-1);
 | |
| +	}
 | |
| +
 | |
| +	{
 | |
| +		const char *p=getenv("TIMEOUT_SOCK");
 | |
| +		int n=atoi(p ? p:"0");
 | |
| +
 | |
| +		if (n > 0)
 | |
| +			TIMEOUT_SOCK=n;
 | |
| +	}
 | |
| +
 | |
| +	{
 | |
| +		const char *p=getenv("TIMEOUT_READ");
 | |
| +		int n=atoi(p ? p:"0");
 | |
| +
 | |
| +		if (n > 0)
 | |
| +			TIMEOUT_READ=n;
 | |
| +	}
 | |
| +
 | |
| +	{
 | |
| +		const char *p=getenv("TIMEOUT_WRITE");
 | |
| +		int n=atoi(p ? p:"0");
 | |
| +
 | |
| +		if (n > 0)
 | |
| +			TIMEOUT_WRITE=n;
 | |
| +	}
 | |
| +
 | |
| +	if (s_connect(s, (const struct sockaddr *)&skun, sizeof(skun),
 | |
| +		      TIMEOUT_SOCK))
 | |
| +	{
 | |
| +		perror("ERR: dovecotauth: s_connect() failed");
 | |
| +		if (errno == ETIMEDOUT || errno == ECONNREFUSED)
 | |
| +			fprintf(stderr, "ERR: [Hint: perhaps dovecot-auth daemon is not running?]\n");
 | |
| +		close(s);
 | |
| +		return (-1);
 | |
| +	}
 | |
| +	return (s);
 | |
| +}
 | |
| +
 | |
| +static int writeauth(int fd, const char *p, unsigned pl)
 | |
| +{
 | |
| +fd_set  fds;
 | |
| +struct  timeval tv;
 | |
| +
 | |
| +	while (pl)
 | |
| +	{
 | |
| +	int     n;
 | |
| +
 | |
| +		FD_ZERO(&fds);
 | |
| +		FD_SET(fd, &fds);
 | |
| +		tv.tv_sec=TIMEOUT_WRITE;
 | |
| +		tv.tv_usec=0;
 | |
| +		if (select(fd+1, 0, &fds, 0, &tv) <= 0 || !FD_ISSET(fd, &fds))
 | |
| +			return (-1);
 | |
| +		n=write(fd, p, pl);
 | |
| +		if (n <= 0)     return (-1);
 | |
| +		p += n;
 | |
| +		pl -= n;
 | |
| +	}
 | |
| +	return (0);
 | |
| +}
 | |
| +
 | |
| +struct enum_getch {
 | |
| +	char buffer[BUFSIZ];
 | |
| +	char *buf_ptr;
 | |
| +	size_t buf_left;
 | |
| +};
 | |
| +
 | |
| +#define getauthc(fd,eg) ((eg)->buf_left-- ? \
 | |
| +			(unsigned char)*((eg)->buf_ptr)++:\
 | |
| +			fillgetauthc((fd),(eg)))
 | |
| +
 | |
| +static int fillgetauthc(int fd, struct enum_getch *eg)
 | |
| +{
 | |
| +	time_t	end_time, curtime;
 | |
| +
 | |
| +	time(&end_time);
 | |
| +	end_time += TIMEOUT_READ;
 | |
| +
 | |
| +	for (;;)
 | |
| +	{
 | |
| +		int     n;
 | |
| +		fd_set  fds;
 | |
| +		struct  timeval tv;
 | |
| +
 | |
| +		time(&curtime);
 | |
| +		if (curtime >= end_time)
 | |
| +			break;
 | |
| +
 | |
| +		FD_ZERO(&fds);
 | |
| +		FD_SET(fd, &fds);
 | |
| +		tv.tv_sec=end_time - curtime;
 | |
| +		tv.tv_usec=0;
 | |
| +		if (select(fd+1, &fds, 0, 0, &tv) <= 0 || !FD_ISSET(fd, &fds))
 | |
| +			break;
 | |
| +
 | |
| +		n=read(fd, eg->buffer, sizeof(eg->buffer));
 | |
| +		if (n <= 0)
 | |
| +			break;
 | |
| +
 | |
| +		eg->buf_ptr=eg->buffer;
 | |
| +		eg->buf_left=n;
 | |
| +
 | |
| +		--eg->buf_left;
 | |
| +		return (unsigned char)*(eg->buf_ptr)++;
 | |
| +	}
 | |
| +	return EOF;
 | |
| +}
 | |
| +
 | |
| +static int readline(int fd, struct enum_getch *eg,
 | |
| +		    char *buf,
 | |
| +		    size_t bufsize)
 | |
| +{
 | |
| +	if (bufsize == 0)
 | |
| +		return EOF;
 | |
| +
 | |
| +	while (--bufsize)
 | |
| +	{
 | |
| +		int ch=getauthc(fd, eg);
 | |
| +
 | |
| +		if (ch == EOF)
 | |
| +			return -1;
 | |
| +		if (ch == '\n')
 | |
| +			break;
 | |
| +
 | |
| +		*buf++=ch;
 | |
| +	}
 | |
| +	*buf=0;
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +/*
 | |
| +** The actual implementation of Dovecot authentication protocol handling follows.
 | |
| +** Full specification of the protocol can be found at: http://wiki.dovecot.org/Authentication%20Protocol
 | |
| +** We are only interested in the "master" type requests for user information.
 | |
| +*/
 | |
| +
 | |
| +int parse_userinfo(const char *user, const char *linebuf,
 | |
| +	int (*func)(struct dovecotauthinfo *, void *), void *arg)
 | |
| +{
 | |
| +	int return_value=1;
 | |
| +	struct dovecotauthinfo a;
 | |
| +	char *buf, *p;
 | |
| +	uid_t u;
 | |
| +
 | |
| +	/* Validate input arguments */
 | |
| +	if (!user || !linebuf)
 | |
| +		return (1);
 | |
| +
 | |
| +	/* Try to allocate buffer */
 | |
| +	buf = (char *)malloc(strlen(linebuf)+1);
 | |
| +	if (!buf)
 | |
| +		return (1);
 | |
| +	strcpy(buf, linebuf);
 | |
| +
 | |
| +	memset(&a, 0, sizeof(a));
 | |
| +	a.homedir="";
 | |
| +
 | |
| +	p = strtok(buf, "\t");
 | |
| +	if (p)
 | |
| +		a.address=p;
 | |
| +	else
 | |
| +		a.address=user;
 | |
| +
 | |
| +	/* Parse any additional parameters */
 | |
| +	while ((p = strtok(0, "\t")) != 0)
 | |
| +	{
 | |
| +		if (strncmp(p, "uid=", 4) == 0)
 | |
| +		{
 | |
| +			u=atol(p+4);
 | |
| +			a.sysuserid = &u;
 | |
| +			if (u == 0)
 | |
| +			{
 | |
| +				fprintf(stderr, "ERR: dovecotauth: Received invalid uid from auth socket\n");
 | |
| +				return_value=1;
 | |
| +				goto cleanup_parse_userinfo;
 | |
| +			}
 | |
| +		}
 | |
| +		else if (strncmp(p, "gid=", 4) == 0)
 | |
| +		{
 | |
| +			a.sysgroupid=atol(p+4);
 | |
| +			if (a.sysgroupid == 0)
 | |
| +			{
 | |
| +				fprintf(stderr, "ERR: dovecotauth: Received invalid gid from auth socket\n");
 | |
| +				return_value=1;
 | |
| +				goto cleanup_parse_userinfo;
 | |
| +			}
 | |
| +		}
 | |
| +		else if (strncmp(p, "system_user=", 12) == 0)
 | |
| +		{
 | |
| +			a.sysusername=p+12;
 | |
| +			if (a.sysusername)
 | |
| +			{
 | |
| +				struct passwd *q=getpwnam(a.sysusername);
 | |
| +
 | |
| +				if (q && q->pw_uid == 0)
 | |
| +				{
 | |
| +					fprintf(stderr, "ERR: dovecotauth: Received invalid system user from auth socket\n");
 | |
| +					return_value=1;
 | |
| +					goto cleanup_parse_userinfo;
 | |
| +				}
 | |
| +			}
 | |
| +		}
 | |
| +		else if (strncmp(p, "home=", 5) == 0)
 | |
| +		{
 | |
| +			a.homedir=p+5;
 | |
| +		}
 | |
| +		else if (strncmp(p, "mail=", 5) == 0)
 | |
| +		{
 | |
| +			a.maildir=p+5;
 | |
| +		}
 | |
| +	}
 | |
| +
 | |
| +	return_value = (*func)(&a, arg);
 | |
| +
 | |
| +cleanup_parse_userinfo:
 | |
| +	free(buf);
 | |
| +	return return_value;
 | |
| +}
 | |
| +
 | |
| +#define	DOVECOTAUTH_LINEBUFSIZE	8192
 | |
| +
 | |
| +int _dovecotauth_getuserinfo(int wrfd, int rdfd, const char *user,
 | |
| +	int (*func)(struct dovecotauthinfo *, void *), void *arg)
 | |
| +{
 | |
| +	static char cmdpart1[]="VERSION\t1\t0\nUSER\t1\t";
 | |
| +	static char cmdpart2[]="\tservice=maildrop\n";
 | |
| +	int return_value=1, handshake=0;
 | |
| +	struct enum_getch eg;
 | |
| +	char *cmdbuf, *linebuf;
 | |
| +
 | |
| +	/* Validate input arguments */
 | |
| +	if (!user)
 | |
| +		return (1);
 | |
| +
 | |
| +	/* Try to allocate buffers */
 | |
| +	cmdbuf=(char *)malloc(strlen(cmdpart1)+strlen(cmdpart2)+strlen(user)+20);
 | |
| +	if (!cmdbuf)
 | |
| +		return (1);
 | |
| +
 | |
| +	linebuf=(char *)malloc(DOVECOTAUTH_LINEBUFSIZE);
 | |
| +	if (!linebuf)
 | |
| +		return (1);
 | |
| +
 | |
| +	/* Initial handshake */
 | |
| +	eg.buf_left=0;
 | |
| +	while (readline(rdfd, &eg, linebuf, DOVECOTAUTH_LINEBUFSIZE) == 0)
 | |
| +	{
 | |
| +		if (strncmp(linebuf, "VERSION\t", 8) == 0)
 | |
| +		{
 | |
| +			if (strncmp(linebuf+8, "1\t", 2) != 0)
 | |
| +			{
 | |
| +				fprintf(stderr, "ERR: dovecotauth: Authentication protocol version mismatch\n");
 | |
| +				return_value=1;
 | |
| +				goto cleanup_dovecotauth_getuserinfo;
 | |
| +			}
 | |
| +		}
 | |
| +		else if (strncmp(linebuf, "SPID\t", 5) == 0)
 | |
| +		{
 | |
| +			/* End of server side handshake */
 | |
| +			handshake=1;
 | |
| +			break;
 | |
| +		}
 | |
| +	}
 | |
| +
 | |
| +	if (!handshake)
 | |
| +	{
 | |
| +		fprintf(stderr, "ERR: dovecotauth: Did not receive proper server handshake from auth socket\n");
 | |
| +		return_value=1;
 | |
| +		goto cleanup_dovecotauth_getuserinfo;
 | |
| +	}
 | |
| +
 | |
| +	/*
 | |
| +	** Try to be helpful in case that user tries to connect to the wrong auth socket.
 | |
| +	** There's a slight chance that this won't execute in case that the previously 
 | |
| +	** returned line ends exactly at the buffer end, but we won't handle that case,
 | |
| +	** since this is just a hint to the user, and not really neccessary.
 | |
| +	** Normally, if user tries to communicate with wrong auth socket, 
 | |
| +	** we would simply time-out, while waiting for information.
 | |
| +	*/
 | |
| +	if (eg.buf_left > 0 && readline(rdfd, &eg, linebuf, DOVECOTAUTH_LINEBUFSIZE) == 0)
 | |
| +	{
 | |
| +		if (strncmp(linebuf, "CUID\t", 5) == 0)
 | |
| +		{
 | |
| +			fprintf(stderr, "ERR: dovecotauth: Trying to connect to what appears to be a client auth socket, instead of a master auth socket\n");
 | |
| +			return_value=1;
 | |
| +			goto cleanup_dovecotauth_getuserinfo;
 | |
| +		}
 | |
| +	}
 | |
| +
 | |
| +	/* Generate our part of communication */
 | |
| +	strcat(strcat(strcpy(cmdbuf, cmdpart1), user), cmdpart2);
 | |
| +
 | |
| +	/* Send our part of communication */
 | |
| +	if (writeauth(wrfd, cmdbuf, strlen(cmdbuf)))
 | |
| +	{
 | |
| +		return_value=1;
 | |
| +		goto cleanup_dovecotauth_getuserinfo;
 | |
| +	}
 | |
| +
 | |
| +	/* Parse returned information */
 | |
| +	eg.buf_left=0;
 | |
| +	if (readline(rdfd, &eg, linebuf, DOVECOTAUTH_LINEBUFSIZE) == 0)
 | |
| +	{
 | |
| +		if (strncmp(linebuf, "USER\t1\t", 7) == 0)
 | |
| +		{
 | |
| +			/* User was found in the database and we now parse returned information */
 | |
| +			return_value=parse_userinfo(user, linebuf+7, func, arg);
 | |
| +			goto cleanup_dovecotauth_getuserinfo;
 | |
| +		}
 | |
| +		else if (strcmp(linebuf, "NOTFOUND\t1") == 0)
 | |
| +		{
 | |
| +			/* User was not found in the database */
 | |
| +			return_value=-1; /* Negative return value means that user is not found! */
 | |
| +			goto cleanup_dovecotauth_getuserinfo;
 | |
| +		}
 | |
| +		else if (strncmp(linebuf, "FAIL\t1", 6) == 0)
 | |
| +		{
 | |
| +			/* An internal error has occurred on Dovecot's end */
 | |
| +			return_value=1;
 | |
| +			goto cleanup_dovecotauth_getuserinfo;
 | |
| +		}
 | |
| +		else
 | |
| +		{
 | |
| +			fprintf(stderr, "ERR: dovecotauth: Received unknown input from auth socket\n");
 | |
| +		}
 | |
| +	}
 | |
| +	else
 | |
| +		fprintf(stderr, "ERR: dovecotauth: Did not receive proper input from auth socket\n");
 | |
| +
 | |
| +cleanup_dovecotauth_getuserinfo:
 | |
| +	free(cmdbuf);
 | |
| +	free(linebuf);
 | |
| +	return return_value;
 | |
| +}
 | |
| +
 | |
| +int dovecotauth_getuserinfo(const char *addr, const char *user,
 | |
| +	int (*func)(struct dovecotauthinfo *, void *), void *arg)
 | |
| +{
 | |
| +	int	s=opensock(addr);
 | |
| +	int	rc;
 | |
| +
 | |
| +	if (s < 0)
 | |
| +	{
 | |
| +		return (1);
 | |
| +	}
 | |
| +	rc = _dovecotauth_getuserinfo(s, s, user, func, arg);
 | |
| +	close(s);
 | |
| +	return rc;
 | |
| +}
 | |
| diff -Naur maildrop-2.3.0/maildrop/dovecotauth.h maildrop-2.3.0-dovecotauth/maildrop/dovecotauth.h
 | |
| --- maildrop-2.3.0/maildrop/dovecotauth.h	1970-01-01 01:00:00.000000000 +0100
 | |
| +++ maildrop-2.3.0-dovecotauth/maildrop/dovecotauth.h	2010-01-31 15:01:38.000000000 +0100
 | |
| @@ -0,0 +1,59 @@
 | |
| +#ifndef	dovecotauth_h
 | |
| +#define	dovecotauth_h
 | |
| +
 | |
| +/*
 | |
| +** Copyright 2009 Marko Njezic
 | |
| +** Licensed under the same terms as Courier Authlib AND/OR Courier Maildrop.
 | |
| +**
 | |
| +** Partially based on courierauth.h from Courier Authlib, which had the following statement:
 | |
| +**
 | |
| +** Copyright 2004 Double Precision, Inc.  See COPYING for
 | |
| +** distribution information.
 | |
| +*/
 | |
| +
 | |
| +#include	<sys/types.h>
 | |
| +
 | |
| +#ifdef	__cplusplus
 | |
| +extern "C" {
 | |
| +#endif
 | |
| +
 | |
| +static const char dovecotauth_h_rcsid[]="$Id$";
 | |
| +
 | |
| +struct dovecotauthinfo {
 | |
| +	const char *address;
 | |
| +	const char *sysusername;
 | |
| +	const uid_t *sysuserid;
 | |
| +	gid_t sysgroupid;
 | |
| +	const char *homedir;
 | |
| +	const char *maildir;
 | |
| +	} ;
 | |
| +
 | |
| +/*
 | |
| +	This structure is modeled after authinfo structure from Courier Authlib.
 | |
| +
 | |
| +	Either sysusername or sysuserid may be NULL, but not both of them.
 | |
| +	They, and sysgroupid, specify the authenticated user's system
 | |
| +	userid and groupid.  homedir points to the authenticated user's
 | |
| +	home directory.  address and maildir, are obvious.
 | |
| +
 | |
| +	After populating this tructure, the lookup function calls the
 | |
| +	callback function that's specified in its second argument.  The
 | |
| +	callback function receives a pointer to the authinfo structure.
 | |
| +
 | |
| +	The callback function also receives a context pointer, which is
 | |
| +	the third argument to the lookup function.
 | |
| +
 | |
| +	The lookup function should return a negative value if the userid
 | |
| +	does not exist, a positive value if there was a temporary error
 | |
| +	looking up the userid, or whatever is the return code from the
 | |
| +	callback function, if the user exists.
 | |
| +*/
 | |
| +
 | |
| +int dovecotauth_getuserinfo(const char *addr, const char *user,
 | |
| +	int (*func)(struct dovecotauthinfo *, void *), void *arg);
 | |
| +
 | |
| +#ifdef	__cplusplus
 | |
| +}
 | |
| +#endif
 | |
| +
 | |
| +#endif
 | |
| diff -Naur maildrop-2.3.0/maildrop/main.C maildrop-2.3.0-dovecotauth/maildrop/main.C
 | |
| --- maildrop-2.3.0/maildrop/main.C	2009-09-06 01:12:45.000000000 +0200
 | |
| +++ maildrop-2.3.0-dovecotauth/maildrop/main.C	2010-01-31 15:11:08.000000000 +0100
 | |
| @@ -32,6 +32,16 @@
 | |
|  #include	<pwd.h>
 | |
|  #include	<grp.h>
 | |
|  #include	"../dbobj.h"
 | |
| +
 | |
| +/*
 | |
| +** This switch can later be moved to config.h file with appropriate 
 | |
| +** configure option like --with-dovecotauth or something similar
 | |
| +*/
 | |
| +#define	DOVECOTAUTH	1
 | |
| +#if DOVECOTAUTH
 | |
| +#include	"dovecotauth.h"
 | |
| +#endif
 | |
| +
 | |
|  #if AUTHLIB
 | |
|  #include	<courierauth.h>
 | |
|  #endif
 | |
| @@ -171,6 +181,14 @@
 | |
|  	"\n"
 | |
|  #endif
 | |
|  #endif
 | |
| +#if DOVECOTAUTH
 | |
| +	"Dovecot Authentication extension enabled."
 | |
| +#if CRLF_TERM
 | |
| +	"\r\n"
 | |
| +#else
 | |
| +	"\n"
 | |
| +#endif
 | |
| +#endif
 | |
|  #if AUTHLIB
 | |
|  	"Courier Authentication Library extension enabled."
 | |
|  #if CRLF_TERM
 | |
| @@ -337,6 +355,98 @@
 | |
|  }
 | |
|  #endif
 | |
|  
 | |
| +#if DOVECOTAUTH
 | |
| +static int callback_dovecotauth(struct dovecotauthinfo *auth,
 | |
| +			    void *void_arg)
 | |
| +{
 | |
| +	Maildrop &maildrop=*(Maildrop *)void_arg;
 | |
| +
 | |
| +	if (VerboseLevel() > 1)
 | |
| +	{
 | |
| +		Buffer b;
 | |
| +
 | |
| +		b.set(auth->sysgroupid);
 | |
| +		b.push(0);
 | |
| +
 | |
| +		merr << "maildrop: dovecotauth: groupid="
 | |
| +		     << b << "\n";
 | |
| +	}
 | |
| +
 | |
| +	setgroupid(auth->sysgroupid);
 | |
| +
 | |
| +	uid_t u;
 | |
| +	if (auth->sysusername)
 | |
| +	{
 | |
| +		struct	passwd *q=getpwnam(auth->sysusername);
 | |
| +
 | |
| +		if (q == NULL)
 | |
| +		{
 | |
| +			merr << "Cannot find system user "
 | |
| +			     << auth->sysusername
 | |
| +			     << "\n";
 | |
| +
 | |
| +			nochangeuidgid();
 | |
| +		}
 | |
| +
 | |
| +		u=q->pw_uid;
 | |
| +	}
 | |
| +	else
 | |
| +		u=*auth->sysuserid;
 | |
| +
 | |
| +	if (VerboseLevel() > 1)
 | |
| +	{
 | |
| +		Buffer b;
 | |
| +
 | |
| +		b.set(u);
 | |
| +		b.push(0);
 | |
| +
 | |
| +		merr << "maildrop: dovecotauth: userid="
 | |
| +		     << b << "\n";
 | |
| +	}
 | |
| +
 | |
| +	setuid(u);
 | |
| +
 | |
| +	if ( getuid() != u)
 | |
| +		nochangeuidgid();
 | |
| +
 | |
| +	if (VerboseLevel() > 1)
 | |
| +	{
 | |
| +		merr << "maildrop: dovecotauth: logname="
 | |
| +		     << auth->address
 | |
| +		     << ", home="
 | |
| +		     << auth->homedir
 | |
| +		     << ", mail="
 | |
| +		     << (auth->maildir ? auth->maildir:"(default)")
 | |
| +		     << "\n";
 | |
| +	}
 | |
| +
 | |
| +	maildrop.init_home=auth->homedir;
 | |
| +	maildrop.init_logname=auth->address;
 | |
| +	maildrop.init_shell="/bin/sh";
 | |
| +	maildrop.init_default=auth->maildir ? auth->maildir:
 | |
| +		GetDefaultMailbox(auth->address);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +int find_in_dovecotauth(const char *addr, Maildrop *maildrop, const char* user)
 | |
| +{
 | |
| +	int rc=dovecotauth_getuserinfo(addr,
 | |
| +				user, callback_dovecotauth, maildrop);
 | |
| +
 | |
| +	if (rc == 0)
 | |
| +		return 1;
 | |
| +
 | |
| +	if (rc > 0)
 | |
| +	{
 | |
| +		errexit=EX_TEMPFAIL;
 | |
| +		throw "Temporary authentication failure.";
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +#endif
 | |
| +
 | |
|  static void tempfail(const char *msg)
 | |
|  {
 | |
|  	errexit = EX_TEMPFAIL;
 | |
| @@ -361,6 +471,9 @@
 | |
|  const	char *numuidgid=0;
 | |
|  #endif
 | |
|  #endif
 | |
| +#if DOVECOTAUTH
 | |
| +const	char *dovecotauth_addr=0;
 | |
| +#endif
 | |
|  
 | |
|  
 | |
|  	umask( 0007 );
 | |
| @@ -446,6 +559,18 @@
 | |
|  		case 'a':
 | |
|  			maildrop.authlib_essential=1;
 | |
|  			break;
 | |
| +#if DOVECOTAUTH
 | |
| +		case 't':
 | |
| +			if (!*optarg && argn < argc)	optarg=argv[argn++];
 | |
| +			if (!*optarg)
 | |
| +			{
 | |
| +				mout << "You didn't specify the location of Dovecot auth socket.\n";
 | |
| +				return (EX_TEMPFAIL);
 | |
| +			}
 | |
| +			else
 | |
| +				dovecotauth_addr=optarg;
 | |
| +			break;
 | |
| +#endif
 | |
|  		case 'h':
 | |
|  			help();
 | |
|  			return (EX_TEMPFAIL);
 | |
| @@ -467,7 +592,17 @@
 | |
|  
 | |
|  		if (*deliverymode)
 | |
|  		{
 | |
| -			found = find_in_authlib(&maildrop, deliverymode);
 | |
| +
 | |
| +#if DOVECOTAUTH
 | |
| +			if (dovecotauth_addr)
 | |
| +			{
 | |
| +				found = find_in_dovecotauth(dovecotauth_addr, &maildrop, deliverymode);
 | |
| +			}
 | |
| +			else
 | |
| +#endif
 | |
| +			{
 | |
| +				found = find_in_authlib(&maildrop, deliverymode);
 | |
| +			}
 | |
|  
 | |
|  			if ( !found )
 | |
|  			{
 | |
| diff -Naur maildrop-2.3.0/maildrop/Makefile.am maildrop-2.3.0-dovecotauth/maildrop/Makefile.am
 | |
| --- maildrop-2.3.0/maildrop/Makefile.am	2009-11-14 23:16:32.000000000 +0100
 | |
| +++ maildrop-2.3.0-dovecotauth/maildrop/Makefile.am	2010-01-31 15:01:38.000000000 +0100
 | |
| @@ -46,7 +46,7 @@
 | |
|  	recipe.C recipe.h recipenode.C recipenode.h recipeparse.C reeval.C \
 | |
|  	reeval.h regexpnode.h rematch.C rematch.h rematchmsg.C rematchmsg.h \
 | |
|  	rematchstr.C rematchstr.h search.C search.h token.C \
 | |
| -	token.h varlist.C varlist.h
 | |
| +	token.h varlist.C varlist.h dovecotauth.c dovecotauth.h
 | |
|  
 | |
|  maildrop_DEPENDENCIES = libmdcommon.la ../maildir/maildir.libdeps
 | |
|  
 | |
| diff -Naur maildrop-2.3.0/maildrop/Makefile.in maildrop-2.3.0-dovecotauth/maildrop/Makefile.in
 | |
| --- maildrop-2.3.0/maildrop/Makefile.in	2009-12-25 23:14:47.000000000 +0100
 | |
| +++ maildrop-2.3.0-dovecotauth/maildrop/Makefile.in	2010-01-31 15:01:38.000000000 +0100
 | |
| @@ -88,7 +88,7 @@
 | |
|  	re.$(OBJEXT) recipe.$(OBJEXT) recipenode.$(OBJEXT) \
 | |
|  	recipeparse.$(OBJEXT) reeval.$(OBJEXT) rematch.$(OBJEXT) \
 | |
|  	rematchmsg.$(OBJEXT) rematchstr.$(OBJEXT) search.$(OBJEXT) \
 | |
| -	token.$(OBJEXT) varlist.$(OBJEXT)
 | |
| +	token.$(OBJEXT) varlist.$(OBJEXT) dovecotauth.$(OBJEXT)
 | |
|  maildrop_OBJECTS = $(am_maildrop_OBJECTS)
 | |
|  maildrop_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
 | |
|  	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
 | |
| @@ -308,7 +308,7 @@
 | |
|  	recipe.C recipe.h recipenode.C recipenode.h recipeparse.C reeval.C \
 | |
|  	reeval.h regexpnode.h rematch.C rematch.h rematchmsg.C rematchmsg.h \
 | |
|  	rematchstr.C rematchstr.h search.C search.h token.C \
 | |
| -	token.h varlist.C varlist.h
 | |
| +	token.h varlist.C varlist.h dovecotauth.c dovecotauth.h
 | |
|  
 | |
|  maildrop_DEPENDENCIES = libmdcommon.la ../maildir/maildir.libdeps
 | |
|  maildrop_LDADD = libmdcommon.la `cat ../maildir/maildir.libdeps`\
 | |
| @@ -471,6 +471,7 @@
 | |
|  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tempfile.Plo@am__quote@
 | |
|  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/token.Po@am__quote@
 | |
|  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/varlist.Po@am__quote@
 | |
| +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dovecotauth.Po@am__quote@
 | |
|  
 | |
|  .C.o:
 | |
|  @am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
 | |
| diff -Naur maildrop-2.3.0/README.dovecotauth maildrop-2.3.0-dovecotauth/README.dovecotauth
 | |
| --- maildrop-2.3.0/README.dovecotauth	1970-01-01 01:00:00.000000000 +0100
 | |
| +++ maildrop-2.3.0-dovecotauth/README.dovecotauth	2010-01-31 15:01:38.000000000 +0100
 | |
| @@ -0,0 +1,46 @@
 | |
| +Dovecot Authentication extension for maildrop
 | |
| +=============================================
 | |
| +** Copyright 2009 Marko Njezic
 | |
| +** Licensed under the same terms as Courier Authlib AND/OR Courier Maildrop.
 | |
| +
 | |
| +When you patch maildrop to include Dovecot Authentication extension, you'll be 
 | |
| +able to do user database lookups against Dovecot. This extension can happily 
 | |
| +coexist with Courier Authlib extension if it is also compiled.
 | |
| +
 | |
| +In order to use it you'll need to specify additional option "-t" that will point 
 | |
| +to the location of Dovecot's auth master socket when starting maildrop in 
 | |
| +delivery mode. For example:
 | |
| +
 | |
| +maildrop -d USER -t /var/run/dovecot/auth-master
 | |
| +
 | |
| +By specifying "-t" option, maildrop will first try user lookup against Dovecot's 
 | |
| +database. If user is not found, maildrop will fallback to local user database 
 | |
| +(i.e. passwd), as usual. Lookups against Courier Authlib will not be done when 
 | |
| +"-t" option is specified. If you want to perform such lookup when both 
 | |
| +extensions are compiled, simply remove "-t" option and maildrop will behave as 
 | |
| +usual.
 | |
| +
 | |
| +One significant difference compared to Courier Authlib extension is that Dovecot 
 | |
| +Authentication extension will never return uid/gid that's equal to zero. If such 
 | |
| +value was returned from database, maildrop will exit with temporary failure. 
 | |
| +This was done in order to prevent accidental mistakes. If you really want to 
 | |
| +deliver as/to root, you'll have to start maildrop without "-t" option and let 
 | |
| +it directly query system user database on its own.
 | |
| +
 | |
| +Make sure that correct permissions are set on Dovecot's auth master socket so 
 | |
| +that maildrop can communicate with it. Also, depending on what type of users are 
 | |
| +being served from Dovecot's database, if user lookup returns local user 
 | |
| +accounts, you may end up with problems when maildrop tries to write mails to the 
 | |
| +spool directory if wrong permission are set on it, since maildrop will reset its 
 | |
| +permissions (uid/gid) to the values returned from user database. This behavior 
 | |
| +is the same as the behavior of lookups against Courier Authlib, since they also 
 | |
| +reset maildrop's permissions. When you want maildrop to deliver to the local 
 | |
| +users, it's best to let it directly query system user database on its own, 
 | |
| +since then it can apply its own "RESET_GID" magic, which will hopefully result 
 | |
| +in "correct" permissions that will allow maildrop to write to the spool 
 | |
| +directory.
 | |
| +
 | |
| +And last but not least, I hope that you'll find this extension useful. 
 | |
| +Especially if you already have an existing user database in Dovecot, but would 
 | |
| +like to use maildrop (with its powerful "xfilter" command) to deliver e-mails, 
 | |
| +without setting up another authentication user database, like Courier Authlib.
 |