From c024a78dbaa9b42db7f18b0fea1894c41e2b0d67 Mon Sep 17 00:00:00 2001 From: Eduardo Chappa Date: Sat, 4 May 2019 12:41:11 -0600 Subject: * Initial release of XOAUTH2 authentication support in Alpine for Gmail. --- pith/imap.c | 101 ++++++++++++++++++++++++++++++++--------- pith/imap.h | 14 ++++-- pith/ldap.c | 6 ++- pith/pine.hlp | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- pith/string.c | 18 ++++++-- pith/string.h | 1 + 6 files changed, 253 insertions(+), 29 deletions(-) (limited to 'pith') diff --git a/pith/imap.c b/pith/imap.c index 5d9a789c..f9e5162f 100644 --- a/pith/imap.c +++ b/pith/imap.c @@ -855,11 +855,17 @@ imap_seq_exec_append(MAILSTREAM *stream, long int msgno, void *args) Result: username and password passed back to imap ----*/ void -mm_login(NETMBX *mb, char *user, char *pwd, long int trial) +mm_login(NETMBX *mb, char *user, char **pwd, long int trial) { mm_login_work(mb, user, pwd, trial, NULL, NULL); } +void +mm_login_method(NETMBX *mb, char *user, void *login, long int trial, char *method) +{ + mm_login_method_work(mb, user, login, trial, method, NULL, NULL); +} + /*---------------------------------------------------------------------- Exported method to retrieve logged in user name associated with stream @@ -887,12 +893,36 @@ cached_user_name(char *host) int imap_same_host(STRLIST_S *hl1, STRLIST_S *hl2) +{ + return imap_same_host_auth(hl1, hl2, NULL); +} + +/* An explanation about this function. The way this is used in the + * new code for XOAUTH2, makes it so that when we are checking if + * the hosts and orighosts are the same, we are given the mb->host + * and mb->orighost pointers, and we cannot transform them in any + * way to be sure that increasing their size will not overflow the + * fixed width buffer that contain them, so we cannot change that. + * For purposes of this function, these values come in the hl2 variable. + * However, for purposes of this function, the values in hl1 are the ones + * that come straight from the cache, and here no transformation is made, + * that is, we save them as we read them, so when we compare the values + * read from the cache, with those that we want to save, we need to make + * sure we "shift" the hl1 variable, but not the hl2 variable. + */ +int +imap_same_host_auth(STRLIST_S *hl1, STRLIST_S *hl2, char *authtype) { STRLIST_S *lp; + size_t len, offset; + len = authtype ? strlen(authtype) : 0; + offset = authtype ? 1 : 0; for( ; hl1; hl1 = hl1->next) for(lp = hl2; lp; lp = lp->next) - if(!strucmp(hl1->name, lp->name)) + if((len == 0 || (!struncmp(hl1->name, authtype, len) + && hl1->name[len] == PWDAUTHSEP)) + && !strucmp(hl1->name + len + offset, lp->name)) return(TRUE); return(FALSE); @@ -949,9 +979,16 @@ imap_get_user(MMLOGIN_S *m_list, STRLIST_S *hostlist) * attempt to login with the password from the cache. */ int -imap_get_passwd(MMLOGIN_S *m_list, char *passwd, char *user, STRLIST_S *hostlist, int altflag) +imap_get_passwd(MMLOGIN_S *m_list, char **passwd, char *user, STRLIST_S *hostlist, int altflag) +{ + return imap_get_passwd_auth(m_list, passwd, user, hostlist, altflag, NULL); +} + +int +imap_get_passwd_auth(MMLOGIN_S *m_list, char **passwd, char *user, STRLIST_S *hostlist, int altflag, char *authtype) { MMLOGIN_S *l; + int len, offset; dprint((9, "imap_get_passwd: checking user=%s alt=%d host=%s%s%s\n", @@ -961,18 +998,22 @@ imap_get_passwd(MMLOGIN_S *m_list, char *passwd, char *user, STRLIST_S *hostlist (hostlist->next && hostlist->next->name) ? ", " : "", (hostlist->next && hostlist->next->name) ? hostlist->next->name : "")); + len = authtype ? strlen(authtype) : 0; + offset = authtype ? 1 : 0; for(l = m_list; l; l = l->next) - if(imap_same_host(l->hosts, hostlist) + if(imap_same_host_auth(l->hosts, hostlist, authtype) && *user - && !strcmp(user, l->user) + && (len == 0 || (!struncmp(l->user, authtype, len) + && l->user[len] == PWDAUTHSEP)) + && !strcmp(user, l->user + len + offset) && l->altflag == altflag){ if(passwd){ - strncpy(passwd, l->passwd, NETMAXPASSWD); - passwd[NETMAXPASSWD-1] = '\0'; + fs_resize((void **) passwd, strlen(l->passwd + len + offset) + 1); + strcpy(*passwd, l->passwd + len + offset); } dprint((9, "imap_get_passwd: match\n")); dprint((10, "imap_get_passwd: trying passwd=\"%s\"\n", - passwd ? passwd : "?")); + passwd && *passwd ? *passwd : "?")); return(TRUE); } @@ -985,16 +1026,29 @@ imap_get_passwd(MMLOGIN_S *m_list, char *passwd, char *user, STRLIST_S *hostlist void imap_set_passwd(MMLOGIN_S **l, char *passwd, char *user, STRLIST_S *hostlist, int altflag, int ok_novalidate, int warned) +{ + imap_set_passwd_auth(l, passwd, user, hostlist, altflag, ok_novalidate, + warned, NULL); +} + +void +imap_set_passwd_auth(MMLOGIN_S **l, char *passwd, char *user, STRLIST_S *hostlist, + int altflag, int ok_novalidate, int warned, char *authtype) { STRLIST_S **listp; size_t len; + size_t authlen, offset; + authlen = authtype ? strlen(authtype) : 0; + offset = authtype ? 1 : 0; dprint((9, "imap_set_passwd\n")); for(; *l; l = &(*l)->next) - if(imap_same_host((*l)->hosts, hostlist) - && !strcmp(user, (*l)->user) + if((authlen == 0 || (!struncmp((*l)->user, authtype, authlen) + && (*l)->user[authlen] == PWDAUTHSEP)) + && !strcmp(user, (*l)->user + authlen + offset) + && imap_same_host_auth((*l)->hosts, hostlist, authtype) && altflag == (*l)->altflag){ - if(strcmp(passwd, (*l)->passwd) || + if(strcmp(passwd, (*l)->passwd + authlen + offset) || (*l)->ok_novalidate != ok_novalidate || (*l)->warned != warned) break; @@ -1008,17 +1062,24 @@ imap_set_passwd(MMLOGIN_S **l, char *passwd, char *user, STRLIST_S *hostlist, } len = strlen(passwd); - if(!(*l)->passwd || strlen((*l)->passwd) < len) - (*l)->passwd = ps_get(len+1); + if(!(*l)->passwd || strlen((*l)->passwd) < len + authlen + offset) + (*l)->passwd = ps_get(len + authlen + offset + 1); - strncpy((*l)->passwd, passwd, len+1); + if(authtype) + sprintf((*l)->passwd, "%s%c%s", authtype, PWDAUTHSEP, passwd); + else + strncpy((*l)->passwd, passwd, len+1); - (*l)->altflag = altflag; - (*l)->ok_novalidate = ok_novalidate; - (*l)->warned = warned; + (*l)->altflag = altflag; (*l)->ok_novalidate = ok_novalidate; (*l)->warned = warned; - if(!(*l)->user) - (*l)->user = cpystr(user); + if(!(*l)->user){ + if(authlen > 0){ + (*l)->user = fs_get(strlen(user) + authlen + offset + 1); + sprintf((*l)->user, "%s%c%s", authtype, PWDAUTHSEP, user); + } + else + (*l)->user = cpystr(user); + } dprint((9, "imap_set_passwd: user=%s altflag=%d\n", (*l)->user ? (*l)->user : "?", @@ -1031,7 +1092,7 @@ imap_set_passwd(MMLOGIN_S **l, char *passwd, char *user, STRLIST_S *hostlist, ; if(!*listp){ - *listp = new_strlist(hostlist->name); + *listp = new_strlist_auth(hostlist->name, authtype, PWDAUTHSEP); dprint((9, "imap_set_passwd: host=%s\n", (*listp)->name ? (*listp)->name : "?")); } diff --git a/pith/imap.h b/pith/imap.h index d58f4e3c..9ed70621 100644 --- a/pith/imap.h +++ b/pith/imap.h @@ -21,7 +21,9 @@ #include "../pith/string.h" -#define NETMAXPASSWD 100 +#define NETMAXPASSWD 512 /* increased from 100 due to token lengths. + * must be less than MAILTMPLEN + */ /* @@ -69,6 +71,8 @@ typedef struct mm_list_s { #define URL_IMAP_IMBXLSTLSUB 0x0010 #define URL_IMAP_ISERVERONLY 0x0020 +/* Marker for Separator of Authentication Method */ +#define PWDAUTHSEP '\001' /* * Exported globals setup by searching functions to tell mm_searched @@ -119,10 +123,13 @@ char *imap_referral(MAILSTREAM *, char *, long); long imap_proxycopy(MAILSTREAM *, char *, char *, long); char *cached_user_name(char *); int imap_same_host(STRLIST_S *, STRLIST_S *); +int imap_same_host_auth(STRLIST_S *, STRLIST_S *, char *); int imap_get_ssl(MMLOGIN_S *, STRLIST_S *, int *, int *); char *imap_get_user(MMLOGIN_S *, STRLIST_S *); -int imap_get_passwd(MMLOGIN_S *, char *, char *, STRLIST_S *, int); +int imap_get_passwd(MMLOGIN_S *, char **, char *, STRLIST_S *, int); +int imap_get_passwd_auth (MMLOGIN_S *, char **, char *, STRLIST_S *, int, char *); void imap_set_passwd(MMLOGIN_S **, char *, char *, STRLIST_S *, int, int, int); +void imap_set_passwd_auth(MMLOGIN_S **, char *, char *, STRLIST_S *, int, int, int, char *); void imap_flush_passwd_cache(int); @@ -130,7 +137,8 @@ void imap_flush_passwd_cache(int); /* called by build_folder_list(), ok if it does nothing */ void set_read_predicted(int); -void mm_login_work (NETMBX *mb,char *user,char *pwd,long trial,char *usethisprompt, char *altuserforcache); +void mm_login_work (NETMBX *mb,char *user,char **pwd,long trial,char *usethisprompt, char *altuserforcache); +void mm_login_method_work (NETMBX *mb,char *user,void *login,long trial, char *method, char *usethisprompt, char *altuserforcache); /* this is necessary to figure out the name of the password file of the application. */ #ifdef PASSFILE diff --git a/pith/ldap.c b/pith/ldap.c index acf592db..f56592d2 100644 --- a/pith/ldap.c +++ b/pith/ldap.c @@ -556,7 +556,7 @@ ldap_lookup(LDAP_SERV_S *info, char *string, CUSTOM_FILT_S *cust, } else if(!ps_global->intr_pending){ int proto = 3, tlsmustbail = 0; - char pwd[NETMAXPASSWD], user[NETMAXUSER]; + char *pwd = NULL, user[NETMAXUSER]; #ifdef _WINDOWS char *passwd = NULL; #else @@ -634,7 +634,7 @@ try_password_again: if(!tlsmustbail){ snprintf(pmt, sizeof(pmt), " %s", (info->nick && *info->nick) ? info->nick : serv); - mm_login_work(&mb, user, pwd, pwdtrial, pmt, info->binddn); + mm_login_work(&mb, user, &pwd, pwdtrial, pmt, info->binddn); if(pwd && pwd[0]) #ifdef _WINDOWS passwd = pwd; @@ -1172,6 +1172,8 @@ try_password_again: } } } + if(pwd) + fs_give((void **) &pwd); } if(we_cancel) diff --git a/pith/pine.hlp b/pith/pine.hlp index 16efc9c2..af37f7ab 100644 --- a/pith/pine.hlp +++ b/pith/pine.hlp @@ -140,7 +140,7 @@ with help text for the config screen and the composer that didn't have any reasonable place to be called from. Dummy change to get revision in pine.hlp ============= h_revision ================= -Alpine Commit 335 2019-04-28 16:01:07 +Alpine Commit 336 2019-05-04 12:40:47 ============= h_news ================= @@ -180,6 +180,8 @@ addresses bugs found in previous releases and has a few additions as well. Additions include: