1/*2Maddy Mail Server - Composable all-in-one email server.3Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors45This program is free software: you can redistribute it and/or modify6it under the terms of the GNU General Public License as published by7the Free Software Foundation, either version 3 of the License, or8(at your option) any later version.910This program is distributed in the hope that it will be useful,11but WITHOUT ANY WARRANTY; without even the implied warranty of12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13GNU General Public License for more details.1415You should have received a copy of the GNU General Public License16along with this program. If not, see <https://www.gnu.org/licenses/>.17*/1819package smtp_downstream2021import (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)2728type saslClientFactory = func(msgMeta *module.MsgMetadata) (sasl.Client, error)2930// 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, nil44 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), nil59 }, nil60 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]), nil66 }, nil67 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(""), nil73 }, nil74 default:75 return nil, config.NodeErr(node, "unknown authentication mechanism: %s", node.Args[0])76 }77}