smtp_sasl_auth_cache.c [plain text]
#include <sys_defs.h>
#include <msg.h>
#include <mymalloc.h>
#include <stringops.h>
#include <base64_code.h>
#include <dict.h>
#include <dsn_util.h>
#include <dict_proxy.h>
#include "smtp.h"
#include "smtp_sasl_auth_cache.h"
#ifdef HAVE_SASL_AUTH_CACHE
SMTP_SASL_AUTH_CACHE *smtp_sasl_auth_cache_init(const char *map, int ttl)
{
const char *myname = "smtp_sasl_auth_cache_init";
SMTP_SASL_AUTH_CACHE *auth_cache;
#define HAS_MULTIPLE_VALUES(s) ((s)[strcspn((s), ", \t\r\n")] != 0)
if (*map == 0)
msg_panic("%s: empty SASL authentication cache name", myname);
if (ttl < 0)
msg_panic("%s: bad SASL authentication cache ttl: %d", myname, ttl);
if (HAS_MULTIPLE_VALUES(map))
msg_fatal("SASL authentication cache name \"%s\" "
"contains multiple values", map);
#define CACHE_DICT_OPEN_FLAGS \
(DICT_FLAG_DUP_REPLACE | DICT_FLAG_SYNC_UPDATE)
#define PROXY_COLON DICT_TYPE_PROXY ":"
#define PROXY_COLON_LEN (sizeof(PROXY_COLON) - 1)
if (strncmp(map, PROXY_COLON, PROXY_COLON_LEN) != 0)
msg_fatal("SASL authentication cache name \"%s\" must start with \""
PROXY_COLON, map);
auth_cache = (SMTP_SASL_AUTH_CACHE *) mymalloc(sizeof(*auth_cache));
auth_cache->dict = dict_open(map, O_CREAT | O_RDWR, CACHE_DICT_OPEN_FLAGS);
auth_cache->ttl = ttl;
auth_cache->dsn = mystrdup("");
auth_cache->text = mystrdup("");
return (auth_cache);
}
static char *smtp_sasl_auth_cache_make_key(const char *host, const char *user)
{
VSTRING *buf = vstring_alloc(100);
vstring_sprintf(buf, "%s;%s", host, user);
return (vstring_export(buf));
}
static char *smtp_sasl_auth_cache_make_pass(const char *password)
{
VSTRING *buf = vstring_alloc(2 * SHA_DIGEST_LENGTH);
base64_encode(buf, (const char *) SHA1((const unsigned char *) password,
strlen(password), 0),
SHA_DIGEST_LENGTH);
return (vstring_export(buf));
}
static char *smtp_sasl_auth_cache_make_value(const char *password,
const char *dsn,
const char *rep_str)
{
VSTRING *val_buf = vstring_alloc(100);
char *pwd_hash;
unsigned long now = (unsigned long) time((time_t *) 0);
pwd_hash = smtp_sasl_auth_cache_make_pass(password);
vstring_sprintf(val_buf, "%lu;%s;%s;%s", now, pwd_hash, dsn, rep_str);
myfree(pwd_hash);
return (vstring_export(val_buf));
}
static int smtp_sasl_auth_cache_valid_value(SMTP_SASL_AUTH_CACHE *auth_cache,
const char *entry,
const char *password)
{
ssize_t len = strlen(entry);
char *cache_hash = mymalloc(len);
char *curr_hash;
unsigned long now = (unsigned long) time((time_t *) 0);
unsigned long time_stamp;
int valid;
auth_cache->dsn = myrealloc(auth_cache->dsn, len);
auth_cache->text = myrealloc(auth_cache->text, len);
if (sscanf(entry, "%lu;%[^;];%[^;];%[^\n]", &time_stamp, cache_hash,
auth_cache->dsn, auth_cache->text) != 4
|| !dsn_valid(auth_cache->dsn)) {
msg_warn("bad smtp_sasl_auth_cache entry: %.100s", entry);
valid = 0;
} else if (time_stamp + auth_cache->ttl < now) {
valid = 0;
} else {
curr_hash = smtp_sasl_auth_cache_make_pass(password);
valid = (strcmp(cache_hash, curr_hash) == 0);
myfree(curr_hash);
}
myfree(cache_hash);
return (valid);
}
int smtp_sasl_auth_cache_find(SMTP_SASL_AUTH_CACHE *auth_cache,
const SMTP_SESSION *session)
{
char *key;
const char *entry;
int valid = 0;
key = smtp_sasl_auth_cache_make_key(session->host, session->sasl_username);
if ((entry = dict_get(auth_cache->dict, key)) != 0)
if ((valid = smtp_sasl_auth_cache_valid_value(auth_cache, entry,
session->sasl_passwd)) == 0)
if (dict_del(auth_cache->dict, key) == 0)
msg_warn("SASL auth failure map %s: entry not deleted: %s",
auth_cache->dict->name, key);
myfree(key);
return (valid);
}
void smtp_sasl_auth_cache_store(SMTP_SASL_AUTH_CACHE *auth_cache,
const SMTP_SESSION *session,
const SMTP_RESP *resp)
{
char *key;
char *value;
key = smtp_sasl_auth_cache_make_key(session->host, session->sasl_username);
value = smtp_sasl_auth_cache_make_value(session->sasl_passwd,
resp->dsn, resp->str);
dict_put(auth_cache->dict, key, value);
myfree(value);
myfree(key);
}
#endif