86 lines
1.6 KiB
Go
86 lines
1.6 KiB
Go
package kcpolicy
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
func RunSocketmap(ctx context.Context, cfg *Config, db *AliasDB) error {
|
|
sock := cfg.Sockets.SocketmapSocket
|
|
_ = os.Remove(sock)
|
|
|
|
l, err := net.Listen("unix", sock)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer l.Close()
|
|
|
|
if err := ChownChmodSocket(sock, cfg); err != nil {
|
|
return err
|
|
}
|
|
|
|
for {
|
|
conn, err := l.Accept()
|
|
if err != nil {
|
|
select {
|
|
case <-ctx.Done():
|
|
return nil
|
|
default:
|
|
return err
|
|
}
|
|
}
|
|
go handleSocketmapConn(conn, cfg, db)
|
|
}
|
|
}
|
|
|
|
// Socketmap protocol: "mapname key\n" -> "OK value\n" or "NOTFOUND\n" or "TEMP\n"
|
|
func handleSocketmapConn(conn net.Conn, cfg *Config, db *AliasDB) {
|
|
defer conn.Close()
|
|
r := bufio.NewReader(conn)
|
|
|
|
for {
|
|
line, err := r.ReadString('\n')
|
|
if err != nil {
|
|
return
|
|
}
|
|
line = strings.TrimSpace(line)
|
|
if line == "" {
|
|
continue
|
|
}
|
|
parts := strings.SplitN(line, " ", 2)
|
|
if len(parts) != 2 {
|
|
fmt.Fprint(conn, "TEMP\n")
|
|
continue
|
|
}
|
|
mapName := parts[0]
|
|
key := strings.ToLower(strings.TrimSpace(parts[1]))
|
|
|
|
if mapName != "alias" {
|
|
fmt.Fprint(conn, "NOTFOUND\n")
|
|
continue
|
|
}
|
|
|
|
// Only handle our domain
|
|
if !strings.HasSuffix(key, "@"+strings.ToLower(cfg.Policy.Domain)) {
|
|
fmt.Fprint(conn, "NOTFOUND\n")
|
|
continue
|
|
}
|
|
|
|
username, ok, err := db.AliasOwner(key)
|
|
if err != nil {
|
|
fmt.Fprint(conn, "TEMP\n")
|
|
continue
|
|
}
|
|
if !ok {
|
|
fmt.Fprint(conn, "NOTFOUND\n")
|
|
continue
|
|
}
|
|
// rewrite alias -> primary rcpt (username@domain)
|
|
fmt.Fprintf(conn, "OK %s@%s\n", username, strings.ToLower(cfg.Policy.Domain))
|
|
}
|
|
}
|