summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEduardo Chappa <chappa@washington.edu>2021-04-04 17:09:46 -0600
committerEduardo Chappa <chappa@washington.edu>2021-04-04 17:09:46 -0600
commit20a011de7f4e60e2dc1498a37c8829fdc207902b (patch)
treee7a4610649c95b7b3275eecf9f1773bf30b96d37
parentb3c7debd83bacac7b076381f8ad4f731391004df (diff)
downloadalpine-20a011de7f4e60e2dc1498a37c8829fdc207902b.tar.xz
* 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.
-rwxr-xr-xalpine/alpine.exebin8858112 -> 8863744 bytes
-rw-r--r--alpine/imap.c255
-rw-r--r--pith/pine.hlp4
3 files changed, 180 insertions, 79 deletions
diff --git a/alpine/alpine.exe b/alpine/alpine.exe
index 0ec0744..fc6c110 100755
--- a/alpine/alpine.exe
+++ b/alpine/alpine.exe
Binary files differ
diff --git a/alpine/imap.c b/alpine/imap.c
index 1d05ac3..6e6ea8c 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 <wincred.h>
#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_<hostname:port>\tuser\taltflag
+ * UWash_Alpine_.partnumber-totalparts_<hostname:port>\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 **) &ltarget);
+ 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)&part;
+ cred.Persist = CRED_PERSIST_ENTERPRISE;
+ g_CredWriteW(&cred, 0);
+ fs_give((void**)&ltarget);
+ }
}
}
#endif /* WINCRED > 0 */
diff --git a/pith/pine.hlp b/pith/pine.hlp
index 06275ed..cb5b846 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.
+<LI> 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.
</UL>
<P>