/* $Id: auth.C,v 1.9 2005/08/17 02:34:29 dm Exp $ */
/*
*
* 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 (!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 ? 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 */
syntax highlighted by Code2HTML, v. 0.9.1