maddy

Fork https://github.com/foxcpp/maddy

git clone git://git.lin.moe/go/maddy.git

 1/*
 2Maddy Mail Server - Composable all-in-one email server.
 3Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors
 4
 5This program is free software: you can redistribute it and/or modify
 6it under the terms of the GNU General Public License as published by
 7the Free Software Foundation, either version 3 of the License, or
 8(at your option) any later version.
 9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program.  If not, see <https://www.gnu.org/licenses/>.
17*/
18
19package smtp_downstream
20
21import (
22	"github.com/emersion/go-sasl"
23	"github.com/foxcpp/maddy/framework/config"
24	"github.com/foxcpp/maddy/framework/exterrors"
25	"github.com/foxcpp/maddy/framework/module"
26)
27
28type saslClientFactory = func(msgMeta *module.MsgMetadata) (sasl.Client, error)
29
30// saslAuthDirective returns saslClientFactory function used to create sasl.Client.
31// for use in outbound connections.
32//
33// Authentication information of the current client should be passed in arguments.
34func saslAuthDirective(_ *config.Map, node config.Node) (interface{}, error) {
35	if len(node.Children) != 0 {
36		return nil, config.NodeErr(node, "can't declare a block here")
37	}
38	if len(node.Args) == 0 {
39		return nil, config.NodeErr(node, "at least one argument required")
40	}
41	switch node.Args[0] {
42	case "off":
43		return nil, nil
44	case "forward":
45		if len(node.Args) > 1 {
46			return nil, config.NodeErr(node, "no additional arguments required")
47		}
48		return func(msgMeta *module.MsgMetadata) (sasl.Client, error) {
49			if msgMeta.Conn == nil || msgMeta.Conn.AuthUser == "" || msgMeta.Conn.AuthPassword == "" {
50				return nil, &exterrors.SMTPError{
51					Code:         530,
52					EnhancedCode: exterrors.EnhancedCode{5, 7, 0},
53					Message:      "Authentication is required",
54					TargetName:   "target.smtp",
55					Reason:       "Credentials forwarding is requested but the client is not authenticated",
56				}
57			}
58			return sasl.NewPlainClient("", msgMeta.Conn.AuthUser, msgMeta.Conn.AuthPassword), nil
59		}, nil
60	case "plain":
61		if len(node.Args) != 3 {
62			return nil, config.NodeErr(node, "two additional arguments are required (username, password)")
63		}
64		return func(*module.MsgMetadata) (sasl.Client, error) {
65			return sasl.NewPlainClient("", node.Args[1], node.Args[2]), nil
66		}, nil
67	case "external":
68		if len(node.Args) > 1 {
69			return nil, config.NodeErr(node, "no additional arguments required")
70		}
71		return func(*module.MsgMetadata) (sasl.Client, error) {
72			return sasl.NewExternalClient(""), nil
73		}, nil
74	default:
75		return nil, config.NodeErr(node, "unknown authentication mechanism: %s", node.Args[0])
76	}
77}