コード例 #1
0
ファイル: sinksmtp.go プロジェクト: karlpilkington/smtpd
// Decide what to do and then do it if it is a rejection or a tempfail.
// If given an id (and it is in the message handling phase) we call
// RejectData(). This is our convenience driver for the rules engine,
// Decide().
//
// Returns false if the message was accepted, true if decider() handled
// a rejection or tempfail.
func decider(ph Phase, evt smtpd.EventInfo, c *Context, convo *smtpd.Conn, id string) bool {
	res := Decide(ph, evt, c)

	logDnsbls(c)
	// Terrible hack to log DNS lookup failure specifics.
	if c.domerr != nil && c.trans.log != nil {
		lmsg := fmt.Sprintf("! %s\n", c.domerr)
		if lmsg != c.trans.lastamsg {
			c.trans.log.Write([]byte(lmsg))
			c.trans.lastamsg = lmsg
		}
	}
	// The moment a rule sets a savedir, it becomes sticky.
	// This lets you select a savedir based on eg from matching
	// instead of having to do games later.
	if sd := c.withprops["savedir"]; sd != "" {
		c.trans.savedir = sd
	}
	// rule notes are deliberately logged every time they hit.
	// this may be a mistake given EHLO retrying as HELO, but
	// I'll see.
	if note := c.withprops["note"]; note != "" {
		c.trans.log.Write([]byte(fmt.Sprintf("! rule note: %s\n", note)))
	}
	// Disable TLS if desired, or just disable asking for client certs.
	switch c.withprops["tls-opt"] {
	case "off":
		convo.Config.TLSConfig = nil
	case "no-client":
		// 'tls-opt no-client' without certificates should not
		// crash.
		if convo.Config.TLSConfig != nil {
			convo.Config.TLSConfig.ClientAuth = tls.NoClientCert
		}
	}

	if res == aNoresult || res == aAccept {
		return false
	}

	if ph == pConnect {
		// TODO: have some way to stall or reject connections
		// in smtpd. Or should that be handled outside of it?
		// Right now a reject result means 'drop', stall will
		// implicitly cause us to go on.
		return res == aReject
	}

	msg := c.withprops["message"]
	switch res {
	case aReject:
		// This is kind of a hack.
		// We assume that 'id' is only set when we should report it,
		// which is kind of safe.
		if msg != "" {
			if id != "" {
				msg += "\nRejected with ID " + id
			}
			convo.RejectMsg(msg)
			return true
		}
		// Default messages are kind of intricate.
		switch {
		case id != "" && ph == pMessage:
			convo.RejectMsg("We do not consent to you emailing %s\nRejected with ID %s", pluralRecips(c), id)
		case ph == pMessage || ph == pData:
			convo.RejectMsg("We do not consent to you emailing %s", pluralRecips(c))
		case ph == pRto:
			convo.RejectMsg("We do not consent to you emailing that address")
		default:
			convo.Reject()
		}
	case aStall:
		if msg != "" {
			convo.TempfailMsg(msg)
		} else {
			convo.Tempfail()
		}
	default:
		panic("impossible res")
	}
	return true
}