Skip to content

Commit f5a5b92

Browse files
AdityaGarg8gitster
authored andcommitted
imap-send: add PLAIN authentication method to OpenSSL
The current implementation for PLAIN in imap-send works just fine if using curl, but if attempted to use for OpenSSL, it is treated as an invalid mechanism. The default implementation for OpenSSL is IMAP LOGIN command rather than AUTH PLAIN. Since AUTH PLAIN is still used today by many email providers in form of app passwords, lets add an implementation that can use AUTH PLAIN if specified. Signed-off-by: Aditya Garg <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 05326a1 commit f5a5b92

File tree

2 files changed

+83
-3
lines changed

2 files changed

+83
-3
lines changed

Documentation/config/imap.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,6 @@ imap.authMethod::
4040
Specify the authentication method for authenticating with the IMAP server.
4141
If Git was built with the NO_CURL option, or if your curl version is older
4242
than 7.34.0, or if you're running git-imap-send with the `--no-curl`
43-
option, the only supported methods are `CRAM-MD5`, `OAUTHBEARER` and
44-
`XOAUTH2`. If this is not set then `git imap-send` uses the basic IMAP
43+
option, the only supported methods are `PLAIN`, `CRAM-MD5`, `OAUTHBEARER`
44+
and `XOAUTH2`. If this is not set then `git imap-send` uses the basic IMAP
4545
plaintext `LOGIN` command.

imap-send.c

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ enum CAPABILITY {
139139
LITERALPLUS,
140140
NAMESPACE,
141141
STARTTLS,
142+
AUTH_PLAIN,
142143
AUTH_CRAM_MD5,
143144
AUTH_OAUTHBEARER,
144145
AUTH_XOAUTH2,
@@ -150,6 +151,7 @@ static const char *cap_list[] = {
150151
"LITERAL+",
151152
"NAMESPACE",
152153
"STARTTLS",
154+
"AUTH=PLAIN",
153155
"AUTH=CRAM-MD5",
154156
"AUTH=OAUTHBEARER",
155157
"AUTH=XOAUTH2",
@@ -851,6 +853,41 @@ static char hexchar(unsigned int b)
851853
}
852854

853855
#define ENCODED_SIZE(n) (4 * DIV_ROUND_UP((n), 3))
856+
static char *plain_base64(const char *user, const char *pass)
857+
{
858+
int user_len = strlen(user);
859+
int pass_len = strlen(pass);
860+
int raw_len = 1 + user_len + 1 + pass_len;
861+
int b64_len;
862+
char *raw, *b64;
863+
864+
/*
865+
* Compose the PLAIN string
866+
*
867+
* The username and password are combined to one string and base64 encoded.
868+
* "\0user\0pass"
869+
*
870+
* The method has been described in RFC4616.
871+
*
872+
* https://datatracker.ietf.org/doc/html/rfc4616
873+
*/
874+
raw = xmallocz(raw_len);
875+
raw[0] = '\0';
876+
memcpy(raw + 1, user, user_len);
877+
raw[1 + user_len] = '\0';
878+
memcpy(raw + 2 + user_len, pass, pass_len);
879+
880+
b64 = xmallocz(ENCODED_SIZE(raw_len));
881+
b64_len = EVP_EncodeBlock((unsigned char *)b64, (unsigned char *)raw, raw_len);
882+
free(raw);
883+
884+
if (b64_len < 0) {
885+
free(b64);
886+
return NULL;
887+
}
888+
return b64;
889+
}
890+
854891
static char *cram(const char *challenge_64, const char *user, const char *pass)
855892
{
856893
int i, resp_len, encoded_len, decoded_len;
@@ -951,6 +988,26 @@ static char *xoauth2_base64(const char *user, const char *access_token)
951988
return b64;
952989
}
953990

991+
static int auth_plain(struct imap_store *ctx, const char *prompt UNUSED)
992+
{
993+
int ret;
994+
char *b64;
995+
996+
b64 = plain_base64(ctx->cfg->user, ctx->cfg->pass);
997+
if (!b64)
998+
return error("PLAIN: base64 encoding failed");
999+
1000+
/* Send the base64-encoded response */
1001+
ret = socket_write(&ctx->imap->buf.sock, b64, strlen(b64));
1002+
if (ret != (int)strlen(b64)) {
1003+
free(b64);
1004+
return error("IMAP error: sending PLAIN response failed");
1005+
}
1006+
1007+
free(b64);
1008+
return 0;
1009+
}
1010+
9541011
static int auth_oauthbearer(struct imap_store *ctx, const char *prompt UNUSED)
9551012
{
9561013
int ret;
@@ -1001,6 +1058,7 @@ static char *cram(const char *challenge_64 UNUSED,
10011058
"you have to build git-imap-send with OpenSSL library.");
10021059
}
10031060

1061+
#define auth_plain NULL
10041062
#define auth_oauthbearer NULL
10051063
#define auth_xoauth2 NULL
10061064

@@ -1198,7 +1256,29 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c
11981256
if (srvc->auth_method) {
11991257
struct imap_cmd_cb cb;
12001258

1201-
if (!strcmp(srvc->auth_method, "CRAM-MD5")) {
1259+
if (!strcmp(srvc->auth_method, "PLAIN")) {
1260+
if (!CAP(AUTH_PLAIN)) {
1261+
fprintf(stderr, "You specified "
1262+
"PLAIN as authentication method, "
1263+
"but %s doesn't support it.\n", srvc->host);
1264+
goto bail;
1265+
}
1266+
1267+
#ifdef NO_OPENSSL
1268+
fprintf(stderr, "You are trying to use PLAIN authentication mechanism "
1269+
"with OpenSSL library, but its support has not been compiled in.");
1270+
goto bail;
1271+
#endif
1272+
1273+
/* PLAIN */
1274+
1275+
memset(&cb, 0, sizeof(cb));
1276+
cb.cont = auth_plain;
1277+
if (imap_exec(ctx, &cb, "AUTHENTICATE PLAIN") != RESP_OK) {
1278+
fprintf(stderr, "IMAP error: AUTHENTICATE PLAIN failed\n");
1279+
goto bail;
1280+
}
1281+
} else if (!strcmp(srvc->auth_method, "CRAM-MD5")) {
12021282
if (!CAP(AUTH_CRAM_MD5)) {
12031283
fprintf(stderr, "You specified "
12041284
"CRAM-MD5 as authentication method, "

0 commit comments

Comments
 (0)