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 /gpglib/mimegpgfork.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 'gpglib/mimegpgfork.c')
| -rw-r--r-- | gpglib/mimegpgfork.c | 449 | 
1 files changed, 449 insertions, 0 deletions
| diff --git a/gpglib/mimegpgfork.c b/gpglib/mimegpgfork.c new file mode 100644 index 0000000..d1b849c --- /dev/null +++ b/gpglib/mimegpgfork.c @@ -0,0 +1,449 @@ +/* +** Copyright 2001-2010 Double Precision, Inc.  See COPYING for +** distribution information. +*/ + + +#include "config.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <ctype.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include "gpg.h" + +#include <sys/types.h> +#if	HAVE_SYS_TIME_H +#include	<sys/time.h> +#endif +#if HAVE_SYS_WAIT_H +#include	<sys/wait.h> +#endif +#ifndef WEXITSTATUS +#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif +#ifndef WIFEXITED +#define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + +#include	"mimegpgfork.h" + +static int libmail_gpgmime_fork(const char *gpgdir, +			const char *passphrase_fd, +			int xargc, char **xargv, int argc, char **argv, +			struct gpgmime_forkinfo *fi) +{ +	int pipes[3][2]; +	int n; +	pid_t p; +	struct sigaction sa; + +	for (n=0; n<3; n++) +	{ +		if (pipe(pipes[n]) < 0) +		{ +			while (n) +			{ +				--n; +				close(pipes[n][0]); +				close(pipes[n][1]); +				return (-1); +			} +		} +	} + +	if (fcntl(pipes[0][1], F_SETFL, O_NONBLOCK) || +	    fcntl(pipes[1][0], F_SETFL, O_NONBLOCK) || +	    fcntl(pipes[2][0], F_SETFL, O_NONBLOCK)) +	{ +		for (n=0; n<3; n++) +		{ +			close(pipes[n][0]); +			close(pipes[n][1]); +		} +		return (-1); +	} + +	signal(SIGCHLD, SIG_DFL); + +	p=fork(); +	if (p < 0) +	{ +		for (n=0; n<3; n++) +		{ +			close(pipes[n][0]); +			close(pipes[n][1]); +		} +		return (-1); +	} + +	if (p == 0) +	{ +		char **newargv; +		int i; +		const char *gpg; + +		dup2(pipes[0][0], 0); +		dup2(pipes[1][1], 1); +		dup2(pipes[2][1], 2); + +		for (n=0; n<3; n++) +		{ +			close(pipes[n][0]); +			close(pipes[n][1]); +		} + +		newargv=malloc( (xargc + argc + 5) * sizeof(char *)); +		if (!newargv) +		{ +			perror("malloc"); +			_exit(1); +		} + +		i=0; +		newargv[i++]="gpg"; +		if (passphrase_fd) +		{ +			int n=atoi(passphrase_fd); + +			if (lseek(n, 0L, SEEK_SET) < 0) +			{ +				perror("passphrase-fd: seek"); +				_exit(1); +			} + +			newargv[i++]="--batch"; +			newargv[i++]="--passphrase-fd"; +			newargv[i++]=(char *)passphrase_fd; +		} + +		for (n=0; n<xargc; n++) +			newargv[i++]=xargv[n]; +		for (n=0; n<argc; n++) +			newargv[i++]=argv[n]; + +		newargv[i]=0; + +		if (gpgdir) +		{ +			char *s; + +			s=malloc(sizeof("GNUPGHOME=")+strlen(gpgdir)); +			if (!s) +			{ +				perror("malloc"); +				exit(1); +			} +			strcat(strcpy(s, "GNUPGHOME="), gpgdir); +			if (putenv(s) < 0) +			{ +				perror("putenv"); +				exit(1); +			} +		} + +		gpg=getenv("GPG"); +		if (!gpg || !*gpg) +			gpg=GPG; + +		execvp(gpg, newargv); +		perror(gpg); +		_exit(1); +	} + +	fi->gpg_errflag=0; +	fi->togpg_fd=pipes[0][1]; +	close(pipes[0][0]); +	fi->fromgpg_fd=pipes[1][0]; +	close(pipes[1][1]); +	fi->fromgpg_errfd=pipes[2][0]; +	close(pipes[2][1]); + +	fi->gpg_writecnt=0; +	fi->gpg_errcnt=0; +	fi->gpg_errbuf[0]=0; +	fi->gpg_pid=p; + +	memset(&sa, 0, sizeof(sa)); +	sa.sa_handler=SIG_IGN; +	sigaction(SIGPIPE, &sa, &fi->old_pipe_sig); + +	fi->gpg_readhandler=0; +	fi->gpg_voidarg=0; +	return (0); +} + +static void gpgmime_writeflush(struct gpgmime_forkinfo *); + +void libmail_gpgmime_write(struct gpgmime_forkinfo *fi, const char *p, size_t n) +{ +	while (n) +	{ +		size_t i; + +		if (fi->gpg_writecnt == sizeof(fi->gpg_writebuf)) +			gpgmime_writeflush(fi); + +		i=sizeof(fi->gpg_writebuf) - fi->gpg_writecnt; + +		if ((size_t)i > n) +			i=n; + +		memcpy(fi->gpg_writebuf + fi->gpg_writecnt, p, i); + +		fi->gpg_writecnt += i; + +		p += i; +		n -= i; +	} +} + +static void libmail_gpgmime_read(struct gpgmime_forkinfo *fi, fd_set *fdr) +{ +	char readbuf[BUFSIZ]; +	int i; + +	if (fi->fromgpg_fd >= 0 && FD_ISSET(fi->fromgpg_fd, fdr)) +	{ +		i=read(fi->fromgpg_fd, readbuf, sizeof(readbuf)); + +		if (i <= 0) +		{ +			close(fi->fromgpg_fd); +			fi->fromgpg_fd= -1; +		} +		else +		{ +			if (fi->gpg_readhandler) +				fi->gpg_errflag= +					(*fi->gpg_readhandler)(readbuf, i, +							       fi->gpg_voidarg +							       ); +		} +	} + +	if (fi->fromgpg_errfd >= 0 && FD_ISSET(fi->fromgpg_errfd, fdr)) +	{ +		i=read(fi->fromgpg_errfd, readbuf, sizeof(readbuf)); + +		if (i <= 0) +		{ +			close(fi->fromgpg_errfd); +			fi->fromgpg_errfd= -1; +		} +		else +		{ +			if (i >= sizeof(fi->gpg_errbuf)-1-fi->gpg_errcnt) +				i=sizeof(fi->gpg_errbuf)-1-fi->gpg_errcnt; +			if (i) +			{ +				memcpy(fi->gpg_errbuf+fi->gpg_errcnt, +				       readbuf, i); +				fi->gpg_errbuf[fi->gpg_errcnt += i]=0; +			} +		} +	} +} + +static void gpgmime_writeflush(struct gpgmime_forkinfo *fi) +{ +	const char *p=fi->gpg_writebuf; +	unsigned n=fi->gpg_writecnt; + +	while (n && !fi->gpg_errflag) +	{ +		fd_set fdr, fdw; +		int maxfd=fi->togpg_fd, i; + +		FD_ZERO(&fdr); +		FD_ZERO(&fdw); + +		FD_SET(fi->togpg_fd, &fdw); + +		if (fi->fromgpg_fd >= 0) +		{ +			FD_SET(fi->fromgpg_fd, &fdr); +			if (fi->fromgpg_fd > maxfd) +				maxfd=fi->fromgpg_fd; +		} + +		if (fi->fromgpg_errfd >= 0) +		{ +			FD_SET(fi->fromgpg_errfd, &fdr); +			if (fi->fromgpg_errfd > maxfd) +				maxfd=fi->fromgpg_errfd; +		} + +		if (select(maxfd+1, &fdr, &fdw, NULL, NULL) <= 0) +			continue; + +		libmail_gpgmime_read(fi, &fdr); + +		if (!FD_ISSET(fi->togpg_fd, &fdw)) +			continue; + +		i=write(fi->togpg_fd, p, n); + +		if (i <= 0) +			fi->gpg_errflag=1; +		else +		{ +			p += i; +			n -= i; +		} +	} +	fi->gpg_writecnt=0; +} + +int libmail_gpgmime_finish(struct gpgmime_forkinfo *fi) +{ +	pid_t p2; +	int waitstat; + +	gpgmime_writeflush(fi); +	close(fi->togpg_fd); +	sigaction(SIGPIPE, &fi->old_pipe_sig, NULL); + +	while (!fi->gpg_errflag && +	       (fi->fromgpg_fd >= 0 || fi->fromgpg_errfd >= 0)) +	{ +		fd_set fdr; +		int maxfd=0; + +		FD_ZERO(&fdr); + +		if (fi->fromgpg_fd >= 0) +		{ +			FD_SET(fi->fromgpg_fd, &fdr); +			if (fi->fromgpg_fd > maxfd) +				maxfd=fi->fromgpg_fd; +		} + +		if (fi->fromgpg_errfd >= 0) +		{ +			FD_SET(fi->fromgpg_errfd, &fdr); +			if (fi->fromgpg_errfd > maxfd) +				maxfd=fi->fromgpg_errfd; +		} + +		if (select(maxfd+1, &fdr, NULL, NULL, NULL) <= 0) +			continue; + +		libmail_gpgmime_read(fi, &fdr); +	} + +	while ((p2=wait(&waitstat)) != fi->gpg_pid) +	{ +		if (p2 < 0 && errno == ECHILD) +			break; +	} + +	if (fi->gpg_errflag == 0) +	{ +		if (!WIFEXITED(waitstat)) +			fi->gpg_errflag=1; +		else +			fi->gpg_errflag=WEXITSTATUS(waitstat); +	} +	return (fi->gpg_errflag); +} + +int libmail_gpgmime_forksignencrypt(const char *gpgdir, +				    const char *passphrase_fd, +				    int flags, +				    int argc, char **argv, +				    int (*output_func)(const char *, +						       size_t, void *), +				    void *output_voidarg, +				    struct gpgmime_forkinfo *gpgfi) +{ +	char *xargvec[5]; +	int xargc=0; +	int rc; + +	if (flags & GPG_SE_SIGN) +	{ +		xargvec[xargc++]="-s"; +		if (! (flags & GPG_SE_ENCRYPT)) +			xargvec[xargc++]="-b"; +	} + +	if (flags & GPG_SE_ENCRYPT) +		xargvec[xargc++]="-e"; + +	xargvec[xargc++]="-a"; + +	rc=libmail_gpgmime_fork(gpgdir, passphrase_fd, +			xargc, xargvec, argc, argv, gpgfi); + +	gpgfi->gpg_readhandler= output_func; +	gpgfi->gpg_voidarg=output_voidarg; +	return (rc); +} + +int libmail_gpgmime_forkchecksign(const char *gpgdir, +			  const char *passphrase_fd, +			  const char *content_filename, +			  const char *signature_filename, +			  int argc, char **argv, +			  struct gpgmime_forkinfo *gpgfi) +{ +	char *xargvec[3]; +	char **newargv; +	int i; +	int rc; + +	xargvec[0]="--verify"; +	xargvec[1]="--charset"; +	xargvec[2]=GPG_CHARSET; + +	newargv=(char **)malloc((argc+2)*sizeof(char *)); +	if (!newargv) +	{ +		perror("malloc"); +		exit(1); +	} + +	for (i=0; i<argc; i++) +		newargv[i]=argv[i]; +	newargv[i++]=(char *)signature_filename; +	newargv[i++]=(char *)content_filename; + +	rc=libmail_gpgmime_fork(gpgdir, passphrase_fd, 3, xargvec, i, newargv, gpgfi); +	free(newargv); +	return (rc); +} + +int libmail_gpgmime_forkdecrypt(const char *gpgdir, +			const char *passphrase_fd, +			int argc, char **argv, +			int (*output_func)(const char *, size_t, void *), +			void *output_voidarg, +			struct gpgmime_forkinfo *gpgfi) +{ +	char *xargv[3]; +	int rc; + +	xargv[0]="--decrypt"; +	xargv[1]="--charset"; +	xargv[2]=GPG_CHARSET; + +	rc=libmail_gpgmime_fork(gpgdir, passphrase_fd, 3, xargv, argc, argv, gpgfi); + +	gpgfi->gpg_readhandler= output_func; +	gpgfi->gpg_voidarg= output_voidarg; +	return (rc); +} + +const char *libmail_gpgmime_getoutput(struct gpgmime_forkinfo *gpgfi) +{ +	return (gpgfi->gpg_errbuf); +} + +const char *libmail_gpgmime_getcharset(struct gpgmime_forkinfo *gpgfi) +{ +	return (GPG_CHARSET); +} | 
