Git fork

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 <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

authored by

Aditya Garg and committed by
Junio C Hamano
ea8681e3 103d7b12

+61 -3
+2 -2
Documentation/config/imap.adoc
··· 40 Specify the authentication method for authenticating with the IMAP server. 41 If Git was built with the NO_CURL option, or if your curl version is older 42 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 45 plaintext `LOGIN` command.
··· 40 Specify the authentication method for authenticating with the IMAP server. 41 If Git was built with the NO_CURL option, or if your curl version is older 42 than 7.34.0, or if you're running git-imap-send with the `--no-curl` 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 45 plaintext `LOGIN` command.
+59 -1
imap-send.c
··· 139 LITERALPLUS, 140 NAMESPACE, 141 STARTTLS, 142 AUTH_CRAM_MD5, 143 AUTH_OAUTHBEARER, 144 AUTH_XOAUTH2, ··· 150 "LITERAL+", 151 "NAMESPACE", 152 "STARTTLS", 153 "AUTH=CRAM-MD5", 154 "AUTH=OAUTHBEARER", 155 "AUTH=XOAUTH2", ··· 851 } 852 853 #define ENCODED_SIZE(n) (4 * DIV_ROUND_UP((n), 3)) 854 static char *cram(const char *challenge_64, const char *user, const char *pass) 855 { 856 int i, resp_len, encoded_len, decoded_len; ··· 947 return b64; 948 } 949 950 static int auth_cram_md5(struct imap_store *ctx, const char *prompt) 951 { 952 int ret; ··· 1007 1008 #else 1009 1010 #define auth_cram_md5 NULL 1011 #define auth_oauthbearer NULL 1012 #define auth_xoauth2 NULL ··· 1219 server_fill_credential(srvc, &cred); 1220 1221 if (srvc->auth_method) { 1222 - if (!strcmp(srvc->auth_method, "CRAM-MD5")) { 1223 if (try_auth_method(srvc, ctx, imap, "CRAM-MD5", AUTH_CRAM_MD5, auth_cram_md5)) 1224 goto bail; 1225 } else if (!strcmp(srvc->auth_method, "OAUTHBEARER")) {
··· 139 LITERALPLUS, 140 NAMESPACE, 141 STARTTLS, 142 + AUTH_PLAIN, 143 AUTH_CRAM_MD5, 144 AUTH_OAUTHBEARER, 145 AUTH_XOAUTH2, ··· 151 "LITERAL+", 152 "NAMESPACE", 153 "STARTTLS", 154 + "AUTH=PLAIN", 155 "AUTH=CRAM-MD5", 156 "AUTH=OAUTHBEARER", 157 "AUTH=XOAUTH2", ··· 853 } 854 855 #define ENCODED_SIZE(n) (4 * DIV_ROUND_UP((n), 3)) 856 + static char *plain_base64(const char *user, const char *pass) 857 + { 858 + struct strbuf raw = STRBUF_INIT; 859 + int b64_len; 860 + char *b64; 861 + 862 + /* 863 + * Compose the PLAIN string 864 + * 865 + * The username and password are combined to one string and base64 encoded. 866 + * "\0user\0pass" 867 + * 868 + * The method has been described in RFC4616. 869 + * 870 + * https://datatracker.ietf.org/doc/html/rfc4616 871 + */ 872 + strbuf_addch(&raw, '\0'); 873 + strbuf_addstr(&raw, user); 874 + strbuf_addch(&raw, '\0'); 875 + strbuf_addstr(&raw, pass); 876 + 877 + b64 = xmallocz(ENCODED_SIZE(raw.len)); 878 + b64_len = EVP_EncodeBlock((unsigned char *)b64, (unsigned char *)raw.buf, raw.len); 879 + strbuf_release(&raw); 880 + 881 + if (b64_len < 0) { 882 + free(b64); 883 + return NULL; 884 + } 885 + return b64; 886 + } 887 + 888 static char *cram(const char *challenge_64, const char *user, const char *pass) 889 { 890 int i, resp_len, encoded_len, decoded_len; ··· 981 return b64; 982 } 983 984 + static int auth_plain(struct imap_store *ctx, const char *prompt UNUSED) 985 + { 986 + int ret; 987 + char *b64; 988 + 989 + b64 = plain_base64(ctx->cfg->user, ctx->cfg->pass); 990 + if (!b64) 991 + return error("PLAIN: base64 encoding failed"); 992 + 993 + /* Send the base64-encoded response */ 994 + ret = socket_write(&ctx->imap->buf.sock, b64, strlen(b64)); 995 + if (ret != (int)strlen(b64)) { 996 + free(b64); 997 + return error("IMAP error: sending PLAIN response failed"); 998 + } 999 + 1000 + free(b64); 1001 + return 0; 1002 + } 1003 + 1004 static int auth_cram_md5(struct imap_store *ctx, const char *prompt) 1005 { 1006 int ret; ··· 1061 1062 #else 1063 1064 + #define auth_plain NULL 1065 #define auth_cram_md5 NULL 1066 #define auth_oauthbearer NULL 1067 #define auth_xoauth2 NULL ··· 1274 server_fill_credential(srvc, &cred); 1275 1276 if (srvc->auth_method) { 1277 + if (!strcmp(srvc->auth_method, "PLAIN")) { 1278 + if (try_auth_method(srvc, ctx, imap, "PLAIN", AUTH_PLAIN, auth_plain)) 1279 + goto bail; 1280 + } else if (!strcmp(srvc->auth_method, "CRAM-MD5")) { 1281 if (try_auth_method(srvc, ctx, imap, "CRAM-MD5", AUTH_CRAM_MD5, auth_cram_md5)) 1282 goto bail; 1283 } else if (!strcmp(srvc->auth_method, "OAUTHBEARER")) {