Logo Search packages:      
Sourcecode: mailavenger version File versions  Download package

auth.C

/* $Id$ */

/*
 *
 * Copyright (C) 2005 David Mazieres (dm@uun.org)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 *
 */

#include "asmtpd.h"

#ifndef SASL

void
smtpd::cmd_auth (str cmd, str arg)
{
  respond ("502 command not implemented\r\n");
}

str
smtpd::helo_auth ()
{
  static str empty ("");
  return empty;
}

#else /* SASL */

#include "serial.h"

static sasl_callback_t saslcbs[] = {
  { SASL_CB_LIST_END, NULL, NULL }
};

inline str
sasl_encode (const char *buf, size_t len)
{
  if (len == 0)
    return "=";
  return armor64 (buf, len);
}

inline str
sasl_decode (const str &buf)
{
  if (buf == "=")
    return "";
  return (dearmor64 (buf));
}

static bool
authinit ()
{
  static int authinitialized;
  if (authinitialized)
    return authinitialized > 0;
  if (sasl_server_init (saslcbs, progname.cstr ())) {
    warn ("sasl_server_init failed\n");
    authinitialized = -1;
    return false;
  }
  authinitialized = 1;
  return true;
}

str
smtpd::helo_auth ()
{
  int res;

  if (!opt->sasl || !authinit ())
    return "";

  if (!sasl) {
    saslstr.clear ();
    saslstr.push_back (opt->hostname);
    saslstr.push_back (strbuf ("%s;%d", inet_ntoa (myipaddr), mytcpport));
    saslstr.push_back (strbuf ("%s;%d", inet_ntoa (ipaddr), tcpport));

    res = sasl_server_new ("smtp",
                     saslstr[0].cstr (),
                     NULL, // realm
                     saslstr[1].cstr (), saslstr[2].cstr (),
                     saslcbs, 0, &sasl);
    if (res)
      return "";
  }

  sasl_security_properties_t prop;
  bzero (&prop, sizeof (prop));
  prop.max_ssf = SASL_SEC_MAXIMUM;
  prop.security_flags |= SASL_SEC_NOANONYMOUS;
  if (!opt->insecuresasl && !encrypted)
    prop.security_flags |= SASL_SEC_NOPLAINTEXT;
  res = sasl_setprop (sasl, SASL_SEC_PROPS, &prop);
  if (res) {
    sasl_dispose (&sasl);
    sasl = NULL;
    return "";
  }

  const char *mech = NULL;
  unsigned mechlen = 0;
  int mechnum = 0;
  res = sasl_listmech (sasl, NULL, "250-AUTH ", " ", "\r\n",
                   &mech, &mechlen, &mechnum);
  return (res || !mechnum) ? str ("") : str (mech, mechlen);
}

void
smtpd::cmd_auth (str cmd, str arg)
{
  static rxx cmdarg ("^(\\S+)(\\s*|\\s+(\\S.*))$");
  if (!sasl) {
    respond ("502 command not implemented\r\n");
    return;
  }
  else if (!arg || !cmdarg.match (arg)) {
    respond ("501 syntax error\r\n");
    return;
  }
  else if (auth_user) {
    respond ("503 already authenticated\r\n");
    return;
  }

  const char *out = NULL;
  unsigned outlen = 0;
  str opt = cmdarg[3];
  if (opt)
    opt = sasl_decode (opt);
  int res = sasl_server_start (sasl, cmdarg[1],
                         opt, opt ? opt.len () : 0,
                         &out, &outlen);
  cmd_auth_2 (res, out, outlen);
}
void
smtpd::cmd_auth_2 (int res, const char *out, unsigned outlen)
{
  switch (res) {
  case SASL_OK:
    {
      const void *val = NULL;
      sasl_getprop (sasl, SASL_USERNAME, &val);
      if (val) {
      quota_user = auth_user = static_cast<const char *> (val);
      if (opt->sasl >= 2 && trust < TRUST_AUTH)
        trust = TRUST_AUTH;
      }
      sasl_dispose (&sasl);
      sasl = NULL;
      respond ("235 OK\r\n");
      break;
    }
  case SASL_CONTINUE:
    aio << "334 " << sasl_encode (out, outlen) << "\r\n";
    cmdwait = true;
    aio->readline (wrap (this, &smtpd::cmd_auth_3));
    break;
  default:
    {
      const void *val = NULL;
      sasl_getprop (sasl, SASL_USERNAME, &val);
      if (!val)
      val = "unknown user";
      warn << "SASL authentication FAILED for "
         << static_cast<const char *> (val) << " from " << name << "\n";
      sasl_dispose (&sasl);
      sasl = NULL;
      respond ("535 authentication failed\r\n");
      break;
    }
  }
}
void
smtpd::cmd_auth_3 (str line, int err)
{
  cmdwait = false;
  if (!line) {
    getcmd (line, err);
    return;
  }

  line = sasl_decode (line);
  if (!line) {
    sasl_dispose (&sasl);
    sasl = NULL;
    respond ("501 base64 decoding error\r\n");
    return;
  }

  const char *out = NULL;
  unsigned outlen = 0;
  int res = sasl_server_step (sasl, line, line.len (), &out, &outlen);
  cmd_auth_2 (res, out, outlen);
}

#endif  /* SASL */

Generated by  Doxygen 1.6.0   Back to index