Commit 66f4500a 66f4500a83dfa67f8e2bd4bdde2ddd9fadbcdfde by Sam Roberts

Implemented AUTH=ANON, the anonymous SASL mechanism.

1 parent 3839724b
......@@ -153,8 +153,8 @@ folder_imap_destroy (folder_t folder)
}
/* Simple User/pass authentication for imap. */
static int
imap_user (authority_t auth)
int
authenticate_imap_login (authority_t auth)
{
folder_t folder = authority_get_owner (auth);
f_imap_t f_imap = folder->data;
......@@ -230,6 +230,131 @@ imap_user (authority_t auth)
return 0;
}
/*
The anonymous SASL mechanism is defined in rfc2245.txt as a single
message from client to server:
message = [email / token]
So the message is optional.
The command is:
C: <tag> authenticate anonymous
The server responds with a request for continuation data (the "message"
in the SASL syntax). We respond with no data, which is legal.
S: +
C:
The server should then respond with OK on success, or else a failure
code (NO or BAD).
If OK, then we are authenticated!
So, states are:
AUTH_ANON_REQ
> g%u AUTHENTICATE ANONYMOUS
AUTH_ANON_WAIT_CONT
< +
AUTH_ANON_MSG
>
AUTH_ANON_WAIT_RESP
< NO/BAD/OK
*/
int
authenticate_imap_sasl_anon (authority_t auth)
{
folder_t folder = authority_get_owner (auth);
f_imap_t f_imap = folder->data;
int status = 0;
assert (f_imap->state == IMAP_AUTH);
switch (f_imap->auth_state)
{
case IMAP_AUTH_ANON_REQ_WRITE:
{
FOLDER_DEBUG1 (folder, MU_DEBUG_PROT, "g%u AUTHENTICATE ANONYMOUS\n",
f_imap->seq);
status = imap_writeline (f_imap, "g%u AUTHENTICATE ANONYMOUS\r\n",
f_imap->seq);
f_imap->seq++;
CHECK_ERROR_CLOSE (folder, f_imap, status);
f_imap->state = IMAP_AUTH_ANON_REQ_SEND;
}
case IMAP_AUTH_ANON_REQ_SEND:
status = imap_send (f_imap);
CHECK_EAGAIN (f_imap, status);
f_imap->state = IMAP_AUTH_ANON_WAIT_CONT;
case IMAP_AUTH_ANON_WAIT_CONT:
status = imap_parse (f_imap);
CHECK_EAGAIN (f_imap, status);
FOLDER_DEBUG0 (folder, MU_DEBUG_PROT, f_imap->buffer);
if (strncmp ("+", f_imap->buffer, 2) == 0)
{
f_imap->state = IMAP_AUTH_ANON_MSG;
}
else
{
/* something is wrong! */
}
f_imap->state = IMAP_AUTH_ANON_MSG;
case IMAP_AUTH_ANON_MSG:
FOLDER_DEBUG0 (folder, MU_DEBUG_PROT, "\n");
status = imap_writeline (f_imap, "\r\n");
CHECK_ERROR_CLOSE (folder, f_imap, status);
f_imap->state = IMAP_AUTH_ANON_MSG_SEND;
case IMAP_AUTH_ANON_MSG_SEND:
status = imap_send (f_imap);
CHECK_EAGAIN (f_imap, status);
f_imap->state = IMAP_AUTH_ANON_WAIT_RESP;
case IMAP_AUTH_ANON_WAIT_RESP:
status = imap_parse (f_imap);
CHECK_EAGAIN (f_imap, status);
FOLDER_DEBUG0 (folder, MU_DEBUG_PROT, f_imap->buffer);
default:
break; /* We're outta here. */
}
CLEAR_STATE (f_imap);
return 0;
}
/* Create/Open the stream for IMAP. */
static int
folder_imap_open (folder_t folder, int flags)
......@@ -239,7 +364,6 @@ folder_imap_open (folder_t folder, int flags)
long port = 143; /* default imap port. */
int status = 0;
size_t len = 0;
int preauth = 0; /* Do we have "preauth"orisation ? */
/* If we are already open for business, noop. */
monitor_wrlock (folder->monitor);
......@@ -252,7 +376,7 @@ folder_imap_open (folder_t folder, int flags)
}
monitor_unlock (folder->monitor);
/* Fetch the pop server name and the port in the url_t. */
/* Fetch the server name and the port in the url_t. */
status = url_get_host (folder->url, NULL, 0, &len);
if (status != 0)
return status;
......@@ -320,38 +444,22 @@ folder_imap_open (folder_t folder, int flags)
/* Are they open for business ? The server send an untag response
for greeting. Thenically it can be OK/PREAUTH/BYE. The BYE is
the one that we do not want, server being unfriendly. */
preauth = (strncasecmp (f_imap->buffer, "* PREAUTH", 9) == 0);
if (strncasecmp (f_imap->buffer, "* OK", 4) != 0 && ! preauth)
{
CHECK_ERROR_CLOSE (folder, f_imap, EACCES);
}
if (folder->authority == NULL && !preauth)
{
char auth[64] = "";
size_t n = 0;
url_get_auth (folder->url, auth, 64, &n);
if (n == 0 || strcasecmp (auth, "*") == 0)
{
authority_create (&(folder->authority), folder->ticket,
folder);
authority_set_authenticate (folder->authority, imap_user,
folder);
}
else
{
/* No other type of Authentication is supported yet. */
/* What can we do ? flag an error ? */
CHECK_ERROR_CLOSE (folder, f_imap, ENOSYS);
}
}
f_imap->state = IMAP_AUTH;
if (strncasecmp (f_imap->buffer, "* PREAUTH", 9) == 0)
{
f_imap->state = IMAP_AUTH_DONE;
}
else
{
if (strncasecmp (f_imap->buffer, "* OK", 4) != 0)
CHECK_ERROR_CLOSE (folder, f_imap, EACCES);
f_imap->state = IMAP_AUTH;
}
}
case IMAP_AUTH:
case IMAP_LOGIN:
case IMAP_LOGIN_ACK:
if (!preauth)
assert (folder->authority);
{
status = authority_authenticate (folder->authority);
CHECK_EAGAIN (f_imap, status);
......
......@@ -25,6 +25,7 @@
#include <folder0.h>
#include <mailbox0.h>
#include <registrar0.h>
#include <auth0.h>
#ifdef __cplusplus
extern "C" {
......@@ -118,6 +119,18 @@ enum imap_state
IMAP_UNSUBSCRIBE, IMAP_UNSUBSCRIBE_ACK
};
enum imap_auth_state
{
/* ANONYMOUS */
IMAP_AUTH_ANON_REQ_WRITE,
IMAP_AUTH_ANON_REQ_SEND,
IMAP_AUTH_ANON_WAIT_CONT,
IMAP_AUTH_ANON_MSG,
IMAP_AUTH_ANON_MSG_SEND,
IMAP_AUTH_ANON_WAIT_RESP,
};
struct literal_string
{
char *buffer;
......@@ -169,6 +182,9 @@ struct _f_imap
/* Login */
char *user;
char *passwd;
/* AUTHENTICATE states */
enum imap_auth_state auth_state;
};
struct _m_imap
......@@ -215,7 +231,10 @@ int imap_write __P ((f_imap_t));
int imap_send __P ((f_imap_t));
int imap_parse __P ((f_imap_t));
int imap_readline __P ((f_imap_t));
char *section_name __P ((msg_imap_t));
char *section_name __P ((msg_imap_t));
int authenticate_imap_login __P ((authority_t auth));
int authenticate_imap_sasl_anon __P ((authority_t auth));
#ifdef __cplusplus
}
......
......@@ -34,6 +34,8 @@
#include <mailbox0.h>
#include <registrar0.h>
#include <imap0.h>
#include <url0.h>
#undef min
#define min(a,b) ((a) < (b) ? (a) : (b))
......@@ -107,7 +109,13 @@ _mailbox_imap_init (mailbox_t mailbox)
{
m_imap_t m_imap;
size_t name_len = 0;
m_imap = mailbox->data = calloc (1, sizeof *m_imap);
folder_t folder = NULL;
assert(mailbox);
folder = mailbox->folder;
m_imap = mailbox->data = calloc (1, sizeof (*m_imap));
if (m_imap == NULL)
return ENOMEM;
......@@ -156,6 +164,33 @@ _mailbox_imap_init (mailbox_t mailbox)
mailbox_get_property (mailbox, &property);
property_set_value (property, "TYPE", "IMAP4", 1);
}
assert(folder);
assert(folder->url);
if (folder->authority == NULL)
{
const char *auth = folder->url->auth;
if (auth == NULL || strcasecmp (auth, "*") == 0)
{
authority_create (&(folder->authority), folder->ticket, folder);
authority_set_authenticate (folder->authority,
authenticate_imap_login, folder);
}
else if (strcasecmp (auth, "anon") == 0)
{
authority_create (&(folder->authority), folder->ticket, folder);
authority_set_authenticate (folder->authority,
authenticate_imap_sasl_anon, folder);
}
else
{
/* Not a supported authentication mechanism. */
return ENOTSUP;
}
}
return 0;
}
......@@ -759,7 +794,6 @@ imap_expunge (mailbox_t mailbox)
static int
imap_append_message (mailbox_t mailbox, message_t msg)
{
size_t total;
int status = 0;
m_imap_t m_imap = mailbox->data;
f_imap_t f_imap = m_imap->f_imap;
......