• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kio

kdesasl.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2001-2002 Michael Häckel <haeckel@kde.org>
00003    $Id: kdesasl.cpp 465272 2005-09-29 09:47:40Z mueller $
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License version 2 as published by the Free Software Foundation.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017    Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "kdesasl.h"
00021 
00022 #include <kmdcodec.h>
00023 #include <kurl.h>
00024 
00025 #include <qstrlist.h>
00026 
00027 #include <stdlib.h>
00028 #include <string.h>
00029 
00030 KDESasl::KDESasl(const KURL &aUrl)
00031 {
00032   mProtocol = aUrl.protocol();
00033   mUser = aUrl.user();
00034   mPass = aUrl.pass();
00035   mFirst = true;
00036 }
00037 
00038 KDESasl::KDESasl(const QString &aUser, const QString &aPass,
00039   const QString &aProtocol)
00040 {
00041   mProtocol = aProtocol;
00042   mUser = aUser;
00043   mPass = aPass;
00044   mFirst = true;
00045 }
00046 
00047 KDESasl::~KDESasl() {
00048 }
00049 
00050 QCString KDESasl::chooseMethod(const QStrIList aMethods)
00051 {
00052   if (aMethods.contains("DIGEST-MD5")) mMethod = "DIGEST-MD5";
00053   else if (aMethods.contains("CRAM-MD5")) mMethod = "CRAM-MD5";
00054   else if (aMethods.contains("PLAIN")) mMethod = "PLAIN";
00055   else if (aMethods.contains("LOGIN")) mMethod = "LOGIN";
00056   else mMethod = QCString();
00057   return mMethod;
00058 }
00059 
00060 void KDESasl::setMethod(const QCString &aMethod)
00061 {
00062   mMethod = aMethod.upper();
00063 }
00064 
00065 QByteArray KDESasl::getPlainResponse()
00066 {
00067   QCString user = mUser.utf8();
00068   QCString pass = mPass.utf8();
00069   int userlen = user.length();
00070   int passlen = pass.length();
00071   // result = $user\0$user\0$pass (no trailing \0)
00072   QByteArray result(2 * userlen + passlen + 2);
00073   if ( userlen ) {
00074     memcpy( result.data(), user.data(), userlen );
00075     memcpy( result.data() + userlen + 1, user.data(), userlen );
00076   }
00077   if ( passlen )
00078     memcpy( result.data() + 2 * userlen + 2, pass.data(), passlen );
00079   result[userlen] = result[2*userlen+1] = '\0';
00080   return result;
00081 }
00082 
00083 QByteArray KDESasl::getLoginResponse()
00084 {
00085   QByteArray result = (mFirst) ? mUser.utf8() : mPass.utf8();
00086   mFirst = !mFirst;
00087   if (result.size()) result.resize(result.size() - 1);
00088   return result;
00089 }
00090 
00091 QByteArray KDESasl::getCramMd5Response(const QByteArray &aChallenge)
00092 {
00093   uint i;
00094   QByteArray secret = mPass.utf8();
00095   int len = mPass.utf8().length();
00096   secret.resize(len);
00097   if (secret.size() > 64)
00098   {
00099     KMD5 md5(secret);
00100     secret.duplicate((const char*)(&(md5.rawDigest()[0])), 16);
00101     len = 16;
00102   }
00103   secret.resize(64);
00104   for (i = len; i < 64; i++) secret[i] = 0;
00105   QByteArray XorOpad(64);
00106   for (i = 0; i < 64; i++) XorOpad[i] = secret[i] ^ 0x5C;
00107   QByteArray XorIpad(64);
00108   for (i = 0; i < 64; i++) XorIpad[i] = secret[i] ^ 0x36;
00109   KMD5 md5;
00110   md5.update(XorIpad);
00111   md5.update(aChallenge);
00112   KMD5 md5a;
00113   md5a.update(XorOpad);
00114   md5a.update(md5.rawDigest(), 16);
00115   QByteArray result = mUser.utf8();
00116   len = mUser.utf8().length();
00117   result.resize(len + 33);
00118   result[len] = ' ';
00119   QCString ch = md5a.hexDigest();
00120   for (i = 0; i < 32; i++) result[i+len+1] = *(ch.data() + i);
00121   return result;
00122 }
00123 
00124 QByteArray KDESasl::getDigestMd5Response(const QByteArray &aChallenge)
00125 {
00126   mFirst = !mFirst;
00127   if (mFirst) return QByteArray();
00128   QCString str, realm, nonce, qop, algorithm, charset;
00129   QCString nc = "00000001";
00130   unsigned int a, b, c, d;
00131   a = 0;
00132   while (a < aChallenge.size())
00133   {
00134     b = a;
00135     while (b < aChallenge.size() && aChallenge[b] != '=') b++;
00136     c = b + 1;
00137     if (aChallenge[c] == '"')
00138     {
00139       d = c + 1;
00140       while (d < aChallenge.size() && aChallenge[d] != '"') d++;
00141       c++;
00142     } else {
00143       d = c;
00144       while (d < aChallenge.size() && aChallenge[d] != ',') d++;
00145     }
00146     str = QCString(aChallenge.data() + c, d - c + 1);
00147     if (qstrnicmp(aChallenge.data() + a, "realm=", 6) == 0) realm = str;
00148     else if (qstrnicmp(aChallenge.data() + a, "nonce=", 6) == 0) nonce = str;
00149     else if (qstrnicmp(aChallenge.data() + a, "qop=", 4) == 0) qop = str;
00150     else if (qstrnicmp(aChallenge.data() + a, "algorithm=", 10) == 0)
00151       algorithm = str;
00152     else if (qstrnicmp(aChallenge.data() + a, "charset=", 8) == 0)
00153       charset = str;
00154     a = (d < aChallenge.size() && aChallenge[d] == '"') ? d + 2 : d + 1;
00155   }
00156   if (qop.isEmpty()) qop = "auth";
00157   qop = "auth";
00158   bool utf8 = qstricmp(charset, "utf-8") == 0;
00159   QCString digestUri = QCString(mProtocol.latin1()) + "/" + realm;
00160 
00161   /* Calculate the response */
00162   /* Code based on code from the http io-slave
00163      Copyright (C) 2000,2001 Dawit Alemayehu <adawit@kde.org>
00164      Copyright (C) 2000,2001 Waldo Bastian <bastian@kde.org>
00165      Copyright (C) 2000,2001 George Staikos <staikos@kde.org> */
00166   KMD5 md, md2;
00167   QCString HA1, HA2;
00168   QCString cnonce;
00169   cnonce.setNum((1 + static_cast<int>(100000.0*rand()/(RAND_MAX+1.0))));
00170   cnonce = KCodecs::base64Encode( cnonce );
00171 
00172   // Calculate H(A1)
00173   QCString authStr = (utf8) ? mUser.utf8() : QCString(mUser.latin1());
00174   authStr += ':';
00175   authStr += realm;
00176   authStr += ':';
00177   authStr += (utf8) ? mPass.utf8() : QCString(mPass.latin1());
00178 
00179   md.update( authStr );
00180   authStr = "";
00181   if ( algorithm == "md5-sess" )
00182   {
00183     authStr += ':';
00184     authStr += nonce;
00185     authStr += ':';
00186     authStr += cnonce;
00187   }
00188   md2.reset();
00189   /* SASL authentication uses rawDigest here, whereas HTTP authentication uses
00190      hexDigest() */
00191   md2.update(md.rawDigest(), 16);
00192   md2.update( authStr );
00193   md2.hexDigest( HA1 );
00194 
00195   // Calcualte H(A2)
00196   authStr = "AUTHENTICATE:";
00197   authStr += digestUri;
00198   if ( qop == "auth-int" || qop == "auth-conf" )
00199   {
00200     authStr += ":00000000000000000000000000000000";
00201   }
00202   md.reset();
00203   md.update( authStr );
00204   md.hexDigest( HA2 );
00205 
00206   // Calcualte the response.
00207   authStr = HA1;
00208   authStr += ':';
00209   authStr += nonce;
00210   authStr += ':';
00211   if ( !qop.isEmpty() )
00212   {
00213     authStr += nc;
00214     authStr += ':';
00215     authStr += cnonce;
00216     authStr += ':';
00217     authStr += qop;
00218     authStr += ':';
00219   }
00220   authStr += HA2;
00221   md.reset();
00222   md.update( authStr );
00223   QCString response = md.hexDigest();
00224   /* End of response calculation */
00225 
00226   QCString result;
00227   if (utf8)
00228   {
00229     result = "charset=utf-8,username=\"" + mUser.utf8();
00230   } else {
00231     result = "charset=iso-8859-1,username=\"" + QCString(mUser.latin1());
00232   }
00233   result += "\",realm=\"" + realm + "\",nonce=\"" + nonce;
00234   result += "\",nc=" + nc + ",cnonce=\"" + cnonce;
00235   result += "\",digest-uri=\"" + digestUri;
00236   result += "\",response=" + response + ",qop=" + qop;
00237   QByteArray ba;
00238   ba.duplicate(result.data(), result.length());
00239   return ba;
00240 }
00241 
00242 QByteArray KDESasl::getBinaryResponse(const QByteArray &aChallenge, bool aBase64)
00243 {
00244   if (aBase64)
00245   {
00246     QByteArray ba;
00247     KCodecs::base64Decode(aChallenge, ba);
00248     KCodecs::base64Encode(getBinaryResponse(ba, false), ba);
00249     return ba;
00250   }
00251   if (qstricmp(mMethod, "PLAIN") == 0) return getPlainResponse();
00252   if (qstricmp(mMethod, "LOGIN") == 0) return getLoginResponse();
00253   if (qstricmp(mMethod, "CRAM-MD5") == 0)
00254     return getCramMd5Response(aChallenge);
00255   if (qstricmp(mMethod, "DIGEST-MD5") == 0)
00256     return getDigestMd5Response(aChallenge);
00257 //    return getDigestMd5Response(QCString("realm=\"elwood.innosoft.com\",nonce=\"OA6MG9tEQGm2hh\",qop=\"auth\",algorithm=md5-sess,charset=utf-8"));
00258   return QByteArray();
00259 }
00260 
00261 QCString KDESasl::getResponse(const QByteArray &aChallenge, bool aBase64)
00262 {
00263   QByteArray ba = getBinaryResponse(aChallenge, aBase64);
00264   return QCString(ba.data(), ba.size() + 1);
00265 }
00266 
00267 QCString KDESasl::method() const {
00268   return mMethod;
00269 }
00270 
00271 bool KDESasl::clientStarts() const {
00272   return method() == "PLAIN";
00273 }
00274 
00275 bool KDESasl::dialogComplete( int n ) const {
00276   if ( method() == "PLAIN" || method() == "CRAM-MD5" )
00277     return n >= 1;
00278   if ( method() == "LOGIN" || method() == "DIGEST-MD5" )
00279     return n >= 2;
00280   return true;
00281 }
00282 
00283 bool KDESasl::isClearTextMethod() const {
00284   return method() == "PLAIN" || method() == "LOGIN" ;
00285 }

kio

Skip menu "kio"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal