📄 smtpd.c
字号:
rejectcount++; reply("503 Start by saying HELO, please\r\n"); return; } if(senders.last) sender = s_to_c(senders.last->p); else sender = "<unknown>"; if(!recipok(s_to_c(path))){ rejectcount++; syslog(0, "smtpd", "Disallowed %s (%s/%s) to blocked, unknown or invalid name %s", sender, him, nci->rsys, s_to_c(path)); reply("550 %s ... user unknown\r\n", s_to_c(path)); return; } rcpt = s_to_c(path); if (!senderok(rcpt)) { rejectcount++; syslog(0, "smtpd", "Disallowed sending IP of %s (%s/%s) to %s", sender, him, nci->rsys, rcpt); reply("550 %s ... sending system not allowed\r\n", rcpt); return; } logged = 0; /* forwarding() can modify 'path' on loopback request */ if(filterstate == ACCEPT && (fflag && !authenticated) && forwarding(path)) { syslog(0, "smtpd", "Bad Forward %s (%s/%s) (%s)", s_to_c(senders.last->p), him, nci->rsys, s_to_c(path)); rejectcount++; reply("550 we don't relay. send to your-path@[] for loopback.\r\n"); return; } listadd(&rcvers, path); reply("250 receiver is %s\r\n", s_to_c(path));}voidquit(void){ reply("221 Successful termination\r\n"); close(0); exits(0);}voidturn(void){ if(rejectcheck()) return; reply("502 TURN unimplemented\r\n");}voidnoop(void){ if(rejectcheck()) return; reply("250 Stop wasting my time!\r\n");}voidhelp(String *cmd){ if(rejectcheck()) return; if(cmd) s_free(cmd); reply("250 Read rfc821 and stop wasting my time\r\n");}voidverify(String *path){ char *p, *q; char *av[4]; if(rejectcheck()) return; if(shellchars(s_to_c(path))){ reply("503 Bad character in address %s.\r\n", s_to_c(path)); return; } av[0] = s_to_c(mailer); av[1] = "-x"; av[2] = s_to_c(path); av[3] = 0; pp = noshell_proc_start(av, (stream *)0, outstream(), (stream *)0, 1, 0); if (pp == 0) { reply("450 We're busy right now, try later\r\n"); return; } p = Brdline(pp->std[1]->fp, '\n'); if(p == 0){ reply("550 String does not match anything.\r\n"); } else { p[Blinelen(pp->std[1]->fp)-1] = 0; if(strchr(p, ':')) reply("550 String does not match anything.\r\n"); else{ q = strrchr(p, '!'); if(q) p = q+1; reply("250 %s <%s@%s>\r\n", s_to_c(path), p, dom); } } proc_wait(pp); proc_free(pp); pp = 0;}/* * get a line that ends in crnl or cr, turn terminating crnl into a nl * * return 0 on EOF */static intgetcrnl(String *s, Biobuf *fp){ int c; for(;;){ c = Bgetc(fp); if(debug) { seek(2, 0, 2); fprint(2, "%c", c); } switch(c){ case -1: goto out; case '\r': c = Bgetc(fp); if(c == '\n'){ if(debug) { seek(2, 0, 2); fprint(2, "%c", c); } s_putc(s, '\n'); goto out; } Bungetc(fp); s_putc(s, '\r'); break; case '\n': s_putc(s, c); goto out; default: s_putc(s, c); break; } }out: s_terminate(s); return s_len(s);}voidlogcall(int nbytes){ Link *l; String *to, *from; to = s_new(); from = s_new(); for(l = senders.first; l; l = l->next){ if(l != senders.first) s_append(from, ", "); s_append(from, s_to_c(l->p)); } for(l = rcvers.first; l; l = l->next){ if(l != rcvers.first) s_append(to, ", "); s_append(to, s_to_c(l->p)); } syslog(0, "smtpd", "[%s/%s] %s sent %d bytes to %s", him, nci->rsys, s_to_c(from), nbytes, s_to_c(to)); s_free(to); s_free(from);}static voidlogmsg(char *action){ Link *l; if(logged) return; logged = 1; for(l = rcvers.first; l; l = l->next) syslog(0, "smtpd", "%s %s (%s/%s) (%s)", action, s_to_c(senders.last->p), him, nci->rsys, s_to_c(l->p));}static intoptoutall(int filterstate){ Link *l; switch(filterstate){ case ACCEPT: case TRUSTED: return filterstate; } for(l = rcvers.first; l; l = l->next) if(!optoutofspamfilter(s_to_c(l->p))) return filterstate; return ACCEPT;}String*startcmd(void){ int n; Link *l; char **av; String *cmd; char *filename; /* * ignore the filterstate if the all the receivers prefer it. */ filterstate = optoutall(filterstate); switch (filterstate){ case BLOCKED: case DELAY: rejectcount++; logmsg("Blocked"); filename = dumpfile(s_to_c(senders.last->p)); cmd = s_new(); s_append(cmd, "cat > "); s_append(cmd, filename); pp = proc_start(s_to_c(cmd), instream(), 0, outstream(), 0, 0); break; case DIALUP: logmsg("Dialup"); rejectcount++; reply("554 We don't accept mail from dial-up ports.\r\n"); /* * we could exit here, because we're never going to accept mail from this * ip address, but it's unclear that RFC821 allows that. Instead we set * the hardreject flag and go stupid. */ hardreject = 1; return 0; case DENIED: logmsg("Denied"); rejectcount++; reply("554-We don't accept mail from %s.\r\n", s_to_c(senders.last->p)); reply("554 Contact postmaster@%s for more information.\r\n", dom); return 0; case REFUSED: logmsg("Refused"); rejectcount++; reply("554 Sender domain must exist: %s\r\n", s_to_c(senders.last->p)); return 0; default: case NONE: logmsg("Confused"); rejectcount++; reply("554-We have had an internal mailer error classifying your message.\r\n"); reply("554-Filterstate is %d\r\n", filterstate); reply("554 Contact postmaster@%s for more information.\r\n", dom); return 0; case ACCEPT: case TRUSTED: /* * now that all other filters have been passed, * do grey-list processing. */ if(gflag) vfysenderhostok(); /* * set up mail command */ cmd = s_clone(mailer); n = 3; for(l = rcvers.first; l; l = l->next) n++; av = malloc(n*sizeof(char*)); if(av == nil){ reply("450 We're busy right now, try later\n"); s_free(cmd); return 0; } n = 0; av[n++] = s_to_c(cmd); av[n++] = "-r"; for(l = rcvers.first; l; l = l->next) av[n++] = s_to_c(l->p); av[n] = 0; /* * start mail process */ pp = noshell_proc_start(av, instream(), outstream(), outstream(), 0, 0); free(av); break; } if(pp == 0) { reply("450 We're busy right now, try later\n"); s_free(cmd); return 0; } return cmd;}/* * print out a header line, expanding any domainless addresses into * address@him */char*bprintnode(Biobuf *b, Node *p){ if(p->s){ if(p->addr && strchr(s_to_c(p->s), '@') == nil){ if(Bprint(b, "%s@%s", s_to_c(p->s), him) < 0) return nil; } else { if(Bwrite(b, s_to_c(p->s), s_len(p->s)) < 0) return nil; } }else{ if(Bputc(b, p->c) < 0) return nil; } if(p->white) if(Bwrite(b, s_to_c(p->white), s_len(p->white)) < 0) return nil; return p->end+1;}static String*getaddr(Node *p){ for(; p; p = p->next) if(p->s && p->addr) return p->s; return nil;}/* * add waring headers of the form * X-warning: <reason> * for any headers that looked like they might be forged. * * return byte count of new headers */static intforgedheaderwarnings(void){ int nbytes; Field *f; nbytes = 0; /* warn about envelope sender */ if(strcmp(s_to_c(senders.last->p), "/dev/null") != 0 && masquerade(senders.last->p, nil)) nbytes += Bprint(pp->std[0]->fp, "X-warning: suspect envelope domain\n"); /* * check Sender: field. If it's OK, ignore the others because this is an * exploded mailing list. */ for(f = firstfield; f; f = f->next){ if(f->node->c == SENDER){ if(masquerade(getaddr(f->node), him)) nbytes += Bprint(pp->std[0]->fp, "X-warning: suspect Sender: domain\n"); else return nbytes; } } /* check From: */ for(f = firstfield; f; f = f->next){ if(f->node->c == FROM && masquerade(getaddr(f->node), him)) nbytes += Bprint(pp->std[0]->fp, "X-warning: suspect From: domain\n"); } return nbytes;}/* * 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 */intpipemsg(int *byteswritten){ int status; char *cp; String *line; String *hdr; int n, nbytes; int sawdot; Field *f; Node *p; Link *l; 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) Bprint(pp->std[0]->fp, "From: /dev/null@%s\n", him); else Bprint(pp->std[0]->fp, "From: %s\n", s_to_c(senders.last->p)); } if(destination == 0){ Bprint(pp->std[0]->fp, "To: "); for(l = rcvers.first; l; l = l->next){ if(l != rcvers.first) Bprint(pp->std[0]->fp, ", "); Bprint(pp->std[0]->fp, "%s", s_to_c(l->p)); } 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) cp = bprintnode(pp->std[0]->fp, p); if(status == 0 && Bprint(pp->std[0]->fp, "\n") < 0){ piperror = "write error"; status = 1; } } if(cp == nil){ piperror = "sender domain"; status = 1; } /* write anything we read following the header */ if(status == 0 && Bwrite(pp->std[0]->fp, cp, s_to_c(hdr) + s_len(hdr) - cp) < 0){ piperror = "write error 2"; status = 1; } s_free(hdr); /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -