haraka / Haraka

A fast, highly extensible, and event driven SMTP server
https://haraka.github.io
MIT License
5.02k stars 662 forks source link

rcpt_to.routes.js can not find address in hmail.rcpt_to #802

Closed abhas closed 9 years ago

abhas commented 9 years ago

rcpt_to.routes.js tries to extract the email address from hmail.rcpt_to on line 105. However, after much debugging I noticed that I don't have hmail.rcpt_to at all -- instead I have hmail.todo.rcpt_to. Additionally the email address extracted from hmail.todo.rcpt_to[0].original has '<' and '>' which need to be removed before a successful match can be made against the rcpt_to.routes.ini file.

Basically I rewrote lines 105 and 106 as:

if (hmail && hmail.todo.rcpt_to && hmail.todo.rcpt_to[0]) {
  address = hmail.todo.rcpt_to[0].original.toLowerCase().replace(/</, "").replace(/>/, "");

I had a related question - since this plugin uses the get_mx hook, it can only be used for outbound mails where connection.relaying is set. Hence, this plugin can not be used in a situation where haraka is the MX for a domain and needs to distribute emails to multiple mail servers using recipient maps of this sort. Basically I'm trying to do something similar to what qmail-ldap does with the mailHost attribute and qmqp. Would it be possible to use this without relaying being set?

What I tried to do (and it worked) was to add the following code where the rcpt hook is handled. Will this have any undesired side-effects?

var do_file_search = function () {
  if (plugin.route_list[address]) {
    txn.results.add(plugin, {pass: 'file.email'});
    connection.relaying = true;
    return next(OK);
  }
smfreegard commented 9 years ago

@abhas

Firstly - yes; the hmail.rcpt_to looks like a bug. Your fix isn't quite right though as hmail.todo.rcpt_to is an array of Address objects so instead of having to call those replaces you can simply do this:

address = hmail.todo.rcpt_to[0].address();

To your related question; yes - this will only work for outbound recipients as it uses the get_mx hook and you absolutely can't do what you have done and set connection.relaying = true in hook_rcpt as you're making yourself an open-relay as all someone needs to do is send a mail to a valid user, get the connection marked as relaying = true, and then send a bunch of recipients to non-local domains....

The correct way to do this - provided you don't ever need to use any of the queue/* plugins is to create a plugin with the following:

var constants = require('./constants');
var outbound = require('./outbound');

exports.hook_queue = exports.hook_queue_outbound = function (next, connection) {
    var transaction = connection.transaction;
    transaction.notes.remote_host = connection.remote_host;
    transaction.notes.remote_ip   = connection.remote_ip;
    transaction.notes.auth_user   = connection.notes.auth_user;

    outbound.send_email(connection.transaction, function(retval, msg) {
        switch(retval) {
            case constants.ok:
                return next(OK, msg);
                break;
            case constants.deny:
                return next(DENY, msg);
                break;
            default:
                return next(DENYSOFT, msg);
        }
    });
}

That basically makes all messages not marked as connection.relaying = true go via the built-in outbound mechanism.

@msimerson - I didn't want to simply go and fix the hmail.todo problem as I know you contributed this plugin from an upstream source and I therefore didn't want you to potentially miss this issue being as you'll probably have to fix it elsewhere too.

abhas commented 9 years ago

@smfreegard Thanks a lot for the inputs and help. Really appreciate your time.

Since I don't plan to use any queue/* plugins, I will try the above piece of code out. I didn't realise the open relay bit about setting the flag in the rcpt hook.

It would be interesting to add LDAP support to rcpt_to.routes.js. I'll work on it one of these days so that this code can be a drop in replacement for qmail-ldap clusters.

msimerson commented 9 years ago

since this plugin uses the get_mx hook, it can only be used for outbound mails where connection.relaying is set.

I stepped around this by using the queue/deliver plugin with a tiny modification, remove the connection.relaying test. (I might have also had to make deliver listen on hook_queue, but I don't recall.) The only messages that ever make it to the queue hook are ones with validated recipients. Those messages are thus queued and then delivered by outbound.