summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEduardo Chappa <chappa@washington.edu>2020-07-28 20:52:28 -0600
committerEduardo Chappa <chappa@washington.edu>2020-07-28 20:52:28 -0600
commit0d181b64d4d433a5ec88c4bfd55cd5a1d5f9a1da (patch)
tree981d63dd006c04c1b884d0b6cbbcd6a405593ae0
parent6591233b484d8f303b64f9042aee516d1b3a9cc6 (diff)
downloadalpine-0d181b64d4d433a5ec88c4bfd55cd5a1d5f9a1da.tar.xz
* XOAUTH2: automatic renew of access token and connection to a server
within 60 seconds of expiration of the access token.
-rw-r--r--alpine/imap.c2
-rw-r--r--imap/src/c-client/imap4r1.c26
-rw-r--r--imap/src/c-client/mail.c11
-rw-r--r--imap/src/c-client/mail.h8
-rw-r--r--imap/src/c-client/nntp.c3
-rw-r--r--imap/src/c-client/oauth2_aux.c45
-rw-r--r--imap/src/c-client/pop3.c3
-rw-r--r--imap/src/osdep/nt/dummynt.c3
-rw-r--r--imap/src/osdep/nt/mbxnt.c3
-rw-r--r--imap/src/osdep/nt/mtxnt.c3
-rw-r--r--imap/src/osdep/nt/tenexnt.c3
-rw-r--r--imap/src/osdep/nt/unixnt.c3
-rw-r--r--imap/src/osdep/unix/dummy.c3
-rw-r--r--imap/src/osdep/unix/mbx.c3
-rw-r--r--imap/src/osdep/unix/mh.c3
-rw-r--r--imap/src/osdep/unix/mix.c3
-rw-r--r--imap/src/osdep/unix/mmdf.c3
-rw-r--r--imap/src/osdep/unix/mtx.c3
-rw-r--r--imap/src/osdep/unix/mx.c3
-rw-r--r--imap/src/osdep/unix/news.c3
-rw-r--r--imap/src/osdep/unix/phile.c3
-rw-r--r--imap/src/osdep/unix/tenex.c3
-rw-r--r--imap/src/osdep/unix/unix.c3
-rw-r--r--pith/newmail.c25
-rw-r--r--pith/pine.hlp5
25 files changed, 154 insertions, 22 deletions
diff --git a/alpine/imap.c b/alpine/imap.c
index 49e4da0..7c518cf 100644
--- a/alpine/imap.c
+++ b/alpine/imap.c
@@ -888,7 +888,7 @@ mm_login_oauth2(NETMBX *mb, char *user, char *method,
ps_global->no_newmail_check_from_optionally_enter = 1;
/* make sure errors are seen */
- if(ps_global->ttyo)
+ if(ps_global->ttyo && !ps_global->noshow_error)
flush_status_messages(0);
token = NULL; /* start from scratch */
diff --git a/imap/src/c-client/imap4r1.c b/imap/src/c-client/imap4r1.c
index db3f119..7343122 100644
--- a/imap/src/c-client/imap4r1.c
+++ b/imap/src/c-client/imap4r1.c
@@ -170,6 +170,7 @@ long imap_delete (MAILSTREAM *stream,char *mailbox);
long imap_rename (MAILSTREAM *stream,char *old,char *newname);
long imap_manage (MAILSTREAM *stream,char *mailbox,char *command,char *arg2);
long imap_status (MAILSTREAM *stream,char *mbx,long flags);
+long imap_renew (MAILSTREAM *stream,MAILSTREAM *m);
MAILSTREAM *imap_open (MAILSTREAM *stream);
IMAPPARSEDREPLY *imap_rimap (MAILSTREAM *stream,char *service,NETMBX *mb,
char *usr,char *tmp);
@@ -316,7 +317,8 @@ DRIVER imapdriver = {
imap_expunge, /* expunge deleted messages */
imap_copy, /* copy messages to another mailbox */
imap_append, /* append string message to mailbox */
- imap_gc /* garbage collect stream */
+ imap_gc, /* garbage collect stream */
+ imap_renew /* renew stream */
};
/* prototype stream */
@@ -793,6 +795,22 @@ long imap_status (MAILSTREAM *stream,char *mbx,long flags)
return ret; /* success */
}
+/* IMAP renew
+ * Accepts: stream to renew
+ * returns 0 if success, 1 if failure
+ */
+long imap_renew (MAILSTREAM *stream, MAILSTREAM *m)
+{
+ IMAPLOCAL *MLOCAL = (IMAPLOCAL *) m->local;
+ NETSTREAM *xnetstream;
+
+ xnetstream = LOCAL->netstream;
+ LOCAL->netstream = MLOCAL->netstream;
+ MLOCAL->netstream = xnetstream;
+
+ return 0L;
+}
+
/* IMAP open
* Accepts: stream to open
* Returns: stream to use on success, NIL on failure
@@ -1210,7 +1228,11 @@ long imap_auth (MAILSTREAM *stream,NETMBX *mb,char *tmp,char *usr)
while (compare_cstring ((reply = imap_reply (stream,tag))->tag,tag))
imap_soutr (stream,"*");
/* good if SASL ok and success response */
- if (ok && imap_OK (stream,reply)) return T;
+ if (ok && imap_OK (stream,reply)){
+ if(stream->auth.name) fs_give((void **) &stream->auth.name);
+ stream->auth.name = cpystr(at->name); /* save method name */
+ return T;
+ }
if (!trial) { /* if main program requested cancellation */
mm_log ("IMAP Authentication cancelled",ERROR);
return NIL;
diff --git a/imap/src/c-client/mail.c b/imap/src/c-client/mail.c
index a9688d4..b52d062 100644
--- a/imap/src/c-client/mail.c
+++ b/imap/src/c-client/mail.c
@@ -1238,6 +1238,17 @@ long mail_status_default (MAILSTREAM *stream,char *mbx,long flags)
return T; /* success */
}
+/* Mail renew stream
+ * Accepts: stream to renew
+ * returns: 0 for success, 1 for failure
+ */
+long mail_renew_stream (MAILSTREAM *stream)
+{
+ MAILSTREAM *m = mail_open(NIL, stream->original_mailbox, OP_SILENT);
+ long rv = stream && m ? (stream->dtb->renew)(stream, m) : 1;
+ mail_close(m);
+ return rv;
+}
/* Mail open
* Accepts: candidate stream for recycling
* mailbox name
diff --git a/imap/src/c-client/mail.h b/imap/src/c-client/mail.h
index adcad4d..9a02c5f 100644
--- a/imap/src/c-client/mail.h
+++ b/imap/src/c-client/mail.h
@@ -1154,6 +1154,10 @@ typedef struct mail_stream {
void *local; /* pointer to driver local data */
char *mailbox; /* mailbox name (canonicalized) */
char *original_mailbox; /* mailbox name (non-canonicalized) */
+ struct {
+ char *name; /* AUTHENTICATE method */
+ unsigned long expiration; /* expiration time for authentication */
+ } auth;
unsigned short use; /* stream use count */
unsigned short sequence; /* stream sequence */
unsigned int inbox : 1; /* stream open on an INBOX */
@@ -1582,6 +1586,8 @@ DRIVER {
long (*append) (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
/* garbage collect stream */
void (*gc) (MAILSTREAM *stream,long gcflags);
+ /* renew stream */
+ long (*renew) (MAILSTREAM *stream, MAILSTREAM *m);
};
@@ -1706,6 +1712,7 @@ long mail_rename (MAILSTREAM *stream,char *old,char *newname);
char *mail_utf7_valid (char *mailbox);
long mail_status (MAILSTREAM *stream,char *mbx,long flags);
long mail_status_default (MAILSTREAM *stream,char *mbx,long flags);
+long mail_renew_stream (MAILSTREAM *stream);
MAILSTREAM *mail_open (MAILSTREAM *stream,char *name,long options);
MAILSTREAM *mail_open_work (DRIVER *d,MAILSTREAM *stream,char *name,
long options);
@@ -2011,3 +2018,4 @@ XOAUTH2_INFO_S *new_xoauth2_info(void);
void free_xoauth2_info(XOAUTH2_INFO_S **);
XOAUTH2_INFO_S *copy_xoauth2_info(XOAUTH2_INFO_S *);
char *oauth2_generate_state(void);
+void renew_accesstoken(MAILSTREAM *);
diff --git a/imap/src/c-client/nntp.c b/imap/src/c-client/nntp.c
index a46a5bd..b8d8989 100644
--- a/imap/src/c-client/nntp.c
+++ b/imap/src/c-client/nntp.c
@@ -202,7 +202,8 @@ DRIVER nntpdriver = {
nntp_expunge, /* expunge deleted messages */
nntp_copy, /* copy messages to another mailbox */
nntp_append, /* append string message to mailbox */
- NIL /* garbage collect stream */
+ NIL, /* garbage collect stream */
+ NIL /* renew stream */
};
/* prototype stream */
diff --git a/imap/src/c-client/oauth2_aux.c b/imap/src/c-client/oauth2_aux.c
index 24827e7..6fab291 100644
--- a/imap/src/c-client/oauth2_aux.c
+++ b/imap/src/c-client/oauth2_aux.c
@@ -405,3 +405,48 @@ XOAUTH2_INFO_S *copy_xoauth2_info(XOAUTH2_INFO_S *x)
if(x->users) y->users = cpystr(x->users);
return y;
}
+
+/* This function does not create a refresh token and and
+ * an access token, but uses an already known refresh token
+ * to generate a refresh token on an ALREADY OPEN stream.
+ * The assumption is that the user has already unlocked all
+ * passwords and the app can access them from some source
+ * (key chain/credentials/memory) to go through this
+ * process seamlessly.
+ */
+void renew_accesstoken(MAILSTREAM *stream)
+{
+ OAUTH2_S oauth2;
+ NETMBX mb;
+ char user[MAILTMPLEN];
+ int tryanother;
+ unsigned long trial = 0;
+
+ memset((void *) &oauth2, 0, sizeof(OAUTH2_S));
+ mail_valid_net_parse(stream->original_mailbox, &mb);
+ user[0] = '\0';
+ mm_login_method (&mb, user, (void *) &oauth2, trial, stream->auth.name);
+
+ if(oauth2.param[OA2_State].value)
+ fs_give((void **) &oauth2.param[OA2_State].value);
+
+ if(stream->auth.expiration == 0){
+ stream->auth.expiration = oauth2.expiration;
+ return;
+ }
+
+ if(oauth2.access_token)
+ fs_give((void **) &oauth2.access_token);
+
+ oauth2.param[OA2_State].value = oauth2_generate_state();
+
+ mm_login_oauth2_c_client_method (&mb, user, stream->auth.name, &oauth2, trial, &tryanother);
+
+ if(oauth2.access_token)
+ mm_login_method (&mb, user, (void *) &oauth2, trial, stream->auth.name);
+
+ stream->auth.expiration = oauth2.expiration;
+ if(oauth2.param[OA2_Id].value) fs_give((void **) &oauth2.param[OA2_Id].value);
+ if(oauth2.param[OA2_Secret].value) fs_give((void **) &oauth2.param[OA2_Secret].value);
+ if(oauth2.param[OA2_Tenant].value) fs_give((void **) &oauth2.param[OA2_Tenant].value);
+}
diff --git a/imap/src/c-client/pop3.c b/imap/src/c-client/pop3.c
index b5b5148..d91b3cc 100644
--- a/imap/src/c-client/pop3.c
+++ b/imap/src/c-client/pop3.c
@@ -154,7 +154,8 @@ DRIVER pop3driver = {
pop3_expunge, /* expunge deleted messages */
pop3_copy, /* copy messages to another mailbox */
pop3_append, /* append string message to mailbox */
- NIL /* garbage collect stream */
+ NIL, /* garbage collect stream */
+ NIL /* renew stream */
};
/* prototype stream */
diff --git a/imap/src/osdep/nt/dummynt.c b/imap/src/osdep/nt/dummynt.c
index 09a72f7..7654313 100644
--- a/imap/src/osdep/nt/dummynt.c
+++ b/imap/src/osdep/nt/dummynt.c
@@ -94,7 +94,8 @@ DRIVER dummydriver = {
dummy_expunge, /* expunge deleted messages */
dummy_copy, /* copy messages to another mailbox */
dummy_append, /* append string message to mailbox */
- NIL /* garbage collect stream */
+ NIL, /* garbage collect stream */
+ NIL /* renew stream */
};
diff --git a/imap/src/osdep/nt/mbxnt.c b/imap/src/osdep/nt/mbxnt.c
index 5ea3b57..f35bfa6 100644
--- a/imap/src/osdep/nt/mbxnt.c
+++ b/imap/src/osdep/nt/mbxnt.c
@@ -157,7 +157,8 @@ DRIVER mbxdriver = {
mbx_expunge, /* expunge deleted messages */
mbx_copy, /* copy messages to another mailbox */
mbx_append, /* append string message to mailbox */
- NIL /* garbage collect stream */
+ NIL, /* garbage collect stream */
+ NIL /* renew stream */
};
/* prototype stream */
diff --git a/imap/src/osdep/nt/mtxnt.c b/imap/src/osdep/nt/mtxnt.c
index 0ca88fb..fa80afd 100644
--- a/imap/src/osdep/nt/mtxnt.c
+++ b/imap/src/osdep/nt/mtxnt.c
@@ -144,7 +144,8 @@ DRIVER mtxdriver = {
mtx_expunge, /* expunge deleted messages */
mtx_copy, /* copy messages to another mailbox */
mtx_append, /* append string message to mailbox */
- NIL /* garbage collect stream */
+ NIL, /* garbage collect stream */
+ NIL /* renew stream */
};
/* prototype stream */
diff --git a/imap/src/osdep/nt/tenexnt.c b/imap/src/osdep/nt/tenexnt.c
index 4c1d0a3..054ce73 100644
--- a/imap/src/osdep/nt/tenexnt.c
+++ b/imap/src/osdep/nt/tenexnt.c
@@ -152,7 +152,8 @@ DRIVER tenexdriver = {
tenex_expunge, /* expunge deleted messages */
tenex_copy, /* copy messages to another mailbox */
tenex_append, /* append string message to mailbox */
- NIL /* garbage collect stream */
+ NIL, /* garbage collect stream */
+ NIL /* renew stream */
};
/* prototype stream */
diff --git a/imap/src/osdep/nt/unixnt.c b/imap/src/osdep/nt/unixnt.c
index 2e92d39..8c14798 100644
--- a/imap/src/osdep/nt/unixnt.c
+++ b/imap/src/osdep/nt/unixnt.c
@@ -177,7 +177,8 @@ DRIVER unixdriver = {
unix_expunge, /* expunge deleted messages */
unix_copy, /* copy messages to another mailbox */
unix_append, /* append string message to mailbox */
- NIL /* garbage collect stream */
+ NIL, /* garbage collect stream */
+ NIL /* renew stream */
};
/* prototype stream */
diff --git a/imap/src/osdep/unix/dummy.c b/imap/src/osdep/unix/dummy.c
index 07ed461..660c916 100644
--- a/imap/src/osdep/unix/dummy.c
+++ b/imap/src/osdep/unix/dummy.c
@@ -93,7 +93,8 @@ DRIVER dummydriver = {
dummy_expunge, /* expunge deleted messages */
dummy_copy, /* copy messages to another mailbox */
dummy_append, /* append string message to mailbox */
- NIL /* garbage collect stream */
+ NIL, /* garbage collect stream */
+ NIL /* renew stream */
};
/* prototype stream */
diff --git a/imap/src/osdep/unix/mbx.c b/imap/src/osdep/unix/mbx.c
index 1f41efc..ddb8ae8 100644
--- a/imap/src/osdep/unix/mbx.c
+++ b/imap/src/osdep/unix/mbx.c
@@ -165,7 +165,8 @@ DRIVER mbxdriver = {
mbx_expunge, /* expunge deleted messages */
mbx_copy, /* copy messages to another mailbox */
mbx_append, /* append string message to mailbox */
- NIL /* garbage collect stream */
+ NIL, /* garbage collect stream */
+ NIL /* renew stream */
};
/* prototype stream */
diff --git a/imap/src/osdep/unix/mh.c b/imap/src/osdep/unix/mh.c
index ebc930e..ab4449f 100644
--- a/imap/src/osdep/unix/mh.c
+++ b/imap/src/osdep/unix/mh.c
@@ -148,7 +148,8 @@ DRIVER mhdriver = {
mh_expunge, /* expunge deleted messages */
mh_copy, /* copy messages to another mailbox */
mh_append, /* append string message to mailbox */
- NIL /* garbage collect stream */
+ NIL, /* garbage collect stream */
+ NIL /* renew stream */
};
/* prototype stream */
diff --git a/imap/src/osdep/unix/mix.c b/imap/src/osdep/unix/mix.c
index 20d2b01..d2b5c71 100644
--- a/imap/src/osdep/unix/mix.c
+++ b/imap/src/osdep/unix/mix.c
@@ -207,7 +207,8 @@ DRIVER mixdriver = {
mix_expunge, /* expunge deleted messages */
mix_copy, /* copy messages to another mailbox */
mix_append, /* append string message to mailbox */
- NIL /* garbage collect stream */
+ NIL, /* garbage collect stream */
+ NIL /* renew stream */
};
/* prototype stream */
diff --git a/imap/src/osdep/unix/mmdf.c b/imap/src/osdep/unix/mmdf.c
index 994c34a..4a9e993 100644
--- a/imap/src/osdep/unix/mmdf.c
+++ b/imap/src/osdep/unix/mmdf.c
@@ -334,7 +334,8 @@ DRIVER mmdfdriver = {
mmdf_expunge, /* expunge deleted messages */
mmdf_copy, /* copy messages to another mailbox */
mmdf_append, /* append string message to mailbox */
- NIL /* garbage collect stream */
+ NIL, /* garbage collect stream */
+ NIL /* renew stream */
};
/* prototype stream */
diff --git a/imap/src/osdep/unix/mtx.c b/imap/src/osdep/unix/mtx.c
index bc7f296..0afa337 100644
--- a/imap/src/osdep/unix/mtx.c
+++ b/imap/src/osdep/unix/mtx.c
@@ -143,7 +143,8 @@ DRIVER mtxdriver = {
mtx_expunge, /* expunge deleted messages */
mtx_copy, /* copy messages to another mailbox */
mtx_append, /* append string message to mailbox */
- NIL /* garbage collect stream */
+ NIL, /* garbage collect stream */
+ NIL /* renew stream */
};
/* prototype stream */
diff --git a/imap/src/osdep/unix/mx.c b/imap/src/osdep/unix/mx.c
index 3f90ab9..54ea6ec 100644
--- a/imap/src/osdep/unix/mx.c
+++ b/imap/src/osdep/unix/mx.c
@@ -148,7 +148,8 @@ DRIVER mxdriver = {
mx_expunge, /* expunge deleted messages */
mx_copy, /* copy messages to another mailbox */
mx_append, /* append string message to mailbox */
- NIL /* garbage collect stream */
+ NIL, /* garbage collect stream */
+ NIL /* renew stream */
};
/* prototype stream */
diff --git a/imap/src/osdep/unix/news.c b/imap/src/osdep/unix/news.c
index 51eb2e6..d80ef00 100644
--- a/imap/src/osdep/unix/news.c
+++ b/imap/src/osdep/unix/news.c
@@ -134,7 +134,8 @@ DRIVER newsdriver = {
news_expunge, /* expunge deleted messages */
news_copy, /* copy messages to another mailbox */
news_append, /* append string message to mailbox */
- NIL /* garbage collect stream */
+ NIL, /* garbage collect stream */
+ NIL /* renew stream */
};
/* prototype stream */
diff --git a/imap/src/osdep/unix/phile.c b/imap/src/osdep/unix/phile.c
index 85aa8cb..e930841 100644
--- a/imap/src/osdep/unix/phile.c
+++ b/imap/src/osdep/unix/phile.c
@@ -134,7 +134,8 @@ DRIVER philedriver = {
phile_expunge, /* expunge deleted messages */
phile_copy, /* copy messages to another mailbox */
phile_append, /* append string message to mailbox */
- NIL /* garbage collect stream */
+ NIL, /* garbage collect stream */
+ NIL /* renew stream */
};
/* prototype stream */
diff --git a/imap/src/osdep/unix/tenex.c b/imap/src/osdep/unix/tenex.c
index 2e1a579..6d8ec01 100644
--- a/imap/src/osdep/unix/tenex.c
+++ b/imap/src/osdep/unix/tenex.c
@@ -150,7 +150,8 @@ DRIVER tenexdriver = {
tenex_expunge, /* expunge deleted messages */
tenex_copy, /* copy messages to another mailbox */
tenex_append, /* append string message to mailbox */
- NIL /* garbage collect stream */
+ NIL, /* garbage collect stream */
+ NIL /* renew stream */
};
/* prototype stream */
diff --git a/imap/src/osdep/unix/unix.c b/imap/src/osdep/unix/unix.c
index 74a1ffa..68f6426 100644
--- a/imap/src/osdep/unix/unix.c
+++ b/imap/src/osdep/unix/unix.c
@@ -194,7 +194,8 @@ DRIVER unixdriver = {
unix_expunge, /* expunge deleted messages */
unix_copy, /* copy messages to another mailbox */
unix_append, /* append string message to mailbox */
- NIL /* garbage collect stream */
+ NIL, /* garbage collect stream */
+ NIL /* renew stream */
};
/* prototype stream */
diff --git a/pith/newmail.c b/pith/newmail.c
index 1f026ee..bdbb2a5 100644
--- a/pith/newmail.c
+++ b/pith/newmail.c
@@ -118,6 +118,31 @@ new_mail(int force_arg, CheckPointTime time_for_check_point, int flags)
if(!force && sp_unsorted_newmail(ps_global->mail_stream))
force = !(flags & NM_DEFER_SORT);
+ /* Some servers prefer to close the connection when the access token expires,
+ * while some others prefer to keep the connection alive. This means we
+ * need to check if the access token is about to expire, and if so renew
+ * the access token and the stream. Under normal circumstances this is done
+ * invisible to the user. Hide error messages here, in case there are any.
+ * The worst thing that could happen is that the user will SEE the error
+ * later, when the connection is closed by the server (and the error will
+ * be seen then.) Sending error messages at this time will confuse users.
+ * Avoid it now.
+ */
+ for(i = 0; i < ps_global->s_pool.nstream; i++){
+ m = ps_global->s_pool.streams[i];
+ if(m && m->auth.name
+ && (!strucmp(m->auth.name, OA2NAME) || !strucmp(m->auth.name, BEARERNAME))
+ && now + 60 > m->auth.expiration){ /* procastinate doing this */
+ int skip = m->auth.expiration == 0 ? 1 : 0;
+ dprint((9, "renew_accesstoken: %s: now = %lu, auth = %s, expiration = %lu\n", STREAMNAME(m), now, m->auth.name, m->auth.expiration));
+ ps_global->noshow_error = 1; /* make this invisible to the user */
+ renew_accesstoken(m);
+ if(skip == 0) mail_renew_stream(m);
+ ps_global->noshow_error = 0; /* return to normal status */
+ dprint((9, "renew_accesstoken: %s: result: expiration = %lu\n", STREAMNAME(m), m->auth.expiration));
+ }
+ }
+
if(!ps_global->mail_stream
|| !(timeo || force || sp_a_locked_stream_changed()))
return(-1);
diff --git a/pith/pine.hlp b/pith/pine.hlp
index 428792b..e215ec9 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 496 2020-07-19 02:52:27
+Alpine Commit 498 2020-07-28 20:52:25
============= h_news =================
<HTML>
<HEAD>
@@ -194,6 +194,9 @@ problems you find with this release.
<LI> Expansion of the configuration screen for XOAUTH2 to include
username, authorization flow, and tenant.
+<LI> XOAUTH2: automatic renew of access token and connection to a server
+ within 60 seconds of expiration of the access token.
+
<LI> If a user has more than one client-id for a service, Alpine tries to
asks the user which client-id to use and associates that client-id to
the credentials in the XOAUTH2 configuration screen.