#include <config.h>
#include <string.h>
#include <sasl/sasl.h>
#include <sasl/saslutil.h>
#include "prot.h"
#include "imap_err.h"
#include "xmalloc.h"
#define BASE64_BUF_SIZE 21848
int saslserver(sasl_conn_t *conn, const char *mech,
const char *init_resp, const char *resp_prefix,
const char *continuation, const char *empty_chal,
struct protstream *pin, struct protstream *pout,
int *sasl_result, char **success_data)
{
char base64[BASE64_BUF_SIZE+1];
char *clientin = NULL;
unsigned int clientinlen = 0;
const char *serverout;
unsigned int serveroutlen;
int r = SASL_OK;
if (success_data) *success_data = NULL;
if ( strcmp( mech, "OD-CHECKPASS" ) == 0 )
{
r = sasl_server_start( conn, mech, init_resp, strlen( init_resp ),
&serverout, &serveroutlen );
if ( r == SASL_CONTINUE )
{
r = sasl_server_step( conn, resp_prefix, strlen( resp_prefix ),
&serverout, &serveroutlen );
}
if ( sasl_result )
{
*sasl_result = r;
}
return( r == SASL_OK ? 0 : IMAP_SASL_FAIL );
}
else if ( strcmp( mech, "OD-CRAM-MD5" ) == 0 )
{
}
else if ( strcmp( mech, "OD-APOP" ) == 0 )
{
r = sasl_server_start( conn, mech, init_resp, strlen( init_resp ),
&serverout, &serveroutlen );
if ( r == SASL_CONTINUE )
{
r = sasl_server_step( conn, resp_prefix, strlen( resp_prefix ),
&serverout, &serveroutlen );
}
if ( sasl_result )
{
*sasl_result = r;
}
return( r == SASL_OK ? 0 : IMAP_SASL_FAIL );
}
if (init_resp) {
clientin = base64;
if (!strcmp(init_resp, "=")) {
base64[0] = '\0';
}
else {
r = sasl_decode64(init_resp, strlen(init_resp),
clientin, BASE64_BUF_SIZE, &clientinlen);
}
}
if (r == SASL_OK)
r = sasl_server_start(conn, mech, clientin, clientinlen,
&serverout, &serveroutlen);
while (r == SASL_CONTINUE) {
char *p;
if (serveroutlen) {
r = sasl_encode64(serverout, serveroutlen,
base64, BASE64_BUF_SIZE, NULL);
if (r != SASL_OK) break;
serverout = base64;
}
else {
serverout = empty_chal;
}
prot_printf(pout, "%s%s\r\n", continuation, serverout);
if (!prot_fgets(base64, BASE64_BUF_SIZE, pin) ||
strncasecmp(base64, resp_prefix, strlen(resp_prefix))) {
if (sasl_result) *sasl_result = SASL_FAIL;
return IMAP_SASL_PROTERR;
}
p = base64 + strlen(base64) - 1;
if (p >= base64 && *p == '\n') *p-- = '\0';
if (p >= base64 && *p == '\r') *p-- = '\0';
p = base64 + strlen(resp_prefix);
if (p[0] == '*') {
if(sasl_result) *sasl_result = SASL_BADPROT;
return IMAP_SASL_CANCEL;
}
clientin = base64;
r = sasl_decode64(p, strlen(p),
clientin, BASE64_BUF_SIZE, &clientinlen);
if (r != SASL_OK) break;
r = sasl_server_step(conn, clientin, clientinlen,
&serverout, &serveroutlen);
}
if (r == SASL_OK && serverout && success_data) {
r = sasl_encode64(serverout, serveroutlen,
base64, BASE64_BUF_SIZE, NULL);
if (r == SASL_OK)
*success_data = (char *) xstrdup(base64);
}
if (sasl_result) *sasl_result = r;
return (r == SASL_OK ? 0 : IMAP_SASL_FAIL);
}