mech-apop.c revision a8e132559a7ebe54c8269d79ce29fa3338c76199
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose/*
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose * APOP (RFC-1460) authentication mechanism.
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose *
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose * Copyright (c) 2004 Andrey Panin <pazke@donpac.ru>
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose *
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose * This software is released under the MIT license.
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose */
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose#include "common.h"
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose#include "mech.h"
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose#include "passdb.h"
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose#include "md5.h"
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose#include "buffer.h"
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose#include "auth-client-connection.h"
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose#include "auth-master-connection.h"
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose#include <stdio.h>
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose#include <unistd.h>
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bosestruct apop_auth_request {
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose struct auth_request auth_request;
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose pool_t pool;
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose /* requested: */
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose char *challenge;
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose /* received: */
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose unsigned char digest[16];
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose};
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bosestatic bool verify_credentials(struct apop_auth_request *request,
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose const char *credentials)
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose{
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose unsigned char digest[16];
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose struct md5_context ctx;
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose md5_init(&ctx);
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose md5_update(&ctx, request->challenge, strlen(request->challenge));
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose md5_update(&ctx, credentials, strlen(credentials));
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose md5_final(&ctx, digest);
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose return memcmp(digest, request->digest, 16) == 0;
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose}
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bosestatic void
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Boseapop_credentials_callback(enum passdb_result result,
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose const char *credentials,
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose struct auth_request *auth_request)
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose{
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose struct apop_auth_request *request =
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose (struct apop_auth_request *)auth_request;
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose switch (result) {
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose case PASSDB_RESULT_OK:
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose if (verify_credentials(request, credentials))
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose auth_request_success(auth_request, NULL, 0);
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose else
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose auth_request_fail(auth_request);
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose break;
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose case PASSDB_RESULT_INTERNAL_FAILURE:
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose auth_request_internal_failure(auth_request);
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose break;
cf93f7c2f2031078bbbff095dae01eb4f8deff85Sumit Bose default:
cf93f7c2f2031078bbbff095dae01eb4f8deff85Sumit Bose auth_request_fail(auth_request);
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose break;
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose }
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose}
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bosestatic void
cf93f7c2f2031078bbbff095dae01eb4f8deff85Sumit Bosemech_apop_auth_initial(struct auth_request *auth_request,
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose const unsigned char *data, size_t data_size)
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose{
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose struct apop_auth_request *request =
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose (struct apop_auth_request *)auth_request;
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose const unsigned char *tmp, *end, *username = NULL;
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose unsigned long pid, connect_uid, timestamp;
cf93f7c2f2031078bbbff095dae01eb4f8deff85Sumit Bose const char *error;
cf93f7c2f2031078bbbff095dae01eb4f8deff85Sumit Bose
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose if (data_size == 0) {
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose /* Should never happen */
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose auth_request_log_info(auth_request, "apop",
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose "no initial respone");
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose auth_request_fail(auth_request);
cf93f7c2f2031078bbbff095dae01eb4f8deff85Sumit Bose return;
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose }
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose tmp = data;
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose end = data + data_size;
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose /* skip the challenge */
cf93f7c2f2031078bbbff095dae01eb4f8deff85Sumit Bose while (tmp != end && *tmp != '\0')
cf93f7c2f2031078bbbff095dae01eb4f8deff85Sumit Bose tmp++;
cf93f7c2f2031078bbbff095dae01eb4f8deff85Sumit Bose
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose if (tmp != end) {
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose /* get the username */
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose username = ++tmp;
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose while (tmp != end && *tmp != '\0')
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose tmp++;
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose }
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose if (tmp + 1 + 16 != end) {
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose /* Should never happen */
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose auth_request_log_info(auth_request, "apop", "malformed data");
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose auth_request_fail(auth_request);
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose return;
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose }
55f7d8034d783c01789d76a2b9ffc901045e8af8Sumit Bose tmp++;
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose /* the challenge must begin with trusted unique ID. we trust only
55f7d8034d783c01789d76a2b9ffc901045e8af8Sumit Bose ourself, so make sure it matches our connection specific UID
55f7d8034d783c01789d76a2b9ffc901045e8af8Sumit Bose which we told to client in handshake. Also require a timestamp
55f7d8034d783c01789d76a2b9ffc901045e8af8Sumit Bose which is later than this process's start time. */
55f7d8034d783c01789d76a2b9ffc901045e8af8Sumit Bose
55f7d8034d783c01789d76a2b9ffc901045e8af8Sumit Bose if (sscanf((const char *)data, "<%lx.%lx.%lx.",
55f7d8034d783c01789d76a2b9ffc901045e8af8Sumit Bose &pid, &connect_uid, &timestamp) != 3 ||
55f7d8034d783c01789d76a2b9ffc901045e8af8Sumit Bose connect_uid != auth_request->connect_uid ||
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose pid != (unsigned long)getpid() ||
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose (time_t)timestamp < process_start_time) {
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose auth_request_log_info(auth_request, "apop",
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose "invalid challenge");
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose auth_request_fail(auth_request);
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose return;
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose }
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose request->challenge = p_strdup(request->pool, (const char *)data);
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose if (!auth_request_set_username(auth_request, (const char *)username,
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose &error)) {
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose auth_request_log_info(auth_request, "apop", "%s", error);
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose auth_request_fail(auth_request);
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose return;
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose }
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose memcpy(request->digest, tmp, sizeof(request->digest));
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose auth_request_lookup_credentials(auth_request, "PLAIN",
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose apop_credentials_callback);
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose}
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bosestatic struct auth_request *mech_apop_auth_new(void)
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose{
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose struct apop_auth_request *request;
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose pool_t pool;
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose pool = pool_alloconly_create("apop_auth_request", 1024);
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose request = p_new(pool, struct apop_auth_request, 1);
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose request->pool = pool;
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose request->auth_request.pool = pool;
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose return &request->auth_request;
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose}
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Boseconst struct mech_module mech_apop = {
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose "APOP",
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose MEMBER(flags) MECH_SEC_PRIVATE | MECH_SEC_DICTIONARY | MECH_SEC_ACTIVE,
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose MEMBER(passdb_need_plain) FALSE,
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose MEMBER(passdb_need_credentials) TRUE,
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose MEMBER(passdb_need_set_credentials) FALSE,
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose mech_apop_auth_new,
859bddc2bf51dc426a3dc56bd9f365e9c5722b65Sumit Bose mech_apop_auth_initial,
55f7d8034d783c01789d76a2b9ffc901045e8af8Sumit Bose NULL,
55f7d8034d783c01789d76a2b9ffc901045e8af8Sumit Bose mech_generic_auth_free
55f7d8034d783c01789d76a2b9ffc901045e8af8Sumit Bose};
5e6622722e84d594298a8324f3685a1bda2b5868Sumit Bose