Beispiel #1
0
void
initstatus()
{
  if(lseek(status, 0, SEEK_SET) != 0) {
    fprintf(Log, "%s:  Seek error on status file\n", thedate());
    return;
  }
  if(read(status, Status, 16*16*sizeof(STATUS)) != 16*16*sizeof(STATUS)) {
        fprintf(Log, "%s:  Read error on status file\n", thedate());
	return;
  }
}
Beispiel #2
0
void
quit(void)
{
	reply("221 2.0.0 Successful termination\r\n");
	if(debug){
		seek(2, 0, 2);
		stamp();
		fprint(2, "# %d sent 221 reply to QUIT %s\n",
			getpid(), thedate());
	}
	close(0);
	exits(0);
}
Beispiel #3
0
void
checkpoint_status()
{
  int h, i, k, offset;

  offset = 0;
  for(h = 0; h < 16; h++) {
    for(i = 0; i < 16; i++) {
      if(Status[h][i].changed) {
	if(lseek(status, offset, SEEK_SET) != offset) {
	  fprintf(Log, "%s:  Seek error on status file\n", thedate());
	} else {
	  if(write(status, &Status[h][i], sizeof(STATUS)) != sizeof(STATUS)) {
	    fprintf(Log, "%s:  Write error on status file\n", thedate());
	  }
	}
	Status[h][i].changed = 0;
	for(k = 0; k < MAXMON; k++) {
	  if(Monitor[k].inuse
	     && Monitor[k].house == h && Monitor[k].unit == i) {
	    /*
	     * Arrange to catch SIGPIPE in case client has gone away.
	     */
	    extern int client;
	    extern void clientgone();
	    void (*prev)();

	    client = k;
	    prev = signal(SIGPIPE, clientgone);
	    printstatus(Monitor[k].user, &Status[h][i]);
	    fflush(Monitor[k].user);
	    signal(SIGPIPE, prev);
	  }
	}
      }
      offset += sizeof(STATUS);
    }
  }
}
Beispiel #4
0
extern int
default_from(message *mp)
{
	char *cp, *lp;

	cp = getenv("upasname");
	lp = getlog();
	if(lp == nil)
		return -1;

	if(cp && *cp)
		s_append(mp->sender, cp);
	else
		s_append(mp->sender, lp);
	s_append(mp->date, thedate());
	return 0;
}
Beispiel #5
0
void
main(int argc, char **argv)
{
	int i, ok, rcvrs;
	char *addr, *rv, *trv, *host, *domain;
	char **errs;
	char hellodomain[256];
	String *from, *fromm, *sender;

	alarmscale = 60*1000;	/* minutes */
	quotefmtinstall();
	fmtinstall('[', encodefmt);
	errs = malloc(argc*sizeof(char*));
	reply = s_new();
	host = 0;
	ARGBEGIN{
	case 'a':
		tryauth = 1;
		if(trysecure == 0)
			trysecure = 1;
		break;
	case 'A':	/* autistic: won't talk to us until we talk (Verizon) */
		autistic = 1;
		break;
	case 'b':
		if (bustedmx >= Maxbustedmx)
			sysfatal("more than %d busted mxs given", Maxbustedmx);
		bustedmxs[bustedmx++] = EARGF(usage());
		break;
	case 'd':
		debug = 1;
		break;
	case 'f':
		filter = 1;
		break;
	case 'g':
		gdomain = EARGF(usage());
		break;
	case 'h':
		host = EARGF(usage());
		break;
	case 'i':
		insecure = 1;
		break;
	case 'p':
		alarmscale = 10*1000;	/* tens of seconds */
		ping = 1;
		break;
	case 's':
		if(trysecure == 0)
			trysecure = 1;
		break;
	case 't':
		trysecure = 2;
		break;
	case 'u':
		user = EARGF(usage());
		break;
	default:
		usage();
		break;
	}ARGEND;

	Binit(&berr, 2, OWRITE);
	Binit(&bfile, 0, OREAD);

	/*
	 *  get domain and add to host name
	 */
	if(*argv && **argv=='.') {
		domain = *argv;
		argv++; argc--;
	} else
		domain = domainname_read();
	if(host == 0)
		host = sysname_read();
	strcpy(hostdomain, domainify(host, domain));
	strcpy(hellodomain, domainify(sysname_read(), domain));

	/*
	 *  get destination address
	 */
	if(*argv == 0)
		usage();
	addr = *argv++; argc--;
	farend = addr;

	/*
	 *  get sender's machine.
	 *  get sender in internet style.  domainify if necessary.
	 */
	if(*argv == 0)
		usage();
	sender = unescapespecial(s_copy(*argv++));
	argc--;
	fromm = s_clone(sender);
	rv = strrchr(s_to_c(fromm), '!');
	if(rv)
		*rv = 0;
	else
		*s_to_c(fromm) = 0;
	from = bangtoat(s_to_c(sender));

	/*
	 *  send the mail
	 */
	if(filter){
		Binit(&bout, 1, OWRITE);
		rv = data(from, &bfile);
		if(rv != 0)
			goto error;
		exits(0);
	}

	/* mxdial uses its own timeout handler */
	if((rv = connect(addr)) != 0)
		exits(rv);

	/* 10 minutes to get through the initial handshake */
	atnotify(timeout, 1);
	alarm(10*alarmscale);
	if((rv = hello(hellodomain, 0)) != 0)
		goto error;
	alarm(10*alarmscale);
	if((rv = mailfrom(s_to_c(from))) != 0)
		goto error;

	ok = 0;
	rcvrs = 0;
	/* if any rcvrs are ok, we try to send the message */
	for(i = 0; i < argc; i++){
		if((trv = rcptto(argv[i])) != 0){
			/* remember worst error */
			if(rv != Giveup)
				rv = trv;
			errs[rcvrs] = strdup(s_to_c(reply));
			removenewline(errs[rcvrs]);
		} else {
			ok++;
			errs[rcvrs] = 0;
		}
		rcvrs++;
	}

	/* if no ok rcvrs or worst error is retry, give up */
	if(ok == 0 || rv == Retry)
		goto error;

	if(ping){
		quit(0);
		exits(0);
	}

	rv = data(from, &bfile);
	if(rv != 0)
		goto error;
	quit(0);
	if(rcvrs == ok)
		exits(0);

	/*
	 *  here when some but not all rcvrs failed
	 */
	fprint(2, "%s connect to %s:\n", thedate(), addr);
	for(i = 0; i < rcvrs; i++){
		if(errs[i]){
			syslog(0, "smtp.fail", "delivery to %s at %s failed: %s", argv[i], addr, errs[i]);
			fprint(2, "  mail to %s failed: %s", argv[i], errs[i]);
		}
	}
	exits(Giveup);

	/*
	 *  here when all rcvrs failed
	 */
error:
	removenewline(s_to_c(reply));
	syslog(0, "smtp.fail", "%s to %s failed: %s",
		ping ? "ping" : "delivery",
		addr, s_to_c(reply));
	fprint(2, "%s connect to %s:\n%s\n", thedate(), addr, s_to_c(reply));
	if(!filter)
		quit(rv);
	exits(rv);
}
Beispiel #6
0
void
data(void)
{
	int status, nbytes;
	char *cp, *ep;
	char errx[ERRMAX];
	Link *l;
	String *cmd, *err;

	if(rejectcheck())
		return;
	if(senders.last == 0){
		reply("503 2.5.2 Data without MAIL FROM:\r\n");
		rejectcount++;
		return;
	}
	if(rcvers.last == 0){
		reply("503 2.5.2 Data without RCPT TO:\r\n");
		rejectcount++;
		return;
	}
	if(!trusted && sendermxcheck()){
		rerrstr(errx, sizeof errx);
		if(strncmp(errx, "rejected:", 9) == 0)
			reply("554 5.7.1 %s\r\n", errx);
		else
			reply("450 4.7.0 %s\r\n", errx);
		for(l=rcvers.first; l; l=l->next)
			syslog(0, "smtpd", "[%s/%s] %s -> %s sendercheck: %s",
				him, nci->rsys, s_to_c(senders.first->p),
				s_to_c(l->p), errx);
		rejectcount++;
		return;
	}

	cmd = startcmd();
	if(cmd == 0)
		return;

	reply("354 Input message; end with <CRLF>.<CRLF>\r\n");
	if(debug){
		seek(2, 0, 2);
		stamp();
		fprint(2, "# sent 354; accepting DATA %s\n", thedate());
	}


	/*
	 *  allow 145 more minutes to move the data
	 */
	alarm(145*60*1000);

	status = pipemsg(&nbytes);

	/*
	 *  read any error messages
	 */
	err = s_new();
	if (debug) {
		stamp();
		fprint(2, "waiting for upas/send to close stderr\n");
	}
	while(s_read_line(pp->std[2]->fp, err))
		;

	alarm(0);
	atnotify(catchalarm, 0);

	if (debug) {
		stamp();
		fprint(2, "waiting for upas/send to exit\n");
	}
	status |= proc_wait(pp);
	if(debug){
		seek(2, 0, 2);
		stamp();
		fprint(2, "# %d upas/send status %#ux at %s\n",
			getpid(), status, thedate());
		if(*s_to_c(err))
			fprint(2, "# %d error %s\n", getpid(), s_to_c(err));
	}

	/*
	 *  if process terminated abnormally, send back error message
	 */
	if(status){
		int code;
		char *ecode;

		if(strstr(s_to_c(err), "mail refused")){
			syslog(0, "smtpd", "++[%s/%s] %s %s refused: %s",
				him, nci->rsys, s_to_c(senders.first->p),
				s_to_c(cmd), firstline(s_to_c(err)));
			code = 554;
			ecode = "5.0.0";
		} else {
			syslog(0, "smtpd", "++[%s/%s] %s %s %s%s%sreturned %#q %s",
				him, nci->rsys,
				s_to_c(senders.first->p), s_to_c(cmd),
				piperror? "error during pipemsg: ": "",
				piperror? piperror: "",
				piperror? "; ": "",
				pp->waitmsg->msg, firstline(s_to_c(err)));
			code = 450;
			ecode = "4.0.0";
		}
		for(cp = s_to_c(err); ep = strchr(cp, '\n'); cp = ep){
			*ep++ = 0;
			reply("%d-%s %s\r\n", code, ecode, cp);
		}
		reply("%d %s mail process terminated abnormally\r\n",
			code, ecode);
	} else {
		/*
		 * if a message appeared on stderr, despite good status,
		 * log it.  this can happen if rewrite.in contains a bad
		 * r.e., for example.
		 */
		if(*s_to_c(err))
			syslog(0, "smtpd",
				"%s returned good status, but said: %s",
				s_to_c(mailer), s_to_c(err));

		if(filterstate == BLOCKED)
			reply("554 5.7.1 we believe this is spam.  "
				"we don't accept it.\r\n");
		else if(filterstate == DELAY)
			reply("450 4.3.0 There will be a delay in delivery "
				"of this message.\r\n");
		else {
			reply("250 2.5.0 sent\r\n");
			logcall(nbytes);
			if(debug){
				seek(2, 0, 2);
				stamp();
				fprint(2, "# %d sent 250 reply %s\n",
					getpid(), thedate());
			}
		}
	}
	proc_free(pp);
	pp = 0;
	s_free(cmd);
	s_free(err);

	listfree(&senders);
	listfree(&rcvers);
}
Beispiel #7
0
void
main(int argc, char **argv)
{
	char *netdir;
	char buf[1024];

	netdir = nil;
	quotefmtinstall();
	fmtinstall('I', eipfmt);
	starttime = time(0);
	ARGBEGIN{
	case 'a':
		authenticate = 1;
		break;
	case 'c':
		tlscert = EARGF(usage());
		break;
	case 'D':
		Dflag++;
		break;
	case 'd':
		debug++;
		break;
	case 'f':				/* disallow relaying */
		fflag = 1;
		break;
	case 'g':
		gflag = 1;
		break;
	case 'h':				/* default domain name */
		dom = EARGF(usage());
		break;
	case 'k':				/* prohibited ip address */
		addbadguy(EARGF(usage()));
		break;
	case 'm':				/* set mail command */
		mailer = mailerpath(EARGF(usage()));
		break;
	case 'n':				/* log peer ip address */
		netdir = EARGF(usage());
		break;
	case 'p':
		passwordinclear = 1;
		break;
	case 'r':
		rflag = 1;			/* verify sender's domain */
		break;
	case 's':				/* save blocked messages */
		sflag = 1;
		break;
	case 't':
		fprint(2, "%s: the -t option is no longer supported, see -c\n",
			argv0);
		tlscert = "/sys/lib/ssl/smtpd-cert.pem";
		break;
	default:
		usage();
	}ARGEND;

	nci = getnetconninfo(netdir, 0);
	if(nci == nil)
		sysfatal("can't get remote system's address: %r");
	parseip(rsysip, nci->rsys);

	if(mailer == nil)
		mailer = mailerpath("send");

	if(debug){
		snprint(buf, sizeof buf, "%s/smtpdb/%ld", UPASLOG, time(0));
		close(2);
		if (create(buf, OWRITE | OEXCL, 0662) >= 0) {
			seek(2, 0, 2);
			fprint(2, "%d smtpd %s\n", getpid(), thedate());
		} else
			debug = 0;
	}
	getconf();
	if (isbadguy())
		exits("banned");
	Binit(&bin, 0, OREAD);

	if (chdir(UPASLOG) < 0)
		syslog(0, "smtpd", "no %s: %r", UPASLOG);
	me = sysname_read();
	if(dom == 0 || dom[0] == 0)
		dom = domainname_read();
	if(dom == 0 || dom[0] == 0)
		dom = me;
	parseinit();
	sayhi();

	/* allow 45 minutes to parse the header */
	atnotify(catchalarm, 1);
	alarm(45*60*1000);
	zzparse();
	exits(0);
}
Beispiel #8
0
/*
 *  pipe message to mailer with the following transformations:
 *	- change \r\n into \n.
 *	- add sender's domain to any addrs with no domain
 *	- add a From: if none of From:, Sender:, or Replyto: exists
 *	- add a Received: line
 */
int
pipemsg(int *byteswritten)
{
	int n, nbytes, sawdot, status, nonhdr, bpr;
	char *cp;
	Field *f;
	Link *l;
	Node *p;
	String *hdr, *line;

	pipesig(&status);	/* set status to 1 on write to closed pipe */
	sawdot = 0;
	status = 0;

	/*
	 *  add a 'From ' line as envelope
	 */
	nbytes = 0;
	nbytes += Bprint(pp->std[0]->fp, "From %s %s remote from \n",
		s_to_c(senders.first->p), thedate());

	/*
	 *  add our own Received: stamp
	 */
	nbytes += Bprint(pp->std[0]->fp, "Received: from %s ", him);
	if(nci->rsys)
		nbytes += Bprint(pp->std[0]->fp, "([%s]) ", nci->rsys);
	nbytes += Bprint(pp->std[0]->fp, "by %s; %s\n", me, thedate());

	/*
	 *  read first 16k obeying '.' escape.  we're assuming
	 *  the header will all be there.
	 */
	line = s_new();
	hdr = s_new();
	while(sawdot == 0 && s_len(hdr) < 16*1024){
		n = getcrnl(s_reset(line), &bin);

		/* eof or error ends the message */
		if(n <= 0)
			break;

		/* a line with only a '.' ends the message */
		cp = s_to_c(line);
		if(n == 2 && *cp == '.' && *(cp+1) == '\n'){
			sawdot = 1;
			break;
		}

		s_append(hdr, *cp == '.' ? cp+1 : cp);
	}

	/*
	 *  parse header
	 */
	yyinit(s_to_c(hdr), s_len(hdr));
	yyparse();

	/*
	 *  Look for masquerades.  Let Sender: trump From: to allow mailing list
	 *  forwarded messages.
	 */
	if(fflag)
		nbytes += forgedheaderwarnings();

	/*
	 *  add an orginator and/or destination if either is missing
	 */
	if(originator == 0){
		if(senders.last == nil || senders.last->p == nil)
			nbytes += Bprint(pp->std[0]->fp, "From: /dev/null@%s\n",
				him);
		else
			nbytes += Bprint(pp->std[0]->fp, "From: %s\n",
				s_to_c(senders.last->p));
	}
	if(destination == 0){
		nbytes += Bprint(pp->std[0]->fp, "To: ");
		for(l = rcvers.first; l; l = l->next){
			if(l != rcvers.first)
				nbytes += Bprint(pp->std[0]->fp, ", ");
			nbytes += Bprint(pp->std[0]->fp, "%s", s_to_c(l->p));
		}
		nbytes += Bprint(pp->std[0]->fp, "\n");
	}

	/*
	 *  add sender's domain to any domainless addresses
	 *  (to avoid forging local addresses)
	 */
	cp = s_to_c(hdr);
	for(f = firstfield; cp != nil && f; f = f->next){
		for(p = f->node; cp != 0 && p; p = p->next) {
			bpr = 0;
			cp = bprintnode(pp->std[0]->fp, p, &bpr);
			nbytes += bpr;
		}
		if(status == 0 && Bprint(pp->std[0]->fp, "\n") < 0){
			piperror = "write error";
			status = 1;
		}
		nbytes++;		/* for newline */
	}
	if(cp == nil){
		piperror = "sender domain";
		status = 1;
	}

	/* write anything we read following the header */
	nonhdr = s_to_c(hdr) + s_len(hdr) - cp;
	if(status == 0 && Bwrite(pp->std[0]->fp, cp, nonhdr) < 0){
		piperror = "write error 2";
		status = 1;
	}
	nbytes += nonhdr;
	s_free(hdr);

	/*
	 *  pass rest of message to mailer.  take care of '.'
	 *  escapes.
	 */
	while(sawdot == 0){
		n = getcrnl(s_reset(line), &bin);

		/* eof or error ends the message */
		if(n <= 0)
			break;

		/* a line with only a '.' ends the message */
		cp = s_to_c(line);
		if(n == 2 && *cp == '.' && *(cp+1) == '\n'){
			sawdot = 1;
			break;
		}
		if(cp[0] == '.'){
			cp++;
			n--;
		}
		nbytes += n;
		if(status == 0 && Bwrite(pp->std[0]->fp, cp, n) < 0){
			piperror = "write error 3";
			status = 1;
		}
	}
	s_free(line);
	if(sawdot == 0){
		/* message did not terminate normally */
		snprint(pipbuf, sizeof pipbuf, "network eof: %r");
		piperror = pipbuf;
		if (pp->pid > 0) {
			syskillpg(pp->pid);
			/* none can't syskillpg, so try a variant */
			sleep(500);
			syskill(pp->pid);
		}
		status = 1;
	}

	if(status == 0 && Bflush(pp->std[0]->fp) < 0){
		piperror = "write error 4";
		status = 1;
	}
	if (debug) {
		stamp();
		fprint(2, "at end of message; %s .\n",
			(sawdot? "saw": "didn't see"));
	}
	stream_free(pp->std[0]);
	pp->std[0] = 0;
	*byteswritten = nbytes;
	pipesigoff();
	if(status && !piperror)
		piperror = "write on closed pipe";
	return status;
}
Beispiel #9
0
void clientgone()
{
    fprintf(Log, "%s:  Deleting monitor table entry %d, client gone\n", thedate(), client);
    fclose(Monitor[client].user);
    Monitor[client].inuse = 0;
}