Esempio n. 1
0
static void start_child(unsigned i, char *line, char **cols)
{
int	pipebuf[2];
const char *hostp;
size_t	hostplen;
pid_t	pid;

	hostp=MODULEDEL_HOST(cols);
	for (hostplen=0; hostp[hostplen] &&
		hostp[hostplen] != '\t'; hostplen++)
		;

	if (info[i].host)	free(info[i].host);
	memcpy(info[i].host=courier_malloc(hostplen+1), hostp, hostplen);
	info[i].host[hostplen]=0;

	if (pipe(pipebuf) < 0)	clog_msg_errno();

	pid=module_fork_noblock(0, &i);

	if (pid == 0)
	{
	unsigned	j;
	char	buf[MAXLONGSIZE+1];
	char *p;

		dup2(pipebuf[0], 0);
		close(pipebuf[0]);
		close(pipebuf[1]);
		fclose(childresultpipe);
		dup2(completionpipe[1], 1);
		close(completionpipe[1]);
		close(completionpipe[0]);
		for (j=0; j<module_nchildren; j++)
			if (info[j].cmdpipe >= 0)
				close(info[j].cmdpipe);

		for (j=0; MODULEDEL_HOST(cols)[j]; j++)
			if (MODULEDEL_HOST(cols)[j] == '\t')
			{
				MODULEDEL_HOST(cols)[j]=0;
				break;
			}

		p=buf+MAXLONGSIZE;
		*p=0;
		do
		{
			* --p = '0' + (i % 10);
		} while ( (i=i / 10) != 0);

		execl("courieresmtp", "courieresmtp", p,
			MODULEDEL_HOST(cols), (char *)0);
		clog_msg_errno();
		_exit(1);
	}
	info[i].pid=pid;
	close (pipebuf[0]);
	info[i].cmdpipe=pipebuf[1];
}
Esempio n. 2
0
void SubmitFile::MessageStart()
{
	bytecount=0;
	sizelimit=config_sizelimit();
	addrlist_map.clear();
	addrlist_gdbm.Close();
	if (ctlfile.fd() < 0)
		openctl();
	unlink(namefile("D", 1).c_str());	// Might be the GDBM file

	int nfd=open(namefile("D",0).c_str(),
		     O_RDWR | O_CREAT | O_TRUNC, PERMISSION);
	if (nfd < 0)
	{
		clog_msg_start_err();
		clog_msg_str(namefile("D",0).c_str());
		clog_msg_str(": ");
		clog_msg_errno();
	}

	datfile.fd(nfd);

	rwrfcptr=rfc2045_alloc_ac();

	if (rwrfcptr == NULL)
		clog_msg_errno();
	diskfull=checkfreespace(&diskspacecheck);
}
Esempio n. 3
0
void SubmitFile::closectl()
{
	const char *p=config_get_local_vhost();

	static const char *env_vars[]={
		"RELAYCLIENT",
		"TCPREMOTEIP",
		0,
	};

	if (p && *p)
		ctlfile << COMCTLFILE_VHOST << p << std::endl;

	if (security.size() > 0)
		ctlfile << COMCTLFILE_SECURITY << security
			<< std::endl;
	if (verpflag)
		ctlfile << COMCTLFILE_VERP << std::endl;

	if (warntime == 0)
		ctlfile << COMCTLFILE_WARNINGSENT << std::endl;

	if (authname)
		ctlfile << COMCTLFILE_AUTHNAME << authname << std::endl;

	for (size_t i=0; env_vars[i]; ++i)
	{
		const char *p=getenv(env_vars[i]);

		if (p)
			ctlfile << COMCTLFILE_ENVVAR << env_vars[i] << "="
				<< p << std::endl;
	}

	ctlfile << COMCTLFILE_MSGSOURCE << msgsource << std::endl
		<< COMCTLFILE_EXPIRES << submit_time + queuetime << std::endl
		<< COMCTLFILE_FAXEXPIRES << submit_time + faxqueuetime << std::endl
		<< COMCTLFILE_WARNING << submit_time + warntime << std::endl << std::flush;

	if (suppressbackscatter)
		ctlfile << COMCTLFILE_TRACK << std::endl;

	if (ctlfile.fail())	clog_msg_errno();
#if EXPLICITSYNC
	ctlfile.sync();
	fsync(ctlfile.fd());
#endif
	ctlfile.close();
	if (ctlfile.fail())	clog_msg_errno();
}
Esempio n. 4
0
int SubmitFile::ChkRecipient(const char *key)
{
	receipient=key;

	// Ignore duplicate addresses.

	if (addrlist_gdbm.IsOpen())
	{
		if (addrlist_gdbm.Exists(receipient))
			return (-1);	/* Already exists */

		if (addrlist_gdbm.Store(receipient, "", "R"))
			clog_msg_errno();
	}
	else
	{
		if (addrlist_map.find(receipient) != addrlist_map.end())
			return (-1);	/* Already exists */
		addrlist_map.insert(receipient);

		if (addrlist_map.size() > SPILLLEVEL)
		{
//
// Store the GDBM file in the name that's reserved for the first hard link
// link to the message file (which is never used).
//
			std::string gdbmname=namefile("D",1);

			if (addrlist_gdbm.Open(gdbmname.c_str(), "N"))
			{
				clog_msg_start_err();
				clog_msg_str(gdbmname.c_str());
				clog_msg_str(": ");
				clog_msg_errno();
			}

			std::set<std::string>::iterator b, e;

			for (b=addrlist_map.begin(),
				     e=addrlist_map.end(); b != e; ++b)
			{
				if (addrlist_gdbm.Store(*b, std::string(""),
							"R"))
					clog_msg_errno();
			}
			addrlist_map.clear();
		}
	}
	return (0);
}
Esempio n. 5
0
void SubmitFile::trapsignals()
{
	signal(SIGINT, sighandler);
	signal(SIGTERM, sighandler);
	signal(SIGHUP, sighandler);
	signal(SIGALRM, sighandler);
	if (atexit(SubmitFile::interrupt)) clog_msg_errno();
}
Esempio n. 6
0
	/* Common rewrite tail function to convert RFC822 tokens back into
	** a text string.
	*/
void rw_rewrite_print(struct rw_info *info)
{
char	*p=rfc822_gettok(info->ptr);

	if (!p)		clog_msg_errno();

	( (struct rw_info_rewrite *)info->udata)->buf=p;
}
Esempio n. 7
0
int main(int argc, char **argv)
{
	struct moduledel *p;
	int waitstat;
	const char *cp;

	clog_open_syslog("courierfax");
	if (chdir(getenv("COURIER_HOME")))
		clog_msg_errno();

	cp=getenv("MAXDELS");
	if (!cp || atoi(cp) != 1)
	{
		clog_msg_start_err();
		clog_msg_str("FATAL: courierfax module misconfiguration, MAXDELS must be 1");
		clog_msg_send();
		exit(0);
	}

	cp=getenv("MAXRCPT");
	if (!cp || atoi(cp) != 1)
	{
		clog_msg_start_err();
		clog_msg_str("FATAL: courierfax module misconfiguration, MAXRCPT must be 1");
		clog_msg_send();
		exit(0);
	}

	module_init(0);
	while ((p=module_getdel()) != NULL)
	{
		pid_t	pid;
		unsigned delid;

		delid=atol(p->delid);

		if ((pid=module_fork(delid, 0)) == -1)
		{
			clog_msg_prerrno();
			module_completed(delid, delid);
			continue;
		}

		if (pid == 0)
		{
			fax(p);
			exit(0);
		}
	}

	module_signal(SIGTERM);
	signal(SIGCHLD, SIG_DFL);
	signal(SIGALRM, killit);
	alarm(5);
	wait(&waitstat);
	alarm(0);
	return (0);
}
Esempio n. 8
0
int	AliasSearch::Search(const char *address, AliasHandler &h)
{
char	*p=0;
const char *q;
char	*hostdomain=0;

	q=strrchr(address, '@');

	/* islocal checks both local domains, and hosted domains,
	** we want to replace domain with 'me' only for local domains.
	*/
	if (!q || (config_islocal(q+1, &hostdomain) && hostdomain == 0))
					/*
					** Make sure we look for aliases for
					** "me"
					*/
	{
		const char *me=config_defaultdomain();
		char *r;

		if (!q)
			q=address+strlen(address);

		p=(char *)courier_malloc(q-address+2+strlen(me));
		if (!p)	clog_msg_errno();
		memcpy(p, address, q-address);
		strcat(strcpy(&p[q-address], "@"), me);
		r=udomainlower(p);	/* For stupid people */
		free(p);
		p=r;
		address=p;
	}
	if (hostdomain)	free(hostdomain);

	if (Try(module_record, address, h) == 0 &&
		TryVirtual(module_record, address, &h) == 0 &&
		Try(local_record, address, h) == 0 &&
		TryVirtual(local_record, address, &h) == 0)
	{
		int rc;

#if HAVE_LDAP
		if (p)
			*strrchr(p, '@')=0;
		// Strip local domain from addresses passed to aliasd

		rc=TryAliasD(address, &h);
#else
		rc=1;
#endif
		if (p)	free(p);
		return (rc);
	}
	if (p)	free(p);
	return (0);
}
Esempio n. 9
0
struct rfc822t *rw_rewrite_tokenize(const char *address)
{
struct rfc822t *tokens=rfc822t_alloc_new(address, NULL, NULL);
int	i;

	if (!tokens)	clog_msg_errno();
	for (i=1; i<tokens->ntokens; i++)
		tokens->tokens[i-1].next=tokens->tokens+i;
	return (tokens);
}
Esempio n. 10
0
void SubmitFile::AddReceipient(const char *r,
	const char *orig, const char *dsn, int delivered)
{
	// If # of receipients in the current control file exceeds the
	// defined batch size, close the current control file.

	if (rcptcount >= batchsize)
	{
		closectl();
//
// The first time we create another control file, rename the first
// control file to Cnnnn.1, which is a flag not to process Cnnnn.2, .3, etc...
//
// Cnnnn.2, .3, ... will be processed only after Cnnnn.1 is renamed to Cnnnn
//
		if (num_control_files_created == 1)
		{
			std::string p=name1stctlfile();
			std::string q=namefile("C", 1);

			if (rename(p.c_str(), q.c_str()))
			{
				clog_msg_start_err();
				clog_msg_str(p.c_str());
				clog_msg_str(" -> ");
				clog_msg_str(q.c_str());
				clog_msg_str(": ");
				clog_msg_errno();
			}
		}
	}

	// Open a new control file, if necessary.

	if (ctlfile.fd() < 0)
		openctl();
	ctlfile << COMCTLFILE_RECEIPIENT << r << std::endl
		<< COMCTLFILE_ORECEIPIENT << (orig ? orig:"") << std::endl
		<< COMCTLFILE_DSN << (dsn ? dsn:"") << std::endl;

	if (delivered)
	{
		ctlfile << COMCTLFILE_DELINFO << rcptcount << ' '
			<< COMCTLFILE_DELINFO_REPLY
			<< " 250 Ok - delivered to alias." << std::endl
			<< COMCTLFILE_DELSUCCESS << rcptcount << ' '
				<< submit_time << " r" << std::endl;
	}
	ctlfile << std::flush;
	++rcptcount;
	if (bofh_chkspamtrap(r))
	{
		spamtrap_flag=1;
	}
}
Esempio n. 11
0
static void found_module(struct rw_info *rwi, struct rw_transport *t,
	const struct rfc822token *host, const struct rfc822token *addr)
{
struct getdelinfo_struct *p=(struct getdelinfo_struct *)rwi->udata;

	if (!t->udata)	return;
	p->drvinfop=(drvinfo *)t->udata;

	char *s=rfc822_gettok(host);

	if (!s)	clog_msg_errno();
	p->host=s;
	free(s);

	s=rfc822_gettok(addr);

	if (!s) clog_msg_errno();
	p->addr=s;
	free(s);
}
Esempio n. 12
0
void AliasSearch::Open( const char *module )
{
char	*p;

	modulename="local";

	if (module)
	{
		modulename=SYSCONFDIR "/aliases-";

		modulename += module;
		modulename += ".dat";
		if (module_alias.Open(modulename, "R") && errno != ENOENT)
			clog_msg_errno();
		modulename=module;
	}

	p=config_localfilename("aliases.dat");

	if (local_alias.Open(p, "R") && errno != ENOENT)
		clog_msg_errno();
	free(p);
}
Esempio n. 13
0
static void do_rw_rewrite_chksyn_print(struct rw_info *info,
				       struct rfc822token *t)
{
	if (rw_syntaxchk(t))
	{
	static const char errmsg[]="Syntax error: ";
	char	*addr=rfc822_gettok(info->ptr);
	char	*buf;

		if (!addr)	clog_msg_errno();
		buf=courier_malloc(strlen(addr)+sizeof(errmsg));
		strcat(strcpy(buf, errmsg), addr);
		free(addr);
		(*info->err_func)(553, buf, info);
		free(buf);
	}
	else
		rw_rewrite_print(info);
}
Esempio n. 14
0
void SubmitFile::Message(const char *p)
{
size_t	l=strlen(p);

	if (sizelimit && bytecount > sizelimit)	return;
	bytecount += l;
	if (sizelimit && bytecount > sizelimit)	return;

	if (diskfull)	return;
	datfile << p;
	if (l > diskspacecheck)
	{
		if (checkfreespace(&diskspacecheck))
		{
			diskfull=1;
			return;
		}
		diskspacecheck += l;
	}
	diskspacecheck -= l;

	if (datfile.fail())	clog_msg_errno();
	rfc2045_parse(rwrfcptr, p, strlen(p));
}
Esempio n. 15
0
void drvinfo::init()
{
unsigned	cnt, i;
struct	rw_transport *p;

	module_dsn=0;
	queuelo=0;
	for (cnt=0, p=rw_transport_first; p; p=p->next)
		++cnt;
	if ((modules=new drvinfo[cnt]) == 0)	clog_msg_errno();
	cnt=0;

	for (p=rw_transport_first; p; p=p->next)
	{
	char	*namebuf=(char *)courier_malloc(
		sizeof( SYSCONFDIR "/module.")+strlen(p->name));

		strcat(strcpy(namebuf, SYSCONFDIR "/module."),
				p->name);

	FILE	*config=fopen(namebuf, "r");

		if (!config)
		{
			clog_msg_start_err();
			clog_msg_str("Cannot open ");
			clog_msg_str(namebuf);
			clog_msg_send();
			exit(1);
		}
		free(namebuf);
		
	unsigned maxdels=1;
	unsigned maxhost=1;
	unsigned maxrcpt=1;
	char	*prog=0;
	char	buf[BUFSIZ];

		while (fgets(buf, sizeof(buf), config) != 0)
		{
		char	*p;

			if ((p=strchr(buf, '#')) != 0)	*p=0;
			p=strtok(buf, " \t\r\n=");
			if (strcmp(p, "MAXDELS") == 0)
			{
				p=strtok(NULL, " \t\r\n=");
				if (p)	maxdels=atoi(p);
			}
			else if (strcmp(p, "MAXHOST") == 0)
			{
				p=strtok(NULL, " \t\r\n=");
				if (p)	maxhost=atoi(p);
			}
			else if (strcmp(p, "MAXRCPT") == 0)
			{
				p=strtok(NULL, " \t\r\n=");
				if (p)	maxrcpt=atoi(p);
			}
			else if (strcmp(p, "PROG") == 0 && !prog)
			{
				p=strtok(NULL, "\t\r\n=");
				if (p)
				{
					prog=(char *)
						courier_malloc(strlen(p)+1);
					strcpy(prog, p);
				}
			}
		}
		fclose(config);
		if (!prog)	continue;	// Input only module

		modules[cnt].module=p;
		p->udata=(void *)&modules[cnt];
		modules[cnt].delinfo_list.resize(maxdels);
		modules[cnt].hosts_list.resize(maxdels);
		queuelo += maxdels;
		modules[cnt].maxhost=maxhost;
		modules[cnt].maxrcpt=maxrcpt;
		modules[cnt].delpfreefirst=0;

		if (strcmp(p->name, DSN) == 0)
			module_dsn= &modules[cnt];

		for (i=0; i<maxdels; i++)
		{
			modules[cnt].delinfo_list[i].delid=i;
			modules[cnt].delinfo_list[i].freenext=
				modules[cnt].delpfreefirst;
			modules[cnt].delpfreefirst=
				&modules[cnt].delinfo_list[i];
		}

		modules[cnt].hdlvrpfree=0;
		for (i=0; i<maxdels; i++)
		{
			modules[cnt].hosts_list[i].next=
				modules[cnt].hdlvrpfree;
			modules[cnt].hdlvrpfree=&modules[cnt].hosts_list[i];
		}
		modules[cnt].hdlvrpfirst=0;
		modules[cnt].hdlvrplast=0;

	int	pipe0[2], pipe1[2];

		if (pipe(pipe0) || pipe(pipe1))
			clog_msg_errno();

		switch (modules[cnt].module_pid=fork())	{
		case 0:
#if 0
// replaced by close-on-exec, below

			for (i=cnt; i; )
			{
				--i;
				fclose(modules[i].module_to);
				close(modules[i].module_from.fd);
			}
#endif
			close(pipe0[1]);
			close(pipe1[0]);
			dup2(pipe0[0], 0);
			dup2(pipe1[1], 1);
			close(pipe0[0]);
			close(pipe1[1]);
			signal(SIGCHLD, SIG_DFL);

			if (chdir(MODULEDIR) ||
				chdir(modules[cnt].module->name))
			{
				clog_msg_start_err();
				clog_msg_str(MODULEDIR "/");
				clog_msg_str(modules[cnt].module->name);
				clog_msg_str(" does not exist.");
				clog_msg_send();
				clog_msg_errno();
			}

			{
			char maxdels_buf[MAXLONGSIZE+15];
			char maxhost_buf[MAXLONGSIZE+15];
			char maxrcpt_buf[MAXLONGSIZE+15];
			const char *sh=getenv("SHELL");

				sprintf(maxdels_buf, "MAXDELS=%ld",
					(long)maxdels);
				sprintf(maxhost_buf, "MAXHOST=%ld",
					(long)maxhost);
				sprintf(maxrcpt_buf, "MAXRCPT=%ld",
					(long)maxrcpt);

				putenv(maxdels_buf);
				putenv(maxhost_buf);
				putenv(maxrcpt_buf);

			const char *ch=courierdir();
			char	*p=(char *)courier_malloc(strlen(ch)+
					sizeof("COURIER_HOME="));

				strcat(strcpy(p,"COURIER_HOME="), ch);
				putenv(p);

				if (!sh)	sh="/bin/sh";
				execl(sh, sh, "-c", prog, (char *)0);
				clog_msg_start_err();
				clog_msg_str(MODULEDIR "/");
				clog_msg_str(modules[cnt].module->name);
				clog_msg_str(": ");
				clog_msg_str(prog);
				clog_msg_send();
				clog_msg_errno();
			}
		case -1:
			clog_msg_errno();
			break;
		}

		close(pipe0[0]);
		close(pipe1[1]);

		if (fcntl(pipe0[1], F_SETFD, FD_CLOEXEC) ||
			fcntl(pipe1[0], F_SETFD, FD_CLOEXEC))
			clog_msg_errno();

		if ((modules[cnt].module_to=fdopen(pipe0[1], "w")) == NULL)
			clog_msg_errno();

		mybuf_init( &modules[cnt].module_from, pipe1[0] );

		clog_msg_start_info();
		clog_msg_str("Started ");
		clog_msg_str(prog);
		clog_msg_str(", pid=");
		clog_msg_int(modules[cnt].module_pid);
		clog_msg_str(", maxdels=");
		clog_msg_int(maxdels);
		clog_msg_str(", maxhost=");
		clog_msg_int(maxhost);
		clog_msg_str(", maxrcpt=");
		clog_msg_int(maxrcpt);
		clog_msg_send();
		free(prog);
		cnt++;
	}
	nmodules=cnt;

	if (queuelo < 200)	queuelo=200;

char	*cfname=config_localfilename("queuelo");
char	*conf=config_read1l(cfname);

	if (conf)
	{
		queuelo=atoi(conf);
		free(conf);
	}
	free(cfname);
	if (queuelo < 20)	queuelo=20;

	cfname=config_localfilename("queuehi");
	conf=config_read1l(cfname);
	if (conf)
	{
		queuehi=atoi(conf);
		free(conf);
	}
	else
		queuehi=queuelo < 500 ? queuelo * 2:queuelo+1000;
	if (queuehi < queuelo)	queuehi=queuelo;
	free(cfname);

	clog_msg_start_info();
	clog_msg_str("queuelo=");
	clog_msg_int(queuelo);
	clog_msg_str(", queuehi=");
	clog_msg_int(queuehi);
	clog_msg_send();

	if (module_dsn == 0)
	{
		clog_msg_start_err();
		clog_msg_str("Driver dsn not found.");
		clog_msg_send();
		exit(1);
	}
}
Esempio n. 16
0
static char *rewrite_from(const char *oldfrom, const char *newuser,
	const char *newhost, const char *newname)
{
struct rfc822t *rfct;
struct rfc822a *rfca;
struct rfc822t *usert, *hostt, *namet;
struct rfc822token attoken, **tp;
char	*p;
const char *q;
char	*gecosname=0;

	if (!oldfrom)
	{
	char	*p=courier_malloc(
			(newuser ? strlen(newuser):0)+
			(newhost ? strlen(newhost):0)+4);
		strcpy(p, "<");
		if (newuser)	strcat(p, newuser);
		if (newuser && newhost)
			strcat(strcat(p, "@"), newhost);
		strcat(p, ">");
		if (newname)
		{
		char *q, *r;

			namet=tokenize_name(newname);
			q=rfc822_gettok(namet->tokens);
			rfc822t_free(namet);
			r=courier_malloc(strlen(p)+strlen(q)+2);
			strcat(strcat(strcpy(r, q), " "), p);
			free(p);
			p=r;
			free(q);
		}
		return (p);
	}

	if ((rfct=rfc822t_alloc_new(oldfrom, NULL, NULL)) == 0 ||
		(rfca=rfc822a_alloc(rfct)) == 0)
	{
		clog_msg_errno();
		return(0);
	}

	if ((q=env("MAILNAME")) || (q=env("NAME")))
		newname=q;

	if (!newname && rfca->naddrs == 0)
		newname=gecosname=get_gecos();

	if ((rfca->naddrs == 0 || rfca->addrs[0].tokens == 0) && newuser == 0)
	{
	struct	passwd *pw=mypwd();

		if (pw)	newuser=pw->pw_name;
	}

	namet=newname ? tokenize_name(newname):0;
	usert=newuser ? rw_rewrite_tokenize(newuser):0;
	hostt=newhost ? rw_rewrite_tokenize(newhost):0;

	if (rfca->naddrs == 0 || rfca->addrs[0].tokens == 0)
	{
	struct rfc822addr a;
	struct rfc822a	fakea;

		if (hostt)
		{
		struct rfc822token *t;

			attoken.token='@';
			attoken.next=hostt->tokens;
			attoken.ptr=0;
			attoken.len=0;

			for (t=usert->tokens; t->next; t=t->next)
				;
			t->next=&attoken;
		}
		fakea.naddrs=1;
		fakea.addrs= &a;

		if (!namet)	namet=tokenize_name("");
		if (!usert)	usert=rw_rewrite_tokenize("");
		a.name=namet->tokens;
		a.tokens=usert->tokens;
		p=rfc822_getaddrs(&fakea);
	}
	else
	{
	struct	rfc822token *t, *u;

		rfca->naddrs=1;
		if (usert)
		{
			for (t=rfca->addrs[0].tokens; t; t=t->next)
				if (t->token == '@')	break;
			
			for (u=usert->tokens; u->next; u=u->next)
				;
			u->next=t;
			rfca->addrs[0].tokens=usert->tokens;;
		}

		if (hostt && rfca->addrs[0].tokens)
		{
			for (tp= &rfca->addrs[0].tokens; *tp;
				tp= &(*tp)->next)
				if ( (*tp)->token == '@')	break;
			*tp=&attoken;
			attoken.token='@';
			attoken.next=hostt->tokens;
			attoken.ptr=0;
			attoken.len=0;
		}
		if (namet)
			rfca->addrs[0].name=namet->tokens;

		p=rfc822_getaddrs(rfca);
	}

	if (!p)	clog_msg_errno();

	if (usert)	rfc822t_free(usert);
	if (hostt)	rfc822t_free(hostt);
	if (namet)	rfc822t_free(namet);
	rfc822t_free(rfct);
	rfc822a_free(rfca);
	if (gecosname)	free(gecosname);
	return (p);
}
Esempio n. 17
0
int main(int argc, char **argv)
{
    if (argc > 1 && strcmp(argv[1], "--version") == 0)
    {
        printf("%s\n", COURIER_COPYRIGHT);
        exit(0);
    }

    if (chdir(courierdir()))
    {
        perror("chdir");
        return (1);
    }
    if (argc < 2)	return (0);

    if (strcmp(argv[1], "stop") == 0)
    {
        int	fd;

        trigger(TRIGGER_STOP);

        /* Wait until the exclusive lock goes away: */

        signal(SIGHUP, SIG_DFL);
        if ((fd=open(TMPDIR "/courierd.lock", O_RDWR|O_CREAT, 0600))
                < 0)	clog_msg_errno();

        alarm(15);	/* But abort after 15 seconds. */

        ll_lock_ex(fd);
        return (0);
    }

    if (strcmp(argv[1], "restart") == 0)
    {
        trigger(TRIGGER_RESTART);
        return (0);
    }

    if (strcmp(argv[1], "flush") == 0)
    {
        ino_t	n;
        struct	ctlfile	ctf;

        if (getuid())
        {
            /*
            ** We'll fail trying to open the pipe anyway, but let's
            ** give a meaningful error message now.
            */
            fprintf(stderr,
                    "courier flush can be executed only by the superuser.\n");
            exit(1);
        }

        if (argc < 3)
        {
            trigger(TRIGGER_FLUSH);	/* Everything */
            exit(0);
        }

        if (comparseqid(argv[2], &n) == 0 &&
                ctlfile_openi(n, &ctf, 1) == 0)
        {
            int c=ctlfile_searchfirst(&ctf, COMCTLFILE_MSGID);

            if (c >= 0 && strcmp(ctf.lines[c]+1, argv[2]) == 0)
            {
                char	*s=courier_malloc(sizeof(TRIGGER_FLUSHMSG)+1+
                                          strlen(argv[2]));

                strcat(strcat(strcpy(s, TRIGGER_FLUSHMSG),
                              argv[2]), "\n");
                trigger(s);
                ctlfile_close(&ctf);
                return (0);
            }
            ctlfile_close(&ctf);
        }
        fprintf(stderr, "No such message.\n");
        exit(1);
        return (1);
    }

    /* Might as well... */

    if (strcmp(argv[1], "start") == 0)
    {
        pid_t	p;
        int	waitstat;
        char	dummy;

        /*
        ** Ok, courierd will close file descriptor 3 when it starts, so we
        ** put a pipe on there, and wait for it to close.
        */
        int	pipefd[2];

        close(3);
        if (open("/dev/null", O_RDONLY) != 3 || pipe(pipefd))
        {
            fprintf(stderr, "Cannot open pipe\n");
            exit(1);
        }

        if (getuid())
        {
            /*
            ** We'll fail trying to execute courierd anyway, but let's
            ** give a meaningful error message now.
            */
            fprintf(stderr, "courier start can be executed only by the superuser.\n");
            return (1);
        }
        signal(SIGCHLD, SIG_DFL);
        while ((p=fork()) == -1)
        {
            perror("fork");
            sleep(10);
        }
        if (p == 0)
        {
            dup2(pipefd[1], 3);
            close(pipefd[1]);
            close(pipefd[0]);
            while ((p=fork()) == -1)
            {
                perror("fork");
                sleep(10);
            }
            if (p == 0)
            {
                /*
                ** stdin from the bitbucket.  stdout to
                ** /dev/null, or the bitbucket.
                */

                signal(SIGHUP, SIG_IGN);
                close(0);
                open("/dev/null", O_RDWR);
                dup2(0, 1);
                dup2(0, 2);
                /* See if we can disconnect from the terminal */

#ifdef	TIOCNOTTY
                {
                    int fd=open("/dev/tty", O_RDWR);

                    if (fd >= 0)
                    {
                        ioctl(fd, TIOCNOTTY, 0);
                        close(fd);
                    }
                }
#endif
                /* Remove any process groups */

#if	HAVE_SETPGRP
#if	SETPGRP_VOID
                setpgrp();
#else
                setpgrp(0, 0);
#endif
#endif
                execl( DATADIR "/courierctl.start",
                       "courierctl.start", (char *)0);
                perror("exec");
                _exit(1);
            }
            _exit(0);
        }
        close(pipefd[1]);
        while (wait(&waitstat) != p)
            ;
        if (read(pipefd[0], &dummy, 1) < 0)
            ; /* ignore */
        close(pipefd[0]);
        close(3);
        return (0);
    }

    if (strcmp(argv[1], "clear") == 0 && argc > 2)
    {
        libmail_changeuidgid(MAILUID, MAILGID);

        if (strcmp(argv[2], "all") == 0)
        {
            courier_clear_all();
        }
        else
        {
            track_save(argv[2], TRACK_ADDRACCEPTED);
            printf("%s cleared.\n", argv[2]);
        }
        return (0);
    }

    if (argc > 2 && strcmp(argv[1], "show") == 0 &&
            strcmp(argv[2], "all") == 0)
    {
        libmail_changeuidgid(MAILUID, MAILGID);
        courier_show_all();
    }

    return (0);
}
Esempio n. 18
0
int main(int argc, char **argv)
{
struct moduledel *p;

	clog_open_syslog("courierlocal");

	if (chdir(courier_home=getenv("COURIER_HOME")))
		clog_msg_errno();

	if (atol(getenv("MAXRCPT")) > 1)
	{
		clog_msg_start_err();
		clog_msg_str("Invalid configuration in config, set MAXRCPT=1");
		clog_msg_send();
		exit(1);
	}

	module_init(0);

	module_delivery_timeout(config_readtime("localtimeout", 15*60));

	while ((p=module_getdel()) != NULL)
	{
	unsigned delid=atol(p->delid);
	unsigned rcptnum;
	struct ctlfile ctf;
	int	pipe1[2], pipe2[2];
	pid_t	pid;
	int datfd;
	struct stat stat_buf;

		pid=module_fork(delid, 0);
		if (pid < 0)
		{
			clog_msg_prerrno();
			module_completed(delid, delid);
			continue;
		}

		if (pid)	continue;

#if     HAVE_SETPGRP
#if     SETPGRP_VOID
		setpgrp();
#else
		setpgrp(0, 0);
#endif
#endif

		if (p->nreceipients != 1)
		{
			clog_msg_start_err();
			clog_msg_str("Invalid message from courierd.");
			clog_msg_send();
			_exit(0);
		}

		rcptnum=atol(p->receipients[0]);
		if (ctlfile_openi(p->inum, &ctf, 0))
		{
			clog_msg_errno();
			_exit(0);
		}

		if (pipe(pipe1) < 0 || pipe(pipe2) < 0
		    || (pid=fork()) < 0)
		{
			clog_msg_prerrno();
			ctlfile_append_reply(&ctf, rcptnum,
				"Can't run courierdeliver.",
				COMCTLFILE_DELDEFERRED, 0);
			ctlfile_close(&ctf);
			_exit(0);
			return (0);
		}

		if ((datfd=open(qmsgsdatname(p->inum), O_RDONLY)) < 0)
		{
			clog_msg_prerrno();
			ctlfile_append_reply(&ctf, rcptnum,
					     "Unable to read message file.",
					     COMCTLFILE_DELDEFERRED, 0);
			ctlfile_close(&ctf);
			_exit(0);
			return (0);
		}

		if (pid == 0)
		{
		const char *host, *homedir, *maildir, *quota;
		char	*buf, *s;

		char	*username, *ext;
		uid_t	u;
		gid_t	g;

			close(pipe1[0]);
			close(pipe2[0]);
			dup2(pipe2[1], 2);
			close(pipe2[1]);
			dup2(pipe1[1], 1);
			close(pipe1[1]);
			close(0);
			if (dup(datfd) != 0)
			{
				clog_msg_start_err();
				clog_msg_str("Unable to read message file.");
				clog_msg_send();
				_exit(EX_TEMPFAIL);
			}
			close(ctf.fd);
			close(datfd);

			/* Contents of host: */
			/* acct!ext!uid!gid!homedir!maildir!quota */

			host=p->host;

			buf=strdup(host);
			if (!buf)
			{
				clog_msg_prerrno();
				_exit(EX_TEMPFAIL);
			}

			s=strchr(buf, '!');
			username=buf;
			if (s)	*s++=0;
			ext=s;
			if (s)	s=strchr(s, '!');
			if (s)	*s++=0;

			u=0;
			while (s && *s != '!')
			{
				if (isdigit((int)(unsigned char)*s))
					u=u*10 + (*s - '0');
				++s;
			}
			if (s)	*s++=0;
			g=0;
			while (s && *s != '!')
			{
				if (isdigit((int)(unsigned char)*s))
					g=g*10 + (*s - '0');
				++s;
			}

			if (s)	*s++=0;

			homedir=s;

			if (s)	s=strchr(s, '!');
			if (s)	*s++=0;

			maildir=s;

			if (s)	s=strchr(s, '!');
			if (s)	*s++=0;

			quota=s;
			
			if (!s)
			{
				clog_msg_start_err();
				clog_msg_str("Invalid local recipient address.");
				clog_msg_send();
				_exit(EX_TEMPFAIL);
			}

			if (chdir(homedir))
			{
				clog_msg_str(homedir);
				clog_msg_str(": ");
				clog_msg_prerrno();
				_exit(EX_TEMPFAIL);
			}

			libmail_changeuidgid(u, g);

			execl( MODULEDIR "/local/courierdeliver",
				"courierdeliver",
				username,
				homedir,
				ext,
				ctf.receipients[rcptnum],
				verp_getsender(&ctf, ctf.receipients[rcptnum]),
				quota,
				maildir,
				(const char *)0);

			clog_msg_start_err();
			clog_msg_prerrno();
			clog_msg_send();
			_exit(EX_TEMPFAIL);
		}

		close(pipe1[1]);
		close(pipe2[1]);

		libmail_changeuidgid(MAILUID, MAILGID);
		if (fstat(datfd, &stat_buf) == 0)
			ctf.msgsize=stat_buf.st_size;

		close(datfd);
		wait_delivery(pid, &ctf, rcptnum, pipe2[0], pipe1[0],
				p->host, p->receipients[1]);
		ctlfile_close(&ctf);
		_exit(0);
	}
	return (0);
}
Esempio n. 19
0
void SubmitFile::do_datafilter( unsigned &last_error, int &flag, int fd,
				struct rw_transport *driver,
				std::string host,
				std::string address,
				unsigned rcptnum,

	unsigned num_control_file,
	unsigned num_receipient,

	const char *okmsg,
	unsigned nrcpts)
{
char	buf[2048];
int	ctf;
int	rc;

	if (driver->rw_ptr->filter_msg == 0)	return;

	buf[0]=0;

	if (lseek(fd, 0L, SEEK_SET) < 0)
		clog_msg_errno();

	// Call the driver's filter function.

	rc=driver->rw_ptr->filter_msg
		? (*driver->rw_ptr->filter_msg)(sending_module, fd,
						host.c_str(),
						address.c_str(),
						sender.c_str(),
						buf, sizeof(buf)):0;
	if (rc == 0)	return;

	if (buf[0] == 0)	// Error but no msg, make one up
		strcpy(buf, "Access denied.");

	ctf=open ( (num_control_files_created == 1 ?
		    name1stctlfile(): namefile( "C", num_control_file+1))
		   .c_str(), O_WRONLY|O_APPEND);
	if (ctf < 0)	clog_msg_errno();

	/*
	** Mark the recipient as delivered, so no more processing is
	** done.
	*/
	ctlfile_append_replyfd(ctf, num_receipient,
		buf, COMCTLFILE_DELSUCCESS, 0);
	close(ctf);

	/*
	** We are now required to return an EXDATA extended error.  If there
	** were any good recipients up until now, we need to return an OK
	** message for those recipients.
	*/

	while (last_error < rcptnum)
	{
		print_xerror(0, okmsg, 0);
		++last_error;
	}

	print_xerror( address.c_str(), buf, rcptnum + 1 == nrcpts);
	++last_error;
	flag=1;
}
Esempio n. 20
0
int SubmitFile::datafilter(const char *datfilename, unsigned nrcpts,
				const char *okmsg)
{
int	fd=open(datfilename, O_RDONLY);
unsigned last_error=0;
int	flag=0;

	if (fd < 0)	clog_msg_errno();

	if (rcptfilterlist_file.is_open())
	{
		// List of receipients was large enough to be dumped into a
		// file.

		rcptfilterlist_file.seekg(0);
		if (rcptfilterlist_file.bad())
			clog_msg_errno();

		// Read recipient list from the dump file, and filter each
		// one.

		RcptFilterInfo r;
		struct rw_transport *rw;
		std::string buf;

		while (!std::getline(rcptfilterlist_file, buf).fail())
		{
			if (sscanf(buf.c_str(), "%u",
				   &r.num_control_file) != 1
			    || std::getline(rcptfilterlist_file, buf).fail()
			    || sscanf(buf.c_str(), "%u",
				      &r.num_receipient) != 1
			    || std::getline(rcptfilterlist_file, buf).fail())
				clog_msg_errno();

			for (rw=rw_transport_first; rw; rw=rw->next)
				if (rw->name == buf)
					break;
			if (!rw)	clog_msg_errno();
			r.driver=rw;
			if ( std::getline(rcptfilterlist_file, r.host).fail()
			     || std::getline(rcptfilterlist_file,
					     r.address).fail()
			     || std::getline(rcptfilterlist_file, buf).fail()
			     || sscanf(buf.c_str(), "%u",
				       &r.rcptnum) != 1)
				clog_msg_errno();

			do_datafilter(last_error, flag, fd,
				      r.driver,
				      r.host,
				      r.address,
				      r.rcptnum,

				      r.num_control_file,
				      r.num_receipient,

				      okmsg, nrcpts);
		}
		if ( rcptfilterlist_file.bad())
			clog_msg_errno();
		rcptfilterlist_file.close();
	}
	else
	{
		std::list<RcptFilterInfo>::iterator ab, ae;

		for (ab=rcptfilterlist.begin(),
			     ae=rcptfilterlist.end(); ab != ae; ++ab)
		{
			RcptFilterInfo &r= *ab;

			do_datafilter(last_error, flag, fd,
				      r.driver,
				      r.host,
				      r.address,
				      r.rcptnum,

				      r.num_control_file,
				      r.num_receipient,

				      okmsg, nrcpts);
		}
	}
	close(fd);
	while (last_error && last_error < nrcpts)
	{
		print_xerror(0, okmsg, ++last_error == nrcpts);
	}
	std::cout << std::flush;
	return (flag);
}
Esempio n. 21
0
int msgq::queuescan2(std::string s)
{
	DIR *tmpdir=opendir(s.c_str());
	struct dirent *de;
	std::list<std::string>	filename_list;

	if (!tmpdir)	clog_msg_errno();

	while ((de=readdir(tmpdir)) != 0)
	{
	const char *p=de->d_name;

		if (*p++ != 'C')	continue;

	ino_t	inum=strtoino(p);

		// Perhaps this one's in the queue already

		if (findq(inum))	continue;	// Already in msgq

		while (isdigit(*p))	p++;
		if (*p++ != '.')	continue;

		while (isdigit(*p))
			++p;

		if (*p)	continue;

		filename_list.push_back(de->d_name);
	}
	closedir(tmpdir);

	if (filename_list.size() == 0)
		return (1);	// Pretend we added something, so keep going

	std::vector<std::string> filename_array;

	filename_array.reserve(filename_list.size());

	filename_array.insert(filename_array.end(),
			      filename_list.begin(), filename_list.end());

	int	rc;
	int	flag=0;

	std::sort(filename_array.begin(), filename_array.end(),
		  std::ptr_fun(sort_by_qtime));


	std::vector<std::string>::iterator b, e;

	b=filename_array.begin();
	e=filename_array.end();

	while (b != e)
	{
		rc=queuescan3(s, *b++, 0);

		if (rc < 0)
			return (-1);
		if (rc)	break;
		flag=1;
	}
	return (flag);
}
Esempio n. 22
0
char	*makeerrmsgtext(int errnum, const char *errtext)
{
char	errnumbuf[4];
int	i;
const char *p;
char	*buf, *q, *r;
int	lastchar;

	if (!errtext || !*errtext)	errtext="Failed.";

	errnumbuf[3]=0;
	for (i=2; i >= 0; --i)
	{
		errnumbuf[i]= (errnum % 10)+'0';
		errnum /= 10;
	}

	/*
	** Calculate size of buffer we'll need.  For each line, we
	** add four bytes for the error number.
	** One line errors may need \n appended.
	*/

	i=6+strlen(errtext);
		/*
		** First line's toll, plus optional trailing \r\n,
		** and null byte.
		*/

	for (p=errtext; *p; p++)
		if (*p == '\n')	i += 4;

	if ((buf=malloc(i)) == 0)	clog_msg_errno();
	for (q=r=buf, p=errtext; *p; )
	{
		r=q;
		strcpy(q, errnumbuf);
		q += 3;
		*q++ = '-';

		if (isdigit((int)(unsigned char)p[0]) &&
			isdigit((int)(unsigned char)p[1]) &&
			isdigit((int)(unsigned char)p[2]) &&
			(p[3] == '-' || p[3] == ' '))
			p += 4;	/* Remove old error message number */

		while (*p)
		{
			lastchar=*q++ = *p++;

			if (lastchar != '\n' && *p == '\0')
			{
				*q++='\n';
			}
			if (lastchar == '\n')	break;
		}
	}
	r[3]=' ';
	*q=0;
	return (buf);
}
Esempio n. 23
0
void SubmitFile::openctl()
{
	std::string filename;

	ctlfile.close();
	if (num_control_files_created == 0)	// First recipient
	{
		for (;;)
		{
		const char *timeptr, *pidptr, *hostnameptr;

			getnewtmpfilenameargs(&timeptr, &pidptr,
						&hostnameptr);

			filename=name1stctlfile();
			current_submit_file=this;

			int nfd=open(filename.c_str(),
				     O_WRONLY | O_TRUNC | O_CREAT | O_EXCL | O_APPEND,
				     PERMISSION);

			if (nfd >= 0)
			  ctlfile.fd(nfd);

			if (nfd >= 0 || errno != EEXIST)
				break;
			current_submit_file=0;
			sleep(3);
		}
		++num_control_files_created;

		if (ctlfile.fd() < 0)
		{
		//
		// One reason why we may not be able to create it
		// would be if the subdirectory, based on current time,
		// does not exist, so fork a tiny program to create it,
		// with the right permissions
		//

		pid_t p=fork();
		pid_t w;
		int wait_stat;

			if (p == -1)
			{
				clog_msg_start_err();
				clog_msg_str("fork: ");
				clog_msg_errno();
			}

			if (p == 0)
			{
				filename=std::string(filename.begin(),
						     std::find(filename.begin()
							       , filename.end()
							       , '/'));

				execl(LIBEXECDIR "/courier/submitmkdir",
				      "submitmkdir", filename.c_str(),
				      (char *)0);
				exit(0);
			}
			while ((w=wait(&wait_stat)) != p)
				if (w == -1 && errno == ECHILD)	break;

			int nfd=open(filename.c_str(),
				     O_WRONLY | O_TRUNC | O_CREAT | O_EXCL | O_APPEND,
				     PERMISSION);

			if (nfd >= 0)
			  ctlfile.fd(nfd);
		}
	}
	else
	{
		++num_control_files_created;
		filename=namefile("C", num_control_files_created);

		int nfd=open(filename.c_str(),
			     O_WRONLY | O_TRUNC | O_CREAT | O_EXCL | O_APPEND,
			     PERMISSION);

		if (nfd >= 0)
			ctlfile.fd(nfd);
	}
	if (ctlfile.fd() < 0)	clog_msg_errno();

struct	stat	stat_buf;
char	ino_buf[sizeof(ino_t)*2+1];

	if (fstat(ctlfile.fd(), &stat_buf) != 0)
		clog_msg_errno();

	rcptcount=0;
	if (num_control_files_created == 1)
	{
	char	time_buf[sizeof(time_t)*2+1];
	char	pid_buf[sizeof(time_t)*2+1];
	char	msgidbuf[sizeof(time_buf)+sizeof(pid_buf)];

		ctltimestamp=stat_buf.st_mtime;
		ctlpid=getpid();

		strcat(strcat(strcpy(msgidbuf,
			libmail_strh_time_t(ctltimestamp, time_buf)), "."),
			libmail_strh_pid_t(getpid(), pid_buf));

		basemsgid=msgidbuf;
		ctlinodenum=stat_buf.st_ino;
	}

	libmail_strh_ino_t( stat_buf.st_ino, ino_buf );

	ctlfile << COMCTLFILE_SENDER << sender << std::endl
		<< COMCTLFILE_FROMMTA << frommta << std::endl
		<< COMCTLFILE_ENVID << envid << std::endl
		<< COMCTLFILE_DSNFORMAT << dsnformat << std::endl
		<< COMCTLFILE_MSGID << ino_buf << '.' << basemsgid << std::endl;

	if (submitdelay)
		ctlfile << COMCTLFILE_SUBMITDELAY << submitdelay << std::endl;

	ctlfile << std::flush;
}
Esempio n. 24
0
int msgq::tmpscan()
{
	int	found=0;

	time(&current_time);

	DIR *tmpdir=opendir(TMPDIR);

	if (!tmpdir)	clog_msg_errno();

	struct dirent *de;
	std::string	subdir;
	std::string	ctlfile, datfile, newctlfile, newdatfile;
	struct	stat stat_buf;
	std::string	qdir, qname;

	while ((de=readdir(tmpdir)) != 0)
	{
	const char *p;

		for (p=de->d_name; *p; p++)
			if (!isdigit((int)(unsigned char)*p))	break;
		if (*p)	continue;	// Subdirs must be named all digits

		subdir=TMPDIR "/";
		subdir += de->d_name;

		DIR *subde=opendir(subdir.c_str());

		while ((de=readdir(subde)) != 0 && found < 100)
		{
			if (strcmp(de->d_name, ".") == 0 ||
				strcmp(de->d_name, "..") == 0)	continue;

			ctlfile=subdir;
			ctlfile += '/';
			ctlfile += de->d_name;

			int	i=-1;

			if (stat(ctlfile.c_str(), &stat_buf))	continue;

			size_t j=ctlfile.size();

			while (j)
			{
				if (ctlfile[--j] == '/')
					break;

				if (ctlfile[j] == '.')
				{
					i=j;
					break;
				}
			}

		ino_t	inum=stat_buf.st_ino;

		// Cleanup timeout. Should always be sufficiently longer than
		// the submit timeout set in submit.C via alarm_timeout.

			if (stat_buf.st_mtime < current_time - 48 * 60 * 60)
			{
				if (de->d_name[0] == 'D')
				{
					datfile=subdir + "/C" +
						(de->d_name+1);

					if (stat(datfile.c_str(), &stat_buf)
					    == 0)
						continue;
						// Wait until the C file is
						// purged

				// Be carefull with Cnnnn.x files, because
				// Cnnnn.1 is used to hold submission of all
				// of them.  A race condition can leave
				// Cnnnn.1 in a submittable state, so if it
				// is removed, other copies of this message
				// can become submittable, during a very small
				// window.

				} else if (de->d_name[0] == 'C' && i >= 0)
				{

				// This race condition is handled simply
				// by not removing Cxxxxx.n if Cxxxxx.n+1
				// exists.

					char	nbuf[NUMBUFSIZE];

					datfile=ctlfile.substr(0, i);

					size_t	n=atoi( ctlfile.c_str()+i+1);

					++n;

					datfile += '.';
					datfile += libmail_str_size_t(n, nbuf);

					if (stat(datfile.c_str(), &stat_buf)
					    == 0)
						continue;
						// Wait until the C.1 file is
						// purged

					unlink(ctlfile.c_str());

					ctlfile=subdir + "/D" +
						(de->d_name+1);
					/* FALLTHRU */
				}
				unlink(ctlfile.c_str());
				continue;
			}

			if (de->d_name[0] != 'C')	continue;
			if (i >= 0)
			{
				datfile=ctlfile.substr(0, i);
				datfile += ".1";

				if (ctlfile == datfile ||
				    stat(datfile.c_str(), &stat_buf) == 0)
					continue;
			}


			datfile=subdir + "/D" + (de->d_name+1);

			newdatfile=qmsgsdatname(inum);
			newctlfile=qmsgsctlname(inum);

			struct	ctlfile ctf;

			if ((access(datfile.c_str(), 0) == 0 &&
			     access(newdatfile.c_str(), 0) == 0) ||
			    access(newctlfile.c_str(), 0) == 0 ||
			    ctlfile_openfn(ctlfile.c_str(), &ctf, 0, 0))
			{
				clog_msg_start_err();
				clog_msg_str("QUEUE FILE CORRUPTION: inode ");
				clog_msg_uint(inum);
				clog_msg_send();
				utime(ctlfile.c_str(), 0);
				// Keep it around
				continue;
			}

		time_t	nextattempt=current_time+delaytime;

			if ((i=ctlfile_searchfirst(&ctf,
				COMCTLFILE_SUBMITDELAY)) >= 0)
				nextattempt=current_time+
					atoi(ctf.lines[i]+1);

			qname=qmsgqname(inum, nextattempt);

			ctlfile_nextattempt(&ctf, nextattempt);

			if (link(ctlfile.c_str(), qname.c_str()))
			{
				mkdir(qmsgqdir(current_time),0755);
				if (link(ctlfile.c_str(), qname.c_str())
				    && errno != EEXIST)
					clog_msg_errno();
			}

			if (rename(datfile.c_str(), newdatfile.c_str()))
			{
				mkdir(qmsgsdir(inum), 0755);
					// We may need to create this dir
				rename(datfile.c_str(), newdatfile.c_str());
			}

			if (rename(ctlfile.c_str(), newctlfile.c_str()))
				clog_msg_errno();

			for (i=qname.size(); i; )
			{
				if (qname[--i] == '/')
					break;
			}

			qdir=qname.substr(0, i);
			qname=qname.substr(i+1);
			++found;
			ctlfile_close(&ctf);

			queuescan3(qdir, qname, de->d_name);
		}
		closedir(subde);

		if (stat(subdir.c_str(), &stat_buf) == 0 &&
			stat_buf.st_mtime < current_time - 2 * 60 * 60)
			rmdir(subdir.c_str());	// Just give it a try
	}
	closedir(tmpdir);
	return (found);
}
Esempio n. 25
0
void msgq::queuescan()
{
static	int queuescan_flag=0;

	if (queuescan_flag)	return;
		// Recursive invocation if message just pulled into queue
		// has been delivered to all of its recipients.

	nextqueuefill=0;

#if 0
clog_msg_start_info();
clog_msg_str("queue scan");
clog_msg_send();
#endif

	try
	{
		std::list<std::string> subdirlist;
		DIR *tmpdir=opendir(MSGQDIR);
		struct dirent *de;
		std::string	s;

		queuescan_flag=1;
		if (!tmpdir)	clog_msg_errno();

		time(&current_time);

		while ((de=readdir(tmpdir)) != 0)
		{
			const char *p;

			for (p=de->d_name; *p; p++)
				if (!isdigit((int)(unsigned char)*p))	break;

			if (*p)	continue;	// Subdirs must be named all digits

			p=de->d_name;
			time_t n=strtotime(p);

			std::list<std::string>::iterator sb, se;

			sb=subdirlist.begin();
			se=subdirlist.end();

			while (sb != se)
			{
				if (strtotime(sb->c_str()) > n)
					break;
				++sb;
			}

			subdirlist.insert(sb, de->d_name);
		}
		closedir(tmpdir);

		while (!subdirlist.empty())
		{
			s=MSGQDIR "/";
			s += subdirlist.front();
			subdirlist.pop_front();

			if (queuescan2(s) <= 0)	break;
				// Stop if we can't add any more msgs
		}
		queuescan_flag=0;
	}
	catch (...)
	{
		queuescan_flag=0;
		throw;
	}
}
Esempio n. 26
0
static void fax(struct moduledel *p)
{
	struct	ctlfile ctf;
	unsigned nreceipients=p->nreceipients;
	const char *host=p->host;
	const char *receipient;
	unsigned nrecipient=(unsigned)atol(p->receipients[0]);
	int pipefd[2];
	pid_t child_proc;
	int faxopts;
	int n_cover_pages;
	FILE *fp;

	struct faxconv_err_args err_args;

	struct sort_file_list *page_list, *pp;


#if     HAVE_SETPGRP
#if     SETPGRP_VOID
        setpgrp();
#else
        setpgrp(0, 0);
#endif
#else
#if     HAVE_SETPGID
        setpgid(0, 0);
#endif
#endif

	if (comgetfaxopts(host, &faxopts))
	{
		clog_msg_start_err();
		clog_msg_str("courierfax: FATAL: invalid host");
		clog_msg_send();
		exit(1);
	}

	putenv(faxopts & FAX_LOWRES ? "FAXRES=lo":"FAXRES=hi");

	if (nreceipients != 1)
	{
		clog_msg_start_err();
		clog_msg_str("courierfax: FATAL: # receipients must be 1");
		clog_msg_send();
		exit(1);
	}

	receipient=p->receipients[1];
	nrecipient=(unsigned)atol(p->receipients[0]);

	if (ctlfile_openi(p->inum, &ctf, 0))
		clog_msg_errno();

	/* Convert message to fax format, use a child process */

	signal(SIGTERM, faxabort);

	if (pipe(pipefd) < 0)
	{
		clog_msg_errno();
	}

	child_proc=fork();
	if (child_proc < 0)
	{
		clog_msg_errno();
		return;
	}

	if (child_proc == 0)
	{
		const char *fn;

		close(0);
		if (open("/dev/null", O_RDONLY) != 0)
			clog_msg_errno();

		close(pipefd[0]);
		close(1);
		if (dup(pipefd[1]) != 1)
		{
			perror("dup");
			exit(1);
		}
		close(2);
		if (dup(pipefd[1]) != 2)
		{
			fprintf(stderr, "ERROR: dup failed\n");
			exit(1);
		}
		close(pipefd[1]);

		libmail_changeuidgid(MAILUID, MAILGID);

		fn=qmsgsdatname(p->inum);

		if (faxconvert(fn, faxopts, &n_cover_pages))
			exit (1);

		if ((fp=fopen(FAXTMPDIR "/.ncoverpages", "w")) == NULL ||
		    fprintf(fp, "%d\n", n_cover_pages) < 0 ||
		    fflush(fp) < 0)
			exit(1);
		fclose(fp);
		exit(0);
	}

	close(pipefd[1]);

	err_args.ctf= &ctf;
	err_args.nreceip=nrecipient;

	if (read_childerrmsg(child_proc, pipefd[0],
			     &faxconvert_cleanup, &err_args))
	{
		ctlfile_close(&ctf);
		return;
	}

	/* Hit it */

	if ((fp=fopen(FAXTMPDIR "/.ncoverpages", "r")) == NULL ||
	    fscanf(fp, "%d", &n_cover_pages) != 1)
	{
		if (fp)
			fclose(fp);

		ctlfile_append_reply(err_args.ctf,
				     err_args.nreceip,
				     "Internal error: cannot read number of cover pages",
				     COMCTLFILE_DELFAIL, 0);
		ctlfile_close(&ctf);
		exit(0);
	}

	page_list=read_dir_sort_filenames(FAXTMPDIR, FAXTMPDIR "/");

	if (!page_list)
	{
		clog_msg_start_err();
		clog_msg_str("courierfax: INTERNAL ERROR - no pages to xmit.");
		clog_msg_send();
		exit(1);
	}

	/* Keep trying until the modem line is unlocked */

	do
	{
		if (pipe(pipefd) < 0)
		{
			clog_msg_errno();
		}

		child_proc=fork();
		if (child_proc < 0)
		{
			clog_msg_errno();
			return;
		}

		if (child_proc == 0)
		{
			unsigned page_cnt=0;
			char **argvec;

			close(pipefd[0]);
			close(0);
			if (open("/dev/null", O_RDONLY) != 0)
			{
				perror("/dev/null");
				exit(1);
			}
			close(1);
			if (dup(pipefd[1]) != 1)
			{
				perror("dup");
				exit(1);
			}
			close(2);
			if (dup(pipefd[1]) != 2)
			{
				fprintf(stderr, "ERROR: dup failed\n");
				exit(1);
			}
			close(pipefd[1]);

			for (pp=page_list; pp; pp=pp->next)
				++page_cnt;

#if 0
			while (page_list)
			{
				unlink(page_list->filename);
				page_list=page_list->next;
			}

			exit(0);
#endif

			argvec=(char **)courier_malloc(sizeof(char *)*
						       (page_cnt+10));

			argvec[0]=SENDFAX;
			argvec[1]="-v";
			argvec[2]="-r";

			page_cnt=3;

			if (faxopts & FAX_LOWRES)
				argvec[page_cnt++]="-n";

			argvec[page_cnt++]=(char *)receipient;

			while (page_list)
			{
				argvec[page_cnt++]=page_list->filename;
				page_list=page_list->next;
			}
			argvec[page_cnt]=0;
			execv(SENDFAX, argvec);
			perror(SENDFAX);
			exit(1);
		}
		close(pipefd[1]);

		err_args.ctf= &ctf;
		err_args.nreceip=nrecipient;
		err_args.file_list=page_list;
		err_args.is_locked=0;
		err_args.n_cover_pages=n_cover_pages;

		if (read_childerrmsg(child_proc, pipefd[0],
				     &faxsend_cleanup, &err_args) == 0)
		{
			size_t npages=0;
			char fmtbuf[NUMBUFSIZE];
			char fmtbuf1[NUMBUFSIZE];
			char fmtbuf2[NUMBUFSIZE+100];

			for (pp=page_list; pp; pp=pp->next)
				++npages;

			libmail_str_size_t(npages, fmtbuf);
			libmail_str_size_t(n_cover_pages, fmtbuf1);

			sprintf(fmtbuf2,
				"%s pages - including %s cover page(s)"
				" - sent by fax.", fmtbuf, fmtbuf1);

			ctlfile_append_reply(&ctf, (unsigned)
					     nrecipient,
					     fmtbuf2,
					     COMCTLFILE_DELSUCCESS, " l");
			break;
		}
	} while (err_args.is_locked);

	ctlfile_close(&ctf);
	rmdir_contents(FAXTMPDIR);
}
Esempio n. 27
0
int SubmitFile::MessageEnd(unsigned rcptnum, int iswhitelisted,
			   int filter_enabled)
{
int	is8bit=0, dorewrite=0, rwmode=0;
const	char *mime=getenv("MIME");
unsigned	n;
struct	stat	stat_buf;

	if (sizelimit && bytecount > sizelimit)
	{
		std::cout << "523 Message length (" <<
			sizelimit << " bytes) exceeds administrative limit."
			<< std::endl << std::flush;
		return (1);
	}

	if (diskfull)
	{
		std::cout << "431 Mail system full." << std::endl << std::flush;
		return (1);
	}

	if (spamtrap_flag)
	{
		std::cout << "550 Spam refused." << std::endl << std::flush;
		return (1);
	}

	if (rwrfcptr->rfcviolation & RFC2045_ERR2COMPLEX)
	{
                std::cout <<
                   "550 Message MIME complexity exceeds the policy maximum."
		     << std::endl << std::flush;
		return (1);
	}

	datfile << std::flush;
	if (datfile.fail())	clog_msg_errno();

	ctlfile << std::flush;
	if (ctlfile.fail())	clog_msg_errno();

	/* Run global filters for this message */

	std::string dfile=namefile("D", 0);

	if (!mime || strcmp(mime, "none"))
	{
		if (mime && strcmp(mime, "7bit") == 0)
		{
			rwmode=RFC2045_RW_7BIT;
			is8bit=0;
		}
		if (mime && strcmp(mime, "8bit") == 0)
			rwmode=RFC2045_RW_8BIT;
		if (rfc2045_ac_check(rwrfcptr, rwmode))
			dorewrite=1;
	}
	else
		(void)rfc2045_ac_check(rwrfcptr, 0);

	if (rwrfcptr->has8bitchars)
		is8bit=1;

	unlink(namefile("D", 1).c_str());	// Might be the GDBM file
					// if receipients read from headers.
	if (dorewrite)
	{
		int	fd1=dup(datfile.fd());
		int	fd2;

		if (fd1 < 0)	clog_msg_errno();
		datfile.close();
		if (datfile.fail())	clog_msg_errno();

		if ((fd2=open(namefile("D", 1).c_str(),
			O_RDWR|O_CREAT|O_TRUNC, PERMISSION)) < 0)
			clog_msg_errno();

		if (call_rfc2045_rewrite(rwrfcptr, fd1, fd2,
					 PACKAGE " " VERSION))
		{
			clog_msg_errno();
			std::cout << "431 Mail system full." << std::endl << std::flush;
			return (1);
		}
		close(fd1);

#if	EXPLICITSYNC
		fsync(fd2);
#endif
		fstat(fd2, &stat_buf);
		close(fd2);

		std::string p=namefile("D", 0);

		unlink(p.c_str());
		if (rename(namefile("D", 1).c_str(), p.c_str()) != 0)
			clog_msg_errno();
	}
	else
	{
		datfile.sync();
#if EXPLICITSYNC
		fsync(datfile.fd());
#endif
		fstat(datfile.fd(), &stat_buf);
		datfile.close();
		if (datfile.fail())	clog_msg_errno();
	}
	if (is8bit)
	{
		ctlfile << COMCTLFILE_8BIT << "\n" << std::flush;
		closectl();

		if (num_control_files_created > 1)
		{
			for (n=1; n < num_control_files_created; n++)
			{
				std::string p=namefile("C", n);

				int nfd=open(p.c_str(), O_WRONLY | O_APPEND);

				if (nfd < 0)	clog_msg_errno();
				ctlfile.fd(nfd);
				ctlfile << COMCTLFILE_8BIT << "\n" << std::flush;
				if (ctlfile.fail())	clog_msg_errno();
#if EXPLICITSYNC
				ctlfile.sync();
				fsync(ctlfile.fd());
#endif
				ctlfile.close();
				if (ctlfile.fail())	clog_msg_errno();
			}
		}
	}
	else
	{
		closectl();
	}

	SubmitFile *voidp=this;

	if (filter_enabled &&
	    run_filter(dfile.c_str(), num_control_files_created,
		       iswhitelisted,
		       &SubmitFile::get_msgid_for_filtering, &voidp))
		return (1);

	std::string cfile=namefile("C", 0);

	for (n=2; n <= num_control_files_created; n++)
	{
		if (link(dfile.c_str(), namefile("D", n).c_str()) != 0)
			clog_msg_errno();
	}

	std::string okmsg("250 Ok. ");

	okmsg += basemsgid;

	int	hasxerror=datafilter(dfile.c_str(), rcptnum, okmsg.c_str());

	current_submit_file=0;
	if (num_control_files_created == 1)
	{
		if (rename(name1stctlfile().c_str(), cfile.c_str()) != 0)
			clog_msg_errno();
	}
	else
	{
		if (rename(namefile("C", 1).c_str(), cfile.c_str()) != 0)
			clog_msg_errno();
	}

	if (!hasxerror)
	{
#if EXPLICITDIRSYNC
		size_t p=cfile.rfind('/');

		if (p != std::string::npos)
		{
			std::string dir=cfile.substr(0, p);

			int fd=open(dir.c_str(), O_RDONLY);

			if (fd >= 0)
			{
				fsync(fd);
				close(fd);
			}
		}
#endif

		std::cout << okmsg << std::endl << std::flush;
	}

	trigger(TRIGGER_NEWMSG);
	return (0);
}
Esempio n. 28
0
int courierbmain()
{
    fd_set	fds, fdc;
    struct	mybuf trigger_buf;

    clog_open_syslog("courierd");
    rw_init_verbose(1);
    if (rw_init_courier(0))	return (1);
    drvinfo::init();

    libmail_changeuidgid(MAILUID, MAILGID);
    signal(SIGPIPE, SIG_IGN);

    respawnlo=config_time_respawnlo();
    respawnhi=config_time_respawnhi();

    retryalpha=config_time_retryalpha();
    retrybeta=config_retrybeta();
    retrygamma=config_time_retrygamma();
    retrymaxdelta=config_retrymaxdelta();
    flushtime=0;
    delaytime=config_time_submitdelay();

    queuefill=config_time_queuefill();
    nextqueuefill=0;

    purgedir(MSGQDIR);
    purgedir(MSGSDIR);
    rmdir(MSGQDIR);
    mkdir(MSGQDIR, 0755);
    trackpurge();

    if ((triggerw=open(triggername, O_WRONLY, 0)) < 0 ||
            (triggerr=open(triggername, O_RDONLY, 0)) < 0)
        clog_msg_errno();

    time(&start_time);

    courierbstart=start_time;

    msgq::init(queuehi);

    shutdown_flag=0;
    FD_ZERO(&fds);

    unsigned nd;
    int	maxfd=triggerr;

    FD_SET(maxfd, &fds);
    mybuf_init(&trigger_buf, triggerr);

    for (nd=0; nd<drvinfo::nmodules; nd++)
    {
        int	fd=drvinfo::modules[nd].module_from.fd;

        if (fd > maxfd)	maxfd=fd;
        FD_SET(fd, &fds);
    }

    ++maxfd;

    time_t	current_time, next_time, shutdown_time;

    current_time=start_time;

    shutdown_time=0;

    msgq::queuescan();	// Initial queue scan

    int	doscantmp=1;

////////////////////////////////////////////////////////////////////////////
//
// Main loop:
//
// A) Scan tmp for new messages.
//
// B) Schedule messages for delivery, when their time comes.
//
// C) Update statistics.
//
// D) Stop scheduling messages when restart signal received.
//
// E) Restart if there's no activity for 5 mins after we've been running
//    for respawnlo amount of times.
//
// F) When we've been running for respawnhi amount of time, stop scheduling
//    messages, restart when all deliveries have been completed.
//
// G) Receive delivery completion messages from modules.
//
////////////////////////////////////////////////////////////////////////////
    for (;;)
    {
        msgq	*mp;

        if (shutdown_flag)
            doscantmp=0;

        if (doscantmp)
            doscantmp=msgq::tmpscan();

        if (shutdown_flag && msgq::inprogress == 0)
            break;

        if (current_time >= start_time + respawnhi && !shutdown_flag)
        {
            clog_msg_start_info();
            clog_msg_str("SHUTDOWN: respawnhi limit reached.");
            clog_msg_send();
            shutdown_flag=1;
            continue;
        }

        if (diskspacelow() && msgq::queuehead &&
                msgq::queuehead->nextsenddel <= current_time)
        {
            clog_msg_start_err();
            clog_msg_str("Low on disk space.");
            clog_msg_send();
            for (mp=msgq::queuehead; mp &&
                    mp->nextsenddel <= current_time + 300;
                    mp=mp->next)
                mp->nextsenddel=current_time+300;
        }

        if (!shutdown_flag)
        {
            while ((mp=msgq::queuehead) != 0 &&
                    mp->nextsenddel <= current_time)
            {
                mp->removewq();
                mp->start_message();
            }
        }

        if (nextqueuefill && nextqueuefill <= current_time)
        {
            nextqueuefill=0;
            if (!shutdown_flag)
            {
                msgq::queuescan();
            }

        }

        next_time=0;
        if ( msgq::queuehead && msgq::queuehead->nextsenddel
                > current_time)
            next_time=msgq::queuehead->nextsenddel;
        if (!shutdown_flag && msgq::inprogress == 0 &&
                shutdown_time == 0)
        {
            shutdown_time=current_time + 5 * 60;
            if (shutdown_time < start_time + respawnlo)
                shutdown_time=start_time + respawnlo;
        }

        if (shutdown_time && (next_time == 0 ||
                              shutdown_time < next_time))
            next_time=shutdown_time;

        if (nextqueuefill)
        {
            /* Or, wake up next time we need to refill the queue */

            if (next_time == 0 || nextqueuefill < next_time)
            {
                next_time=nextqueuefill;
            }
        }

        fdc=fds;

        struct	timeval	tv;

        if (next_time)
        {
            tv.tv_sec= next_time > current_time ?
                       next_time - current_time:0;
            tv.tv_usec=0;
        }

#if 1
        {
            char buf[40];

            clog_msg_start_info();
            clog_msg_str("Waiting.  shutdown time=");
            strcpy(buf, shutdown_time ? ctime(&shutdown_time):"none\n");
            *strchr(buf, '\n')=0;
            clog_msg_str(buf);

            clog_msg_str(", wakeup time=");
            strcpy(buf, next_time ? ctime(&next_time):"none\n");
            *strchr(buf, '\n')=0;
            clog_msg_str(buf);
            clog_msg_str(", queuedelivering=");
            clog_msg_int(msgq::queuedelivering);
            clog_msg_str(", inprogress=");
            clog_msg_int(msgq::inprogress);
            clog_msg_send();
        }
#endif

        while (select(maxfd, &fdc, (fd_set *)0, (fd_set *)0,
                      (next_time && doscantmp == 0 ?
                       &tv:(struct timeval *)0)) < 0)
        {
            if (errno != EINTR)	clog_msg_errno();
        }
        time(&current_time);
        if (shutdown_time)
        {
            if (current_time >= shutdown_time &&
                    msgq::inprogress == 0)
            {
                clog_msg_start_info();
                clog_msg_str("SHUTDOWN: respawnlo limit reached, system inactive.");
                clog_msg_send();
                shutdown_flag=1;
            }
            shutdown_time=0;
        }

        /* Handle commands sent via the trigger pipe */

        if (FD_ISSET(triggerr, &fdc))
        {
            unsigned	l;
            char	cmdbuf[256];
            int	c;

            do
            {
                l=0;
                do
                {
                    c=mybuf_get(&trigger_buf);
                    if (l < sizeof(cmdbuf)-1)
                        cmdbuf[l++]=c;
                } while (c != '\n');
                cmdbuf[l]=0;

                if (strcmp(cmdbuf, TRIGGER_NEWMSG) == 0)
                    doscantmp=1;
                else if (strcmp(cmdbuf, TRIGGER_RESTART) == 0)
                {
                    shutdown_flag=1;
                    clog_msg_start_info();
                    clog_msg_str("SHUTDOWN: Restarting...");
                    clog_msg_send();
                }
                else if (strcmp(cmdbuf, TRIGGER_STOP) == 0)
                {
                    clog_msg_start_info();
                    clog_msg_str("SHUTDOWN: Stopping...");
                    clog_msg_send();
                    _exit(99);
                }
                else if (strcmp(cmdbuf, TRIGGER_FLUSH) == 0)
                {
                    flushtime=current_time;
                    for (mp=msgq::queuehead; mp;
                            mp=mp->next)
                        mp->nextsenddel=current_time;
                }
                else if (strncmp(cmdbuf, TRIGGER_FLUSHMSG,
                                 sizeof(TRIGGER_FLUSHMSG)-1) == 0)
                {
                    char *p;
                    ino_t	n;

                    if ((p=strchr(cmdbuf, '\n')) != 0)
                        *p=0;

                    p=cmdbuf+sizeof(TRIGGER_FLUSHMSG)-1;
                    while (*p == ' ')	++p;
                    if (comparseqid(p, &n) == 0 &&
                            !shutdown_flag)
                        msgq::flushmsg(n, p);
                }
            } while (mybuf_more(&trigger_buf));
        }

        for (nd=0; nd<drvinfo::nmodules; nd++)
        {
            struct mybuf *p= &drvinfo::modules[nd].module_from;
            size_t	delnum;
            int	c;

            if (!FD_ISSET(p->fd, &fdc))	continue;
            do
            {
                delnum=0;
                while (errno=0, ((c=mybuf_get(p)) != '\n'))
                {
                    if (c < 0)
                    {
                        if (errno == EINTR)
                            continue;

                        clog_msg_start_err();
                        clog_msg_str("MODULE ");
                        clog_msg_str(
                            drvinfo::modules[nd]
                            .module->name);
                        clog_msg_str(" ABORTED.");
                        clog_msg_send();
                        _exit(1);
                    }
                    if (c >= '0' && c <= '9')
                        delnum=delnum * 10 + (c-'0');
                }
                msgq::completed(drvinfo::modules[nd], delnum);
            } while (mybuf_more(p));
            if (!shutdown_flag)	shutdown_time=0;
        }
    }

    close(triggerr);
    close(triggerw);

    drvinfo::cleanup();
    return (0);
}
Esempio n. 29
0
void SubmitFile::ReceipientFilter(struct rw_transport *rw,
		const char *host,
		const char *addr,
		unsigned rcptnum)
{

	if (rcptfilterlist_file.is_open())
	{
		rcptfilterlist_file
			<< num_control_files_created - 1 << std::endl
			<< rcptcount - 1 << std::endl
			<< rw->name << std::endl
			<< host << std::endl
			<< addr << std::endl
			<< rcptnum << std::endl;

		return;
	}

	rcptfilterlist.push_back(RcptFilterInfo());
	RcptFilterInfo &last_pos=rcptfilterlist.back();

	last_pos.num_control_file=num_control_files_created - 1;
	last_pos.num_receipient=rcptcount - 1;
	last_pos.driver=rw;
	last_pos.host=host;
	last_pos.address=addr;
	last_pos.rcptnum=rcptnum;

	if (rcptfilterlist.size() > SPILLLEVEL)
	{
		std::string filename=namefile("R", 0);

		rcptfilterlist_file.open(filename.c_str(),
					 std::ios::in | std::ios::out
					 | std::ios::trunc);
		if (!rcptfilterlist_file.is_open())
		{
			clog_msg_start_err();
			clog_msg_str(filename.c_str());
			clog_msg_str(": ");
			clog_msg_errno();
		}

		unlink(filename.c_str());	/* Immediately delete it */

		std::list<RcptFilterInfo>::iterator ab, ae;

		for (ab=rcptfilterlist.begin(),
			     ae=rcptfilterlist.end(); ab != ae; ++ab)
		{
			RcptFilterInfo &p= *ab;

			rcptfilterlist_file << p.num_control_file << std::endl
				<< p.num_receipient << std::endl
				<< p.driver->name << std::endl
				<< p.host << std::endl
				<< p.address << std::endl
				<< p.rcptnum << std::endl;
		}
		rcptfilterlist.clear();
	}
}
Esempio n. 30
0
static void esmtpparent()
{
unsigned i;
fd_set	fdc, fds;
time_t	current_time;

	libmail_changeuidgid(MAILUID, MAILGID);
	module_init(&terminated_child);

	if ((info=(struct esmtpchildinfo *)malloc(sizeof(*info)*
		module_nchildren)) == 0)
		clog_msg_errno();
	for (i=0; i<module_nchildren; i++)
	{
		info[i].pid= -1;
		info[i].cmdpipe= -1;
		info[i].host=0;
		info[i].pendel=0;
	}
	if (pipe(completionpipe) < 0)
		clog_msg_errno();

	if ((childresultpipe=fdopen(completionpipe[0], "r")) == 0)
		clog_msg_errno();
	FD_ZERO(&fdc);
	FD_SET(0, &fdc);
	FD_SET(completionpipe[0], &fdc);
	mybuf_init(&courierdbuf, 0);
	mybuf_init(&childbuf, completionpipe[0]);

	module_blockset();
	time(&current_time);

	for (;;)
	{
	time_t	wait_time;
	struct	timeval	tv;

		wait_time=0;
		for (i=0; i<module_nchildren; i++)
		{
			if (!ESMTP_IDLE(&info[i]))	continue;
			if (info[i].termtime <= current_time)
			{
				close(info[i].cmdpipe);
				info[i].cmdpipe= -1;
				continue;
			}

			if (wait_time == 0 || info[i].termtime < wait_time)
				wait_time=info[i].termtime;
		}

		if (wait_time)
		{
			tv.tv_sec= wait_time - current_time;
			tv.tv_usec=0;
		}

		fds=fdc;

		module_blockclr();
                while (select(completionpipe[0]+1, &fds, (fd_set *)0, (fd_set *)0,
                                (wait_time ? &tv:(struct timeval *)0)) < 0)
                {
                        if (errno != EINTR)     clog_msg_errno();
                }

		module_blockset();
		time(&current_time);

		if (FD_ISSET(completionpipe[0], &fds))
		{
		char	*line;

			do
			{
			pid_t	p;

				line=module_getline( &call_mybuf_get,
						&childbuf);

				if (parse_ack(line, &i, &p) ||
					i >= module_nchildren ||
					(p == info[i].pid &&
						!ESMTP_BUSY(&info[i])))
				{
					clog_msg_start_err();
					clog_msg_str("INVALID message from child process.");
					clog_msg_send();
					_exit(0);
				}
				if (p != info[i].pid)	continue;
				info[i].isbusy=0;
				info[i].termtime=current_time + esmtpkeepalive;
				if (info[i].pendel)
				{
					free(info[i].pendel);
					info[i].pendel=0;
				}

				module_completed(i, module_delids[i]);
			} while (mybuf_more(&childbuf));
		}

		if (!FD_ISSET(0, &fds))	continue;

		do
		{
		char	**cols;
		const char *hostp;
		size_t	hostplen;
		time_t	misctime;
		unsigned j;
		char	*line;

			line=module_getline( &call_mybuf_get, &courierdbuf);
			if (!line)
			{
				module_restore();

				/*
				** If all processes are idle, wait for them
				** to finish normally.  Otherwise, kill
				** the processes.
				*/

				for (j=0; j<module_nchildren; j++)
					if (ESMTP_BUSY(&info[j]))
						break;

				if (j < module_nchildren)
				{
					for (j=0; j<module_nchildren; j++)
						if (info[j].pid > 0)
							kill(info[j].pid,
								SIGTERM);
				}
				else
				{
				int	waitstat;

					for (j=0; j<module_nchildren; j++)
					{
						if (info[j].cmdpipe > 0)
						{
							close(info[j].cmdpipe);
							info[j].cmdpipe= -1;
						}
					}
					while (wait(&waitstat) != -1 ||
						errno == EINTR)
						;
				}
				_exit(0);
			}

			cols=module_parsecols(line);

			if (!cols)	_exit(0);

			hostp=MODULEDEL_HOST(cols);
			for (hostplen=0; hostp[hostplen] &&
				hostp[hostplen] != '\t'; hostplen++)
				;

			for (i=0; i<module_nchildren; i++)
			{
				if (!ESMTP_IDLE(&info[i])) continue;
				if (memcmp(info[i].host, hostp, hostplen) == 0
					&& info[i].host[hostplen] == 0)
					break;
			}

			if (i < module_nchildren)	/* Reuse a process */
			{
				send_child(i, line, cols);
				continue;
			}

			for (i=0; i<module_nchildren; i++)
				if (ESMTP_NOCHILD(&info[i]))	break;

			if (i < module_nchildren)	/* We can fork */
			{
				start_child(i, line, cols);
				send_child(i, line, cols);
				continue;
			}

			/*
			** Find a process that's been idled the longest,
			** and reuse that one.
			*/

			misctime=0;
			j=0;
			for (i=0; i<module_nchildren; i++)
			{
				if (ESMTP_IDLE(&info[i]) &&
					(misctime == 0 || misctime >
						info[i].termtime))
				{
					j=i;
					misctime=info[i].termtime;
				}
			}
			if (misctime)
			{
				if (info[j].pendel)
				{
					clog_msg_start_err();
					clog_msg_str("INTERNAL ERROR: unexpected scheduled delivery.");
					clog_msg_send();
					_exit(1);
				}

				info[j].pendel=strcpy(
					courier_malloc(strlen(line)+1),
					line);
				close(info[j].cmdpipe);
				info[j].cmdpipe= -1;
				continue;
			}

			/* The ONLY remaining possibility is something in
			** the TERMINATING stage, without another delivery
			** already scheduled for that slot.
			*/

			for (i=0; i<module_nchildren; i++)
			{
				if (ESMTP_TERMINATING(&info[i]) &&
					info[i].pendel == 0)
					break;
			}

			if (i < module_nchildren)
			{
				info[i].pendel=strcpy(
					courier_malloc(strlen(line)+1),
					line);
				continue;
			}

			clog_msg_start_err();
			clog_msg_str("INTERNAL ERROR: unexpected delivery.");
			clog_msg_send();
			_exit(1);
		} while (mybuf_more(&courierdbuf));
	}
}