mirror of
https://blitiri.com.ar/repos/chasquid
synced 2025-12-18 14:47:03 +00:00
courier: Let the users configure the mail delivery agent
This patch adds configuration options for the MDA binary and command line arguments, and changes the (soon to be renamed) procmail courier to make use of them.
This commit is contained in:
@@ -51,6 +51,9 @@ func main() {
|
|||||||
go http.ListenAndServe(conf.MonitoringAddress, nil)
|
go http.ListenAndServe(conf.MonitoringAddress, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
courier.MailDeliveryAgentBin = conf.MailDeliveryAgentBin
|
||||||
|
courier.MailDeliveryAgentArgs = conf.MailDeliveryAgentArgs
|
||||||
|
|
||||||
s := NewServer()
|
s := NewServer()
|
||||||
s.Hostname = conf.Hostname
|
s.Hostname = conf.Hostname
|
||||||
s.MaxDataSize = conf.MaxDataSizeMb * 1024 * 1024
|
s.MaxDataSize = conf.MaxDataSizeMb * 1024 * 1024
|
||||||
|
|||||||
@@ -47,6 +47,14 @@ func Load(path string) (*Config, error) {
|
|||||||
c.Address = append(c.Address, "systemd")
|
c.Address = append(c.Address, "systemd")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.MailDeliveryAgentBin == "" {
|
||||||
|
c.MailDeliveryAgentBin = "procmail"
|
||||||
|
}
|
||||||
|
if len(c.MailDeliveryAgentArgs) == 0 {
|
||||||
|
c.MailDeliveryAgentArgs = append(c.MailDeliveryAgentArgs,
|
||||||
|
"-d", "%user%")
|
||||||
|
}
|
||||||
|
|
||||||
logConfig(c)
|
logConfig(c)
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
@@ -57,4 +65,5 @@ func logConfig(c *Config) {
|
|||||||
glog.Infof(" Max data size (MB): %d", c.MaxDataSizeMb)
|
glog.Infof(" Max data size (MB): %d", c.MaxDataSizeMb)
|
||||||
glog.Infof(" Addresses: %v", c.Address)
|
glog.Infof(" Addresses: %v", c.Address)
|
||||||
glog.Infof(" Monitoring address: %s", c.MonitoringAddress)
|
glog.Infof(" Monitoring address: %s", c.MonitoringAddress)
|
||||||
|
glog.Infof(" MDA: %s %v", c.MailDeliveryAgentBin, c.MailDeliveryAgentArgs)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,12 @@ var _ = proto.Marshal
|
|||||||
var _ = fmt.Errorf
|
var _ = fmt.Errorf
|
||||||
var _ = math.Inf
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// Hostname to use when we say hello.
|
// Hostname to use when we say hello.
|
||||||
// For aesthetic purposes, but may help if our ip address resolves to it.
|
// For aesthetic purposes, but may help if our ip address resolves to it.
|
||||||
@@ -36,8 +42,42 @@ type Config struct {
|
|||||||
// Address for the monitoring http server.
|
// Address for the monitoring http server.
|
||||||
// Default: no monitoring http server.
|
// Default: no monitoring http server.
|
||||||
MonitoringAddress string `protobuf:"bytes,4,opt,name=monitoring_address" json:"monitoring_address,omitempty"`
|
MonitoringAddress string `protobuf:"bytes,4,opt,name=monitoring_address" json:"monitoring_address,omitempty"`
|
||||||
|
// Mail delivery agent (MDA, also known as LDA) to use.
|
||||||
|
// This should point to the binary to use to deliver email to local users.
|
||||||
|
// The content of the email will be passed via stdin.
|
||||||
|
// If it exits unsuccessfully, we assume the mail was not delivered.
|
||||||
|
// Default: "procmail".
|
||||||
|
MailDeliveryAgentBin string `protobuf:"bytes,5,opt,name=mail_delivery_agent_bin" json:"mail_delivery_agent_bin,omitempty"`
|
||||||
|
// Command line arguments for the mail delivery agent. One per argument.
|
||||||
|
// Some replacements will be done:
|
||||||
|
// - "%user%" -> local user (anything before the @)
|
||||||
|
// - "%domain%" -> domain (anything after the @)
|
||||||
|
// Default: "-d", "%user" (adequate for procmail)
|
||||||
|
MailDeliveryAgentArgs []string `protobuf:"bytes,6,rep,name=mail_delivery_agent_args" json:"mail_delivery_agent_args,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Config) Reset() { *m = Config{} }
|
func (m *Config) Reset() { *m = Config{} }
|
||||||
func (m *Config) String() string { return proto.CompactTextString(m) }
|
func (m *Config) String() string { return proto.CompactTextString(m) }
|
||||||
func (*Config) ProtoMessage() {}
|
func (*Config) ProtoMessage() {}
|
||||||
|
func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*Config)(nil), "Config")
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { proto.RegisterFile("config.proto", fileDescriptor0) }
|
||||||
|
|
||||||
|
var fileDescriptor0 = []byte{
|
||||||
|
// 169 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x8e, 0x41, 0xca, 0xc2, 0x30,
|
||||||
|
0x10, 0x46, 0xe9, 0xdf, 0xdf, 0xaa, 0x83, 0x60, 0xc9, 0xc6, 0xc1, 0x8d, 0xc5, 0x95, 0x2b, 0x37,
|
||||||
|
0x1e, 0xc1, 0x83, 0x0c, 0x53, 0x13, 0xe3, 0x40, 0x93, 0x48, 0x12, 0x44, 0x3d, 0x8f, 0x07, 0xb5,
|
||||||
|
0x06, 0xdc, 0xb9, 0xfd, 0xde, 0xe3, 0xf1, 0xc1, 0xe2, 0x14, 0xfc, 0x59, 0xec, 0xfe, 0x1a, 0x43,
|
||||||
|
0x0e, 0xdb, 0x57, 0x05, 0xcd, 0xb1, 0x0c, 0xaa, 0x85, 0xd9, 0x25, 0xa4, 0xec, 0xd9, 0x19, 0xac,
|
||||||
|
0xba, 0x6a, 0x37, 0x57, 0x08, 0xad, 0xe3, 0x3b, 0x69, 0xce, 0x4c, 0x49, 0x9e, 0x86, 0x5c, 0x8f,
|
||||||
|
0x7f, 0x23, 0xa9, 0xd5, 0x12, 0xa6, 0xac, 0x75, 0x34, 0x29, 0x61, 0xdd, 0xd5, 0xa3, 0xba, 0x06,
|
||||||
|
0xe5, 0x82, 0x97, 0x1c, 0xa2, 0x78, 0x4b, 0x5f, 0xf6, 0x5f, 0x32, 0x1b, 0x58, 0x39, 0x96, 0x81,
|
||||||
|
0xb4, 0x19, 0xe4, 0x66, 0xe2, 0x83, 0xd8, 0x1a, 0x9f, 0xa9, 0x17, 0x8f, 0x93, 0x22, 0x74, 0x80,
|
||||||
|
0xbf, 0x04, 0x8e, 0x36, 0x61, 0xf3, 0xc9, 0xf7, 0x4d, 0x79, 0x7b, 0x78, 0x07, 0x00, 0x00, 0xff,
|
||||||
|
0xff, 0xa3, 0xe4, 0x58, 0xd3, 0xbd, 0x00, 0x00, 0x00,
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,5 +18,19 @@ message Config {
|
|||||||
// Address for the monitoring http server.
|
// Address for the monitoring http server.
|
||||||
// Default: no monitoring http server.
|
// Default: no monitoring http server.
|
||||||
string monitoring_address = 4;
|
string monitoring_address = 4;
|
||||||
|
|
||||||
|
// Mail delivery agent (MDA, also known as LDA) to use.
|
||||||
|
// This should point to the binary to use to deliver email to local users.
|
||||||
|
// The content of the email will be passed via stdin.
|
||||||
|
// If it exits unsuccessfully, we assume the mail was not delivered.
|
||||||
|
// Default: "procmail".
|
||||||
|
string mail_delivery_agent_bin = 5;
|
||||||
|
|
||||||
|
// Command line arguments for the mail delivery agent. One per argument.
|
||||||
|
// Some replacements will be done:
|
||||||
|
// - "%user%" -> local user (anything before the @)
|
||||||
|
// - "%domain%" -> domain (anything after the @)
|
||||||
|
// Default: "-d", "%user" (adequate for procmail)
|
||||||
|
repeated string mail_delivery_agent_args = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,10 @@ import (
|
|||||||
var (
|
var (
|
||||||
// Location of the procmail binary, and arguments to use.
|
// Location of the procmail binary, and arguments to use.
|
||||||
// The string "%user%" will be replaced with the local user.
|
// The string "%user%" will be replaced with the local user.
|
||||||
procmailBin = "procmail"
|
// TODO: Make these a part of the courier instance itself? Why do they
|
||||||
procmailArgs = []string{"-d", "%user%"}
|
// have to be global?
|
||||||
|
MailDeliveryAgentBin = "procmail"
|
||||||
|
MailDeliveryAgentArgs = []string{"-d", "%user%"}
|
||||||
|
|
||||||
// Give procmail 1m to deliver mail.
|
// Give procmail 1m to deliver mail.
|
||||||
procmailTimeout = 1 * time.Minute
|
procmailTimeout = 1 * time.Minute
|
||||||
@@ -39,10 +41,10 @@ func (p *Procmail) Deliver(from string, to string, data []byte) error {
|
|||||||
|
|
||||||
// Prepare the command, replacing the necessary arguments.
|
// Prepare the command, replacing the necessary arguments.
|
||||||
args := []string{}
|
args := []string{}
|
||||||
for _, a := range procmailArgs {
|
for _, a := range MailDeliveryAgentArgs {
|
||||||
args = append(args, strings.Replace(a, "%user%", user, -1))
|
args = append(args, strings.Replace(a, "%user%", user, -1))
|
||||||
}
|
}
|
||||||
cmd := exec.Command(procmailBin, args...)
|
cmd := exec.Command(MailDeliveryAgentBin, args...)
|
||||||
|
|
||||||
cmdStdin, err := cmd.StdinPipe()
|
cmdStdin, err := cmd.StdinPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ func TestProcmail(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
procmailBin = "tee"
|
MailDeliveryAgentBin = "tee"
|
||||||
procmailArgs = []string{dir + "/%user%"}
|
MailDeliveryAgentArgs = []string{dir + "/%user%"}
|
||||||
|
|
||||||
p := Procmail{}
|
p := Procmail{}
|
||||||
err = p.Deliver("from@x", "to@y", []byte("data"))
|
err = p.Deliver("from@x", "to@y", []byte("data"))
|
||||||
@@ -31,8 +31,8 @@ func TestProcmail(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestProcmailTimeout(t *testing.T) {
|
func TestProcmailTimeout(t *testing.T) {
|
||||||
procmailBin = "/bin/sleep"
|
MailDeliveryAgentBin = "/bin/sleep"
|
||||||
procmailArgs = []string{"1"}
|
MailDeliveryAgentArgs = []string{"1"}
|
||||||
procmailTimeout = 100 * time.Millisecond
|
procmailTimeout = 100 * time.Millisecond
|
||||||
|
|
||||||
p := Procmail{}
|
p := Procmail{}
|
||||||
@@ -48,19 +48,21 @@ func TestProcmailBadCommandLine(t *testing.T) {
|
|||||||
p := Procmail{}
|
p := Procmail{}
|
||||||
|
|
||||||
// Non-existent binary.
|
// Non-existent binary.
|
||||||
procmailBin = "thisdoesnotexist"
|
MailDeliveryAgentBin = "thisdoesnotexist"
|
||||||
err := p.Deliver("from", "to", []byte("data"))
|
err := p.Deliver("from", "to", []byte("data"))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Unexpected success: %q %v", procmailBin, procmailArgs)
|
t.Errorf("Unexpected success: %q %v",
|
||||||
|
MailDeliveryAgentBin, MailDeliveryAgentArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Incorrect arguments.
|
// Incorrect arguments.
|
||||||
procmailBin = "cat"
|
MailDeliveryAgentBin = "cat"
|
||||||
procmailArgs = []string{"--fail_unknown_option"}
|
MailDeliveryAgentArgs = []string{"--fail_unknown_option"}
|
||||||
|
|
||||||
err = p.Deliver("from", "to", []byte("data"))
|
err = p.Deliver("from", "to", []byte("data"))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Unexpected success: %q %v", procmailBin, procmailArgs)
|
t.Errorf("Unexpected success: %q %v",
|
||||||
|
MailDeliveryAgentBin, MailDeliveryAgentArgs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,6 +79,13 @@ var (
|
|||||||
InvalidUsernameErr = errors.New("username contains invalid characters")
|
InvalidUsernameErr = errors.New("username contains invalid characters")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func New(fname string) *DB {
|
||||||
|
return &DB{
|
||||||
|
fname: fname,
|
||||||
|
users: map[string]user{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Load the database from the given file.
|
// Load the database from the given file.
|
||||||
// Return the database, a list of warnings (if any), and a fatal error if the
|
// Return the database, a list of warnings (if any), and a fatal error if the
|
||||||
// database could not be loaded.
|
// database could not be loaded.
|
||||||
@@ -194,7 +201,11 @@ func (db *DB) Write() error {
|
|||||||
base64.StdEncoding.EncodeToString([]byte(user.password)))
|
base64.StdEncoding.EncodeToString([]byte(user.password)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return safeio.WriteFile(db.fname, buf.Bytes(), db.finfo.Mode())
|
mode := os.FileMode(0660)
|
||||||
|
if db.finfo != nil {
|
||||||
|
mode = db.finfo.Mode()
|
||||||
|
}
|
||||||
|
return safeio.WriteFile(db.fname, buf.Bytes(), mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does this user exist in the database?
|
// Does this user exist in the database?
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package userdb
|
package userdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -41,7 +42,7 @@ func dbEquals(a, b *DB) bool {
|
|||||||
|
|
||||||
for k, av := range a.users {
|
for k, av := range a.users {
|
||||||
bv, ok := b.users[k]
|
bv, ok := b.users[k]
|
||||||
if !ok || av != bv {
|
if !ok || av.name != bv.name || av.password != bv.password {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,6 +204,25 @@ func TestWrite(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNew(t *testing.T) {
|
||||||
|
fname := fmt.Sprintf("%s/userdb_test-%d", os.TempDir(), os.Getpid())
|
||||||
|
db1 := New(fname)
|
||||||
|
db1.AddUser("user", "passwd")
|
||||||
|
db1.Write()
|
||||||
|
|
||||||
|
db2, ws, err := Load(fname)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error loading: %v", err)
|
||||||
|
}
|
||||||
|
if len(ws) != 0 {
|
||||||
|
t.Errorf("warnings loading: %v", ws)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !dbEquals(db1, db2) {
|
||||||
|
t.Errorf("databases differ. db1:%v != db2:%v", db1, db2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestInvalidUsername(t *testing.T) {
|
func TestInvalidUsername(t *testing.T) {
|
||||||
fname := mustCreateDB(t, "")
|
fname := mustCreateDB(t, "")
|
||||||
defer removeIfSuccessful(t, fname)
|
defer removeIfSuccessful(t, fname)
|
||||||
|
|||||||
Reference in New Issue
Block a user