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 /cgi | |
| 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 'cgi')
| -rw-r--r-- | cgi/.gitignore | 2 | ||||
| -rw-r--r-- | cgi/Makefile.am | 11 | ||||
| -rw-r--r-- | cgi/cgi.c | 842 | ||||
| -rw-r--r-- | cgi/cgi.h | 170 | ||||
| -rw-r--r-- | cgi/cgicheckbox.c | 41 | ||||
| -rw-r--r-- | cgi/cgicookie.c | 72 | ||||
| -rw-r--r-- | cgi/cgidaemon.c | 376 | ||||
| -rw-r--r-- | cgi/cgidaemond.c | 484 | ||||
| -rw-r--r-- | cgi/cgiextrapath.c | 21 | ||||
| -rw-r--r-- | cgi/cgihasversion.c | 16 | ||||
| -rw-r--r-- | cgi/cgihttpscriptptr.c | 48 | ||||
| -rw-r--r-- | cgi/cgihttpsscriptptr.c | 47 | ||||
| -rw-r--r-- | cgi/cgiinput.c | 154 | ||||
| -rw-r--r-- | cgi/cginocache.c | 23 | ||||
| -rw-r--r-- | cgi/cgiredirect.c | 19 | ||||
| -rw-r--r-- | cgi/cgirelscriptptr.c | 28 | ||||
| -rw-r--r-- | cgi/cgiselect.c | 134 | ||||
| -rw-r--r-- | cgi/cgitextarea.c | 120 | ||||
| -rw-r--r-- | cgi/cgiuseragent.c | 52 | ||||
| -rw-r--r-- | cgi/cgiversion.c | 32 | ||||
| -rw-r--r-- | cgi/configure.in | 155 | 
21 files changed, 2847 insertions, 0 deletions
| diff --git a/cgi/.gitignore b/cgi/.gitignore new file mode 100644 index 0000000..aed92c0 --- /dev/null +++ b/cgi/.gitignore @@ -0,0 +1,2 @@ +/cgi_config.h +/cgi_config.h.in diff --git a/cgi/Makefile.am b/cgi/Makefile.am new file mode 100644 index 0000000..fa3fd70 --- /dev/null +++ b/cgi/Makefile.am @@ -0,0 +1,11 @@ +# +# Copyright 1998 - 2007 Double Precision, Inc.  See COPYING for +# distribution information. + + +noinst_LTLIBRARIES=libcgi.la + +libcgi_la_SOURCES=cgi.h cgi.c cgiextrapath.c cgiselect.c cgicheckbox.c\ +	cgiinput.c cgihttpscriptptr.c cgihttpsscriptptr.c cgirelscriptptr.c \ +	cginocache.c cgiredirect.c cgitextarea.c cgiversion.c cgihasversion.c \ +	cgicookie.c cgiuseragent.c cgidaemon.c cgidaemond.c diff --git a/cgi/cgi.c b/cgi/cgi.c new file mode 100644 index 0000000..f94bdf0 --- /dev/null +++ b/cgi/cgi.c @@ -0,0 +1,842 @@ +/* +** Copyright 1998 - 2012 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +/* +*/ +#include	"cgi.h" +#include	<stdio.h> +#include	<stdlib.h> +#include	<string.h> +#include	<ctype.h> +#include	<errno.h> + +#if	HAVE_UNISTD_H +#include	<unistd.h> +#endif + +#if	TIME_WITH_SYS_TIME +#include	<sys/time.h> +#include	<time.h> +#else +#if	HAVE_SYS_TIME_H +#include	<sys/time.h> +#else +#include	<time.h> +#endif +#endif + +#ifndef	CGIMAXARG +#define	CGIMAXARG	500000 +#endif + +#ifndef	CGIMAXFORMDATAARG +#define	CGIMAXFORMDATAARG	2000000 +#endif + +#if CGIMAXARG < 256 +#error CGIMAXARG too small +#endif + +#if CGIMAXFORMDATAARG < 1024 +#error CGIMAXFORMDATAARG too small +#endif + +#if	CGIFORMDATA + +#include	<fcntl.h> +#include	<sys/types.h> +#include	<sys/stat.h> +#include	"rfc2045/rfc2045.h" + +static void cgi_formdata(unsigned long); + +#ifndef	HAVE_STRNCASECMP +extern int strncasecmp(const char *, const char *, size_t); +#endif + +static int cgiformfd; +static char hascgiformfd=0; +static struct rfc2045 *rfc2045p=0; + +#endif + +extern void error(const char *); + +static void enomem() +{ +	error("Out of memory."); +} + +static char *cgi_args=0; + +struct cgi_arglist *cgi_arglist=0; + +static size_t cgi_maxarg() +{ +	const char *p=getenv("SQWEBMAIL_MAXARGSIZE"); +	size_t n=0; + +	if (p) +		n=atoi(p); + +	if (n < CGIMAXARG) +		n=CGIMAXARG; +	return n; +} + +static size_t cgi_maxformarg() +{ +	const char *p=getenv("SQWEBMAIL_MAXATTSIZE"); +	size_t n=0; + +	if (p) +		n=atoi(p); + +	if (n < CGIMAXFORMDATAARG) +		n=CGIMAXFORMDATAARG; +	return n; +} + +/* +**	Set up CGI arguments.  Initializes cgi_arglist link list. +** +**	arg1<NUL>value1<NUL>arg2<NUL>value2<NUL> ... argn<NUL>valuen<NUL><NUL> +*/ + +static void cgi_setup_1(); + +void cgi_setup() +{ +struct cgi_arglist *p; + +	cgi_setup_1(); + +	if (cgi_arglist) +		cgi_arglist->prev=0; + +	/* Initialize the prev pointer */ + +	for (p=cgi_arglist; p; p=p->next) +		if (p->next) +			p->next->prev=p; +} + + +static void cgi_setup_1() +{ +char	*p=getenv("REQUEST_METHOD"), *q, *r; +char	*args; +unsigned long cl; +int	c; +struct cgi_arglist *argp; + +	if (p && strcmp(p, "GET") == 0)	/* This is a GET post */ +	{ +		args=getenv("QUERY_STRING"); +		if (!args)	return; +		if (strlen(args) > cgi_maxarg())	enomem(); +		cgi_args=malloc(strlen(args)+1);	/* Extra insurance */ +		if (!cgi_args)	return; +		strcpy(cgi_args,args); +		args=cgi_args; +	} +	else if (p && strcmp(p, "POST") == 0) +	{ +		args=getenv("CONTENT_TYPE"); +		if (!args)	return; + +#if	CGIFORMDATA + +		if (strncasecmp(args,"multipart/form-data;", 20) == 0) +		{ +			args=getenv("CONTENT_LENGTH"); +			if (!args)	return; +			cl=atol(args); +			if (cl > cgi_maxformarg()) +			{ +				printf("Content-Type: text/html\n\n"); +				printf("<html><body><h1>Attachment size (%ld MB) exceeds limit set by system administrator (%ld MB)</h1></body></html>\n", +					(long)(cl / (1024 * 1024)), +					(long)(cgi_maxformarg() / (1024 * 1024))); +				fake_exit(1); +			} +			cgi_formdata(cl); +			return; +		} +#endif + +		if (strncmp(args, "application/x-www-form-urlencoded", 33)) +			return; +		args=getenv("CONTENT_LENGTH"); +		if (!args)	return; +		cl=atol(args); +		if (cl > cgi_maxarg()) +		{ +			printf("Content-Type: text/html\n\n"); + 			printf("<html><body><h1>Message size (%ld MB) exceeds limit set by system administrator (%ld MB)</h1></body></html>\n", + 			       (long)(cl / (1024 * 1024)), + 			       (long)(cgi_maxarg() / (1024 * 1024))); +			fake_exit(1); +		} +	cgi_args=malloc(cl+1);	/* Extra insurance */ +		if (!cgi_args)	return; +		q=cgi_args; +		while (cl) +		{ +			c=getchar(); +			if (c < 0) +			{ +				free(cgi_args); +				cgi_args=0; +				return; +			} +			*q++=c; +			--cl; +		} +		*q=0; +		args=cgi_args; +	} +	else	return; + +	q=args; +	while (*q) +	{ +		argp=malloc(sizeof(*cgi_arglist)); +		if (!argp)	enomem(); +		argp->next=cgi_arglist; +		cgi_arglist=argp; +		argp->argname=q; +		argp->argvalue=""; +		p=q; +		while (*q && *q != '&') +			q++; +		if (*q)	*q++=0; +		if ((r=strchr(p, '=')) != 0) +		{ +			*r++='\0'; +			argp->argvalue=r; +			cgiurldecode(r); +		} +		cgiurldecode(p); +	} +} + +static char *cgiurlencode_common(const char *buf, const char *punct) +{ +char	*newbuf=0; +size_t	cnt=0; +int	pass; +const char *p; +static const char hex[]="0123456789ABCDEF"; + +	for (pass=0; pass<2; pass++) +	{ +		if (pass && (newbuf=malloc(cnt+1)) == 0)	enomem(); +		cnt=0; +		for (p=buf; *p; p++) +		{ +			if (strchr(punct, *p) || *p < 32 || *p >= 127) +			{ +				if (pass) +				{ +					newbuf[cnt]='%'; +					newbuf[cnt+1]=hex[ +						((int)(unsigned char)*p) / 16]; +					newbuf[cnt+2]=hex[ *p & 15 ]; +				} +				cnt += 3; +				continue; +			} +			if (pass) +				newbuf[cnt]= *p == ' ' ? '+':*p; +			++cnt; +		} +	} +	newbuf[cnt]=0; +	return (newbuf); +} + +char *cgiurlencode(const char *buf) +{ +	return (cgiurlencode_common(buf, "\"?;<>&=/:%@+#")); +} + +char *cgiurlencode_noamp(const char *buf) +{ +	return (cgiurlencode_common(buf, "\"?<>=/:%@+#")); +} + +char *cgiurlencode_noeq(const char *buf) +{ +	return (cgiurlencode_common(buf, "\"?;<>&/:%@+#")); +} + +void cgi_cleanup() +{ +#if	CGIFORMDATA + +	if (hascgiformfd) +	{ +		close(cgiformfd); +		hascgiformfd=0; +	} +#endif + +} + +const char *cgi(const char *arg) +{ +struct cgi_arglist *argp; + +	for (argp=cgi_arglist; argp; argp=argp->next) +		if (strcmp(argp->argname, arg) == 0) +			return (argp->argvalue); +	return (""); +} + +char *cgi_multiple(const char *arg, const char *sep) +{ +struct cgi_arglist *argp; +size_t	l=1; +char	*buf; + +	for (argp=cgi_arglist; argp; argp=argp->next) +		if (strcmp(argp->argname, arg) == 0) +			l += strlen(argp->argvalue)+strlen(sep); + +	buf=malloc(l); +	if (!buf)	return(0); +	*buf=0; + +	/* +	** Because the cgi list is build from the tail end up, we go backwards +	** now, so that we return options in the same order they were selected. +	*/ + +	argp=cgi_arglist; +	while (argp && argp->next) +		argp=argp->next; + +	for (; argp; argp=argp->prev) +		if (strcmp(argp->argname, arg) == 0) +		{ +			if (*buf)	strcat(buf, sep); +			strcat(buf, argp->argvalue); +		} +	return (buf); +} + +static char *nybble(char *p, int *n) +{ +	if ( *p >= '0' && *p <= '9') +		(*n) = (*n) * 16 + (*p++ - '0'); +	else if ( *p >= 'A' && *p <= 'F') +		(*n) = (*n) * 16 + (*p++ - 'A' + 10); +	else if ( *p >= 'a' && *p <= 'f') +		(*n) = (*n) * 16 + (*p++ - 'a' + 10); +	return (p); +} + +void cgiurldecode(char *q) +{ +char	*p=q; +int	c; + +	while (*q) +	{ +		if (*q == '+') +		{ +			*p++=' '; +			q++; +			continue; +		} +		if (*q != '%') +		{ +			*p++=*q++; +			continue; +		} +		++q; +		c=0; +		q=nybble(q, &c); +		q=nybble(q, &c); + +		if (c && c != '\r') +			/* Ignore CRs we get in TEXTAREAS */ +			*p++=c; +	} +	*p++=0; +} + +void cgi_put(const char *cginame, const char *cgivalue) +{ +struct cgi_arglist *argp; + +	for (argp=cgi_arglist; argp; argp=argp->next) +		if (strcmp(argp->argname, cginame) == 0) +		{ +			argp->argvalue=cgivalue; +			return; +		} + +	argp=malloc(sizeof(*cgi_arglist)); +	if (!argp)	enomem(); +	argp->next=cgi_arglist; +	argp->prev=0; +	if (argp->next) +		argp->next->prev=argp; +	cgi_arglist=argp; +	argp->argname=cginame; +	argp->argvalue=cgivalue; +} + +#if	CGIFORMDATA + +/**************************************************************************/ + +/* multipart/formdata decoding */ + +static char *disposition_name=NULL, *disposition_filename=NULL; + +static char *formargbuf; +static char *formargptr; + +static int save_formdata(const char *p, size_t l, void *miscptr) +{ +	memcpy(formargptr, p, l); +	formargptr += l; +	return (0); +} + +static void cgiformdecode(struct rfc2045 *p, struct rfc2045id *a, void *b) +{ +off_t start_pos, end_pos, start_body; +char	buf[512]; +int	n; +off_t	dummy; + +	a=a; +	b=b; + +	if (disposition_name) +		free(disposition_name); +	if (disposition_filename) +		free(disposition_filename); + +	if (rfc2231_udecodeDisposition(p, "name", NULL, &disposition_name) < 0) +		disposition_name=NULL; + +	if (rfc2231_udecodeDisposition(p, "filename", NULL, +				       &disposition_filename) < 0) +		disposition_filename=NULL; + +	if (!p->content_disposition +	    || strcmp(p->content_disposition, "form-data"))	return; + +	if (!disposition_name || !*disposition_name)	return; + +	if (!disposition_filename || !*disposition_filename) +	{ +		rfc2045_mimepos(p, &start_pos, &end_pos, &start_body, +			&dummy, &dummy); + +		if (lseek(cgiformfd, start_body, SEEK_SET) == -1) +			enomem(); + +		formargbuf=malloc(end_pos - start_body+1); +		if (!formargbuf)	enomem(); +		formargptr=formargbuf; + +		rfc2045_cdecode_start(p, &save_formdata, 0); +		while (start_body < end_pos) +		{ +			n=sizeof(buf); +			if (n > end_pos - start_body) +				n=end_pos-start_body; +			n=read(cgiformfd, buf, n); +			if (n <= 0)	enomem(); +			rfc2045_cdecode(p, buf, n); +			start_body += n; +		} +		rfc2045_cdecode_end(p); + +		*formargptr=0; +		{ +			char	*name=strdup(disposition_name); +			char	*value=strdup(formargbuf); +			char	*p, *q; + +			/* Just like for GET/POSTs, strip CRs. */ + +			for (p=q=value; *p; p++) +			{ +				if (*p == '\r')	continue; +				*q++ = *p; +			} +			*q++='\0'; +			cgi_put(name, value); +		} +		free(formargbuf); +	} +} + +static const char *cgitempdir="/tmp"; + +void cgiformdatatempdir(const char *p) +{ +	cgitempdir=p; +} + +static void cgiformfdw(const char *p, size_t n) +{ +	while (n) +	{ +	int	k=write(cgiformfd, p, n); + +		if (k <= 0)	enomem(); +		p += k; +		n -= k; +	} +} + +static void cgi_formdata(unsigned long contentlength) +{ +char	pidbuf[MAXLONGSIZE]; +char	timebuf[MAXLONGSIZE]; +char	cntbuf[MAXLONGSIZE]; +time_t	t; +unsigned long cnt; +int	n; +char	*filename, *p; + +static const char fakeheader[]="MIME-Version: 1.0\nContent-Type: "; +char	buf[BUFSIZ]; + +	sprintf(pidbuf, "%lu", (unsigned long)getpid()); +	time(&t); +	sprintf(timebuf, "%lu", (unsigned long)t); +	cnt=0; + +	buf[sizeof(buf)-1]=0; +	if (gethostname(buf, sizeof(buf)-1) != 0) +		buf[0]='\0'; + +	do +	{ +		sprintf(cntbuf, "%lu", (unsigned long)cnt); +		filename=malloc(strlen(pidbuf)+strlen(timebuf)+strlen(cntbuf) +				+strlen(cgitempdir)+strlen(buf)+10); +		if (!filename)	enomem(); +		sprintf(filename, "%s/%s.%s_%s.%s", cgitempdir, +				timebuf, pidbuf, cntbuf, buf); +		cgiformfd=open(filename, O_RDWR | O_CREAT | O_EXCL, 0644); +	} while (cgiformfd < 0); +	unlink(filename);	/* !!!MUST WORK!!! */ +	hascgiformfd=1; +	p=getenv("CONTENT_TYPE"); +	free(filename); +	cgiformfdw(fakeheader, strlen(fakeheader)); +	cgiformfdw(p, strlen(p)); +	cgiformfdw("\n\n", 2); + +	clearerr(stdin); + +	while (contentlength) +	{ +		n=sizeof(buf); +		if (n > contentlength)	n=contentlength; + +		n=fread(buf, 1, n, stdin); +		if (n <= 0) +			enomem(); +		cgiformfdw(buf, n); +		contentlength -= n; +	} + +	rfc2045p=rfc2045_alloc(); +	lseek(cgiformfd, 0L, SEEK_SET); +	while ((n=read(cgiformfd, buf, sizeof(buf))) > 0) +		rfc2045_parse(rfc2045p, buf, n); +	rfc2045_parse_partial(rfc2045p); +	rfc2045_decode(rfc2045p, &cgiformdecode, 0); + +} + +struct cgigetfileinfo { +	int (*start_file)(const char *, const char *, void *); +	int (*file)(const char *, size_t, void *); +	void (*end_file)(void *); +	size_t filenum; +	void *voidarg; +	} ; + + +static void cgifiledecode(struct rfc2045 *p, struct rfc2045id *a, void *b) +{ +off_t start_pos, end_pos, start_body; +char	buf[512]; +int	n; +struct cgigetfileinfo *c; +off_t	dummy; + +	a=a; +	c=(struct cgigetfileinfo *)b; + +	if (c->filenum == 0)	return;	/* Already retrieved this one. */ + +	if (disposition_name) +		free(disposition_name); +	if (disposition_filename) +		free(disposition_filename); + +	if (rfc2231_udecodeDisposition(p, "name", NULL, &disposition_name) < 0 +	    || +	    rfc2231_udecodeDisposition(p, "filename", NULL, +				       &disposition_filename) < 0) +	{ +		disposition_name=disposition_filename=NULL; +		enomem(); +	} + +	if (!p->content_disposition +	    || strcmp(p->content_disposition, "form-data"))	return; + +	if (!*disposition_name)	return; + +	if (!*disposition_filename)	return; + +	rfc2045_mimepos(p, &start_pos, &end_pos, &start_body, +			&dummy, &dummy); + +	if (start_body == end_pos)	/* NULL FILE */ +			return; + +	if ( --c->filenum )	return;	/* Not this one */ + +	if ( (*c->start_file)(disposition_name, disposition_filename, +			      c->voidarg) ) +		return; + +	if (lseek(cgiformfd, start_body, SEEK_SET) == -1) +		enomem(); + +	rfc2045_cdecode_start(p, c->file, c->voidarg); +	while (start_body < end_pos) +	{ +		n=sizeof(buf); +		if (n > end_pos - start_body) +			n=end_pos-start_body; +		n=read(cgiformfd, buf, n); +		if (n <= 0)	enomem(); +		rfc2045_cdecode(p, buf, n); +		start_body += n; +	} +	rfc2045_cdecode_end(p); +	(*c->end_file)(c->voidarg); +} + +int cgi_getfiles( int (*start_file)(const char *, const char *, void *), +		int (*file)(const char *, size_t, void *), +		void (*end_file)(void *), size_t filenum, void *voidarg) +{ +	struct cgigetfileinfo gfi; + +	gfi.start_file=start_file; +	gfi.file=file; +	gfi.end_file=end_file; +	gfi.filenum=filenum; +	gfi.voidarg=voidarg; + +	if (rfc2045p) rfc2045_decode(rfc2045p, &cgifiledecode, &gfi); +	if (gfi.filenum)	return (-1); +	return (0); +} + +#endif + +/* cookies */ + +int cgi_set_cookie_url(struct cgi_set_cookie_info *cookie_info, +		       const char *url) +{ +	const char *p; + +	if (cookie_info->domain) +		free(cookie_info->domain); +	if (cookie_info->path) +		free(cookie_info->path); + +	cookie_info->secure=0; + +	if (strncmp(url, "https://", 8) == 0) +		cookie_info->secure=1; + +	for (p=url; *p; p++) +	{ +		if (*p == ':') +		{ +			url= ++p; +			break; +		} + +		if (*p == '/') +			break; +	} + +	if (strncmp(url, "//", 2) == 0) +	{ +		p= url += 2; + +		while (*url) +		{ +			if (*url == '/') +				break; +			++url; +		} + +		if ((cookie_info->domain=malloc(url-p+1)) == NULL) +			return -1; + +		memcpy(cookie_info->domain, p, url-p); +		cookie_info->domain[url-p]=0; +	} + +	if ((cookie_info->path=strdup(url)) == NULL) +		return -1; +	return 0; +} + +void cgi_set_cookies(struct cgi_set_cookie_info *cookies, +		     size_t n_cookies) +{ +	size_t i; +	const char *sep=""; + +	printf("Set-Cookie: "); + +	for (i=0; i<n_cookies; i++, cookies++) +	{ +		printf("%s%s=\"%s\"; ", sep, cookies->name, cookies->value); +		sep="; "; + +		if (cookies->path) +			printf("Path=\"%s\"; ", cookies->path); + +		if (cookies->secure) +			printf("Secure; "); + +		if (cookies->age >= 0) +			printf("Max-Age=%d; ", cookies->age); +		printf("Version=1"); +	} + +	printf("\n"); +	fflush(stdout); +} + +/* +** Parse Cookie: header +** +** get_cookie_value() skips over a single cookie name=value, returning # of +** bytes, excluding quotes (if any), plus one more (for the trailing \0). +** +** out_ptr, if not NULL, receives ptr to the next byte after name=value +** +** out_value, if not NULL receives the cookie's value, excluding any quotes. +*/ + +static size_t get_cookie_value(const char *ptr, const char **out_ptr, +			       char *out_value) +{ +	int in_quote=0; +	size_t cnt=1; + +	while (*ptr) +	{ +		if (!in_quote) +		{ +			if (*ptr == ';' || *ptr == ',' || +			    isspace((int)(unsigned char)*ptr)) +				break; +		} + +		if (*ptr == '"') +		{ +			in_quote= ~in_quote; +			++ptr; +			continue; +		} + +		if (out_value) +			*out_value++ = *ptr; +		++cnt; +		++ptr; +	} + +	if (out_value) +		*out_value=0; + +	if (out_ptr) +		*out_ptr=ptr; +	return cnt; +} + +/* +** Search for a cookie. +** +** Returns NULL and sets errno=ENOENT, if cookie not found. +** +** Returns malloc-ed buffer that holds the cookie's value (or NULL if +** malloc fails). +*/ + +char *cgi_get_cookie(const char *cookie_name) +{ +	size_t cookie_name_len=strlen(cookie_name); +	const char *cookie=getenv("HTTP_COOKIE"); + +	if (!cookie) +		cookie=""; + +	while (*cookie) +	{ +		if (isspace((int)(unsigned char)*cookie) || +		    *cookie == ';' || *cookie == ',') +		{ +			++cookie; +			continue; +		} + +		if (strncmp(cookie, cookie_name, cookie_name_len) == 0 && +		    cookie[cookie_name_len] == '=') +		{ +			char *buf; + +			cookie += cookie_name_len; +			++cookie; + +			if ((buf=malloc(get_cookie_value(cookie, NULL, NULL))) +			    == NULL) +			{ +				return NULL; +			} + +			get_cookie_value(cookie, NULL, buf); + +			if (*buf == 0) /* Pretend not found */ +			{ +				free(buf); +				errno=ENOENT; +				return NULL; +			} + +			return buf; +		} + +		get_cookie_value(cookie, &cookie, NULL); +	} + +	errno=ENOENT; +	return NULL; +} diff --git a/cgi/cgi.h b/cgi/cgi.h new file mode 100644 index 0000000..1001368 --- /dev/null +++ b/cgi/cgi.h @@ -0,0 +1,170 @@ +/* +*/ +#ifndef	cgi_h +#define	cgi_h + +#if	HAVE_CONFIG_H +#include	"cgi/cgi_config.h" +#endif +#include "../unicode/unicode.h" + +#ifdef __cplusplus + +extern "C" { + +#endif + +#include <string.h> + +/* +** Copyright 1998 - 2007 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +extern void fake_exit(int); + +void cgi_setup(); +void cgi_cleanup(); +const char *cgi(const char *); +char *cgi_multiple(const char *, const char *); + +char	*cgi_cookie(const char *); +void	cgi_setcookie(const char *, const char *); + +int	cgi_useragent(const char *); + +struct cgi_arglist { +	struct cgi_arglist *next; +	struct cgi_arglist *prev;	/* Used by cgi_multiple */ +	const char *argname; +	const char *argvalue; +	} ; + +extern struct cgi_arglist *cgi_arglist; + +extern void cgiurldecode(char *); +extern void cgi_put(const char *, const char *); + +extern char *cgiurlencode(const char *); +extern char *cgiurlencode_noamp(const char *); +extern char *cgiurlencode_noeq(const char *); + +#if	HAVE_UNISTD_H +#include	<unistd.h> +#endif + +int cgi_getfiles( int (*)(const char *, const char *, void *), +		int (*)(const char *, size_t, void *), +		void (*)(void *), size_t, void *); + +extern const char *cgihttpscriptptr(); +extern const char *cgihttpsscriptptr(); +extern const char *cgiextrapath(); + +extern void cgihttpscriptptr_init(); +extern void cgihttpsscriptptr_init(); + +extern const char *cgirelscriptptr(); +extern void cginocache(); +extern void cgiredirect(const char *); +extern void cgiversion(unsigned *, unsigned *); +extern int cgihasversion(unsigned, unsigned); + +struct cgi_set_cookie_info { +	const char *name; +	const char *value; + +	char *domain; +	char *path; +	int age; +	int secure; +}; + +#define cgi_set_cookie_info_init(i) (memset((i), 0, sizeof(*(i))), (i)->age=-1) +#define cgi_set_cookie_info_free(i) do { if ((i)->path) \ +			free((i)->path);		\ +		if ((i)->domain)			\ +			free((i)->domain);		\ +	} while(0) + +#define cgi_set_cookie_session(c,n,v) ( ((c)->name=(n)), ((c)->value)=(v)) +#define cgi_set_cookie_expired(c,n) ( ((c)->name=(n)), ((c)->value)="",\ +				      (c)->age=0) + +extern int cgi_set_cookie_url(struct cgi_set_cookie_info *i, +			      const char *url); + +#define cgi_set_cookie_secure(c) ((c)->secure=1) + +extern void cgi_set_cookies(struct cgi_set_cookie_info *cookies, +			    size_t n_cookies); + +extern char *cgi_get_cookie(const char *cookie_name); + +extern char *cgi_select(const char *name, +			const char *optvalues, +			const char *optlabels, +			const char *default_value, +			size_t list_size, +			const char *flags); /* "m" - multiple, "d" -disabled */ +extern char *cgi_checkbox(const char *name, +			  const char *value, +			  const char *flags); +extern char *cgi_input(const char *name, +		       const unicode_char *value, +		       int size, +		       int maxlength, +		       const char *opts); + +extern char *cgi_textarea(const char *name, +			  int rows, +			  int cols, +			  const unicode_char *value, +			  const char *wrap, +			  const char *opts); + +extern void cgiformdatatempdir(const char *); +		/* Specify directory for formdata temp file */ + +extern void cgi_daemon(int nprocs, const char *lockfile, +		       void (*postinit)(void *), +		       void (*handler)(void *), +		       void *dummy); +extern void cgi_connectdaemon(const char *sockfilename, int pass_fd); + +#define SOCKENVIRONLEN 8192 + +#define VALIDCGIVAR(p) \ +		    (strncmp((p), "DOCUMENT_", 9) == 0 || \ +		     strncmp((p), "GATEWAY_", 8) == 0 || \ +		     strncmp((p), "HTTP_", 5) == 0 || \ +		     strncmp((p), "HTTPS=", 6) == 0 || \ +		     strncmp((p), "SSL_", 4) == 0 || \ +		     strncmp((p), "QUERY_STRING=", 13) == 0 || \ +		     strncmp((p), "SQWEBMAIL_", 10) == 0 || \ +		     strncmp((p), "REMOTE_", 7) == 0 || \ +		     strncmp((p), "REQUEST_", 8) == 0 || \ +		     strncmp((p), "SCRIPT_", 7) == 0 || \ +		     strncmp((p), "SERVER_", 7) == 0 || \ +		     strncmp((p), "CONTENT_", 8) == 0 || \ +		     strncmp((p), "PATH_INFO=", 10) == 0) + +#define CGI_PASSFD 0 + +#if CGI_PASSFD_MSGACCRIGHTS +#undef CGI_PASSFD +#define CGI_PASSFD 1 +#endif + +#if CGI_PASSFD_MSGCONTROL +#undef CGI_PASSFD +#define CGI_PASSFD 1 +#endif + +#ifdef __cplusplus + +} + +#endif + +#endif diff --git a/cgi/cgicheckbox.c b/cgi/cgicheckbox.c new file mode 100644 index 0000000..87f35af --- /dev/null +++ b/cgi/cgicheckbox.c @@ -0,0 +1,41 @@ +/* +** Copyright 2007 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +/* +*/ + +#include	"cgi.h" +#include	<stdio.h> +#include	<string.h> +#include	<stdlib.h> +#include	<ctype.h> + +char *cgi_checkbox(const char *name, +		   const char *value, +		   const char *flags) +{ +	char *buf; + +	if (!value) +		value=""; + +	buf=malloc(strlen(name)+strlen(flags)+200); + +	if (!buf) +		return NULL; + +	strcpy(buf, "<input type='checkbox' name='"); +	strcat(buf, name); +	strcat(buf, "' value='"); +	strcat(buf, value); +	strcat(buf, "'"); + +	if (strchr(flags, '*')) +		strcat(buf, " checked='checked'"); +	if (strchr(flags, 'd')) +		strcat(buf, " disabled='disabled'"); +	strcat(buf, " />"); +	return buf; +} diff --git a/cgi/cgicookie.c b/cgi/cgicookie.c new file mode 100644 index 0000000..704b7fc --- /dev/null +++ b/cgi/cgicookie.c @@ -0,0 +1,72 @@ +/* +** Copyright 2007 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +/* +*/ + +#include	"cgi.h" +#include	<stdio.h> +#include	<string.h> +#include	<stdlib.h> +#include	<ctype.h> + +extern void error(const char *); + +static void enomem() +{ +	error("Out of memory."); +} + +char	*cgi_cookie(const char *p) +{ +size_t	pl=strlen(p); +const char *c=getenv("HTTP_COOKIE"); +char	*buf; + +	while (c && *c) +	{ +	size_t	i; + +		for (i=0; c[i] && c[i] != '='; i++) +			; +		if (i == pl && strncmp(p, c, i) == 0) +		{ +			c += i; +			if (*c)	++c;	/* skip over = */ +			for (i=0; c[i] && c[i] != ';'; i++) +				; + +			buf=malloc(i+1); +			if (!buf)	enomem(); +			memcpy(buf, c, i); +			buf[i]=0; +			cgiurldecode(buf); +			return (buf); +		} +		c=strchr(c, ';'); +		if (c) +			do +			{ +				++c; +			} while (isspace((int)(unsigned char)*c)); +	} +	buf=malloc(1); +	if (!buf)	enomem(); +	*buf=0; +	return (buf); +} + +void cgi_setcookie(const char *name, const char *value) +{ +char	*p; +const	char *sn; + +	p=cgiurlencode(value); +	sn=getenv("SCRIPT_NAME"); +	if (!sn || !*sn) +		sn="/"; +	printf("Set-Cookie: %s=%s; path=%s\n", name, value, sn); +	free(p); +} diff --git a/cgi/cgidaemon.c b/cgi/cgidaemon.c new file mode 100644 index 0000000..fa42cbf --- /dev/null +++ b/cgi/cgidaemon.c @@ -0,0 +1,376 @@ +/* +** Copyright 2003-2007 Double Precision, Inc.  See COPYING for +** distribution information. +*/ + + +/* +*/ +#include	"cgi.h" +#include	<stdio.h> +#include	<errno.h> +#include	<stdlib.h> +#if	HAVE_UNISTD_H +#include	<unistd.h> +#endif +#include	<string.h> +#include	<signal.h> +#include	<sys/types.h> +#include	<sys/stat.h> +#include        <sys/socket.h> +#include        <sys/un.h> +#if	HAVE_FCNTL_H +#include	<fcntl.h> +#endif +#include	<ctype.h> +#if HAVE_SYS_WAIT_H +#include	<sys/wait.h> +#endif + +#if	HAVE_SYS_SELECT_H +#include	<sys/select.h> +#endif + +#if	HAVE_SYS_UIO_H +#include	<sys/uio.h> +#endif + + +extern char **environ; + +static void err(const char *func, const char *msg) +{ +	cginocache(); + +	printf("Content-Type: text/html; charset='utf-8'\n\n" +	       "<html><head><title>Internal error</title></head>\n" +	       "<body><h1>Internal Error</h1>\n" +	       "<p>The webmail system is temporarily unavailable.  An error" +	       " occured in function %s: %s</p></body></html>\n", func, +	       msg); +	fflush(stdout); +	exit(0); +} + +static void connect_err(const char *func) +{ +	cginocache(); + +	printf("Content-Type: text/html; charset='us-ascii'\n\n" +	       "<html><head><title>System unavailable</title></head>\n" +	       "<body><h1>System unavailable</h1>\n" +	       "<p>The web page you're trying to access is not available" +	       " at this time. Please try again later.\n" +	       "</p><p>" +	       "(%s: %s)</p></body></html>\n", func, strerror(errno)); +	fflush(stdout); +	exit(0); +} + +static void sys_err(const char *func) +{ +	err(func, strerror(errno)); +} + +static const char *force_write(int s, const char *p, size_t l) +{ +	while (l) +	{ +		int n; + +		n=write(s, p, l); +		if (n <= 0) +			return ("write"); +		p += n; +		l -= n; +	} +	return NULL; +} + +/* Pass along the CGI environment variables to sqwebmaild */ + +static void send_environ(int fd, int passfd) +{ +	char buf[SOCKENVIRONLEN]; + +	char *p=buf+sizeof(size_t)+1; +	size_t l=sizeof(buf)-sizeof(size_t)-2; +	size_t i; +	const char *cp; + +	buf[sizeof(l)]=passfd; + +	for (i=0; environ[i]; i++) +	{ +		size_t m; + +		if (!VALIDCGIVAR(environ[i])) +			continue; + +		m=strlen(environ[i])+1; + +		if (m > l) +			err("CGI", "CGI environment exceeds allowed " +			    "maximum size."); + +		memcpy(p, environ[i], m); +		p += m; +		l -= m; +	} + +	l=p-(buf+sizeof(l)+1); +	memcpy(buf, &l, sizeof(l)); + +	cp=force_write(fd, buf, l + sizeof(l)+1); +	if (cp) +		sys_err(cp); + +	/* +	** If the platform supports it, pass the file descriptors +	** to sqwebmaild. +	*/ + +#if	CGI_PASSFD + +	if (passfd) +	{ +		struct iovec iov; +		char dummy; + +#if CGI_PASSFD_MSGACCRIGHTS + +		int fdbuf[2]; +		struct msghdr msg; + +		fdbuf[0]=0; +		fdbuf[1]=1; +		memset(&iov, 0, sizeof(iov)); +		msg.msg_accrights=(caddr_t)fdbuf; +		msg.msg_accrightslen=sizeof(fdbuf); +#endif + +#if CGI_PASSFD_MSGCONTROL + +		int fdbuf[2]; +		struct msghdr msg; +		struct cmsghdr *cmsg; +		char buf[CMSG_SPACE(sizeof(fdbuf))]; + +		fdbuf[0]=0; +		fdbuf[1]=1; + +		memset(&msg, 0, sizeof(msg)); +		msg.msg_control=buf; +		msg.msg_controllen=sizeof(buf); +		cmsg = CMSG_FIRSTHDR(&msg); +		cmsg->cmsg_level=SOL_SOCKET; +		cmsg->cmsg_type=SCM_RIGHTS; +		cmsg->cmsg_len=CMSG_LEN(sizeof(fdbuf)); +		memcpy(CMSG_DATA(cmsg), fdbuf, sizeof(fdbuf)); +#endif +		msg.msg_iov=&iov; +		msg.msg_iovlen=1; +		iov.iov_base=&dummy; +		iov.iov_len=1; + +		dummy=0; +		if (sendmsg(fd, &msg, 0) < 0) +			sys_err("sendmsg(filedescriptor)"); +	} +#endif + +} + +static void passthrough(int s, int passed_fd) +{ +	char toclientbuf[8192]; +	char tosqbuf[8192]; + +	char *toclientptr, *tosqptr; +	size_t toclientlen, tosqlen; +	int stdin_closed=0; + +	toclientptr=NULL; +	tosqptr=NULL; +	toclientlen=0; +	tosqlen=0; + +	if (passed_fd) +	{ +		stdin_closed=1;  /* sqwebmaild will read on the fd itself */ +		if (fcntl(s, F_SETFL, O_NDELAY) < 0) +			sys_err("fcntl"); +	} + +	/* When the file descriptor is passed, we will not do any actual I/O, +	** so there's no need to set stdin/stdout to nonblock mode +	*/ +	else if (fcntl(0, F_SETFL, O_NDELAY) < 0 || +		 fcntl(1, F_SETFL, O_NDELAY) < 0 || +		 fcntl(s, F_SETFL, O_NDELAY) < 0) +		sys_err("fcntl"); + +	for (;;) +	{ +		fd_set fdr, fdw; + +		FD_ZERO(&fdr); +		FD_ZERO(&fdw); + +		if (tosqlen) +			FD_SET(s, &fdw); +		else if (!stdin_closed) +			FD_SET(0, &fdr); + +		if (toclientlen) +			FD_SET(1, &fdw); +		else +			FD_SET(s, &fdr); + +		if (select(s+1, &fdr, &fdw, 0, NULL) <= 0) +		{ +			fcntl(1, F_SETFL, 0); +			sys_err("select"); +		} + +		if (tosqlen) +		{ +			if (FD_ISSET(s, &fdw)) +			{ +				int m=write(s, tosqptr, tosqlen); + +				if (m <= 0) +				{ +					fcntl(1, F_SETFL, 0); +					sys_err("write"); +				} + +				tosqptr += m; +				tosqlen -= m; +			} +		} +		else +		{ +			if (FD_ISSET(0, &fdr)) +			{ +				int m=read(0, tosqbuf, sizeof(tosqbuf)); + +				if (m < 0) /* network error */ +					return; + +				if (m == 0) +					stdin_closed=1; + +				tosqptr=tosqbuf; +				tosqlen=m; +			} +		} + +		if (toclientlen) +		{ +			if (FD_ISSET(1, &fdw)) +			{ +				int m=write(1, toclientptr, toclientlen); + +				if (m <= 0) +					return; /* Client aborted, nocare */ + +				toclientptr += m; +				toclientlen -= m; +			} +		} +		else +		{ +			if (FD_ISSET(s, &fdr)) +			{ +				int m=read(s, toclientbuf, +					   sizeof(toclientbuf)); + +				if (m <= 0) +					return; + +				toclientptr=toclientbuf; +				toclientlen=m; +			} +		} +	} +} + +void cgi_connectdaemon(const char *sockfilename, int pass_fd) +{ +	int	s; +	struct  sockaddr_un ssun; +	int	triedagain=0; +	int	rc; + +	/* Connect to sqwebmaild via a socket */ + +	signal(SIGPIPE, SIG_IGN); +	if ((s=socket(PF_UNIX, SOCK_STREAM, 0)) < 0) +		sys_err("socket"); + +	if (fcntl(s, F_SETFL, O_NDELAY) < 0) +		sys_err("fcntl"); + +	ssun.sun_family=AF_UNIX; +	strcpy(ssun.sun_path, sockfilename); + +	while ((rc=connect(s, (struct sockaddr *)&ssun, sizeof(ssun))) < 0 +	       && errno == EAGAIN) +	{ +		if (++triedagain > 5) +			break; +		sleep(1); +		ssun.sun_family=AF_UNIX; +		strcpy(ssun.sun_path, sockfilename); +	} + +	if (rc < 0) +	{ +		struct	timeval	tv; +		fd_set	fds; + +		int	errcode; +		socklen_t errcode_l; + +		if (errno != EINPROGRESS) +			connect_err("connect"); + +		tv.tv_sec=30; +		tv.tv_usec=0; +		FD_ZERO(&fds); +		FD_SET(s, &fds); +		if (select(s+1, 0, &fds, 0, &tv) <= 0) +			connect_err("select"); + + +		errcode_l=sizeof(errcode); + +		if (getsockopt(s, SOL_SOCKET, SO_ERROR, &errcode, &errcode_l) +		    < 0) +			connect_err("setsockopt"); + + +		if (errcode) +		{ +			errno=errcode; +			connect_err("connect"); +		} +	} + +	if (triedagain) +	{ +		fprintf(stderr, +		       "CRIT: Several attempts were necessary to connect to sqwebmaild\n"); +		fprintf(stderr, +		       "CRIT: Consider increasing the number of pre-forked sqwebmaild processes\n"); +	} + +	if (fcntl(s, F_SETFL, 0) < 0) +		sys_err("fcntl"); + +	send_environ(s, pass_fd); +	passthrough(s, pass_fd); +	close(s); +	exit(0); +} diff --git a/cgi/cgidaemond.c b/cgi/cgidaemond.c new file mode 100644 index 0000000..fd928fb --- /dev/null +++ b/cgi/cgidaemond.c @@ -0,0 +1,484 @@ +/* +** Copyright 2007 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +/* +*/ +#include	"cgi.h" +#include	<stdio.h> +#include	<stdlib.h> +#include	<string.h> + +#if	HAVE_UNISTD_H +#include	<unistd.h> +#endif + +#if	TIME_WITH_SYS_TIME +#include	<sys/time.h> +#include	<time.h> +#else +#if	HAVE_SYS_TIME_H +#include	<sys/time.h> +#else +#include	<time.h> +#endif +#endif +#if HAVE_SYS_WAIT_H +#include	<sys/wait.h> +#endif +#include	<errno.h> +#include	<fcntl.h> +#include	<sys/types.h> +#include	<sys/stat.h> +#include        <sys/socket.h> +#include	<sys/uio.h> +#include        <sys/un.h> + +static int read_environ(int); + +static int start_daemon(const char *lockfilename); + +static void run_daemon(int fd, int termfd, int connfd, void (*handler)(void *), +		       void *dummy); + +static void run_prefork(int fd, size_t ndaemons, void (*handler)(void *), +			void *dummy); + +void cgi_daemon(int nprocs, const char *lockfile, +		void (*postinit)(void *), void (*handler)(void *), +		void *dummy) +{ +	int fd=start_daemon(lockfile); + +	if (postinit) +		(*postinit)(dummy); + +	if (nprocs > 0) +		run_prefork(fd, nprocs, handler, dummy); +	else +		run_daemon(fd, -1, -1, handler, dummy); +} + +/* Start in daemon mode.  Return listening socket file descriptor */ + +static int start_daemon(const char *lockfile) +{ +	int     fd; +	struct  sockaddr_un skun; + +	unlink(lockfile); + +	fd=socket(PF_UNIX, SOCK_STREAM, 0); +        if (fd < 0) +	{ +		perror("socket"); +		return (-1); +	} + +        skun.sun_family=AF_UNIX; +        strcpy(skun.sun_path, lockfile); +        if (bind(fd, (const struct sockaddr *)&skun, sizeof(skun)) || +                listen(fd, SOMAXCONN) || +                chmod(skun.sun_path, 0777) || +                fcntl(fd, F_SETFL, O_NONBLOCK) < 0) +        { +                perror(lockfile); +                close(fd); +                return (-1); +        } +	return fd; +} + +static int prefork(int listenfd, int *allpipes, size_t ndaemos, +		   int *termpipe, void (*handler)(void *), void *dummy); + +static void run_prefork(int fd, size_t ndaemons, void (*handler)(void *), +			void *dummy) +{ +	int *cpipes; /* Completion pipes from preforked processes */ +	int termpipe[2]; /* Termination pipe to preforked processes */ +	size_t i; + +	if ((cpipes=malloc(sizeof(int)*ndaemons)) == NULL) +	{ +		fprintf(stderr, +		       "CRIT: malloc failed: %s\n", +		       strerror(errno)); +		exit(1); +	} + +	if (pipe(termpipe) < 0) +	{ +		fprintf(stderr, +			"CRIT: pipe failed: %s\n", +			strerror(errno)); +		exit(1); +	} + + +	/* Start the initial set of preforked daemons */ + +	for (i=0; i<ndaemons; i++) +		cpipes[i]= -1; + +	for (i=0; i<ndaemons; i++) +		cpipes[i]=prefork(fd, cpipes, ndaemons, termpipe, handler, +				  dummy); + + +	for (;;) +	{ +		fd_set	fdr; +		int	maxfd=0; + +		FD_ZERO(&fdr); + +		for (i=0; i<ndaemons; i++) +		{ +			if (cpipes[i] >= maxfd) +				maxfd=cpipes[i]+1; + +			FD_SET(cpipes[i], &fdr); +		} + +		if (select(maxfd, &fdr, NULL, NULL, NULL) <= 0) +			continue; + +		/* +		** When child process gets a connection, it closes its +		** completion pipe, which makes the pipe selectable for +		** read. +		*/ + +		for (i=0; i<ndaemons; i++) +		{ +			if (FD_ISSET(cpipes[i], &fdr)) +			{ +				close(cpipes[i]); +				cpipes[i]= -1; +				cpipes[i]=prefork(fd, cpipes, +						  ndaemons, termpipe, handler, +						  dummy); +			} +		} +	} +} + +/* Start a preforked process */ + +static int prefork(int listenfd, int *allpipes, size_t ndaemons, +		   int *termpipe, void (*handler)(void *), void *dummy) +{ +	int newpipe[2]; +	pid_t p; +	int waitstat; +	size_t i; + +	if (pipe(newpipe) < 0) +	{ +		fprintf(stderr, +			"CRIT: pipe failed: %s\n", strerror(errno)); +		exit(1); +	} + +	while ((p=fork()) < 0) +	{ +		fprintf(stderr, +			"CRIT: fork failed: %s\n", strerror(errno)); +		sleep(5); +	} + +	if (p) /* parent */ +	{ +		close(newpipe[1]); + +		/* Wait for first child process to go away */ + +		while (wait(&waitstat) != p) +			; + +		return (newpipe[0]); +	} + +	close(newpipe[0]); +	close(termpipe[1]); + +	/* New child doesn't need pipes from other children */ + +	for (i=0; i<ndaemons; i++) +		if (allpipes[i] >= 0) +			close(allpipes[i]); + +	/* Fork once more, so that the parent process can continue */ + +	if (fork()) +		exit(0); + +	run_daemon(listenfd, termpipe[0], newpipe[1], handler, dummy); +	return (-1); +} + +static void run_daemon(int fd, int termfd, int acceptedfd, +		       void (*handler)(void *), void *dummy) +{ +	int cfd; + +	for (;;) +	{ +		fd_set	fdr; +		pid_t p; +		int maxfd; + +		FD_ZERO(&fdr); + +		FD_SET(fd, &fdr); + +		maxfd=fd; + +		if (termfd >= 0) +		{ +			if (termfd > maxfd) +				maxfd=termfd; + +			FD_SET(termfd, &fdr); +		} + +		if (select(maxfd+1, &fdr, NULL, NULL, NULL) <= 0) +			continue; +		if (termfd >= 0 && +		    FD_ISSET(termfd, &fdr)) /* Terminate all child procs */ +			exit(0); + +		if (!FD_ISSET(fd, &fdr)) +			continue; + +		cfd=accept(fd, NULL, 0); + +		if (cfd < 0) +			continue; + +		if (acceptedfd >= 0) /* preforked daemon */ +		{ +			if (termfd >= 0) +				close(termfd); +			close(acceptedfd); +			break; +		} + +		p=fork(); + +		if (p < 0) +		{ +			fprintf(stderr, +			       "CRIT: fork() failed: %s\n", strerror(errno)); +			continue; +		} + +		if (p) +		{ +			int dummy; + +			close(cfd); +			while (wait(&dummy) != p) +				continue; +			continue; +		} + +		/* Child forks once more, parent exits */ + +		if (fork()) +			exit(0); + +		break; + +	} + +	/* child */ + +	if (fcntl(cfd, F_SETFL, 0) < 0) +	{ +		fprintf(stderr, +		       "CRIT: fcntl(): %s\n", strerror(errno)); +		exit(0); +	} + +	close(fd); +	if (read_environ(cfd)) +	{ +		close(0); +		close(1); +		if (dup(cfd) != 0 || dup(cfd) != 1) +		{ +			fprintf(stderr, +			       "CRIT: dup() did not work as expected\n"); +			exit(0); +		} +		close(cfd); +	} + +	if (fcntl(0, F_SETFL, 0) < 0 || +	    fcntl(1, F_SETFL, 0) < 0) +	{ +		fprintf(stderr, +		       "CRIT: fcntl() failed: %s\n", strerror(errno)); +		exit(0); +	} + +	(*handler)(dummy); +	exit(0); +} + + +/* Read environment from the sqwebmail stub */ + +static void force_read(int cfd, char *p, size_t l) +{ +	int m; + +	while (l) +	{ +		m=read(cfd, p, l); +		if (m <= 0) +		{ +			fprintf(stderr, +			       "WARN: socket closed while reading" +			       " environment.\n"); +			exit(0); +		} + +		p += m; +		l -= m; +	} +} + +/* Receive CGI environment */ + +static int read_environ(int cfd) +{ +	static char buf[SOCKENVIRONLEN]; +	size_t l; +	char *p; +	int passfd; + +	force_read(cfd, buf, 1+sizeof(l)); + +	memcpy(&l, buf, sizeof(l)); +	passfd=buf[sizeof(l)]; + +	if (l >= sizeof(buf)) +	{ +		fprintf(stderr, +		       "WARN: invalid environment received via socket.\n"); +		exit(0); +	} + +	alarm(10); /* Just in case - punt */ +	force_read(cfd, buf, l); +	buf[l]=0; +	alarm(0); + +	/* Vet environment strings for only known good strings */ + +	p=buf; +	while (p < buf+l) +	{ +		if (strchr(p, '=') == NULL || +		    !VALIDCGIVAR(p)) +		{ +			fprintf(stderr, +			       "WARN: invalid environment received" +			       " via socket: %s\n" , p); +			exit(0); +		} + +		putenv(p); + +		while (*p++) +			; +	} + +	/* Receive file descriptors, if supported by the platform */ + +#if	CGI_PASSFD + +	if (passfd) +	{ +		struct iovec iov; +		char dummy; + +#if CGI_PASSFD_MSGACCRIGHTS + +		int fdbuf[2]; +		struct msghdr msg; +#endif + +#if CGI_PASSFD_MSGCONTROL + +		int fdbuf[2]; +		struct msghdr msg; +		struct cmsghdr *cmsg; +		char buf[CMSG_SPACE(sizeof(fdbuf))]; +#endif + +#if CGI_PASSFD_MSGACCRIGHTS +		memset(&iov, 0, sizeof(iov)); +		msg.msg_accrights=(caddr_t)fdbuf; +		msg.msg_accrightslen=sizeof(fdbuf); +#endif + + +#if CGI_PASSFD_MSGCONTROL +		memset(&msg, 0, sizeof(msg)); +		msg.msg_control=buf; +		msg.msg_controllen=sizeof(buf); +#endif + +		msg.msg_iov=&iov; +		msg.msg_iovlen=1; + +		iov.iov_base=&dummy; +		iov.iov_len=1; + +		if (recvmsg(cfd, &msg, 0) <= 0) +		{ +			perror("Internal error - recvmsg() failed"); +			exit(0); +		} + +#if CGI_PASSFD_MSGACCRIGHTS + +		if (msg.msg_accrightslen < sizeof(fdbuf)) +		{ +			perror("Internal error - malformed recvmsg()"); +			exit(0); +		} + +#endif + +#if CGI_PASSFD_MSGCONTROL +		if (msg.msg_controllen < sizeof(buf) || +		    (cmsg = CMSG_FIRSTHDR(&msg))->cmsg_level != SOL_SOCKET || +		    cmsg->cmsg_type != SCM_RIGHTS || +		    cmsg->cmsg_len != CMSG_LEN(sizeof(fdbuf))) +		{ +			perror("Internal error - malformed recvmsg()"); +			exit(0); +		} + +		memcpy(fdbuf, CMSG_DATA(cmsg), sizeof(fdbuf)); +#endif +		close(0); +		close(1); +		if (dup(fdbuf[0]) != 0 || dup(fdbuf[1]) != 1) +			fprintf(stderr, +			       "CRIT: dup() did not work as expected in" +			       " read_environ()\n"); +		close(fdbuf[0]); +		close(fdbuf[1]); +		return 0; +	} +#endif + +	return 1; +} diff --git a/cgi/cgiextrapath.c b/cgi/cgiextrapath.c new file mode 100644 index 0000000..3cd3aa6 --- /dev/null +++ b/cgi/cgiextrapath.c @@ -0,0 +1,21 @@ +/* +** Copyright 2007 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +/* +*/ +#include	"cgi.h" +#include <stdlib.h> +#include <unistd.h> +#if	HAVE_UNISTD_H +#include	<unistd.h> +#endif + +const char *cgiextrapath() +{ +	const char *pi=getenv("PATH_INFO"); + +	if (!pi) pi=""; +	return pi; +} diff --git a/cgi/cgihasversion.c b/cgi/cgihasversion.c new file mode 100644 index 0000000..a323677 --- /dev/null +++ b/cgi/cgihasversion.c @@ -0,0 +1,16 @@ +/* +** Copyright 1998 - 1999 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +/* +*/ +#include	"cgi.h" + +int cgihasversion(unsigned major, unsigned minor) +{ +unsigned vmajor, vminor; + +	cgiversion(&vmajor, &vminor); +	return (vmajor > major || (vmajor == major && vminor >= minor)); +} diff --git a/cgi/cgihttpscriptptr.c b/cgi/cgihttpscriptptr.c new file mode 100644 index 0000000..9f5ee25 --- /dev/null +++ b/cgi/cgihttpscriptptr.c @@ -0,0 +1,48 @@ +/* +** Copyright 1998 - 2007 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +/* +*/ +#include	"cgi.h" + +#if	HAVE_UNISTD_H +#include	<unistd.h> +#endif + +#include	<string.h> +#include	<stdlib.h> +#include	<stdio.h> + +static char *scriptptr=0; + +extern void error(const char *); + +void cgihttpscriptptr_init() +{ +	/* Reinitialisation required when running as fastcgi */ +	if (scriptptr) { +		free(scriptptr); +		scriptptr=0; +	} +} + +const char *cgihttpscriptptr() +{ +	if (!scriptptr) +	{ +	char	*p=getenv("SCRIPT_NAME"); +	char	*h=getenv("HTTP_HOST"); +	char	*q; + +		if (!h)	h=""; +		if (!p)	p=""; + +		q=malloc(strlen(p)+strlen(h)+sizeof("http://")); +		if (!q)	error("Out of memory."); +		sprintf(q, "http:%s%s%s", (*h ? "//":""), h, p); +		scriptptr=q; +	} +	return (scriptptr); +} diff --git a/cgi/cgihttpsscriptptr.c b/cgi/cgihttpsscriptptr.c new file mode 100644 index 0000000..93f5339 --- /dev/null +++ b/cgi/cgihttpsscriptptr.c @@ -0,0 +1,47 @@ +/* +** Copyright 1998 - 2007 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +/* +*/ +#include	"cgi.h" + +#if	HAVE_UNISTD_H +#include	<unistd.h> +#endif + +#include	<string.h> +#include	<stdlib.h> +#include	<stdio.h> + +static char *scriptptr=0; +extern void error(const char *); + +void cgihttpsscriptptr_init() +{ +	/* Reinitialisation required when running as fastcgi */  +	if (scriptptr) { +		free(scriptptr); +		scriptptr=0; +	} +} + +const char *cgihttpsscriptptr() +{ +	if (!scriptptr) +	{ +	char	*p=getenv("SCRIPT_NAME"); +	char	*h=getenv("HTTP_HOST"); +	char	*q; + +		if (!h)	h=""; +		if (!p)	p=""; + +		q=malloc(strlen(p)+strlen(h)+sizeof("https://")); +		if (!q)	error("Out of memory."); +		sprintf(q, "https:%s%s%s", (*h ? "//":""), h, p); +		scriptptr=q; +	} +	return (scriptptr); +} diff --git a/cgi/cgiinput.c b/cgi/cgiinput.c new file mode 100644 index 0000000..64769de --- /dev/null +++ b/cgi/cgiinput.c @@ -0,0 +1,154 @@ +/* +** Copyright 2007 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +/* +*/ + +#include	"cgi.h" +#include	<stdio.h> +#include	<string.h> +#include	<stdlib.h> +#include	<ctype.h> + +void cgi_output_unicode_escapes(const unicode_char *value, +				const char *escapes, +				void (*output_func)(const char *, size_t, +						    void *), +				void *output_arg) +{ +	while (value && *value) +	{ +		size_t i; + +		for (i=0; value[i]; i++) +		{ +			if (value[i] > 127 || +			    strchr(escapes, value[i])) +				break; +		} + +		while (i) +		{ +			char buf[100]; + +			size_t n=sizeof(buf); +			size_t j; + +			if (n > i) +				n=i; + +			for (j=0; j<n; j++) +				buf[j]=value[j]; + +			(*output_func)(buf, j, output_arg); + +			value += j; +			i -= j; +		} + +		if (*value) +		{ +			char buf[100]; + +			sprintf(buf, "&#%lu;", (unsigned long)value[i]); + +			(*output_func)(buf, 0, output_arg); +			++value; +		} +	} +} + + +static void do_cgi_input(const char *name, +			 const unicode_char *value, +			 int size, +			 int maxlength, +			 const char *flags, + +			 void (*output_func)(const char *, size_t, +					     void *), +			 void *output_arg) +{ +	(*output_func)("<input name='", 0, output_arg); +	(*output_func)(name, 0, output_arg); +	(*output_func)("'", 0, output_arg); + +	if (strchr(flags, 'r')) +		(*output_func)(" readonly='readonly'", 0, output_arg); +	if (strchr(flags, 'd')) +		(*output_func)(" disabled='disabled'", 0, output_arg); + +	(*output_func)("'", 0, output_arg); + +	if (size) +	{ +		char buf[100]; + +		sprintf(buf, " size=%d", size); + +		(*output_func)(buf, 0, output_arg); +	} + +	if (maxlength) +	{ +		char buf[100]; + +		sprintf(buf, " maxlength=%d", maxlength); + +		(*output_func)(buf, 0, output_arg); +	} + +	(*output_func)(" value='", 0, output_arg); + +	cgi_output_unicode_escapes(value, "<>'&", output_func, output_arg); + +	(*output_func)("' />", 0, output_arg); +} + +static void cnt_bytes(const char *str, size_t cnt, void *arg) +{ +	if (!cnt) +		cnt=strlen(str); + +	*(size_t *)arg += cnt; +} + +static void save_bytes(const char *str, size_t cnt, void *arg) +{ +	char **p=(char **)arg; + +	if (!cnt) +		cnt=strlen(str); + +	memcpy(*p, str, cnt); + +	*p += cnt; +} + +char *cgi_input(const char *name, +		const unicode_char *value, +		int size, +		int maxlength, +		const char *flags) +{ +	size_t cnt=1; +	char *buf; +	char *ptr; + +	if (!flags) +		flags=""; + +	do_cgi_input(name, value, size, maxlength, flags, cnt_bytes, &cnt); + +	buf=malloc(cnt); + +	if (!buf) +		return NULL; + +	ptr=buf; +	do_cgi_input(name, value, size, maxlength, flags, save_bytes, &ptr); +	*ptr=0; +	return buf; +} diff --git a/cgi/cginocache.c b/cgi/cginocache.c new file mode 100644 index 0000000..43c9481 --- /dev/null +++ b/cgi/cginocache.c @@ -0,0 +1,23 @@ +/* +** Copyright 1998 - 2007 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +/* +*/ +#include	"cgi.h" +#include	<stdio.h> + +void cginocache() +{ +	if (cgi_useragent("MSIE")) +	{ +		printf("Cache-Control: private\n"); +		printf("Pragma: private\n"); +	} +	else +	{ +		printf("Cache-Control: no-store\n"); +		printf("Pragma: no-cache\n"); +	} +} diff --git a/cgi/cgiredirect.c b/cgi/cgiredirect.c new file mode 100644 index 0000000..7651159 --- /dev/null +++ b/cgi/cgiredirect.c @@ -0,0 +1,19 @@ +/* +** Copyright 1998 - 2007 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +/* +*/ +#include	"cgi.h" +#include	<stdio.h> + +void cgiredirect(const char *buf) +{ +	if (cgihasversion(1,1)) +		printf("Status: 303 Moved\n"); +				/* Alas, Communicator can't handle it */ +	cginocache(); +	printf("Location: %s\n\n", buf); +	printf("URI: %s\n", buf); +} diff --git a/cgi/cgirelscriptptr.c b/cgi/cgirelscriptptr.c new file mode 100644 index 0000000..edce813 --- /dev/null +++ b/cgi/cgirelscriptptr.c @@ -0,0 +1,28 @@ +/* +** Copyright 1999-2007 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +/* +*/ +#include	"cgi.h" + +#if	HAVE_UNISTD_H +#include	<unistd.h> +#endif + +#include	<string.h> +#include	<stdlib.h> +#include	<stdio.h> + +extern void error(const char *); + +const char *cgirelscriptptr() +{ +	const char *p=getenv("HTTPS"); + +	if (p && strcasecmp(p, "on") == 0) +		return (cgihttpsscriptptr()); + +	return (cgihttpscriptptr()); +} diff --git a/cgi/cgiselect.c b/cgi/cgiselect.c new file mode 100644 index 0000000..647e1fa --- /dev/null +++ b/cgi/cgiselect.c @@ -0,0 +1,134 @@ +/* +** Copyright 2007 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +/* +*/ + +#include	"cgi.h" +#include	<stdio.h> +#include	<string.h> +#include	<stdlib.h> +#include	<ctype.h> + +static void do_cgi_select(const char *name, +			  const char *optvalues, +			  const char *optlabels, +			  const char *default_value, +			  size_t list_size, +			  const char *flags, + +			  void (*output_func)(const char *, size_t, void *), +			  void *output_arg) +{ +	(*output_func)("<select name='", 0, output_arg); +	(*output_func)(name, 0, output_arg); +	(*output_func)("'", 0, output_arg); + +	if (strchr(flags, 'm')) +		(*output_func)(" multiple='multiple'", 0, output_arg); +	if (strchr(flags, 'd')) +		(*output_func)(" disabled='disabled'", 0, output_arg); + +	(*output_func)("'>", 0, output_arg); + +	if (!optvalues) +		optvalues=""; + +	while (*optlabels) +	{ +		const char *label_start=optlabels; +		const char *value_start=optvalues; + +		while (*optlabels) +		{ +			if (*optlabels == '\n') +				break; +			++optlabels; +		} + +		while (*optvalues) +		{ +			if (*optvalues == '\n') +				break; +			++optvalues; +		} + +		(*output_func)("<option", 0, output_arg); + +		if (*value_start) +		{ +			if (default_value && +			    optvalues - value_start == strlen(default_value) && +			    strncmp(value_start, default_value, +				    optvalues-value_start) == 0) +			{ +				(*output_func)(" selected='selected'", 0, +					       output_arg); +			} + +			(*output_func)(" value='", 0, output_arg); +			(*output_func)(value_start, optvalues-value_start, +				       output_arg); +			(*output_func)("'", 0, output_arg); +		} +		(*output_func)(">", 0, output_arg); +		(*output_func)(label_start, optlabels-label_start, output_arg); +		(*output_func)("</option>", 0, output_arg); +		if (*optlabels) +			++optlabels; +		if (*optvalues) +			++optvalues; +	} + +	(*output_func)("</select>", 0, output_arg); +} + +static void cnt_bytes(const char *str, size_t cnt, void *arg) +{ +	if (!cnt) +		cnt=strlen(str); + +	*(size_t *)arg += cnt; +} + +static void save_bytes(const char *str, size_t cnt, void *arg) +{ +	char **p=(char **)arg; + +	if (!cnt) +		cnt=strlen(str); + +	memcpy(*p, str, cnt); +	*p += cnt; +} + +char *cgi_select(const char *name, +		 const char *optvalues, +		 const char *optlabels, +		 const char *default_value, +		 size_t list_size, +		 const char *flags) +{ +	size_t cnt=1; +	char *buf; +	char *ptr; + +	if (!flags) +		flags=""; + +	do_cgi_select(name, optvalues, optlabels, default_value, +		      list_size, flags, cnt_bytes, &cnt); + +	buf=malloc(cnt); + +	if (!buf) +		return NULL; + +	ptr=buf; +	do_cgi_select(name, optvalues, optlabels, default_value, +		      list_size, flags, save_bytes, &ptr); +	*ptr=0; +	return buf; +} diff --git a/cgi/cgitextarea.c b/cgi/cgitextarea.c new file mode 100644 index 0000000..e9d814b --- /dev/null +++ b/cgi/cgitextarea.c @@ -0,0 +1,120 @@ +/* +** Copyright 2007 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +/* +*/ + +#include	"cgi.h" +#include	<stdio.h> +#include	<string.h> +#include	<stdlib.h> +#include	<ctype.h> + +extern void cgi_output_unicode_escapes(const unicode_char *value, +				       const char *escapes, +				       void (*output_func)(const char *, +							   size_t, +							   void *), +				       void *output_arg); + +static void do_cgi_textarea(const char *name, +			    int rows, +			    int cols, +			    const unicode_char *value, +			    const char *opts, +			    const char *wrap, +			    void (*output_func)(const char *, size_t, +						void *), +			    void *output_arg) +{ +	(*output_func)("<textarea name='", 0, output_arg); +	(*output_func)(name, 0, output_arg); +	(*output_func)("'", 0, output_arg); + +	if (strchr(opts, 'r')) +		(*output_func)(" readonly='readonly'", 0, output_arg); +	if (strchr(opts, 'd')) +		(*output_func)(" disabled='disabled'", 0, output_arg); + +	(*output_func)("'", 0, output_arg); + +	if (rows) +	{ +		char buf[100]; + +		sprintf(buf, " rows='%d'", rows); + +		(*output_func)(buf, 0, output_arg); +	} + +	if (cols) +	{ +		char buf[100]; + +		sprintf(buf, " cols='%d'", cols); + +		(*output_func)(buf, 0, output_arg); +	} + +	if (wrap) +	{ +		(*output_func)(" wrap='", 0, output_arg); +		(*output_func)(wrap, 0, output_arg); +		(*output_func)("'", 0, output_arg); +	} + +	(*output_func)(">", 0, output_arg); + +	cgi_output_unicode_escapes(value, "<>'&", output_func, output_arg); + +	(*output_func)("</textarea>", 0, output_arg); +} + +static void cnt_bytes(const char *str, size_t cnt, void *arg) +{ +	if (!cnt) +		cnt=strlen(str); + +	*(size_t *)arg += cnt; +} + +static void save_bytes(const char *str, size_t cnt, void *arg) +{ +	char **p=(char **)arg; + +	if (!cnt) +		cnt=strlen(str); + +	memcpy(*p, str, cnt); + +	*p += cnt; +} + +char *cgi_textarea(const char *name, +		   int rows, +		   int cols, +		   const unicode_char *value, +		   const char *wrap, +		   const char *opts) +{ +	size_t cnt=1; +	char *buf; +	char *ptr; + +	if (!opts) +		opts=""; + +	do_cgi_textarea(name, rows, cols, value, opts, wrap, cnt_bytes, &cnt); + +	buf=malloc(cnt); + +	if (!buf) +		return NULL; + +	ptr=buf; +	do_cgi_textarea(name, rows, cols, value, opts, wrap, save_bytes, &ptr); +	*ptr=0; +	return buf; +} diff --git a/cgi/cgiuseragent.c b/cgi/cgiuseragent.c new file mode 100644 index 0000000..e1aa0a2 --- /dev/null +++ b/cgi/cgiuseragent.c @@ -0,0 +1,52 @@ +/* +** Copyright 2000 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +/* +*/ + +#include	"cgi.h" +#include	<stdio.h> +#include	<string.h> +#include	<stdlib.h> +#include	<ctype.h> + +extern void error(const char *); + +int cgi_useragent(const char *p) +{ +	const char *c=getenv("HTTP_USER_AGENT"); + +	for ( ; c && *c; c++) +	{ +		size_t i; + +		if (isalpha((int)(unsigned char)*c)) +			continue; + +		for (i=0; p[i]; i++) +		{ +			int a,b; + +			a=(unsigned char)p[i]; +			b=(unsigned char)c[i+1]; +			if (!b) +				break; + +			a=toupper(a); +			b=toupper(b); +			if (a != b) +				break; +		} + +		if (p[i] == 0) +		{ +			int b=(unsigned char)c[i+2]; + +			if (b == 0 || !isalpha(b)) +				return (1); +		} +	} +	return (0); +} diff --git a/cgi/cgiversion.c b/cgi/cgiversion.c new file mode 100644 index 0000000..265b297 --- /dev/null +++ b/cgi/cgiversion.c @@ -0,0 +1,32 @@ +/* +** Copyright 1998 - 1999 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +/* +*/ +#include	"cgi.h" +#include	<stdlib.h> +#include	<ctype.h> + +void cgiversion(unsigned *major, unsigned *minor) +{ +const char *p=getenv("SERVER_PROTOCOL"); + +	*major=0; +	*minor=0; +	if (!p)	return; +	if ( toupper(*p++) != 'H' || +		toupper(*p++) != 'T' || +		toupper(*p++) != 'T' || +		toupper(*p++) != 'P' || +		*p++ != '/')	return; + +	while (isdigit(*p)) +		*major= *major * 10 + (*p++ - '0'); +	if (*p++ == '.') +	{ +		while (isdigit(*p)) +			*minor= *minor * 10 + (*p++ - '0'); +	} +} diff --git a/cgi/configure.in b/cgi/configure.in new file mode 100644 index 0000000..9169322 --- /dev/null +++ b/cgi/configure.in @@ -0,0 +1,155 @@ +dnl Process this file with autoconf to produce a configure script. +dnl +dnl Copyright 1998 - 2005 Double Precision, Inc.  See COPYING for +dnl distribution information. + +AC_INIT(cgi, 0.10, [courier-users@lists.sourceforge.net]) + +>confdefs.h  # Kill PACKAGE_ macros + +AC_CONFIG_SRCDIR(cgi.c) +AC_CONFIG_AUX_DIR(../..) +AM_INIT_AUTOMAKE([foreign no-define]) + +AM_CONFIG_HEADER(cgi_config.h) + +dnl Checks for programs. +AC_USE_SYSTEM_EXTENSIONS +AC_PROG_CC +AC_PROG_AWK +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_LIBTOOL + +dnl Checks for libraries. + +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS(fcntl.h sys/time.h sys/wait.h sys/select.h sys/uio.h unistd.h) +AC_HEADER_TIME + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_SIZE_T + +AC_CACHE_CHECK([for socklen_t], +        cgi_cv_hassocklen_t, +  +AC_COMPILE_IFELSE([ +AC_LANG_SOURCE( [ +#include <sys/types.h> +#include <sys/socket.h> +  +socklen_t sl_t; +],[ +	accept(0, 0, &sl_t); +])], +	cgi_cv_hassocklen_t=yes, +	cgi_cv_hassocklen_t=no) +) +  +socklen_t="int" +  +if test $cgi_cv_hassocklen_t = yes +then +	: +else +	AC_DEFINE_UNQUOTED(socklen_t, int, [ Default definition for socklen_t ]) +fi + + +dnl Checks for library functions. +AC_CHECK_FUNCS(strdup strncasecmp) + +dnl Other checks + +AC_ARG_WITH(formdata, +	[  --with-formdata                Compile support for multipart/formdata], +	AC_DEFINE_UNQUOTED(CGIFORMDATA, 1, +		[ Whether to generate code to handle multipart/formdata ])) + +AC_ARG_WITH(maxargsize, +	[  --with-maxargsize=nbytes       Limit maximum size of CGI args], +	CFLAGS="$CFLAGS -DCGIMAXARG=$withval") + +AC_ARG_WITH(maxformargsize, +	[  --with-maxformargsize=nbytes   Maximum size of multipart/formdata uploads], +	CFLAGS="$CFLAGS -DCGIMAXFORMDATAARG=$withval") + +AC_TRY_RUN( [ + +#include	<stdio.h> +#include	<stdlib.h> +#include	<limits.h> + +int main() +{ +FILE	*fp=fopen("conftestval", "w"); + +	if (!fp)	exit(1); +	fprintf(fp, "-%lu\n", ULONG_MAX); +	fclose(fp); +	return (0); +} +] +	, [ MAXLONGSIZE=`wc -c conftestval | awk ' { print $1 } '  ` ], +	[ +		AC_MSG_ERROR(Unable to run test program.) +	] , +	[ +		MAXLONGSIZE=60 +		AC_MSG_WARN([Cross compiling, setting MAXLONGSIZE to $MAXLONGSIZE]) +	] +		) + +AC_CACHE_CHECK([how to pass file descriptors], +		    ac_cv_sqwebmail_passfd, + +AC_TRY_COMPILE( [ +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/uio.h> + +int fd; struct msghdr msg; ], +[ +	msg.msg_accrights=(caddr_t)fd; +	msg.msg_accrightslen=sizeof(fd); +], +	ac_cv_sqwebmail_passfd=msg_accrights, + +	AC_TRY_COMPILE( [ +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/uio.h> + +struct msghdr msg; struct cmsghdr cmsg; char buf; +], +[ +              msg.msg_control = &buf; +              msg.msg_controllen = 1; +], +	ac_cv_sqwebmail_passfd=msg_control, +	ac_cv_sqwebmail_passfd=none))) + +if test "$ac_cv_sqwebmail_passfd" = "msg_accrights" +then +	AC_DEFINE_UNQUOTED(CGI_PASSFD_MSGACCRIGHTS,1, +		[Pass file descriptors in msg_accrights]) +fi + +if test "$ac_cv_sqwebmail_passfd" = "msg_control" +then +	AC_DEFINE_UNQUOTED(CGI_PASSFD_MSGCONTROL,1, +		[Pass file descriptors in msg_control]) +fi + + +if test "$GCC" = yes ; then +        CFLAGS="$CFLAGS -Wall" +fi + +CFLAGS="$CFLAGS -I.. -I$srcdir/.." +AC_SYS_LARGEFILE + +AC_DEFINE_UNQUOTED(MAXLONGSIZE, $MAXLONGSIZE, [ Calculate max size of long ]) +AC_OUTPUT(Makefile) | 
