From cd53b13aa5acaecb776c82cd6566122a6893240d Mon Sep 17 00:00:00 2001 From: Eduardo Chappa Date: Wed, 19 Feb 2020 00:39:42 -0700 Subject: * Added support for SALS-IR (rfc 4959) and similar support for other protocols (SMTP, NNTP, POP3) as some SMTP servers do not support a round-trip two step authentication. For example, davmail does not support PLAIN authentication in SMTP using the challenge-response scheme. Implemented after a report by Geoffrey Bodwin. --- imap/src/c-client/auth_bea.c | 24 +++++++++++++----------- imap/src/c-client/auth_ext.c | 10 +++++----- imap/src/c-client/auth_gss.c | 27 ++++++++++++++------------- imap/src/c-client/auth_log.c | 10 +++++----- imap/src/c-client/auth_md5.c | 8 ++++---- imap/src/c-client/auth_oa2.c | 22 ++++++++++++---------- imap/src/c-client/auth_pla.c | 20 ++++++++++---------- imap/src/c-client/imap4r1.c | 29 +++++++++++++++++++++-------- imap/src/c-client/mail.c | 1 + imap/src/c-client/mail.h | 6 ++++-- imap/src/c-client/nntp.c | 19 ++++++++++++------- imap/src/c-client/pop3.c | 31 +++++++++++++++++++++++-------- imap/src/c-client/smtp.c | 19 ++++++++++++------- pith/pine.hlp | 7 ++++++- 14 files changed, 142 insertions(+), 91 deletions(-) diff --git a/imap/src/c-client/auth_bea.c b/imap/src/c-client/auth_bea.c index 683d769f..b9bf61e1 100644 --- a/imap/src/c-client/auth_bea.c +++ b/imap/src/c-client/auth_bea.c @@ -11,7 +11,7 @@ * ======================================================================== */ -long auth_oauthbearer_client (authchallenge_t challenger,authrespond_t responder, +long auth_oauthbearer_client (authchallenge_t challenger,authrespond_t responder, char *base, char *service,NETMBX *mb,void *stream, unsigned long port, unsigned long *trial,char *user); #ifndef HTTP_OAUTH2_INCLUDED @@ -19,7 +19,7 @@ void mm_login_oauth2_c_client_method (NETMBX *, char *, char *, OAUTH2_S *, unsi #endif /* HTTP_OAUTH2_INCLUDED */ AUTHENTICATOR auth_bea = { - AU_HIDE, /* hidden */ + AU_HIDE | AU_SINGLE, /* hidden, single trip */ BEARERNAME, /* authenticator name */ NIL, /* always valid */ auth_oauthbearer_client, /* client method */ @@ -77,7 +77,7 @@ char *oauth2_generate_state(void) * Returns: T if success, NIL otherwise, number of trials incremented if retry */ -long auth_oauthbearer_client (authchallenge_t challenger,authrespond_t responder, +long auth_oauthbearer_client (authchallenge_t challenger,authrespond_t responder,char *base, char *service,NETMBX *mb,void *stream, unsigned long port, unsigned long *trial,char *user) { @@ -94,12 +94,14 @@ long auth_oauthbearer_client (authchallenge_t challenger,authrespond_t responder mm_log ("SECURITY PROBLEM: insecure server advertised AUTH=OAUTHBEARER",WARN); /* get initial (empty) challenge */ - if ((challenge = (*challenger) (stream,&clen)) != NULL) { - fs_give ((void **) &challenge); - if (clen) { /* abort if challenge non-empty */ - mm_log ("Server bug: non-empty initial OAUTHBEARER challenge",WARN); - (*responder) (stream,NIL,0); - ret = LONGT; /* will get a BAD response back */ + if (base || (challenge = (*challenger) (stream,&clen)) != NULL) { + if(base == NIL){ + fs_give ((void **) &challenge); + if (clen) { /* abort if challenge non-empty */ + mm_log ("Server bug: non-empty initial OAUTHBEARER challenge",WARN); + (*responder) (stream,NIL,NIL,0); + ret = LONGT; /* will get a BAD response back */ + } } mm_login_method (mb, user, (void *) &oauth2, *trial, BEARERNAME); @@ -137,7 +139,7 @@ long auth_oauthbearer_client (authchallenge_t challenger,authrespond_t responder /* empty challenge or user requested abort or client does not have info */ if(!oauth2.access_token) { - (*responder) (stream,NIL,0); + (*responder) (stream,NIL,NIL,0); *trial = 0; /* cancel subsequent attempts */ ret = LONGT; /* will get a BAD response back */ } @@ -166,7 +168,7 @@ long auth_oauthbearer_client (authchallenge_t challenger,authrespond_t responder for (u = oauth2.access_token; *u; *t++ = *u++); *t++ = '\001'; /* delimiting ^A */ *t++ = '\001'; /* delimiting ^A */ - if ((*responder) (stream,response,rlen)) { + if ((*responder) (stream,base,response,rlen)) { if ((challenge = (*challenger) (stream,&clen)) != NULL) fs_give ((void **) &challenge); else { diff --git a/imap/src/c-client/auth_ext.c b/imap/src/c-client/auth_ext.c index b85f6bbf..6f8cf3af 100644 --- a/imap/src/c-client/auth_ext.c +++ b/imap/src/c-client/auth_ext.c @@ -27,7 +27,7 @@ * Last Edited: 30 August 2006 */ -long auth_external_client (authchallenge_t challenger,authrespond_t responder, +long auth_external_client (authchallenge_t challenger,authrespond_t responder,char *base, char *service,NETMBX *mb,void *stream, unsigned long port, unsigned long *trial,char *user); char *auth_external_server (authresponse_t responder,int argc,char *argv[]); @@ -52,7 +52,7 @@ AUTHENTICATOR auth_ext = { /* secure, has full auth, hidden */ * Returns: T if success, NIL otherwise, number of trials incremented if retry */ -long auth_external_client (authchallenge_t challenger,authrespond_t responder, +long auth_external_client (authchallenge_t challenger,authrespond_t responder,char *base, char *service,NETMBX *mb,void *stream, unsigned long port, unsigned long *trial,char *user) { @@ -60,10 +60,10 @@ long auth_external_client (authchallenge_t challenger,authrespond_t responder, unsigned long clen; long ret = NIL; *trial = 65535; /* never retry */ - if ((challenge = (*challenger) (stream,&clen)) != NULL) { - fs_give ((void **) &challenge); + if (base || (challenge = (*challenger) (stream,&clen)) != NULL) { + if(base == NIL) fs_give ((void **) &challenge); /* send authorization id (empty string OK) */ - if ((*responder) (stream,strcpy (user,mb->user),strlen (mb->user))) { + if ((*responder) (stream,base,strcpy (user,mb->user),strlen(mb->user))) { if ((challenge = (*challenger) (stream,&clen)) != NULL) fs_give ((void **) &challenge); else ret = LONGT; /* check the authentication */ diff --git a/imap/src/c-client/auth_gss.c b/imap/src/c-client/auth_gss.c index c6cc9079..4ed612c2 100644 --- a/imap/src/c-client/auth_gss.c +++ b/imap/src/c-client/auth_gss.c @@ -29,7 +29,7 @@ long auth_gssapi_valid (void); -long auth_gssapi_client (authchallenge_t challenger,authrespond_t responder, +long auth_gssapi_client (authchallenge_t challenger,authrespond_t responder, char *base, char *service,NETMBX *mb,void *stream, unsigned long port, unsigned long *trial,char *user); long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal, @@ -89,7 +89,8 @@ long auth_gssapi_valid (void) * Returns: T if success, NIL otherwise, number of trials incremented if retry */ -long auth_gssapi_client (authchallenge_t challenger,authrespond_t responder, +long auth_gssapi_client (authchallenge_t challenger,authrespond_t +responder,char *base, char *service,NETMBX *mb,void *stream,unsigned long port, unsigned long *trial,char *user) { @@ -101,12 +102,12 @@ long auth_gssapi_client (authchallenge_t challenger,authrespond_t responder, if ((chal.value = (*challenger) (stream,(unsigned long *) &chal.length)) != NULL) { if (chal.length) { /* abort if challenge non-empty */ mm_log ("Server bug: non-empty initial GSSAPI challenge",WARN); - (*responder) (stream,NIL,0); + (*responder) (stream,NIL,NIL,0); ret = LONGT; /* will get a BAD response back */ } else if (mb->authuser[0] && strcmp (mb->authuser,myusername ())) { mm_log ("Can't use Kerberos: invalid /authuser",WARN); - (*responder) (stream,NIL,0); + (*responder) (stream,NIL,NIL,0); ret = LONGT; /* will get a BAD response back */ } else ret = auth_gssapi_client_work (challenger,chal,responder,service,mb, @@ -148,7 +149,7 @@ long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal, if (gss_import_name (&smn,&buf,GSS_C_NT_HOSTBASED_SERVICE,&crname) != GSS_S_COMPLETE) { mm_log ("Can't import Kerberos service name",WARN); - (*responder) (stream,NIL,0); + (*responder) (stream,NIL,NIL,0); } else { data = (*bn) (BLOCK_SENSITIVE,NIL); @@ -163,7 +164,7 @@ long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal, while (smj == GSS_S_CONTINUE_NEEDED) { if (chal.value) fs_give ((void **) &chal.value); /* send response, get next challenge */ - i = (*responder) (stream,resp.value,resp.length) && + i = (*responder) (stream,NIL,resp.value,resp.length) && (chal.value = (*challenger) (stream,(unsigned long *) &chal.length)); gss_release_buffer (&smn,&resp); if (i) { /* negotiate continuation with KDC */ @@ -184,7 +185,7 @@ long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal, } else { /* error in continuation */ mm_log ("Error in negotiating Kerberos continuation",WARN); - (*responder) (stream,NIL,0); + (*responder) (stream,NIL,NIL,0); /* don't need context any more */ gss_delete_sec_context (&smn,&ctx,NIL); break; @@ -195,7 +196,7 @@ long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal, case GSS_S_COMPLETE: if (chal.value) fs_give ((void **) &chal.value); /* get prot mechanisms and max size */ - if ((*responder) (stream,resp.value ? resp.value : "",resp.length) && + if ((*responder) (stream,NIL,resp.value ? resp.value : "",resp.length) && (chal.value = (*challenger) (stream,(unsigned long *)&chal.length))&& (gss_unwrap (&smn,ctx,&chal,&resp,&conf,&qop) == GSS_S_COMPLETE) && (resp.length >= 4) && (*((char *) resp.value) & AUTH_GSSAPI_P_NONE)){ @@ -210,7 +211,7 @@ long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal, /* successful negotiation */ switch (smj = gss_wrap (&smn,ctx,NIL,qop,&buf,&conf,&resp)) { case GSS_S_COMPLETE: - if ((*responder) (stream,resp.value,resp.length)) ret = T; + if ((*responder) (stream,NIL,resp.value,resp.length)) ret = T; gss_release_buffer (&smn,&resp); break; default: @@ -233,7 +234,7 @@ long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal, gss_release_buffer (&dsmn,&resp); } while (dsmj == GSS_S_CONTINUE_NEEDED); - (*responder) (stream,NIL,0); + (*responder) (stream,NIL,NIL,0); } } /* flush final challenge */ @@ -252,7 +253,7 @@ long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal, sprintf (tmp,"Kerberos credentials expired (try running kinit) for %s", mb->host); mm_log (tmp,WARN); - (*responder) (stream,NIL,0); + (*responder) (stream,NIL,NIL,0); } break; case GSS_S_FAILURE: @@ -267,7 +268,7 @@ long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal, stream,user,NIL); break; /* done */ } - else (*responder) (stream,NIL,0); + else (*responder) (stream,NIL,NIL,0); case GSS_S_CONTINUE_NEEDED: sprintf (tmp,kerberos_try_kinit (smn) ? "Kerberos error: %.80s (try running kinit) for %.80s" : @@ -298,7 +299,7 @@ long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal, gss_release_buffer (&dsmn,&resp); } while (dsmj == GSS_S_CONTINUE_NEEDED); - (*responder) (stream,NIL,0); + (*responder) (stream,NIL,NIL,0); break; } /* finished with credentials name */ diff --git a/imap/src/c-client/auth_log.c b/imap/src/c-client/auth_log.c index 9c8d76ab..618e2a0b 100644 --- a/imap/src/c-client/auth_log.c +++ b/imap/src/c-client/auth_log.c @@ -27,7 +27,7 @@ * Last Edited: 30 August 2006 */ -long auth_login_client (authchallenge_t challenger,authrespond_t responder, +long auth_login_client (authchallenge_t challenger,authrespond_t responder, char *base, char *service,NETMBX *mb,void *stream, unsigned long port, unsigned long *trial,char *user); char *auth_login_server (authresponse_t responder,int argc,char *argv[]); @@ -55,7 +55,7 @@ AUTHENTICATOR auth_log = { * Returns: T if success, NIL otherwise, number of trials incremented if retry */ -long auth_login_client (authchallenge_t challenger,authrespond_t responder, +long auth_login_client (authchallenge_t challenger,authrespond_t responder, char *base, char *service,NETMBX *mb,void *stream, unsigned long port, unsigned long *trial,char *user) { @@ -68,16 +68,16 @@ long auth_login_client (authchallenge_t challenger,authrespond_t responder, fs_give ((void **) &challenge); mm_login (mb,user, &pwd,*trial); if (!pwd) { /* user requested abort */ - (*responder) (stream,NIL,0); + (*responder) (stream,NIL,NIL,0); *trial = 0; /* cancel subsequent attempts */ ret = LONGT; /* will get a BAD response back */ } /* send user name */ - else if ((*responder) (stream,user,strlen (user)) && + else if ((*responder) (stream,NIL,user,strlen (user)) && (challenge = (*challenger) (stream,&clen))) { fs_give ((void **) &challenge); /* send password */ - if ((*responder) (stream,pwd,strlen (pwd))) { + if ((*responder) (stream,NIL,pwd,strlen (pwd))) { if ((challenge = (*challenger) (stream,&clen)) != NULL) fs_give ((void **) &challenge); else { diff --git a/imap/src/c-client/auth_md5.c b/imap/src/c-client/auth_md5.c index fea96739..a1c1f5e1 100644 --- a/imap/src/c-client/auth_md5.c +++ b/imap/src/c-client/auth_md5.c @@ -44,7 +44,7 @@ typedef struct { /* Prototypes */ long auth_md5_valid (void); -long auth_md5_client (authchallenge_t challenger,authrespond_t responder, +long auth_md5_client (authchallenge_t challenger,authrespond_t responder,char *base, char *service,NETMBX *mb,void *stream, unsigned long port, unsigned long *trial,char *user); char *auth_md5_server (authresponse_t responder,int argc,char *argv[]); @@ -95,7 +95,7 @@ long auth_md5_valid (void) * Returns: T if success, NIL otherwise, number of trials incremented if retry */ -long auth_md5_client (authchallenge_t challenger,authrespond_t responder, +long auth_md5_client (authchallenge_t challenger,authrespond_t responder,char *base, char *service,NETMBX *mb,void *stream, unsigned long port, unsigned long *trial,char *user) { @@ -108,7 +108,7 @@ long auth_md5_client (authchallenge_t challenger,authrespond_t responder, mm_login (mb,user, &pwd,*trial); if (!pwd) { /* user requested abort */ fs_give ((void **) &challenge); - (*responder) (stream,NIL,0); + (*responder) (stream,NIL,NIL,0); *trial = 0; /* cancel subsequent attempts */ ret = LONGT; /* will get a BAD response back */ } @@ -118,7 +118,7 @@ long auth_md5_client (authchallenge_t challenger,authrespond_t responder, pwd,strlen (pwd))); fs_give ((void **) &challenge); /* send credentials, allow retry if OK */ - if ((*responder) (stream,tmp,strlen (tmp))) { + if ((*responder) (stream,NIL,tmp,strlen (tmp))) { if ((challenge = (*challenger) (stream,&clen)) != NULL) fs_give ((void **) &challenge); else { diff --git a/imap/src/c-client/auth_oa2.c b/imap/src/c-client/auth_oa2.c index bda9dd90..1608ad0c 100644 --- a/imap/src/c-client/auth_oa2.c +++ b/imap/src/c-client/auth_oa2.c @@ -11,7 +11,7 @@ * ======================================================================== */ -long auth_oauth2_client (authchallenge_t challenger,authrespond_t responder, +long auth_oauth2_client (authchallenge_t challenger,authrespond_t responder, char *base, char *service,NETMBX *mb,void *stream, unsigned long port, unsigned long *trial,char *user); @@ -20,7 +20,7 @@ void mm_login_oauth2_c_client_method (NETMBX *, char *, char *, OAUTH2_S *, unsi #endif /* HTTP_OAUTH2_INCLUDED */ AUTHENTICATOR auth_oa2 = { - AU_HIDE, /* hidden */ + AU_HIDE | AU_SINGLE, /* hidden */ OA2NAME, /* authenticator name */ NIL, /* always valid */ auth_oauth2_client, /* client method */ @@ -75,7 +75,7 @@ char *oauth2_generate_state(void) * Returns: T if success, NIL otherwise, number of trials incremented if retry */ -long auth_oauth2_client (authchallenge_t challenger,authrespond_t responder, +long auth_oauth2_client (authchallenge_t challenger,authrespond_t responder, char *base, char *service,NETMBX *mb,void *stream, unsigned long port, unsigned long *trial,char *user) { @@ -93,11 +93,13 @@ long auth_oauth2_client (authchallenge_t challenger,authrespond_t responder, /* get initial (empty) challenge */ if ((challenge = (*challenger) (stream,&clen)) != NULL) { - fs_give ((void **) &challenge); - if (clen) { /* abort if challenge non-empty */ - mm_log ("Server bug: non-empty initial XOAUTH2 challenge",WARN); - (*responder) (stream,NIL,0); - ret = LONGT; /* will get a BAD response back */ + if(base == NIL){ + fs_give ((void **) &challenge); + if (clen) { /* abort if challenge non-empty */ + mm_log ("Server bug: non-empty initial XOAUTH2 challenge",WARN); + (*responder) (stream,NIL,NIL,0); + ret = LONGT; /* will get a BAD response back */ + } } /* @@ -168,7 +170,7 @@ long auth_oauth2_client (authchallenge_t challenger,authrespond_t responder, /* empty challenge or user requested abort or client does not have info */ if(!oauth2.access_token) { - (*responder) (stream,NIL,0); + (*responder) (stream,NIL,NIL,0); *trial = 0; /* cancel subsequent attempts */ ret = LONGT; /* will get a BAD response back */ } @@ -184,7 +186,7 @@ long auth_oauth2_client (authchallenge_t challenger,authrespond_t responder, for (u = oauth2.access_token; *u; *t++ = *u++); *t++ = '\001'; /* delimiting ^A */ *t++ = '\001'; /* delimiting ^A */ - if ((*responder) (stream,response,rlen)) { + if ((*responder) (stream,base,response,rlen)) { if ((challenge = (*challenger) (stream,&clen)) != NULL) fs_give ((void **) &challenge); else { diff --git a/imap/src/c-client/auth_pla.c b/imap/src/c-client/auth_pla.c index 6b58948a..befd7f8c 100644 --- a/imap/src/c-client/auth_pla.c +++ b/imap/src/c-client/auth_pla.c @@ -27,13 +27,13 @@ * Last Edited: 30 August 2006 */ -long auth_plain_client (authchallenge_t challenger,authrespond_t responder, +long auth_plain_client (authchallenge_t challenger,authrespond_t responder,char *base, char *service,NETMBX *mb,void *stream, unsigned long port, unsigned long *trial,char *user); char *auth_plain_server (authresponse_t responder,int argc,char *argv[]); AUTHENTICATOR auth_pla = { - AU_AUTHUSER | AU_HIDE, /* allow authuser, hidden */ + AU_AUTHUSER | AU_HIDE | AU_SINGLE, /* allow authuser, hidden, single trip */ "PLAIN", /* authenticator name */ NIL, /* always valid */ auth_plain_client, /* client method */ @@ -52,30 +52,30 @@ AUTHENTICATOR auth_pla = { * Returns: T if success, NIL otherwise, number of trials incremented if retry */ -long auth_plain_client (authchallenge_t challenger,authrespond_t responder, +long auth_plain_client (authchallenge_t challenger,authrespond_t responder,char *base, char *service,NETMBX *mb,void *stream, unsigned long port, unsigned long *trial,char *user) { char *u, *pwd = NIL; - void *challenge; + void *challenge = NIL; unsigned long clen; long ret = NIL; /* snarl if not SSL/TLS session */ if (!mb->sslflag && !mb->tlsflag) mm_log ("SECURITY PROBLEM: insecure server advertised AUTH=PLAIN",WARN); /* get initial (empty) challenge */ - if ((challenge = (*challenger) (stream,&clen)) != NULL) { - fs_give ((void **) &challenge); + if(base || (challenge = (*challenger) (stream,&clen)) != NULL) { + if(base == NIL) fs_give ((void **) &challenge); #if 0 - if (clen) { /* abort if challenge non-empty */ + if (clen) { /* abort if challenge non-empty */ mm_log ("Server bug: non-empty initial PLAIN challenge",WARN); (*responder) (stream,NIL,0); - ret = LONGT; /* will get a BAD response back */ + ret = LONGT; /* will get a BAD response back */ } #endif mm_login (mb,user, &pwd,*trial); if (!pwd) { /* empty challenge or user requested abort */ - (*responder) (stream,NIL,0); + (*responder) (stream,NIL,NIL,0); *trial = 0; /* cancel subsequent attempts */ ret = LONGT; /* will get a BAD response back */ } @@ -92,7 +92,7 @@ long auth_plain_client (authchallenge_t challenger,authrespond_t responder, /* copy password */ for (u = pwd; *u; *t++ = *u++); /* send credentials */ - if ((*responder) (stream,response,rlen)) { + if ((*responder) (stream,base,response,rlen)) { if ((challenge = (*challenger) (stream,&clen)) != NULL) fs_give ((void **) &challenge); else { diff --git a/imap/src/c-client/imap4r1.c b/imap/src/c-client/imap4r1.c index 86354d40..1b4241da 100644 --- a/imap/src/c-client/imap4r1.c +++ b/imap/src/c-client/imap4r1.c @@ -177,7 +177,7 @@ long imap_anon (MAILSTREAM *stream,char *tmp); long imap_auth (MAILSTREAM *stream,NETMBX *mb,char *tmp,char *usr); long imap_login (MAILSTREAM *stream,NETMBX *mb,char *pwd,char *usr); void *imap_challenge (void *stream,unsigned long *len); -long imap_response (void *stream,char *s,unsigned long size); +long imap_response (void *stream,char *base,char *s,unsigned long size); void imap_close (MAILSTREAM *stream,long options); void imap_fast (MAILSTREAM *stream,char *sequence,long flags); void imap_flags (MAILSTREAM *stream,char *sequence,long flags); @@ -1107,7 +1107,7 @@ long imap_anon (MAILSTREAM *stream,char *tmp) mm_log (broken,ERROR); return NIL; } - if (imap_challenge (stream,&i)) imap_response (stream,s,strlen (s)); + if (imap_challenge (stream,&i)) imap_response (stream,NIL,s,strlen (s)); /* get response */ if (!(reply = &LOCAL->reply)->tag) reply = imap_fake (stream,tag,broken); /* what we wanted? */ @@ -1145,7 +1145,7 @@ long imap_auth (MAILSTREAM *stream,NETMBX *mb,char *tmp,char *usr) unsigned long trial,ua,uasaved; int ok; char tag[16]; - char *lsterr = NIL; + char *lsterr = NIL, *base; AUTHENTICATOR *at, *atsaved; IMAPPARSEDREPLY *reply; for (ua = LOCAL->cap.auth, LOCAL->saslcancel = NIL; LOCAL->netstream && ua && @@ -1176,10 +1176,12 @@ long imap_auth (MAILSTREAM *stream,NETMBX *mb,char *tmp,char *usr) sprintf (tag,"%08lx",0xffffffff & (stream->gensym++)); /* build command */ sprintf (tmp,"%s AUTHENTICATE %s",tag,at->name); - if (imap_soutr (stream,tmp)) { + base = (at->flags & AU_SINGLE) && LOCAL->cap.sasl_ir + ? (char *) tmp : NIL; + if (base || imap_soutr (stream,tmp)) { /* hide client authentication responses */ if (!(at->flags & AU_SECURE)) LOCAL->sensitive = T; - ok = (*at->client) (imap_challenge,imap_response,"imap",mb,stream, + ok = (*at->client) (imap_challenge,imap_response,base,"imap",mb,stream, net_port(LOCAL->netstream),&trial,usr); LOCAL->sensitive = NIL; /* unhide */ /* make sure have a response */ @@ -1311,15 +1313,26 @@ void *imap_challenge (void *s,unsigned long *len) * Returns: T if successful, else NIL */ -long imap_response (void *s,char *response,unsigned long size) +long imap_response (void *s,char *base,char *response,unsigned long size) { MAILSTREAM *stream = (MAILSTREAM *) s; unsigned long i,j,ret; char *t,*u; if (response) { /* make CRLFless BASE64 string */ if (size) { - for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0; + if(base){ + char *s, *v; + + v = (char *) rfc822_binary ((void *) response,size,&i); + t = fs_get((strlen(base) + strlen(v) + 1 + 2)*sizeof(char)); + for(s = base, u = t; *s; s++) *u++ = *s; + *u++ = ' '; + for (s = v,j = 0; j < i; j++) if (s[j] > ' ') *u++ = s[j]; + fs_give((void **) &v); + } else { + for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0; j < i; j++) if (t[j] > ' ') *u++ = t[j]; + } *u = '\0'; /* tie off string for mm_dlog() */ if (stream->debug) mail_dlog (t,LOCAL->sensitive); /* append CRLF */ @@ -1330,7 +1343,7 @@ long imap_response (void *s,char *response,unsigned long size) else ret = imap_soutr (stream,""); } else { /* abort requested */ - ret = imap_soutr (stream,"*"); + ret = base ? NIL : imap_soutr (stream,"*"); LOCAL->saslcancel = T; /* mark protocol-requested SASL cancel */ } return ret; diff --git a/imap/src/c-client/mail.c b/imap/src/c-client/mail.c index e591a521..85398688 100644 --- a/imap/src/c-client/mail.c +++ b/imap/src/c-client/mail.c @@ -6370,6 +6370,7 @@ long net_getbuffer (void *st,unsigned long size,char *buffer) long net_soutr (NETSTREAM *stream,char *string) { + mm_log(string, ERROR); return (*stream->dtb->soutr) (stream->stream,string); } diff --git a/imap/src/c-client/mail.h b/imap/src/c-client/mail.h index 1a4e1b04..d7c52dd8 100644 --- a/imap/src/c-client/mail.h +++ b/imap/src/c-client/mail.h @@ -548,6 +548,8 @@ #define AU_HIDE (long) 0x10000000 /* authenticator disabled */ #define AU_DISABLE (long) 0x20000000 + /* can do single trip */ +#define AU_SINGLE (long) 0x40000000 /* Garbage collection flags */ @@ -1377,10 +1379,10 @@ typedef long (*mailproxycopy_t) (MAILSTREAM *stream,char *sequence, typedef long (*tcptimeout_t) (long overall,long last, char *host); typedef long (*ucs4width_t) (unsigned long c); typedef void *(*authchallenge_t) (void *stream,unsigned long *len); -typedef long (*authrespond_t) (void *stream,char *s,unsigned long size); +typedef long (*authrespond_t) (void *stream,char *base,char *s,unsigned long size); typedef long (*authcheck_t) (void); typedef long (*authclient_t) (authchallenge_t challenger, - authrespond_t responder,char *service,NETMBX *mb, + authrespond_t responder, char *base, char *service,NETMBX *mb, void *s, unsigned long port, unsigned long *trial,char *user); typedef char *(*authresponse_t) (void *challenge,unsigned long clen, unsigned long *rlen); diff --git a/imap/src/c-client/nntp.c b/imap/src/c-client/nntp.c index 51d20b7f..bce7c636 100644 --- a/imap/src/c-client/nntp.c +++ b/imap/src/c-client/nntp.c @@ -154,7 +154,7 @@ long nntp_send_work (SENDSTREAM *stream,char *command,char *args); long nntp_send_auth (SENDSTREAM *stream,long flags); long nntp_send_auth_work (SENDSTREAM *stream,NETMBX *mb,char *pwd,long flags); void *nntp_challenge (void *s,unsigned long *len); -long nntp_response (void *s,char *response,unsigned long size); +long nntp_response (void *s,char *base,char *response,unsigned long size); long nntp_reply (SENDSTREAM *stream); long nntp_fake (SENDSTREAM *stream,char *text); long nntp_soutr (void *stream,char *s); @@ -2045,7 +2045,7 @@ long nntp_send_auth (SENDSTREAM *stream,long flags) long nntp_send_auth_work (SENDSTREAM *stream,NETMBX *mb,char *pwd,long flags) { unsigned long trial,auths; - char tmp[MAILTMPLEN],usr[MAILTMPLEN], *pwd2 = NIL; + char tmp[MAILTMPLEN],usr[MAILTMPLEN], *pwd2 = NIL, *base; AUTHENTICATOR *at; char *lsterr = NIL; long ret = NIL; @@ -2068,10 +2068,15 @@ long nntp_send_auth_work (SENDSTREAM *stream,NETMBX *mb,char *pwd,long flags) fs_give ((void **) &lsterr); } stream->saslcancel = NIL; - if (nntp_send (stream,"AUTHINFO SASL",at->name) == NNTPCHALLENGE) { + if(at->flags & AU_SINGLE){ + sprintf(tmp, "AUTHINFO SASL %s", at->name); /* create base string */ + base = (char *) tmp; + } + else base = NIL; + if ((at->flags & AU_SINGLE) || nntp_send (stream,"AUTHINFO SASL",at->name) == NNTPCHALLENGE) { /* hide client authentication responses */ if (!(at->flags & AU_SECURE)) stream->sensitive = T; - if ((*at->client) (nntp_challenge,nntp_response,"nntp",mb,stream, + if ((*at->client) (nntp_challenge,nntp_response,base,"nntp",mb,stream, net_port(stream->netstream), &trial,usr)) { if (stream->replycode == NNTPAUTHED) ret = LONGT; /* if main program requested cancellation */ @@ -2163,7 +2168,7 @@ void *nntp_challenge (void *s,unsigned long *len) * Returns: T, always */ -long nntp_response (void *s,char *response,unsigned long size) +long nntp_response (void *s,char *base,char *response,unsigned long size) { SENDSTREAM *stream = (SENDSTREAM *) s; unsigned long i,j; @@ -2173,13 +2178,13 @@ long nntp_response (void *s,char *response,unsigned long size) for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0; j < i; j++) if (t[j] > ' ') *u++ = t[j]; *u = '\0'; /* tie off string */ - i = nntp_send_work (stream,t,NIL); + i = base ? nntp_send_work(stream, base, t) : nntp_send_work (stream,t,NIL); fs_give ((void **) &t); } else i = nntp_send_work (stream,"",NIL); } else { /* abort requested */ - i = nntp_send_work (stream,"*",NIL); + i = base ? 0L : nntp_send_work (stream,"*",NIL); stream->saslcancel = T; /* mark protocol-requested SASL cancel */ } return LONGT; diff --git a/imap/src/c-client/pop3.c b/imap/src/c-client/pop3.c index 94df54f6..b93ef8fb 100644 --- a/imap/src/c-client/pop3.c +++ b/imap/src/c-client/pop3.c @@ -91,7 +91,7 @@ MAILSTREAM *pop3_open (MAILSTREAM *stream); long pop3_capa (MAILSTREAM *stream,long flags); long pop3_auth (MAILSTREAM *stream,NETMBX *mb,char *pwd,char *usr); void *pop3_challenge (void *stream,unsigned long *len); -long pop3_response (void *stream,char *s,unsigned long size); +long pop3_response (void *stream,char *base,char *s,unsigned long size); void pop3_close (MAILSTREAM *stream,long options); void pop3_fetchfast (MAILSTREAM *stream,char *sequence,long flags); char *pop3_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *size, @@ -555,7 +555,7 @@ long pop3_capa (MAILSTREAM *stream,long flags) long pop3_auth (MAILSTREAM *stream,NETMBX *mb,char *pwd,char *usr) { unsigned long i,trial,auths = 0, authsaved; - char *t, *app_pwd = NIL; + char *t, *app_pwd = NIL, *base; AUTHENTICATOR *at, *atsaved; long ret = NIL; long flags = (stream->secure ? AU_SECURE : NIL) | @@ -635,11 +635,15 @@ long pop3_auth (MAILSTREAM *stream,NETMBX *mb,char *pwd,char *usr) mm_log (pwd,WARN); fs_give ((void **) &t); } + if(at->flags & AU_SINGLE){ + sprintf(pwd, "AUTH %s", at->name); + base = (char *) pwd; + } else base = NIL; LOCAL->saslcancel = NIL; - if (pop3_send (stream,"AUTH",at->name)) { + if ((at->flags & AU_SINGLE) || pop3_send (stream,"AUTH",at->name)) { /* hide client authentication responses */ if (!(at->flags & AU_SECURE)) LOCAL->sensitive = T; - if ((*at->client) (pop3_challenge,pop3_response,"pop",mb,stream, + if ((*at->client) (pop3_challenge,pop3_response,base,"pop",mb,stream, net_port(LOCAL->netstream),&trial,usr) && LOCAL->response) { if (*LOCAL->response == '+') ret = LONGT; /* if main program requested cancellation */ @@ -735,15 +739,26 @@ void *pop3_challenge (void *s,unsigned long *len) * Returns: T if successful, else NIL */ -long pop3_response (void *s,char *response,unsigned long size) +long pop3_response (void *s,char *base,char *response,unsigned long size) { MAILSTREAM *stream = (MAILSTREAM *) s; unsigned long i,j,ret; char *t,*u; if (response) { /* make CRLFless BASE64 string */ if (size) { - for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0; - j < i; j++) if (t[j] > ' ') *u++ = t[j]; + if(base){ + char *s, *v; + + v = (char *) rfc822_binary ((void *) response,size,&i); + t = fs_get((strlen(base) + strlen(v) + 1 + 2)*sizeof(char)); + for(s = base, u = t; *s; s++) *u++ = *s; + *u++ = ' '; + for (s = v,j = 0; j < i; j++) if (s[j] > ' ') *u++ = s[j]; + fs_give((void **) &v); + } else { + for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0; + j < i; j++) if (t[j] > ' ') *u++ = t[j]; + } *u = '\0'; /* tie off string for mm_dlog() */ if (stream->debug) mail_dlog (t,LOCAL->sensitive); /* append CRLF */ @@ -754,7 +769,7 @@ long pop3_response (void *s,char *response,unsigned long size) else ret = net_sout (LOCAL->netstream,"\015\012",2); } else { /* abort requested */ - ret = net_sout (LOCAL->netstream,"*\015\012",3); + ret = base ? NIL : net_sout (LOCAL->netstream,"*\015\012",3); LOCAL->saslcancel = T; /* mark protocol-requested SASL cancel */ } pop3_reply (stream); /* get response */ diff --git a/imap/src/c-client/smtp.c b/imap/src/c-client/smtp.c index 96abd5fa..30bfd293 100644 --- a/imap/src/c-client/smtp.c +++ b/imap/src/c-client/smtp.c @@ -59,7 +59,7 @@ /* Function prototypes */ void *smtp_challenge (void *s,unsigned long *len); -long smtp_response (void *s,char *response,unsigned long size); +long smtp_response (void *s,char *base,char *response,unsigned long size); long smtp_auth (SENDSTREAM *stream,NETMBX *mb,char *tmp); long smtp_rcpt (SENDSTREAM *stream,ADDRESS *adr,long *error); long smtp_send (SENDSTREAM *stream,char *command,char *args); @@ -283,7 +283,7 @@ long smtp_auth (SENDSTREAM *stream,NETMBX *mb,char *tmp) { unsigned long trial,auths, authsaved; char *lsterr = NIL; - char usr[MAILTMPLEN]; + char usr[MAILTMPLEN], *base; AUTHENTICATOR *at, *atsaved; long ret = NIL; for (auths = ESMTP.auth, stream->saslcancel = NIL; @@ -311,11 +311,16 @@ long smtp_auth (SENDSTREAM *stream,NETMBX *mb,char *tmp) mm_log (tmp,WARN); fs_give ((void **) &lsterr); } + if(at->flags & AU_SINGLE){ + sprintf(tmp, "AUTH %s", at->name); + base = (char *) tmp; + } + else base = NIL; stream->saslcancel = NIL; - if (smtp_send (stream,"AUTH",at->name) == SMTPAUTHREADY) { + if ((at->flags & AU_SINGLE) || smtp_send (stream,"AUTH",at->name) == SMTPAUTHREADY) { /* hide client authentication responses */ if (!(at->flags & AU_SECURE)) stream->sensitive = T; - if ((*at->client) (smtp_challenge,smtp_response,"smtp",mb,stream, + if ((*at->client) (smtp_challenge,smtp_response,base,"smtp",mb,stream, net_port(stream->netstream),&trial,usr)) { if (stream->replycode == SMTPAUTHED) { ESMTP.auth = NIL; /* disable authenticators */ @@ -375,7 +380,7 @@ void *smtp_challenge (void *s,unsigned long *len) * Returns: T, always */ -long smtp_response (void *s,char *response,unsigned long size) +long smtp_response (void *s,char* base,char *response,unsigned long size) { SENDSTREAM *stream = (SENDSTREAM *) s; unsigned long i,j; @@ -385,13 +390,13 @@ long smtp_response (void *s,char *response,unsigned long size) for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0; j < i; j++) if (t[j] > ' ') *u++ = t[j]; *u = '\0'; /* tie off string */ - i = smtp_send (stream,t,NIL); + i = base ? smtp_send(stream, base, t) : smtp_send (stream,t,NIL); fs_give ((void **) &t); } else i = smtp_send (stream,"",NIL); } else { /* abort requested */ - i = smtp_send (stream,"*",NIL); + i = base ? 0L : smtp_send (stream,"*",NIL); stream->saslcancel = T; /* mark protocol-requested SASL cancel */ } return LONGT; diff --git a/pith/pine.hlp b/pith/pine.hlp index fa22dd9b..1a3de03b 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 407 2020-02-09 22:46:28 +Alpine Commit 408 2020-02-19 00:39:37 ============= h_news ================= @@ -184,6 +184,11 @@ any problems you find with this release.
  • Add support for the OAUTHBEARER authentication method in Gmail. Thanks to Alexander Perlis for suggesting it and explaining how the method works. +
  • Support for the SASL-IR IMAP extension that avoids a round trip during + authentication. Similar support added for the SMTP, NNTP and POP3 + protocols. Thanks to Geoffrey Bodwin for a report that lead to this + implementation. +
  • New variable system-certs-path that allows users to indicate the location of the directory where certificates are located. In PC-Alpine this must be C:\\libressl\\ssl\\certs. The C: drive can be replaced -- cgit v1.2.3-70-g09d2