/*
* Copyright 1988 by Rayan S. Zachariassen, all rights reserved.
* This will be free software, but only when it is finished.
*/
/*
* Several extensive changes by Matti Aarnio <mea@nic.funet.fi>
* Copyright 1991-2003.
*/
#include "smtpserver.h"
/*
* The way VRFY and EXPN are implemented, and even MAIL FROM and RCPT TO
* checking, we somehow connect to a router and ask it to do stuff for us.
* There are three routines, one to connect to the router, one to kill it
* off again, and the line-getting routine that gets everything the router
* prints at us, one line at a time.
*/
static char promptbuf[30];
static int promptlen;
static FILE *tofp = NULL, *fromfp = NULL;
static char *mgets __((SmtpState * SS, int *, FILE *));
static char *mgets(SS, flagp, fp)
SmtpState *SS;
int *flagp;
FILE *fp;
{
register int bufsize, c;
register char *cp;
char *buf;
int ccnt = 0;
if (*flagp) {
*flagp = 0;
return NULL;
}
bufsize = 16;
cp = buf = emalloc(bufsize);
while ((c = getc(fp)) != EOF) {
*cp = c;
++ccnt;
if (c == '\n') {
*flagp = 0;
break;
}
++cp;
if ((cp - buf) >= promptlen &&
strncmp(cp - promptlen, promptbuf, promptlen) == 0) {
*cp = 0;
if (debug)
type(SS,0,NULL,"mgets() buf=\"%s\"\r\n", buf);
free(buf);
buf = NULL;
*flagp = 1;
return NULL;
}
if (bufsize - 2 < ccnt) {
bufsize <<= 1;
buf = erealloc(buf, bufsize);
cp = buf + ccnt;
}
}
if (buf)
*cp = '\0';
if (debug && buf)
type(SS,0,NULL, "mgets() buf=\"%s\"\r\n", buf);
if (c == EOF) {
if (debug)
type(SS,0,NULL,"mgets() got EOF!\r\n");
free(buf);
return NULL;
}
return buf;
}
#ifndef HAVE_PUTENV
static const char *newenviron[] =
{ "SMTPSERVER=y", NULL };
#endif
static int callr __((SmtpState * SS));
static int callr(SS)
SmtpState *SS;
{
int sawend, rpid = 0, to[2], from[2];
char *bufp;
char *cp;
if (pipe(to) < 0 || pipe(from) < 0)
return -1;
#if 0
#if 0
SIGNAL_HANDLE(SIGCHLD, SIG_DFL); /* ?? SIG_DFL on SVR4 ? */
#else
SIGNAL_HANDLE(SIGCHLD, reaper);
#endif
SIGNAL_HANDLE(SIGPIPE, SIG_IGN);
#endif
if (routerprog == NULL) {
if ((cp = (char *)getzenv("MAILBIN")) == NULL) {
zsyslog((LOG_ERR, "MAILBIN unspecified in zmailer.conf"));
return -1;
}
routerprog = emalloc(strlen(cp) + sizeof "router" + 2);
sprintf(routerprog, "%s/router", cp);
}
if ((rpid = fork()) == 0) { /* child */
rpid = getpid();
dup2(to[0], 0);
dup2(from[1], 1);
dup2(from[1], 2);
close(to[0]);
close(to[1]);
close(from[0]);
close(from[1]);
runasrootuser(); /* XXX: security alert! */
#ifdef HAVE_PUTENV
putenv("SMTPSERVER=y");
#else
environ = (char **) newenviron;
#endif
execl(routerprog, "router", "-io-i", (char *) NULL);
#define BADEXEC "8@$#&(\n\n"
write(1, BADEXEC, strlen(BADEXEC));
_exit(1);
} else if (rpid < 0)
return -1;
close(to[0]);
close(from[1]);
tofp = fdopen(to[1], "w");
fromfp = fdopen(from[0], "r");
/* stuff a command to print something recognizable down the pipe */
sprintf(promptbuf, "%d# ", (int)getpid());
promptlen = strlen(promptbuf);
/*
* Gotta be careful here: ihostaddr is generated within the program
* from the IP address, but rhostname is specified by the remote host.
* Although it may be caught by partridge(), lets make extra sure.
*/
for (cp = SS->rhostname; *cp; ++cp)
if (*cp == '\'')
*cp = '?';
if (SS->rhostname[strlen(SS->rhostname) - 1] == '\\')
SS->rhostname[strlen(SS->rhostname) - 1] = '?';
fprintf(tofp, "PS1='%s' ; %s %s '%s' '%s'\n", promptbuf,
ROUTER_SERVER, RKEY_INIT, SS->rhostname, SS->ihostaddr);
fflush(tofp);
if (debug) {
type(SS,0,NULL, "==> PS1='%s' ; %s %s '%s' '%s'\r\n", promptbuf,
ROUTER_SERVER, RKEY_INIT, SS->rhostname, SS->ihostaddr);
typeflush(SS);
}
sawend = 0;
while ((bufp = mgets(SS, &sawend, fromfp)) != NULL) {
if (strncmp(cp, BADEXEC, strlen(BADEXEC) - 2) == 0) {
free(cp);
killr(SS, rpid);
return -1;
}
/*printf("241%c%s\n", sawend == 1 ? ' ' : '-', buf); */
free(bufp);
}
return rpid;
}
void killr(SS, rpid)
SmtpState *SS;
int rpid;
{
if (rpid > 0) {
if (tofp == NULL)
fclose(tofp);
tofp = NULL;
if (fromfp == NULL)
fclose(fromfp);
fromfp = NULL;
kill(rpid, SIGKILL);
}
}
/*
* Now we can do VRFY et al using the router we have connected to.
*/
char *
router(SS, function, holdlast, args, len)
SmtpState *SS;
const char *function, *args;
const int holdlast, len;
{
char *bufp, *prevb = NULL;
int sawend = 0, i, j, s;
const char *args0 = args;
if (args == NULL) {
type(SS, 501, NULL, NULL);
return NULL;
}
if (!enable_router) {
type(SS, 400, "4.4.0","Interactive routing subsystem is not enabled");
return NULL;
}
if (routerpid <= 0 && (routerpid = callr(SS)) <= 0) {
type(SS, 451, NULL, NULL);
return NULL;
}
j = 20 + strlen(ROUTER_SERVER) + strlen(function);
bufp = malloc(j);
if (!bufp) {
type(SS, 400, NULL, "Huh! Out of memory!");
return NULL;
}
sprintf(bufp, "%s %s '", ROUTER_SERVER, function);
s = strlen(bufp);
/* Wrap the user input string into simple quotes, then if
the input string contains said character, do (difficult)
'...'"'"'...' juggling of the quotes. */
for (i = 0; *args && i < len; ++args, ++i) {
if ((s + 10) >= j) {
j += 20;
bufp = realloc(bufp,j);
if (!bufp) {
type(SS, 400, NULL, "Huh! Out of memory!");
return NULL;
}
}
if (*args == '\'') {
strcpy(bufp+s, "'\"'\"");
s += strlen(bufp+s);
}
bufp[s++] = *args;
}
bufp[s++] = '\'';
bufp[s] = 0;
fprintf(tofp, "%s\n", bufp);
fflush(tofp);
if (debug)
type(SS, 0, NULL, "==> %s", bufp);
free(bufp); /* Its done its job, throw it away.. */
for ( ;!sawend; ) {
/*
* We want to give the router the opportunity to report
* result codes, e.g. for boolean requests. If the first
* three characters are digits and the 4th a space or '-',
* then pass through.
*/
bufp = mgets(SS, &sawend, fromfp);
if (debug)
type(SS, 0, NULL, "mgets()->%p (%s), sawend=%d\r\n",
bufp, (bufp ? bufp : "<NULL>"), sawend);
if (!bufp) {
/* Huh! Got an EOF, while probably didn't expect it ?
Lets find out what the subprocess status was */
bufp = emalloc(80 + strlen(args0) + strlen(function) +
sizeof(ROUTER_SERVER));
sprintf(bufp, "400 Huh! Router server EOFed (crashed?) on us! Help! Last cmd was: %s %s \"%.*s\"", ROUTER_SERVER, function, len, args0);
break;
}
if (prevb != NULL) {
if (strlen(prevb) > 4 &&
isdigit(prevb[0]) && isdigit(prevb[1]) && isdigit(prevb[2])
&& (prevb[3] == ' ' || prevb[3] == '-')) {
int code = atoi(prevb);
type(SS, -code, NULL, "%s", prevb+4);
} else {
type(SS, -250, NULL, "%s", prevb);
}
free(prevb);
}
prevb = bufp;
}
if (!holdlast && prevb != NULL) {
/* -------- Print the last line too -------- */
if (strlen(prevb) > 4 &&
isdigit(prevb[0]) && isdigit(prevb[1]) && isdigit(prevb[2])
&& (prevb[3] == ' ')) {
int code = atoi(prevb);
type(SS, code, NULL, "%s", prevb+4);
} else {
type(SS, 250, NULL, "%s", prevb);
}
strncpy(prevb, "dummy-replacement-string", strlen(prevb));
} else {
/* Uhhh.... No output! */
if (!prevb)
type(SS, 400, NULL, "**INTERNAL*ERROR**");
}
typeflush(SS);
if (debug)
type(SS,0,NULL,"router()->%p (%s)\r\n", prevb, prevb ? prevb : "<NULL>");
return prevb; /* It may be unfreeable pointer... */
}
syntax highlighted by Code2HTML, v. 0.9.1