[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-pim
Subject:    [Kde-pim] [PATCH] SASL authentication enhacement
From:       Szombathelyi "György" <gyurco () freemail ! hu>
Date:       2004-08-29 15:06:18
Message-ID: 200408291706.18597.gyurco () freemail ! hu
[Download RAW message or body]

Hello!

I wrote a patch for kio_imap4. It uses the cyrus-sasl package for SASL 
authentication instead of KSASL class. It has several advantages, including 
Kerberos support, and also can use any cyrus-sasl plugins. I didn't use QCA 
(Qt Cryptographic Architecture), because SASL in QCA has only a signal-slot 
interface, which is not optimal for ioslaves.
The patch contains modifications for kio_imap4, and for the account 
configuration dialog in KMail (I added the GSSAPI mechanism). If accepted, I 
will add cyrus-sasl support to more ioslaves, namely SMTP, POP3 and SIEVE.
May I commit?

Bye,
Gyorgy

____________________________________________________________________
Miert fizetsz az internetert? Korlatlan, ingyenes internet hozzaferes a FreeStarttol.
Probald ki most! http://www.freestart.hu

["imap-sasl.diff" (text/x-diff)]

Index: kioslaves/imap4/Makefile.am
===================================================================
RCS file: /home/kde/kdepim/kioslaves/imap4/Makefile.am,v
retrieving revision 1.24
diff -u -p -u -r1.24 Makefile.am
--- kioslaves/imap4/Makefile.am	20 Aug 2004 15:44:37 -0000	1.24
+++ kioslaves/imap4/Makefile.am	29 Aug 2004 14:53:24 -0000
@@ -7,7 +7,7 @@ kde_module_LTLIBRARIES = kio_imap4.la
 kio_imap4_la_SOURCES = 	imapcommand.cc imaplist.cc mailaddress.cc \
   mimeheader.cc rfcdecoder.cc imap4.cc imapinfo.cc imapparser.cc mailheader.cc \
   mimehdrline.cc  mimeio.cc
-kio_imap4_la_LIBADD  = -lkdesasl $(LIB_KIO)
+kio_imap4_la_LIBADD  = -lkdesasl $(LIB_KIO) $(SASL2_LIBS)
 kio_imap4_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) -module $(KDE_PLUGIN)
 
 noinst_HEADERS = imap4.h
Index: kioslaves/imap4/configure.in.in
===================================================================
RCS file: /home/kde/kdepim/kioslaves/imap4/configure.in.in,v
retrieving revision 1.1
diff -u -p -u -r1.1 configure.in.in
--- kioslaves/imap4/configure.in.in	13 Apr 2004 16:28:13 -0000	1.1
+++ kioslaves/imap4/configure.in.in	29 Aug 2004 14:53:24 -0000
@@ -1 +1,14 @@
 KDE_CHECK_SSL
+
+sasl2_header="no"
+SASL2_LIBS=""
+
+AC_CHECK_HEADERS([sasl/sasl.h], sasl2_header="yes")
+if test "$sasl2_header" = "yes" ; then
+  AC_CHECK_LIB(sasl2, sasl_client_init, SASL2_LIBS="-lsasl2")
+fi
+
+if test "x$SASL2_LIBS" != "x" ; then
+  AC_DEFINE_UNQUOTED(HAVE_LIBSASL2, 1, [Define if you have cyrus-sasl2 libraries])
+fi
+AC_SUBST(SASL2_LIBS)
Index: kioslaves/imap4/imap4.cc
===================================================================
RCS file: /home/kde/kdepim/kioslaves/imap4/imap4.cc,v
retrieving revision 1.188
diff -u -p -u -r1.188 imap4.cc
--- kioslaves/imap4/imap4.cc	20 Aug 2004 15:44:37 -0000	1.188
+++ kioslaves/imap4/imap4.cc	29 Aug 2004 14:53:24 -0000
@@ -62,6 +62,12 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 
+#ifdef HAVE_LIBSASL2
+extern "C" {
+#include <sasl/sasl.h>
+}
+#endif
+
 #include <qbuffer.h>
 #include <qdatetime.h>
 #include <kprotocolmanager.h>
@@ -85,6 +91,20 @@ extern "C"
   int kdemain (int argc, char **argv);
 }
 
+#ifdef HAVE_LIBSASL2
+static sasl_callback_t callbacks[] = {
+    { SASL_CB_ECHOPROMPT, NULL, NULL },
+    { SASL_CB_NOECHOPROMPT, NULL, NULL },
+    { SASL_CB_GETREALM, NULL, NULL },
+    { SASL_CB_USER, NULL, NULL },
+    { SASL_CB_AUTHNAME, NULL, NULL },
+    { SASL_CB_PASS, NULL, NULL },
+    { SASL_CB_GETOPT, NULL, NULL },
+    { SASL_CB_CANON_USER, NULL, NULL },
+    { SASL_CB_LIST_END, NULL, NULL }
+};
+#endif
+
 int
 kdemain (int argc, char **argv)
 {
@@ -97,6 +117,13 @@ kdemain (int argc, char **argv)
     ::exit (-1);
   }
 
+#ifdef HAVE_LIBSASL2
+  if ( sasl_client_init( callbacks ) != SASL_OK ) {
+    fprintf(stderr, "SASL library initialization failed!\n");
+    ::exit (-1);
+  }
+#endif
+
   //set debug handler
 
   IMAP4Protocol *slave;
@@ -109,6 +136,10 @@ kdemain (int argc, char **argv)
   slave->dispatchLoop ();
   delete slave;
 
+#ifdef HAVE_LIBSASL2
+  sasl_done();
+#endif
+  
   return 0;
 }
 
@@ -1631,6 +1662,7 @@ bool IMAP4Protocol::makeLogin ()
 
     myAuth = metaData("auth");
     myTLS  = metaData("tls");
+    kdDebug(7116) << "myAuth: " << myAuth << endl;
 
     imapCommand *cmd;
 
@@ -1727,9 +1759,13 @@ bool IMAP4Protocol::makeLogin ()
     }
     else
     {
-      if (!clientAuthenticate (myUser, myPass, myAuth, mySSL, resultInfo))
+#ifdef HAVE_LIBSASL2      
+      if (!clientAuthenticate (myUser, myPass, myHost, myAuth, mySSL, resultInfo))
         error(KIO::ERR_COULD_NOT_LOGIN, i18n("Unable to authenticate via %1.\n"
         "The server replied:\n%2").arg(myAuth).arg(resultInfo));
+#else
+      error(KIO::ERR_COULD_NOT_LOGIN, i18n("SASL authentication is not compiled into kio_imap4."));
+#endif        
     }
   }
 
Index: kioslaves/imap4/imapparser.cc
===================================================================
RCS file: /home/kde/kdepim/kioslaves/imap4/imapparser.cc,v
retrieving revision 1.87
diff -u -p -u -r1.87 imapparser.cc
--- kioslaves/imap4/imapparser.cc	12 Aug 2004 20:21:16 -0000	1.87
+++ kioslaves/imap4/imapparser.cc	29 Aug 2004 14:53:27 -0000
@@ -22,6 +22,10 @@
  *
  *********************************************************************/
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #include "rfcdecoder.h"
 
 #include "imapparser.h"
@@ -37,6 +41,12 @@
 #include <stdlib.h>
 #include <unistd.h>
 
+#ifdef HAVE_LIBSASL2
+extern "C" {
+#include <sasl/sasl.h>
+}
+#endif
+
 #include <qregexp.h>
 #include <qbuffer.h>
 #include <qstring.h>
@@ -45,7 +55,6 @@
 #include <kdebug.h>
 #include <kmdcodec.h>
 #include <kurl.h>
-#include <kio/kdesasl.h>
 
 imapParser::imapParser ()
 {
@@ -136,42 +145,120 @@ imapParser::clientLogin (const QString &
   return retVal;
 }
 
+#ifdef HAVE_LIBSASL2
+static void sasl_interact( const QString &aUser, const QString &aPass, void *in )
+{
+  kdDebug(7116) << "sasl_interact" << endl;
+  sasl_interact_t *interact = ( sasl_interact_t * ) in;
+
+  while( interact->id != SASL_CB_LIST_END ) {
+    kdDebug(7116) << "SASL_INTERACT id: " << interact->id << endl;
+    switch( interact->id ) {
+      case SASL_CB_AUTHNAME:
+        kdDebug(7116) << "SASL_CB_AUTHNAME: '" << aUser << "'" << endl;
+        interact->result = strdup( aUser.utf8() );
+        interact->len = strlen( (const char *) interact->result );
+        break;
+      case SASL_CB_PASS:
+        kdDebug(7116) << "SASL_CB_PASS: [hidden] " << endl;
+        interact->result = strdup( aPass.utf8() );
+        interact->len = strlen( (const char *) interact->result );
+        break;
+      default:
+        interact->result = NULL; interact->len = 0;
+        break;
+    }
+    interact++;
+  }
+}
+#endif
 
 bool
-imapParser::clientAuthenticate (const QString & aUser, const QString & aPass,
-  const QString & aAuth, bool isSSL, QString & resultInfo)
+imapParser::clientAuthenticate (const QString & aUser, const QString & aPass, 
+  const QString & aFQDN, const QString & aAuth, bool isSSL, QString & resultInfo)
 {
-  imapCommand *cmd;
   bool retVal = false;
+#ifdef HAVE_LIBSASL2
+  int result;
+  sasl_conn_t *conn = NULL;
+  sasl_interact_t *client_interact = NULL;
+  const char *out = NULL;
+  uint outlen;
+  const char *mechusing = NULL;
+    
+  kdDebug(7116) << "aAuth: " << aAuth << " FQDN: " << aFQDN << " isSSL: " << isSSL << endl;
 
   // see if server supports this authenticator
   if (!hasCapability ("AUTH=" + aAuth))
     return false;
 
+//  result = sasl_client_new( isSSL ? "imaps" : "imap",
+  result = sasl_client_new( "imap", /* FIXME: with cyrus-imapd, even imaps' digest-uri 
+                                       must be 'imap'. I don't know if it's good or bad. */
+                       aFQDN.latin1(),
+                       0, 0, NULL, 0, &conn );
+
+  if ( result != SASL_OK ) {
+    kdDebug(7116) << "sasl_client_new failed with: " << result << endl;
+    resultInfo = QString::fromUtf8( sasl_errdetail( conn ) );
+    return false;
+  }
+
+  do {
+    result = sasl_client_start(conn, aAuth.latin1(), &client_interact,
+                       0, &outlen, &mechusing);
+
+    if (result == SASL_INTERACT) sasl_interact( aUser, aPass, client_interact );
+  } while ( result == SASL_INTERACT );
+
+  if ( result != SASL_CONTINUE && result != SASL_OK ) {
+    kdDebug(7116) << "sasl_client_start failed with: " << result << endl;
+    resultInfo = QString::fromUtf8( sasl_errdetail( conn ) );
+    sasl_dispose( &conn );
+    return false;
+  }
+  imapCommand *cmd;
+  
   // then lets try it
   cmd = sendCommand (new imapCommand ("AUTHENTICATE", aAuth));
-  KDESasl sasl(aUser, aPass, isSSL ? "imaps" : "imap");
-  sasl.setMethod(aAuth.latin1());
+
   while (!cmd->isComplete ())
   {
     //read the next line
     while (parseLoop() == 0);
 
-    if (!continuation.isEmpty ())
+    if (!continuation.isEmpty())
     {
-      QByteArray challenge;
-      challenge.duplicate(continuation.data() + 2, continuation.size() - 2);
-      challenge.resize(challenge.size() - 2); // trim CRLF
-
-      if (aAuth.upper () == "ANONYMOUS")
-      {
-        // we should present the challenge to the user and ask
-        // him for a mail-address or what ever
-        challenge = KCodecs::base64Encode(aUser.utf8());
-      } else {
-        challenge = sasl.getResponse(challenge);
-      }
-
+      QByteArray challenge, tmp;
+//      kdDebug(7116) << "S: " << QCString(continuation.data(),continuation.size()+1) << endl;
+      if ( continuation.size() > 4 ) {
+        tmp.setRawData( continuation.data() + 2, continuation.size() - 4 );
+        KCodecs::base64Decode( tmp, challenge );
+//        kdDebug(7116) << "S-1: " << QCString(challenge.data(),challenge.size()+1) << endl;
+        tmp.resetRawData( continuation.data() + 2, continuation.size() - 4 );
+      }
+
+      do {
+        result = sasl_client_step(conn, challenge.isEmpty() ? 0 : challenge.data(), 
+                                  challenge.size(),
+                                  &client_interact,  
+                                  &out, &outlen);
+
+        if ( result == SASL_INTERACT ) sasl_interact( aUser, aPass, client_interact );
+      } while ( result == SASL_INTERACT );
+      
+      if ( result != SASL_CONTINUE && result != SASL_OK ) {
+        kdDebug(7116) << "sasl_client_step failed with: " << result << endl;
+        resultInfo = QString::fromUtf8( sasl_errdetail( conn ) );
+        sasl_dispose( &conn );
+        return false;
+      }
+      
+      tmp.setRawData( out, outlen );
+//      kdDebug(7116) << "C-1: " << QCString(tmp.data(),tmp.size()+1) << endl;
+      KCodecs::base64Encode( tmp, challenge );
+      tmp.resetRawData( out, outlen );
+//      kdDebug(7116) << "C: " << QCString(challenge.data(),challenge.size()+1) << endl;
       parseWriteLine (challenge);
       continuation.resize(0);
     }
@@ -185,6 +272,8 @@ imapParser::clientAuthenticate (const QS
   resultInfo = cmd->resultInfo();
   completeQueue.removeRef (cmd);
 
+  sasl_dispose( &conn ); //we don't use sasl_en/decode(), so it's safe to dispose the connection.
+#endif //HAVE_LIBSASL2
   return retVal;
 }
 
Index: kioslaves/imap4/imapparser.h
===================================================================
RCS file: /home/kde/kdepim/kioslaves/imap4/imapparser.h,v
retrieving revision 1.37
diff -u -p -u -r1.37 imapparser.h
--- kioslaves/imap4/imapparser.h	21 Apr 2004 21:18:25 -0000	1.37
+++ kioslaves/imap4/imapparser.h	29 Aug 2004 14:53:27 -0000
@@ -232,7 +232,7 @@ public:
    * @return success or failure
    */
   bool clientAuthenticate (const QString & aUser, const QString & aPass,
-               const QString & aAuth, bool isSSL, QString & resultInfo);
+    const QString & aFQDN, const QString & aAuth, bool isSSL, QString & resultInfo);
 
   /**
    * main loop for the parser
Index: kmail/accountdialog.cpp
===================================================================
RCS file: /home/kde/kdepim/kmail/accountdialog.cpp,v
retrieving revision 1.155
diff -u -p -u -r1.155 accountdialog.cpp
--- kmail/accountdialog.cpp	3 Aug 2004 21:27:21 -0000	1.155
+++ kmail/accountdialog.cpp	29 Aug 2004 14:53:36 -0000
@@ -954,6 +954,7 @@ void AccountDialog::makeImapAccountPage(
      mImap.authGroup );
   mImap.authCramMd5 = new QRadioButton( i18n("CRAM-MD&5"), mImap.authGroup );
   mImap.authDigestMd5 = new QRadioButton( i18n("&DIGEST-MD5"), mImap.authGroup );
+  mImap.authGSSAPI = new QRadioButton( i18n("&GSSAPI"), mImap.authGroup );
   mImap.authAnonymous = new QRadioButton( i18n("&Anonymous"), mImap.authGroup );
   vlay->addWidget( mImap.authGroup );
 
@@ -1106,6 +1107,8 @@ void AccountDialog::setupSettings()
       mImap.authCramMd5->setChecked( TRUE );
     else if (ai.auth() == "DIGEST-MD5")
       mImap.authDigestMd5->setChecked( TRUE );
+    else if (ai.auth() == "GSSAPI")
+      mImap.authGSSAPI->setChecked( TRUE );
     else if (ai.auth() == "ANONYMOUS")
       mImap.authAnonymous->setChecked( TRUE );
     else if (ai.auth() == "PLAIN")
@@ -1156,6 +1159,8 @@ void AccountDialog::setupSettings()
       mImap.authCramMd5->setChecked( TRUE );
     else if (ai.auth() == "DIGEST-MD5")
       mImap.authDigestMd5->setChecked( TRUE );
+    else if (ai.auth() == "GSSAPI")
+      mImap.authGSSAPI->setChecked( TRUE );
     else if (ai.auth() == "ANONYMOUS")
       mImap.authAnonymous->setChecked( TRUE );
     else if (ai.auth() == "PLAIN")
@@ -1470,6 +1475,8 @@ unsigned int AccountDialog::imapCapabili
       capa |= CRAM_MD5;
     else if ( cur == "AUTH=DIGEST-MD5" )
       capa |= Digest_MD5;
+    else if ( cur == "AUTH=GSSAPI" )
+      capa |= GSSAPI;
     else if ( cur == "AUTH=ANONYMOUS" )
       capa |= Anonymous;
     else if ( cur == "STARTTLS" )
@@ -1508,6 +1515,7 @@ void AccountDialog::enableImapAuthMethod
   mImap.authLogin->setEnabled( capa & Login );
   mImap.authCramMd5->setEnabled( capa & CRAM_MD5 );
   mImap.authDigestMd5->setEnabled( capa & Digest_MD5 );
+  mImap.authGSSAPI->setEnabled( capa & GSSAPI );
   mImap.authAnonymous->setEnabled( capa & Anonymous );
 }
 
@@ -1647,6 +1655,8 @@ void AccountDialog::saveSettings()
       epa.setAuth("CRAM-MD5");
     else if (mImap.authDigestMd5->isChecked())
       epa.setAuth("DIGEST-MD5");
+    else if (mImap.authGSSAPI->isChecked())
+      epa.setAuth("GSSAPI");
     else if (mImap.authAnonymous->isChecked())
       epa.setAuth("ANONYMOUS");
     else if (mImap.authLogin->isChecked())
@@ -1698,6 +1708,8 @@ void AccountDialog::saveSettings()
       epa.setAuth("CRAM-MD5");
     else if (mImap.authDigestMd5->isChecked())
       epa.setAuth("DIGEST-MD5");
+    else if (mImap.authGSSAPI->isChecked())
+      epa.setAuth("GSSAPI");
     else if (mImap.authAnonymous->isChecked())
       epa.setAuth("ANONYMOUS");
     else if (mImap.authLogin->isChecked())
Index: kmail/accountdialog.h
===================================================================
RCS file: /home/kde/kdepim/kmail/accountdialog.h,v
retrieving revision 1.46
diff -u -p -u -r1.46 accountdialog.h
--- kmail/accountdialog.h	23 May 2004 22:04:31 -0000	1.46
+++ kmail/accountdialog.h	29 Aug 2004 14:53:36 -0000
@@ -169,6 +169,7 @@ class AccountDialog : public KDialogBase
       QRadioButton *authLogin;
       QRadioButton *authCramMd5;
       QRadioButton *authDigestMd5;
+      QRadioButton *authGSSAPI;
       QRadioButton *authAnonymous;
       QPushButton  *checkCapabilities;
       KMFolderComboBox  *trashCombo;
@@ -237,6 +238,7 @@ class AccountDialog : public KDialogBase
       UIDL       = 256,
       STLS       = 512, // TLS for POP
       STARTTLS   = 512, // TLS for IMAP
+      GSSAPI     = 1024,
       AllCapa    = 0xffffffff
     };
     unsigned int mCurCapa;


_______________________________________________
kde-pim mailing list
kde-pim@mail.kde.org
https://mail.kde.org/mailman/listinfo/kde-pim
kde-pim home page at http://pim.kde.org/

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic