From 20a011de7f4e60e2dc1498a37c8829fdc207902b Mon Sep 17 00:00:00 2001 From: Eduardo Chappa Date: Sun, 4 Apr 2021 17:09:46 -0600 Subject: * PC-Alpine only: Some service providers produce access tokens that are too long to save them in the Windows Credentials, so they will be saved as several broken pieces, which means that old versions od Alpine will NOT be able to use saved passwords, once this version of Alpine is used. --- alpine/alpine.exe | Bin 8858112 -> 8863744 bytes alpine/imap.c | 255 +++++++++++++++++++++++++++++++++++++----------------- pith/pine.hlp | 4 + 3 files changed, 180 insertions(+), 79 deletions(-) diff --git a/alpine/alpine.exe b/alpine/alpine.exe index 0ec07449..fc6c110f 100755 Binary files a/alpine/alpine.exe and b/alpine/alpine.exe differ diff --git a/alpine/imap.c b/alpine/imap.c index 1d05ac3e..6e6ea8cb 100644 --- a/alpine/imap.c +++ b/alpine/imap.c @@ -59,6 +59,8 @@ static char rcsid[] = "$Id: imap.c 1266 2009-07-14 18:39:12Z hubert@u.washington #include #define TNAME "UWash_Alpine_" #define TNAMESTAR "UWash_Alpine_*" +#define PWDBUFFERSIZE (250) +#define MAXPWDBUFFERSIZE (2*PWDBUFFERSIZE) /* This number must be less than 512 */ /* * WinCred Function prototypes @@ -3216,6 +3218,20 @@ line_get(char *tmp, size_t len, char **textp) return 1; } + +typedef struct pwd_s { + char *blob; + char **blobarray; + char *host; + char *user; + char *sflags; + char *passwd; + char *orighost; +} ALPINE_PWD_S; + +#define SAME_VALUE(X, Y) ((((X) == NULL && (Y) == NULL) \ + || ((X) && (Y) && !strcmp((X), (Y)))) ? 1 : 0) + /* * For UNIX: * Passfile lines are @@ -3227,7 +3243,7 @@ line_get(char *tmp, size_t len, char **textp) * * else for WINDOWS: * Use Windows credentials. The TargetName of the credential is - * UWash_Alpine_\tuser\taltflag + * UWash_Alpine_.partnumber-totalparts_\tuser\taltflag * and the blob consists of * passwd\torighost (if different from host) * @@ -3247,15 +3263,16 @@ read_passfile(pinerc, l) DWORD count, k; PCREDENTIAL *pcred; char *tmp, *blob, *target = NULL; - char *host, *user, *sflags, *passwd, *orighost; + ALPINE_PWD_S **pwd; char *ui[5]; int i, j; + unsigned long m, n, p, loc; if(using_passfile == 0) return(using_passfile); if(!g_CredInited){ - if(init_wincred_funcs() != 1){ + if (init_wincred_funcs() != 1) { using_passfile = 0; return(using_passfile); } @@ -3265,72 +3282,139 @@ read_passfile(pinerc, l) using_passfile = 1; - if(g_CredEnumerateW(lfilter, 0, &count, &pcred)){ - if(pcred){ - for(k = 0; k < count; k++){ - - host = user = sflags = passwd = orighost = NULL; - ui[0] = ui[1] = ui[2] = ui[3] = ui[4] = NULL; - + /* this code exists because the XOAUTH2 support makes us save + * access tokens as if they were passwords. However, some servers + * produce extremely long access-tokens that do not fit in the credentials + * and therefore need to be split into several entries. + * + * The plan is the following: + * step 1: Read and save all the information in the credentials + * step 2: flatten the information into one line + * step 3: process that line. + */ + if (g_CredEnumerateW(lfilter, 0, &count, &pcred)) { + pwd = fs_get((count + 1)*sizeof(ALPINE_PWD_S *)); + memset((void *)pwd, 0, (count + 1)*sizeof(ALPINE_PWD_S *)); + if (pwd && pcred) { + /* this is step 1 */ + for (k = 0; k < count; k++) { /* go through each credential */ target = lptstr_to_utf8(pcred[k]->TargetName); tmp = srchstr(target, TNAME); - - if(tmp){ + if (tmp) { tmp += strlen(TNAME); - for(i = 0, j = 0; tmp[i] && j < 3; j++){ - for(ui[j] = &tmp[i]; tmp[i] && tmp[i] != '\t'; i++) - ; /* find end of data */ - - if(tmp[i]) - tmp[i++] = '\0'; /* tie off data */ + if (*tmp == '.') { + tmp++; + m = strtoul(tmp, &tmp, 10); + if (*tmp == '-') { + tmp++; + n = strtol(tmp, &tmp, 10); + if (*tmp == '_') tmp++; + } + } + else { + m = n = 1; } - host = ui[0]; - user = ui[1]; - sflags = ui[2]; - } + ui[0] = ui[1] = ui[2] = ui[3] = ui[4] = NULL; + for (i = 0, j = 0; tmp[i] && j < 3; j++) { + for (ui[j] = &tmp[i]; tmp[i] && tmp[i] != '\t'; i++) + ; /* find end of data */ - blob = (char *) pcred[k]->CredentialBlob; - if(blob){ - for(i = 0, j = 3; blob[i] && j < 5; j++){ - for(ui[j] = &blob[i]; blob[i] && blob[i] != '\t'; i++) - ; /* find end of data */ + if (tmp[i]) + tmp[i++] = '\0'; /* tie off data */ + } - if(blob[i]) - blob[i++] = '\0'; /* tie off data */ + /* improve this. We are trying to find where we saved + * this data, and in general this is fast if there is + * only a few data, which is not unreasonable, but probably + * can be done better. + */ + for (loc = 0; pwd[loc] + && !(SAME_VALUE(ui[0], pwd[loc]->host) + && SAME_VALUE(ui[1], pwd[loc]->user) + && SAME_VALUE(ui[2], pwd[loc]->sflags)); loc++); + + if (pwd[loc] == NULL) { + pwd[loc] = fs_get(sizeof(ALPINE_PWD_S)); + memset((void *) pwd[loc], 0, sizeof(ALPINE_PWD_S)); + pwd[loc]->blobarray = fs_get((n + 1) * sizeof(char*)); + memset((void *) pwd[loc]->blobarray, 0, (n + 1) * sizeof(char*)); } - passwd = ui[3]; - orighost = ui[4]; + if (pwd[loc]->host == NULL) + pwd[loc]->host = ui[0] ? cpystr(ui[0]) : NULL; + if (pwd[loc]->user == NULL) + pwd[loc]->user = ui[1] ? cpystr(ui[1]) : NULL; + if (pwd[loc]->sflags == NULL) + pwd[loc]->sflags = ui[2] ? cpystr(ui[2]) : NULL; + blob = (char *) pcred[k]->CredentialBlob; + pwd[loc]->blobarray[m - 1] = blob ? cpystr(blob) : NULL; } - - if(passwd && host && user){ /* valid field? */ + if (target) fs_give((void**)&target); + } + /* step 2 */ + for (k = 0; k < count; k++) { + if (pwd[k]) { + for (i = 0, j = 0; pwd[k]->blobarray[j]; j++) + i += strlen(pwd[k]->blobarray[j]); + pwd[k]->blob = fs_get(i + 1); + pwd[k]->blob[0] = '\0'; + for (j = 0; pwd[k]->blobarray[j]; j++) { + strcat(pwd[k]->blob, pwd[k]->blobarray[j]); + fs_give((void **) &pwd[k]->blobarray[j]); + } + fs_give((void **) pwd[k]->blobarray); + } + else k = count; /* we are done with this step! */ + } + /* step 3 */ + for (k = 0; k < count; k++) { + if (pwd[k] && pwd[k]->blob) { + blob = pwd[k]->blob; + for (i = 0, j = 3; blob[i] && j < 5; j++) { + for (ui[j] = &blob[i]; blob[i] && blob[i] != '\t'; i++) + ; /* find end of data */ + + if (blob[i]) + blob[i++] = '\0'; /* tie off data */ + } + if (pwd[k]->passwd == NULL) + pwd[k]->passwd = ui[3] ? cpystr(ui[3]) : NULL; + if (pwd[k]->orighost == NULL) + pwd[k]->orighost = ui[4] ? cpystr(ui[4]) : NULL; + fs_give((void **) &pwd[k]->blob); + } + } + /* now process all lines, and free memory */ + for (k = 0; k < count && pwd[k] != NULL; k++){ + if (pwd[k]->passwd && pwd[k]->host && pwd[k]->user) { /* valid field? */ STRLIST_S hostlist[2]; int flags; - tmp = sflags ? strchr(sflags, PWDAUTHSEP) : NULL; - flags = sflags ? atoi(tmp ? ++tmp : sflags) : 0; - hostlist[0].name = host; - if(orighost){ + tmp = pwd[k]->sflags ? strchr(pwd[k]->sflags, PWDAUTHSEP) : NULL; + flags = pwd[k]->sflags ? atoi(tmp ? ++tmp : pwd[k]->sflags) : 0; + hostlist[0].name = pwd[k]->host; + if (pwd[k]->orighost) { hostlist[0].next = &hostlist[1]; - hostlist[1].name = orighost; + hostlist[1].name = pwd[k]->orighost; hostlist[1].next = NULL; } - else{ + else { hostlist[0].next = NULL; } - - imap_set_passwd(l, passwd, user, hostlist, flags & 0x01, 0, 0); + imap_set_passwd(l, pwd[k]->passwd, pwd[k]->user, hostlist, flags & 0x01, 0, 0); } - - if(target) - fs_give((void **) &target); + if (pwd[k]->passwd) fs_give((void **) &pwd[k]->passwd); + if (pwd[k]->user) fs_give((void **) &pwd[k]->user); + if (pwd[k]->host) fs_give((void **) &pwd[k]->host); + if (pwd[k]->sflags) fs_give((void **) &pwd[k]->sflags); + if (pwd[k]->orighost) fs_give((void **) &pwd[k]->orighost); + fs_give((void **) &pwd[k]); } - - g_CredFree((PVOID) pcred); + g_CredFree((PVOID)pcred); } - } - + fs_give((void **) pwd); + } return(1); # else /* old windows */ @@ -3693,8 +3777,10 @@ write_passfile(pinerc, l) char *authend, *authtype; #ifdef WINCRED # if (WINCRED > 0) + int i, j, k; char target[10*MAILTMPLEN]; - char blob[10*MAILTMPLEN]; + char blob[10 * MAILTMPLEN], blob2[10*MAILTMPLEN], *blobp; + char part[MAILTMPLEN]; CREDENTIAL cred; LPTSTR ltarget = 0; @@ -3704,40 +3790,51 @@ write_passfile(pinerc, l) dprint((9, "write_passfile\n")); for(; l; l = l->next){ + /* determine how many parts to create first */ + snprintf(blob, sizeof(blob), "%s%s%s", + l->passwd ? l->passwd : "", + (l->hosts&& l->hosts->next&& l->hosts->next->name) + ? "\t" : "", + (l->hosts&& l->hosts->next&& l->hosts->next->name) + ? l->hosts->next->name : ""); + i = strlen(blob); + blobp = blob; + for (j = 1; i > MAXPWDBUFFERSIZE; j++, i -= PWDBUFFERSIZE); authtype = l->passwd; authend = strchr(l->passwd, PWDAUTHSEP); - if(authend != NULL){ - *authend = '\0'; - sprintf(blob, "%s%c%d", authtype, PWDAUTHSEP, l->altflag); - *authend = PWDAUTHSEP; + if (authend != NULL){ + *authend = '\0'; + sprintf(blob2, "%s%c%d", authtype, PWDAUTHSEP, l->altflag); + *authend = PWDAUTHSEP; } else - sprintf(blob, "%d", l->altflag); - - snprintf(target, sizeof(target), "%s%s\t%s\t%s", - TNAME, - (l->hosts && l->hosts->name) ? l->hosts->name : "", - l->user ? l->user : "", - blob); - ltarget = utf8_to_lptstr((LPSTR) target); - - if(ltarget){ - snprintf(blob, sizeof(blob), "%s%s%s", - l->passwd ? l->passwd : "", - (l->hosts && l->hosts->next && l->hosts->next->name) - ? "\t" : "", - (l->hosts && l->hosts->next && l->hosts->next->name) - ? l->hosts->next->name : ""); - memset((void *) &cred, 0, sizeof(cred)); - cred.Flags = 0; - cred.Type = CRED_TYPE_GENERIC; - cred.TargetName = ltarget; - cred.CredentialBlobSize = strlen(blob)+1; - cred.CredentialBlob = (LPBYTE) &blob; - cred.Persist = CRED_PERSIST_ENTERPRISE; - g_CredWriteW(&cred, 0); - - fs_give((void **) <arget); + sprintf(blob2, "%d", l->altflag); + for (k = 1, i = strlen(blob), blobp = blob; k <= j; k++) { + snprintf(target, sizeof(target), "%s.%d-%d_%s\t%s\t%s", + TNAME, k, j, + (l->hosts && l->hosts->name) ? l->hosts->name : "", + l->user ? l->user : "", + blob2); + ltarget = utf8_to_lptstr((LPSTR)target); + if (ltarget) { + memset((void*)&cred, 0, sizeof(cred)); + cred.Flags = 0; + cred.Type = CRED_TYPE_GENERIC; + cred.TargetName = ltarget; + if (i > MAXPWDBUFFERSIZE) { + strncpy(part, blobp, PWDBUFFERSIZE); + part[PWDBUFFERSIZE] = '\0'; + blobp += PWDBUFFERSIZE; + i -= PWDBUFFERSIZE; + } + else + strcpy(part, blobp); + cred.CredentialBlobSize = strlen(part) + 1; + cred.CredentialBlob = (LPBYTE)∂ + cred.Persist = CRED_PERSIST_ENTERPRISE; + g_CredWriteW(&cred, 0); + fs_give((void**)<arget); + } } } #endif /* WINCRED > 0 */ diff --git a/pith/pine.hlp b/pith/pine.hlp index 06275ed6..cb5b8466 100644 --- a/pith/pine.hlp +++ b/pith/pine.hlp @@ -201,6 +201,10 @@ New features include: to login to outlook, since the original client-id can only be used for the device method. One needs a special client-id and client-secret to use the authorize method in Outlook. +
  • PC-Alpine only: Some service providers produce access tokens that are too long + to save them in the Windows Credentials, so they will be saved as several broken + pieces, which means that old versions od Alpine will NOT be able to use saved + passwords, once this version of Alpine is used.

    -- cgit v1.2.3-54-g00ecf