Пример #1
0
int
auth_cram_md5_client(
  auth_instance *ablock,                 /* authenticator block */
  smtp_inblock *inblock,                 /* input connection */
  smtp_outblock *outblock,               /* output connection */
  int timeout,                           /* command timeout */
  uschar *buffer,                        /* for reading response */
  int buffsize)                          /* size of buffer */
{
auth_cram_md5_options_block *ob =
  (auth_cram_md5_options_block *)(ablock->options_block);
uschar *secret = expand_string(ob->client_secret);
uschar *name = expand_string(ob->client_name);
uschar *challenge, *p;
int i;
uschar digest[16];

/* If expansion of either the secret or the user name failed, return CANCELLED
or ERROR, as approriate. */

if (!secret || !name)
  {
  if (expand_string_forcedfail)
    {
    *buffer = 0;           /* No message */
    return CANCELLED;
    }
  string_format(buffer, buffsize, "expansion of \"%s\" failed in "
    "%s authenticator: %s",
    !secret ? ob->client_secret : ob->client_name,
    ablock->name, expand_string_message);
  return ERROR;
  }

/* Initiate the authentication exchange and read the challenge, which arrives
in base 64. */

if (smtp_write_command(outblock, FALSE, "AUTH %s\r\n", ablock->public_name) < 0)
  return FAIL_SEND;
if (!smtp_read_response(inblock, buffer, buffsize, '3', timeout))
  return FAIL;

if (b64decode(buffer + 4, &challenge) < 0)
  {
  string_format(buffer, buffsize, "bad base 64 string in challenge: %s",
    big_buffer + 4);
  return ERROR;
  }

/* Run the CRAM-MD5 algorithm on the secret and the challenge */

compute_cram_md5(secret, challenge, digest);

/* Create the response from the user name plus the CRAM-MD5 digest */

string_format(big_buffer, big_buffer_size - 36, "%s", name);
for (p = big_buffer; *p; ) p++;
*p++ = ' ';

for (i = 0; i < 16; i++)
  {
  sprintf(CS p, "%02x", digest[i]);
  p += 2;
  }

/* Send the response, in base 64, and check the result. The response is
in big_buffer, but b64encode() returns its result in working store,
so calling smtp_write_command(), which uses big_buffer, is OK. */

buffer[0] = 0;
if (smtp_write_command(outblock, FALSE, "%s\r\n", b64encode(big_buffer,
  p - big_buffer)) < 0) return FAIL_SEND;

return smtp_read_response(inblock, (uschar *)buffer, buffsize, '2', timeout)
  ? OK : FAIL;
}
Пример #2
0
int
auth_spa_client(
  auth_instance *ablock,                 /* authenticator block */
  smtp_inblock *inblock,                 /* connection inblock */
  smtp_outblock *outblock,               /* connection outblock */
  int timeout,                           /* command timeout */
  uschar *buffer,                        /* buffer for reading response */
  int buffsize)                          /* size of buffer */
{
       auth_spa_options_block *ob =
               (auth_spa_options_block *)(ablock->options_block);
       SPAAuthRequest   request;
       SPAAuthChallenge challenge;
       SPAAuthResponse  response;
       char msgbuf[2048];
       char *domain = NULL;
       char *username, *password;

       /* Code added by PH to expand the options */

       *buffer = 0;    /* Default no message when cancelled */

       username = CS expand_string(ob->spa_username);
       if (username == NULL)
         {
         if (expand_string_forcedfail) return CANCELLED;
         string_format(buffer, buffsize, "expansion of \"%s\" failed in %s "
           "authenticator: %s", ob->spa_username, ablock->name,
           expand_string_message);
         return ERROR;
         }

       password = CS expand_string(ob->spa_password);
       if (password == NULL)
         {
         if (expand_string_forcedfail) return CANCELLED;
         string_format(buffer, buffsize, "expansion of \"%s\" failed in %s "
           "authenticator: %s", ob->spa_password, ablock->name,
           expand_string_message);
         return ERROR;
         }

       if (ob->spa_domain != NULL)
         {
         domain = CS expand_string(ob->spa_domain);
         if (domain == NULL)
           {
           if (expand_string_forcedfail) return CANCELLED;
           string_format(buffer, buffsize, "expansion of \"%s\" failed in %s "
             "authenticator: %s", ob->spa_domain, ablock->name,
             expand_string_message);
           return ERROR;
           }
         }

       /* Original code */

    if (smtp_write_command(outblock, FALSE, "AUTH %s\r\n",
         ablock->public_name) < 0)
               return FAIL_SEND;

       /* wait for the 3XX OK message */
       if (!smtp_read_response(inblock, (uschar *)buffer, buffsize, '3', timeout))
               return FAIL;

       DSPA("\n\n%s authenticator: using domain %s\n\n",
               ablock->name, domain);

       spa_build_auth_request (&request, CS username, domain);
       spa_bits_to_base64 (US msgbuf, (unsigned char*)&request,
               spa_request_length(&request));

       DSPA("\n\n%s authenticator: sending request (%s)\n\n", ablock->name,
               msgbuf);

       /* send the encrypted password */
       if (smtp_write_command(outblock, FALSE, "%s\r\n", msgbuf) < 0)
               return FAIL_SEND;

       /* wait for the auth challenge */
       if (!smtp_read_response(inblock, (uschar *)buffer, buffsize, '3', timeout))
               return FAIL;

       /* convert the challenge into the challenge struct */
       DSPA("\n\n%s authenticator: challenge (%s)\n\n",
               ablock->name, buffer + 4);
       spa_base64_to_bits ((char *)(&challenge), sizeof(challenge), (const char *)(buffer + 4));

       spa_build_auth_response (&challenge, &response,
               CS username, CS password);
       spa_bits_to_base64 (US msgbuf, (unsigned char*)&response,
               spa_request_length(&response));
       DSPA("\n\n%s authenticator: challenge response (%s)\n\n", ablock->name,
               msgbuf);

       /* send the challenge response */
       if (smtp_write_command(outblock, FALSE, "%s\r\n", msgbuf) < 0)
               return FAIL_SEND;

       /* If we receive a success response from the server, authentication
       has succeeded. There may be more data to send, but is there any point
       in provoking an error here? */
       if (smtp_read_response(inblock, US buffer, buffsize, '2', timeout))
               return OK;

       /* Not a success response. If errno != 0 there is some kind of transmission
       error. Otherwise, check the response code in the buffer. If it starts with
       '3', more data is expected. */
       if (errno != 0 || buffer[0] != '3')
               return FAIL;

       return FAIL;
}