Exemple #1
0
int rw_init_courier(const char *name)
{
unsigned	i;
int	err=0;

	if (rw_init_verbose_flag)
	{
		clog_msg_start_info();
		clog_msg_str("Loading STATIC transport module libraries.");
		clog_msg_send();
	}
	if (rw_install_start())	return (-1);
	for (i=0; rw_static[i].name; i++)
		/* name != 0 really meaningless for static libs, but,
		** what the heck...
		*/
		if ((name == 0 || strcmp(name,
			rw_static[i].name) == 0) &&
			rw_install(rw_static[i].name,
				rw_static[i].rw_install,
				rw_static[i].rw_init))
			err=1;

	if (err || rw_install_init())
	{
		clog_msg_start_err();
		clog_msg_str("Transport module installation has FAILED.");
		clog_msg_send();
		return (-1);
	}
	return (0);
}
Exemple #2
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);
}
Exemple #3
0
static void reap_child(pid_t pid, int exit_status)
{
	int	n;
	fd_set fd0;
	struct timeval tv;

	FD_ZERO(&fd0);
	FD_SET(0, &fd0);

	tv.tv_sec=0;
	tv.tv_usec=0;

	if (select(1, &fd0, 0, 0, &tv) >= 0)
	{
		if (FD_ISSET(0, &fd0))
			return;
	}

	n=wait_reforkchild(nchildren, children, pid);

	if (n < 0)
	{
	unsigned u;

		clog_open_syslog("perlfilter");
		clog_msg_str("ERR: Unable to restart a child process"
				" - aborting.");
		clog_msg_send();
		for (u=0; u<nchildren; u++)
			if (children[u] >= 0)
				kill(children[u], SIGKILL);
		exit(0);
	}

	if (n > 0)
	{
		wait_restore();
		if (exit_status)
		{
			clog_open_syslog("perlfilter");
			clog_msg_str("ERR: Child process ");
			clog_msg_uint(pid);
			clog_msg_str(" terminated - restarting.");
			clog_msg_send();
		}
		perlfilter();
	}
}
Exemple #4
0
void msgq::init(unsigned qs)
{
	queue.resize(qs);
	queuehashfirst.resize(qs);
	queuehashlast.resize(qs);

	queuehead=0;
	queuetail=0;
	queuefree=0;
	queuedelivering=0;
	queuewaiting=0;
	inprogress=0;
	backup_relay_driver=0;

char *filename=config_localfilename("backuprelay");
char *buf=config_read1l(filename);

	free(filename);
	if (buf)
	{
		const char *h=strtok(buf, " \t\r\n");

		if (h)
		{
			backup_relay=h;
			h=strtok(0, " \t\r\n");
			if (!h)	h="esmtp";

		struct rw_transport *t=rw_search_transport(h);

			if (!t)
			{
				clog_msg_start_err();
				clog_msg_str("BACKUP RELAY DRIVER NOT FOUND: ");
				clog_msg_str(h);
				clog_msg_send();
				exit(1);
			}
			backup_relay_driver=(drvinfo *)t->udata;
		}
	}

unsigned	i;

	for (i=0; i<qs; i++)
	{
		queue[i].next=queuefree;
		queuefree=&queue[i];
		queuehashfirst[i]=0;
		queuehashlast[i]=0;
	}
}
Exemple #5
0
void qmsgunlink(ino_t n, time_t rightnow)
{
	const char *bigbrother=getenv("ARCHIVEDIR");

	if (bigbrother && *bigbrother)
	{
		struct tm *tmptr=localtime(&rightnow);

		/* Archive this message */

		if (tmptr)
		{
			const char *dname=qmsgsdatname(n);
			const char *tname=strrchr(dname, '/');

			char *p=courier_malloc(strlen(bigbrother)+
					       strlen(tname)+40);

			sprintf(p, "%s/%04d.%02d.%02d%s",
				bigbrother, tmptr->tm_year + 1900,
				tmptr->tm_mon+1,
				tmptr->tm_mday, tname);

			if (bigbrother_create_rename(dname, p) == 0)
			{
				dname=qmsgsctlname(n);

				strcpy(strrchr(p, '/'), strrchr(dname, '/'));

				if (rename(dname, p) == 0)
				{
					free(p);
					return;
				}
			}

			clog_msg_start_err();
			clog_msg_str("Unable to move ");
			clog_msg_str(dname);
			clog_msg_str(" to ");
			clog_msg_str(p);
			clog_msg_send();
			clog_msg_prerrno();

			free(p);
		}
	}

	unlink(qmsgsdatname(n));
	unlink(qmsgsctlname(n));
}
Exemple #6
0
void trackpurge(const char *trackdir)
{
	struct stat stat_buf;

	if (stat(trackdir, &stat_buf) == 0 && stat_buf.st_uid != geteuid())
	{
		clog_msg_start_err();
		clog_msg_str("Warning: ");
		clog_msg_str(trackdir);
		clog_msg_str(" is not owned by the correct uid");
		clog_msg_send();
	}

	if (dopurge(trackdir))
	{
		clog_msg_start_err();
		clog_msg_str("Cannot open ");
		clog_msg_str(trackdir);
		clog_msg_send();
		clog_msg_prerrno();
		return;
	}
}
Exemple #7
0
static void terminated_child(unsigned idx, unsigned delid)
{
	if (ESMTP_TERMINATING(&info[idx]))
	{
	char	*p;

		if ((p=info[idx].pendel) != 0)
		{
		char **cols=module_parsecols(info[idx].pendel);

			/*
			** Clear to 0 to prevent infinite loop if fork fails
			** in start_child.
			*/
			info[idx].pendel=0;
			start_child(idx, info[idx].pendel, cols);
			info[idx].pendel=p;
			send_child(idx, info[idx].pendel, cols);
			return;
		}

		info[idx].pid= -1;
		return;
	}

	/* Oops, something crashed.  Clean it up */

	clog_msg_start_err();
	if (info[idx].pid < 0)
	{
		clog_msg_str("Unable to fork");
	}
	else
	{
		clog_msg_str("Crashed child process ");
		clog_msg_uint(info[idx].pid);
	}

	if (ESMTP_BUSY(&info[idx]))
	{
		clog_msg_str(", while delivering to ");
		clog_msg_str(info[idx].host);
		module_completed(idx, delid);
	}
	clog_msg_send();
	close(info[idx].cmdpipe);
	info[idx].cmdpipe= -1;
	info[idx].pid= -1;
}
Exemple #8
0
int cargs(int argc, char **argv, const struct courier_args *argp)
{
int	argn;
int	i,l=0;
const char *argval;

	if ((progname=strrchr(argv[0], '/')) != 0)
		++progname;
	else
		progname=argv[0];

	for (argn=1; argn<argc; argn++)
	{
		if (argv[argn][0] != '-')	break;
		if (argv[argn][1] == 0)
		{
			++argn;
			break;
		}
		if (argv[argn][0] != '-')	break;
		for (i=0; argp[i].argname; i++)
		{
			l=strlen(argp[i].argname);
			if (strncmp(argv[argn]+1, argp[i].argname, l) == 0 &&
				(argv[argn][l+1] == '=' ||
					argv[argn][l+1] == '\0'))
				break;
		}
		if (!argp[i].argname)
		{
			clog_open_stderr(progname);
			clog_msg_start_err();
			clog_msg_str("Invalid argument: ");
			clog_msg_str(argv[argn]);
			clog_msg_send();
			exit(1);
		}

		if (*(argval=argv[argn]+1+l))
			++argval;

		if (argp[i].argval)
			*argp[i].argval=argval;

		if (argp[i].argfunc)
			(*argp[i].argfunc)(argval);
	}
	return (argn);
}
Exemple #9
0
static void kill1filter(struct filterinfo **p)
{
int	waitstat;
pid_t	pid;
struct	filterinfo *pp= *p;

	*p=pp->next;

	clog_msg_start_info();
	clog_msg_str("Stopping ");
	clog_msg_str(pp->filtername);
	clog_msg_send();
	close(pp->fd0);
	while ((pid=wait(&waitstat)) >= 0 && pid != pp->p)
		;
	free(pp->filtername);
	free(pp);
}
Exemple #10
0
static void purgedir(const char *dirname)
{
    std::string	buf;
    DIR	*p;
    struct dirent *de;

    clog_msg_start_info();
    clog_msg_str("Purging ");
    clog_msg_str(dirname);
    clog_msg_send();

    p=opendir(dirname);
    if (!p)	return;
    while ((de=readdir(p)) != NULL)
    {
        if (de->d_name[0] == '.')	continue;
        buf=dirname;
        buf += '/';
        buf += de->d_name;
        rmdir(buf.c_str());		// Just for the hell of it
    }
    closedir(p);
}
Exemple #11
0
static int faxsend_cleanup(int errcode, char *errmsg, void *vp)
{
	struct faxconv_err_args *args=(struct faxconv_err_args *)vp;
	unsigned pages_sent=0;
	char *p, *q;

	int i;
	time_t now_time;

	unsigned coverpage_cnt=0;
	unsigned page_cnt=0;

	/* Check how many files sendfax renamed (were succesfully sent) */

	while (args->file_list)
	{
		if (access(args->file_list->filename, 0) == 0)
			break;

		if (coverpage_cnt < args->n_cover_pages)
			++coverpage_cnt;
		else
			++pages_sent;
		args->file_list=args->file_list->next;
	}

	/* Strip out any blank lines in captured output from sendfax */

	for (p=q=errmsg; *p; p++)
	{
		if (*p == '\n' && (p[1] == '\n' || p[1] == 0))
			continue;

		*q++=*p;
	}
	*q=0;

	/* Find the last message from sendfax */

	for (p=q=errmsg; *p; p++)
	{
		if (*p != '\n')
			continue;

		*p=0;

		/* Dump sendfax's output to the log */

		if (*q)
		{
			clog_msg_start_info();
			clog_msg_str("courierfax: " SENDFAX ": ");
			clog_msg_str(q);
			clog_msg_send();
		}
		q=p+1;
	}

	if (*q)	/* Last line of the error message */
	{
		clog_msg_start_info();
		clog_msg_str("courierfax: " SENDFAX ": ");
		clog_msg_str(q);
		clog_msg_send();
	}
	else	/* Default message */
	{
		q=SENDFAX ": completed.";
	}

	/*
	** Ugly hack: capture the following message from sendfax:
	**
	** /usr/sbin/sendfax: cannot access fax device(s) (locked?)
	*/

#if 0
	lockflag=0;
	p=strchr(q, ':');
	if (p)
	{
		static const char msg1[]="cannot access fax device";
		static const char msg2[]="locked";

		++p;
		while (*p && isspace((int)(unsigned char)*p))
			p++;

		if (*p && strncasecmp(p, msg1, sizeof(msg1)-1) == 0)
		{
			p += sizeof(msg1);
			while (*p && !isspace((int)(unsigned char)*p))
				++p;

			p=strchr(p, '(');

			if (p && strncmp(p+1, msg2, sizeof(msg2)-1) == 0)
			{
				args->is_locked=1;
				clog_msg_start_info();
				clog_msg_str("courierfax: detected locked"
					     " modem line, sleeping...");
				clog_msg_send();
				sleep(60);
				return (-1);
			}
		}
	}
#else

	if (errcode == 2)
	{
		args->is_locked=1;
		clog_msg_start_info();
		clog_msg_str("courierfax: detected locked"
			     " modem line, sleeping...");
		clog_msg_send();
		sleep(60);
		return (-1);
	}
#endif

	ctlfile_append_connectioninfo(args->ctf, args->nreceip,
				      COMCTLFILE_DELINFO_REPLY, q);

	sprintf(errmsg, "%u cover pages, %u document pages sent.",
		coverpage_cnt, page_cnt);

	i=ctlfile_searchfirst(args->ctf, COMCTLFILE_FAXEXPIRES);

	time(&now_time);
	ctlfile_append_reply(args->ctf, args->nreceip,
			     errmsg,
			     (pages_sent == 0 &&
			      i >= 0 &&
			      errcode < 10 &&
			      now_time < strtotime(args->ctf->lines[i]+1)
			      ? COMCTLFILE_DELDEFERRED:
			      COMCTLFILE_DELFAIL_NOTRACK), 0);
	return (-1);
}
Exemple #12
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);
}
int submit_fork_virtual(char **args, char **env,
			void (*func)(const char *))
{
int	pipe0[2], pipe1[2];

	printfunc=func;

	submit_error=1;
	log_error_prefix_func=0;
	if (pipe(pipe0))
	{
		clog_msg_start_err();
		clog_msg_str(LIBEXECDIR "/courier/submit: ");
		clog_msg_str(strerror(errno));
		clog_msg_send();
		return (-1);
	}
	if (pipe(pipe1))
	{
		close(pipe0[0]);
		close(pipe0[1]);
		clog_msg_start_err();
		clog_msg_str(LIBEXECDIR "/courier/submit: ");
		clog_msg_str(strerror(errno));
		clog_msg_send();
		return (-1);
	}

	submit_pid=fork();
	if ( submit_pid == 0)
	{
	static char execfailed[]="400 Unable to submit message - service temporarily unavailable.\n";

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

		if (chdir(courierdir()))
			exit(1);

		execve( LIBEXECDIR "/courier/submit", args, env );

		clog_msg_start_err();
		clog_msg_str(LIBEXECDIR "/courier/submit: ");
		clog_msg_str(strerror(errno));
		clog_msg_send();
		if (write(1, execfailed, sizeof(execfailed)-1) != 1)
			; /* ignore */
		exit(1);
	}
	close(pipe0[0]);
	close(pipe1[1]);

	if (submit_pid == -1)
	{
		clog_msg_start_err();
		clog_msg_str(LIBEXECDIR "/courier/submit: ");
		clog_msg_str(strerror(errno));
		clog_msg_send();
		close(pipe0[1]);
		close(pipe1[0]);
		return (-1);
	}
	if (fcntl(pipe0[1], F_SETFD, FD_CLOEXEC) ||
	    (submit_to=fdopen(pipe0[1], "w")) == NULL)
	{
		clog_msg_start_err();
		clog_msg_str(LIBEXECDIR "/courier/submit: ");
		clog_msg_str(strerror(errno));
		clog_msg_send();
		close(pipe0[1]);
		close(pipe1[0]);
		(void)submit_wait_noreset();
		return (-1);
	}

	if (fcntl(pipe1[0], F_SETFD, FD_CLOEXEC) ||
	    (fromsubmit=fdopen(pipe1[0], "r")) == NULL)
	{
		clog_msg_start_err();
		clog_msg_str(LIBEXECDIR "/courier/submit: ");
		clog_msg_str(strerror(errno));
		clog_msg_send();
		fclose(submit_to);
		close(pipe1[0]);
		(void)submit_wait_noreset();
		return (-1);
	}
	submit_error=0;
	signal(SIGINT, sighandler);
	signal(SIGTERM, sighandler);
	signal(SIGHUP, sighandler);
	return (0);
}
Exemple #14
0
/*
**	sighup attempts to synchronize everything.
*/
static void sighup()
{
struct filterinfo **pp;
DIR	*dirp;
struct dirent *de;

	/* Start any new filters */

	dirp=opendir(FILTERACTIVEDIR);
	while (dirp && (de=readdir(dirp)) != 0)
	{
	char	*n;
	int	pipefd[2];
	struct filterinfo *newp;

		if (de->d_name[0] == '.')
			continue;

		for (pp= &filterlist; *pp; pp= &(*pp)->next)
			if (strcmp( (*pp)->filtername, de->d_name) == 0)
				break;

		if (*pp)	continue;

		n=malloc(sizeof(FILTERACTIVEDIR "/")+strlen(de->d_name));
		if (!n)
		{
			perror("malloc");
			exit(1);
		}
		strcat(strcpy(n, FILTERACTIVEDIR "/"), de->d_name);

		if ( (newp=(struct filterinfo *)
				malloc(sizeof(struct filterinfo))) == 0 ||
			(newp->filtername=malloc(strlen(de->d_name)+1)) == 0)
		{
			perror("malloc");
			exit(1);
		}
		strcpy(newp->filtername, de->d_name);
		newp->next=filterlist;
		filterlist=newp;

		if (pipe(pipefd) < 0)
		{
			perror("pipe");
			exit(1);
		}

		newp->fd0=pipefd[1];

		while ((newp->p=fork()) < 0)
		{
			perror("fork");
			sleep(3);
		}

		if ( newp->p == 0)
		{
			dup2(pipefd[0], 0);
			close(pipefd[0]);
			close(pipefd[1]);
			execl(n, de->d_name, (char *)0);
			perror("exec");
			exit(1);
		}
		free(n);
		close(pipefd[0]);
		if (fcntl(newp->fd0, F_SETFD, FD_CLOEXEC) < 0)
		{
			perror("fcntl");
			exit(1);
		}
		clog_msg_start_info();
		clog_msg_str("Starting ");
		clog_msg_str(newp->filtername);
		clog_msg_send();
	}
	if (dirp)	closedir(dirp);

	/* Then, kill any filters that should not be running any more */

	for (pp= &filterlist; *pp; )
	{
	char	*n=activename( (*pp)->filtername );

		if (access(n, 0) == 0)
		{
			free(n);
			pp= &(*pp)->next;
			continue;
		}
		free(n);
		kill1filter(pp);
	}

	/* Finally, remove any sockets for filters that don't run any more */

  {
  static const char *dirs[2]={FILTERSOCKETDIR, ALLFILTERSOCKETDIR};
  int i;

    for (i=0; i<2; i++)
    {
	dirp=opendir(dirs[i]);
	while (dirp && (de=readdir(dirp)) != 0)
	{
	char	*n;

		if (de->d_name[0] == '.')
			continue;

		for (pp= &filterlist; *pp; pp= &(*pp)->next)
			if (strcmp( (*pp)->filtername, de->d_name) == 0)
				break;

		if (*pp)	continue;

		n=malloc(strlen(dirs[i])+strlen(de->d_name)+2);
		if (!n)
		{
			perror("malloc");
			exit(1);
		}
		strcat(strcat(strcpy(n, dirs[i]), "/"), de->d_name);
		unlink(n);
		free(n);
	}
	if (dirp)	closedir(dirp);
    }
  }
}
Exemple #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);
	}
}
Exemple #16
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);
}
static int read_resp_oneline(char *errcode, int doprint)
{
	static char linebuf[BUFSIZ];
	char	*c;
	int	rc;
	char	prev_errcode=errcode[0];

	if (submit_error ||
		fgets(linebuf, sizeof(linebuf), fromsubmit) == NULL)
	{
	const char *errmsg="Service temporarily unavailable.";

		if (!errcode[0])
			strcpy(errcode, "432");

		if (!submit_error)
		{
			submit_error=1;
			clog_msg_start_err();
			clog_msg_str("submitclient: EOF from submit.");
#if 0
			{
				const char *p=getenv("TCPREMOTEIP");

				if (p)
				{
					clog_msg_str(" (ip: ");
					clog_msg_str(p);
					clog_msg_str(")");
				}
			}
#endif
			clog_msg_send();
		}
		if (doprint)
		{
			(*printfunc)(errcode);
			(*printfunc)(" ");
			(*printfunc)(errmsg);
			(*printfunc)(doprint & PRINT_CRLF ? "\r\n":"\n");
			(*printfunc)(0);
		}
		return(-1);
	}

	if (!isdigit((int)(unsigned char)linebuf[0]) ||
		!isdigit((int)(unsigned char)linebuf[1]) ||
		!isdigit((int)(unsigned char)linebuf[2]) ||
		(errcode[0] && strncmp(errcode, linebuf, 3)) ||
		(linebuf[3] != ' ' && linebuf[3] != '-'))
	{
	char	*p;

		clog_msg_start_err();
		clog_msg_str("submitclient: bad response from submit: ");
		if ((p=strchr(linebuf, '\n')) != 0)	*p=0;
		clog_msg_str(linebuf);
		if (p)	*p='\n';
		clog_msg_send();

		if (!errcode[0])
			strcpy(errcode, "432");
		if (doprint)
		{
			(*printfunc)(errcode);
			(*printfunc)(" ");
		}
		submit_error=1;
		rc=1;
	}
	else
	{
		if (!errcode[0])
		{
			memcpy(errcode, linebuf, 3);
			errcode[3]=0;
		}
		rc=0;
		if (linebuf[3] == ' ')	rc=1;
	}

	if ((c=strchr(linebuf, '\n')) != NULL)	*c=0;

	switch (errcode[0])	{
	case '1':
	case '2':
	case '3':
		if (doprint & PRINT_ERRORS)
			doprint=0;
		break;
	default:
		if (prev_errcode == 0 && errcode[0] == '5' &&
		    teergrubefunc)
		{
			(*teergrubefunc)();
		}

		if (log_error_prefix_func)
		{
			clog_msg_start_err();
			(*log_error_prefix_func)();
			clog_msg_str(linebuf);
			clog_msg_send();
		}
	}

	if (doprint)
		(*printfunc)(linebuf);

	if (!c)
	{
	int	ch;
	int	n=0;
	char	buf[256];

		while ((ch=getc(fromsubmit)) != '\n')
		{
			if (ch < 0)
			{
				submit_error=1;
				clog_msg_start_err();
				clog_msg_str("submitclient: EOF from submit.");
#if 0
				{
					const char *p=getenv("TCPREMOTEIP");

					if (p)
					{
						clog_msg_str(" (ip: ");
						clog_msg_str(p);
						clog_msg_str(")");
					}
				}
#endif
				clog_msg_send();
				break;
			}
			if (doprint)
			{
				buf[n++]=ch;
				if (n == sizeof(buf)-1)
				{
					buf[n]=0;
					(*printfunc)(buf);
					n=0;
				}
			}
		}
		if (doprint)
		{
			buf[n]=0;
			(*printfunc)(buf);
		}
	}

	if (doprint)
	{
		(*printfunc)(doprint & PRINT_CRLF ? "\r\n":"\n");
		(*printfunc)(0);
	}
	return (rc);
}
Exemple #18
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_start_err();
		clog_msg_str(LIBEXECDIR "/courier/submit: ");
		clog_msg_str(filename.c_str());
		clog_msg_str(": ");
		clog_msg_str(strerror(errno));
		clog_msg_send();
		exit(1);
	}

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;
}
Exemple #19
0
int msgq::queuescan3(std::string subdir, std::string name,
		     const char *isnewmsg)
{
	struct ctlfile	ctlinfo;
	ino_t	inum;
	time_t	deltime, delsendtime;
	const char *p=name.c_str();
	struct	stat	stat_buf;

	++p;
	inum=strtoino(p);
	while (isdigit(*p))	p++;
	++p;
	deltime=strtotime(p);
	name= subdir + '/' + name;
	if (ctlfile_openfn(name.c_str(), &ctlinfo, 0, 1))
	{
		if (errno)
		{
			clog_msg_start_err();
			clog_msg_str("Cannot read ");
			clog_msg_str(name.c_str());
			clog_msg_send();
			clog_msg_prerrno();
		}
		return (0);
	}
	delsendtime=deltime;
	if (flushtime && ctlinfo.mtime < flushtime && flushtime < deltime)
		delsendtime=flushtime;

	if (!queuefree)
	{
	msgq	*p;

//
// msgq array is full.  See if we can remove the last message from the
// pending queue.

		p=queuetail;
		if (p && p->nextsenddel > delsendtime)
		{

#if 0
clog_msg_start_info();
clog_msg_str("Removing ");
clog_msg_uint(p->msgnum);
clog_msg_str(" to make room for this message.");
clog_msg_send();
#endif

			p->removewq();
			p->removeq();
		}
	}

msgq	*newq=queuefree;

	if (!newq)
	{
		ctlfile_close(&ctlinfo);

		if (queuefill && nextqueuefill == 0)
		{
			nextqueuefill=current_time + queuefill;
		}
		return (1);
	}

	const char *cn=qmsgsctlname(inum);

	if ( stat(cn, &stat_buf) == -1 )
	{
		unlink(name.c_str());
		unlink(qmsgsdatname(inum));
		unlink(cn);
		ctlfile_close(&ctlinfo);
		return (0);
	}


#if 0
clog_msg_start_info();
clog_msg_str("Adding ");
clog_msg_uint(inum);
clog_msg_str(" to queue.");
clog_msg_send();
#endif

	queuefree=newq->next;
	++queuedelivering;

	ino_t	hashbucket=inum % queuehashfirst.size();

	if (queuehashfirst[hashbucket])
		queuehashfirst[hashbucket]->prevhash=newq;
	else
		queuehashlast[hashbucket]=newq;

	newq->nexthash=queuehashfirst[hashbucket];
	newq->prevhash=0;
	queuehashfirst[hashbucket]=newq;

	newq->nksize= (unsigned long)stat_buf.st_size;
	ctlinfo.starttime=stat_buf.st_mtime;

int	k=ctlfile_searchfirst(&ctlinfo, COMCTLFILE_MSGID);

	newq->msgid= k < 0 ? "": ctlinfo.lines[k]+1;

	newq->msgnum=inum;
	newq->nextdel=deltime;
	newq->nextsenddel=delsendtime;
	newq->rcptinfo_list.resize(0);
	newq->rcptcount=0;
	newq->cancelled=ctlinfo.cancelled;

	if (isnewmsg)
	{
		int auth;

		clog_msg_start_info();
		clog_msg_str("newmsg,id=");
		logmsgid(newq);

		auth=ctlfile_searchfirst(&ctlinfo, COMCTLFILE_AUTHNAME);

		if (auth >= 0)
		{
			clog_msg_str(", auth=");
			clog_msg_str(ctlinfo.lines[auth]+1);
		}

		int m=ctlfile_searchfirst(&ctlinfo, COMCTLFILE_FROMMTA);

		if (m >= 0)
		{
			clog_msg_str(": ");
			clog_msg_str(ctlinfo.lines[m]+1);
		}

		clog_msg_send();
	}

	unsigned	i, j;
	std::string host, addr;

	k=ctlfile_searchfirst(&ctlinfo, COMCTLFILE_SENDER);

	struct rfc822t *sendert=rw_rewrite_tokenize(k < 0 ? "":ctlinfo.lines[k]+1);
	std::string	errmsg;

	for (i=0; i<ctlinfo.nreceipients; i++)
	{
		for (j=0; ctlinfo.lines[j]; j++)
		{
			switch (ctlinfo.lines[j][0])	{
			case COMCTLFILE_DELSUCCESS:
			case COMCTLFILE_DELFAIL:
				if ((unsigned)atoi(ctlinfo.lines[j]+1) == i)
					break;
				// This one has been delivered
			default:
				continue;
			}
			break;
		}
		if (ctlinfo.lines[j])	continue;

	drvinfo *module=getdelinfo(sendert->tokens,
			ctlinfo.receipients[i], host, addr, errmsg);

		if (!module)
		{
			ctlfile_append_reply(&ctlinfo, i, errmsg.c_str(),
					     SMTPREPLY_TYPE(errmsg.c_str()),
					     0);
			continue;
		}

		/* Check if it's time to move the message to a backup relay */

		if (backup_relay_driver &&
			ctlfile_searchfirst(&ctlinfo, COMCTLFILE_WARNINGSENT)
			>= 0 &&
		    strcmp(module->module->name,
			   backup_relay_driver->module->name) == 0)
		{
			// module=backup_relay_driver;
			host=backup_relay;
		}

		/* Group all recipients for the same driver and host together */

		for (j=0; j<newq->rcptcount; j++)
			if (strcmp(module->module->name,
				   newq->rcptinfo_list[j].delmodule->
				   module->name) == 0 &&
			    newq->rcptinfo_list[j].delhost == host &&
			    newq->rcptinfo_list[j].addresses.size()
			    < module->maxrcpt )
				break;
		if (j == newq->rcptcount)
		{
#if 0
clog_msg_start_info();
clog_msg_str("id=");
logmsgid(newq);
clog_msg_str(",new rcpt list - module=");
clog_msg_str(module->module->name);
clog_msg_str(", host=");
clog_msg_str(host);
clog_msg_send();
#endif
			newq->rcptinfo_list.resize(++newq->rcptcount);

		struct	rw_info_rewrite rwir;
		struct	rw_info	rwi;

			rwir.buf=0;
			rwir.errmsg=0;
			rw_info_init(&rwi, sendert->tokens, rw_err_func);
			rwi.sender=0;
			rwi.mode=RW_OUTPUT|RW_ENVSENDER;
			rwi.udata= (void *)&rwir;
			rw_rewrite_module(module->module, &rwi,
				rw_rewrite_chksyn_print);

		char *address=((struct rw_info_rewrite *)rwi.udata)->buf;
		char *errmsg= ((struct rw_info_rewrite *)rwi.udata)->errmsg;

			if (!address)
			{
				ctlfile_append_reply(&ctlinfo, i, errmsg,
					SMTPREPLY_TYPE(errmsg), 0);
				newq->rcptinfo_list.resize(--newq->rcptcount);
				free(errmsg);
				continue;
			}

			if (errmsg)	free(errmsg);
			newq->rcptinfo_list[j].init(newq, module, host, address);
			free(address);
		}
#if 0
clog_msg_start_info();
clog_msg_str("id=");
logmsgid(newq);
clog_msg_str(",module=");
clog_msg_str(module->module->name);
clog_msg_str(", host=");
clog_msg_str(host);
clog_msg_str(", addr=<");
clog_msg_str(addr);
clog_msg_str(">");
clog_msg_send();
#endif

		newq->rcptinfo_list[j].addresses.push_back(addr);
		newq->rcptinfo_list[j].addressesidx.push_back(i);
	}
	rfc822t_free(sendert);
	ctlfile_close(&ctlinfo);

	if (newq->nextsenddel <= current_time ||

/*
** If there are no more recipients, we want to call done() via
** start_message.  HOWEVER, if DSN injection FAILED, we want to respect
** the rescheduled delivery attempt time.  We can detect that if isnewmsg == 0
*/
		(newq->rcptinfo_list.size() == 0 && isnewmsg))
	{
		newq->start_message();
		return (0);
	}

msgq	*qp, *qprev;

	for (qprev=queuetail, qp=0; qprev; qp=qprev, qprev=qp->prev)
		if (qprev->nextsenddel < newq->nextsenddel)
			break;

	newq->next=qp;
	newq->prev=qprev;

	if (qprev)	qprev->next=newq;
	else		queuehead=newq;

	if (qp)	qp->prev=newq;
	else	queuetail=newq;
	++queuewaiting;
	return (0);
}
Exemple #20
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;
	}
}
Exemple #21
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);
}
Exemple #22
0
void msgq::start_message()
{
//
// Schedule deliveries for this message.
//

#if 0
clog_msg_start_info();
clog_msg_str("Start message ");
logmsgid(this);
clog_msg_send();
#endif

	size_t n=rcptinfo_list.size();

	if (n == 0)
	{
		done(this, 0);
		return;
	}

	size_t i;

	for (i=0; i<n; i++)
	{
		rcptinfo &ri=rcptinfo_list[i];

	drvinfo *drvp=ri.delmodule;
	dlvrhost *hostp, *freehostp=0;

//
// Check if the same host has any deliveries in progress, or pending.
// Search the hdlvrpfree/hdlvrplast link list for this host.
//
		for (hostp=drvp->hdlvrplast; hostp; hostp=hostp->prev)
		{
			if (hostp->hostname == ri.delhost)
{
#if 0
clog_msg_start_info();
clog_msg_str("Found host ");
clog_msg_str(ri.delhost);
clog_msg_str(", # of deliveries=");
clog_msg_uint(hostp->dlvrcount);
clog_msg_send();
#endif
				break;
}

//
// Just in case we don't find it, remember the last host at the end of the
// MRU list which does not have any deliveries in progress.
//
			if (!freehostp &&
				drvp->hdlvrpfree == 0 && hostp->dlvrcount == 0)
				freehostp=hostp;
				// Recycle a host struct used longest ago
		}
		if (!hostp)
		{
//
// Did not find this host.
//
			if (drvp->hdlvrpfree)
			{
//
// There's an unused host structure, take it.
//
				hostp=drvp->hdlvrpfree;
				drvp->hdlvrpfree=hostp->next;
			}
			else if (freehostp)
			{
//
// Recycle a host structure for a host without any current deliveries,
// remove it from the MRU list.
//
				hostp=freehostp;
				if (hostp->next)
					hostp->next->prev=hostp->prev;
				else
					drvp->hdlvrplast=hostp->prev;
				if (hostp->prev)
					hostp->prev->next=hostp->next;
				else
					drvp->hdlvrpfirst=hostp->next;
			}

			if (hostp)
			{
//
// Ok, initialize this host, and stick it at the end of the MRU list.
//
				hostp->hostname=ri.delhost;
				hostp->dlvrcount=0;
				hostp->next=0;
				if ((hostp->prev=drvp->hdlvrplast) != 0)
					drvp->hdlvrplast->next=hostp;
				else
					drvp->hdlvrpfirst=hostp;
				drvp->hdlvrplast=hostp;
				if (hostp->pending_list)
					hostp->pending_list->hostp=0;
				hostp->pending_list=0;
			}
		}
//
// Determine if we can start a new delivery.  The conditions are:
// A) We found an unused host structure, and the number of deliveries in
// progress to this host is less than the maximum set for the module,
//
// AND
//
// B) The total number of current deliveries to this host is less than
// the maximum set for this module (there's an available delivery slot
// structure)
//
		if (hostp && hostp->dlvrcount < drvp->maxhost &&
			drvp->delpfreefirst)
		{
		delinfo *newdi=drvp->delpfreefirst;

			drvp->delpfreefirst=newdi->freenext;
			newdi->dlvrphost=hostp;
			newdi->rcptlist=&ri;

			ri.pending=0;
			hostp->dlvrcount++;
			startdelivery(drvp, newdi);
			continue;
		}
//
// We are unable to start the delivery at this time.  At the recipient list
// to the list of pending deliveries for this host.
//
// The first thing is to make sure that this host structure has the pending
// list structure allocated.
//

	pendelinfo *pi;

		if (hostp)
		{
			if ((pi=hostp->pending_list) == 0)
			{
				drvp->pendelinfo_list.push_back(pendelinfo());

				std::list<pendelinfo>::iterator pos=
					--drvp->pendelinfo_list.end();

				pi=& *pos;
				pi->pos=pos;
				pi->drvp=drvp;
				pi->hostname=ri.delhost;
				pi->hostp=hostp;
				hostp->pending_list=pi;
			}
		}
		else
		{
			std::list<pendelinfo>::iterator pos;

//
// We don't even have a host structure.
// That's ok, search the pendelinfo_list of this module anyway.
//
			pi=0;

			for (pos=drvp->pendelinfo_list.begin();
			     pos != drvp->pendelinfo_list.end();
			     ++pos)
			{
				pi=& *pos;
				if (pi->hostname == ri.delhost) break;
				pi=0;
			}
			if (!pi)
			{
				drvp->pendelinfo_list.push_back(pendelinfo());
				pos= --drvp->pendelinfo_list.end();

				pi=& *pos;
				pi->pos=pos;
				pi->drvp=drvp;
				pi->hostname=ri.delhost;
				pi->hostp=0;
			}
		}

		ri.pending=pi;
		pi->receipient_list.push_back(&ri);

		ri.pendingpos= --pi->receipient_list.end();
	}
}
Exemple #23
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);
}
Exemple #24
0
static void perlfilter()
{
char *embedding[] = { "", WRAPPERPL };
char *args[] = { "", "0", NULL, NULL, NULL};
int exitstatus = 0;
int	sock;
PerlInterpreter *my_perl;
 
	if((my_perl = perl_alloc()) == NULL)
	{
		fprintf(stderr, "no memory!");
		exit(1);
	}
	perl_construct(my_perl);
 
	exitstatus = perl_parse(my_perl, xs_init, 2, embedding, NULL);
 
	if (exitstatus || (exitstatus=perl_run(my_perl)) != 0)
	{
		fprintf(stderr, "Cannot parse " WRAPPERPL "\n");
		exit(exitstatus);
	}

	while ((sock=lf_accept(listen_sock)) >= 0)
	{
	char	sockbuf[100];

		args[0]=filter;
		sprintf(sockbuf, "%d", sock);
		args[2]=sockbuf;

		{
		dSP ;
		ENTER ;
		SAVETMPS ;

		perl_call_argv("Embed::Persistent::eval_file",
			G_VOID | G_DISCARD | G_EVAL, args);

#ifdef	ERRSV
		if(SvTRUE(ERRSV))
#else
		if(SvTRUE(GvSV(errgv)))
#endif
		{
			clog_open_syslog("perlfilter");
			clog_msg_start_err();
			clog_msg_str("eval error: ");

#ifdef	ERRSV
			clog_msg_str(SvPV(ERRSV,PL_na));
#else
			clog_msg_str(SvPV(GvSV(errgv),na));
#endif
			clog_msg_send();
		}
		FREETMPS ;
		LEAVE ;
		}

		close(sock);	/* Just in case */
	}
#ifdef	perl_destruct_level
	perl_destruct_level=0;
#else
	PL_perl_destruct_level=0;
#endif
	perl_destruct(my_perl);
	perl_free(my_perl);
	exit(0);
}
Exemple #25
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));
	}
}