Exemple #1
0
/*
 * Authenticate to the server with the Challenge-Response Authentication
 * Mechanism (CRAM).  The authentication type associated with CRAM is
 * "CRAM-MD5".
 */
int
auth_cram_md5(session *ssn, const char *user, const char *pass)
{
	int t;
	size_t n;
	unsigned int i;
	unsigned char *chal, *resp, *out, *buf;
	unsigned char md[EVP_MAX_MD_SIZE], mdhex[EVP_MAX_MD_SIZE * 2 + 1];
	unsigned int mdlen;
	HMAC_CTX hmac;

	if ((t = imap_authenticate(ssn, "CRAM-MD5")) == -1)
		return -1;

	if (response_authenticate(ssn, t, &chal) ==
	    STATUS_RESPONSE_CONTINUE) {
		n = strlen((char *)(chal)) * 3 / 4 + 1;
		resp = (unsigned char *)xmalloc(n * sizeof(char));
		memset(resp, 0, n);

		EVP_DecodeBlock(resp, chal, strlen((char *)(chal)));

		HMAC_Init(&hmac, (const unsigned char *)pass, strlen(pass),
		    EVP_md5());
		HMAC_Update(&hmac, resp, strlen((char *)(resp)));
		HMAC_Final(&hmac, md, &mdlen);

		xfree(chal);
		xfree(resp);

		for (i = 0; i < mdlen; i++)
			snprintf((char *)(mdhex) + i * 2, mdlen * 2 - i * 2 + 1,
			    "%02x", md[i]);
		mdhex[mdlen * 2] = '\0';

		n = strlen(user) + 1 + strlen((char *)(mdhex)) + 1;
		buf = (unsigned char *)xmalloc(n * sizeof(unsigned char));
		memset(buf, 0, n);

		snprintf((char *)(buf), n, "%s %s", user, mdhex);

		n = (strlen((char *)(buf)) + 3) * 4 / 3 + 1;
		out = (unsigned char *)xmalloc(n * sizeof(unsigned char));
		memset(out, 0, n);

		EVP_EncodeBlock(out, buf, strlen((char *)(buf)));

		imap_continuation(ssn, (char *)(out), strlen((char *)(out)));

		xfree(buf);
		xfree(out);
	} else
		return -1;

	return response_authenticate(ssn, t, NULL);
}
Exemple #2
0
/*
 * Connect to the server, login to the IMAP server, get it's capabilities, get
 * the namespace of the mailboxes.
 */
int
request_login(session **ssnptr, const char *server, const char *port, const
    char *ssl, const char *user, const char *pass)
{
	int t, r, rg = -1, rl = -1; 
	session *ssn = *ssnptr;
	
	if (*ssnptr && (*ssnptr)->socket != -1)
		return STATUS_PREAUTH;

	if (!*ssnptr) {
		ssn = *ssnptr = session_new();

		ssn->server = server;
		ssn->port = port;
		ssn->username = user;
		ssn->password = pass;

		if (strlen(ssl) != 0)
			ssn->sslproto = ssl;
	} else {
		debug("recovering connection: %s://%s@%s:%s/%s\n",
		    ssn->sslproto ?"imaps" : "imap", ssn->username, ssn->server,
		    ssn->port, ssn->selected ? ssn->selected : "");
	}

	if (open_connection(ssn) == -1)
		goto fail;

	CHECK(rg = response_greeting(ssn));

	if (opts.debug) {
		CHECK(t = send_request(ssn, "NOOP"));
		CHECK(response_generic(ssn, t));
	}

	CHECK(t = send_request(ssn, "CAPABILITY"));
	CHECK(response_capability(ssn, t));

	if (!ssn->sslproto && ssn->capabilities & CAPABILITY_STARTTLS &&
	    get_option_boolean("starttls")) {
		CHECK(t = send_request(ssn, "STARTTLS"));
		CHECK(r = response_generic(ssn, t));
		if (r == STATUS_OK) {
			if (open_secure_connection(ssn) == -1)
				goto fail;
			CHECK(t = send_request(ssn, "CAPABILITY"));
			CHECK(response_capability(ssn, t));
		}
	}

	if (rg != STATUS_PREAUTH) {
		if (ssn->capabilities & CAPABILITY_CRAMMD5 &&
		    get_option_boolean("crammd5")) {
			unsigned char *in, *out;
			CHECK(t = send_request(ssn, "AUTHENTICATE CRAM-MD5"));
			CHECK(r = response_authenticate(ssn, t, &in));
			if (r == STATUS_CONTINUE) {
				if ((out = auth_cram_md5(ssn->username,
				    ssn->password, in)) == NULL)
					goto abort;
				CHECK(send_continuation(ssn, (char *)(out),
				    strlen((char *)(out))));
				xfree(out);
				CHECK(rl = response_generic(ssn, t));
			} else
				goto abort;
		}
		if (rl != STATUS_OK) {
			CHECK(t = send_request(ssn, "LOGIN \"%s\" \"%s\"",
			    ssn->username, ssn->password));
			CHECK(rl = response_generic(ssn, t));
		}

		if (rl == STATUS_NO) {
			error("username %s or password rejected at %s\n",
			    ssn->username, ssn->server);
			close_connection(ssn);
			session_destroy(ssn);
			return STATUS_NO;
		}
	} else {
		rl = STATUS_PREAUTH;
	}

	CHECK(t = send_request(ssn, "CAPABILITY"));
	CHECK(response_capability(ssn, t));

	if (ssn->capabilities & CAPABILITY_NAMESPACE &&
	    get_option_boolean("namespace")) {
		CHECK(t = send_request(ssn, "NAMESPACE"));
		CHECK(response_namespace(ssn, t));
	}

	if (ssn->selected) {
		CHECK(t = send_request(ssn, "SELECT \"%s\"",
		    apply_namespace(ssn->selected, ssn->ns.prefix,
		    ssn->ns.delim)));
		CHECK(response_select(ssn, t));
	}

	return rl;
abort:
	close_connection(ssn);
fail:
	session_destroy(ssn);

	return -1;
}