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

kio

kssl.cc

Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002  *
00003  * Copyright (C) 2000-2003 George Staikos <staikos@kde.org>
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 as published by the Free Software Foundation; either
00008  * version 2 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Library General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Library General Public License
00016  * along with this library; see the file COPYING.LIB.  If not, write to
00017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019  */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #include <config.h>
00023 #endif
00024 
00025 // this hack provided by Malte Starostik to avoid glibc/openssl bug
00026 // on some systems
00027 #ifdef KSSL_HAVE_SSL
00028 #include <unistd.h>
00029 #include <netinet/in.h>
00030 #include <sys/socket.h>
00031 #define crypt _openssl_crypt
00032 #include <openssl/ssl.h>
00033 #include <openssl/x509.h>
00034 #include <openssl/x509v3.h>
00035 #include <openssl/pem.h>
00036 #include <openssl/rand.h>
00037 #undef crypt
00038 #endif
00039 
00040 #include "kssl.h"
00041 
00042 #include <kdebug.h>
00043 #include <kstandarddirs.h>
00044 #include <ksock.h>
00045 #include <ksockaddr.h>
00046 
00047 #include <kopenssl.h>
00048 #include <ksslx509v3.h>
00049 #include <ksslpkcs12.h>
00050 #include <ksslsession.h>
00051 #include <klocale.h>
00052 #include <ksocks.h>
00053 
00054 #define sk_dup d->kossl->sk_dup
00055 
00056 class KSSLPrivate {
00057 public:
00058     KSSLPrivate() {
00059         lastInitTLS = false;
00060         kossl = KOpenSSLProxy::self();
00061         session = 0L;
00062     }
00063 
00064     ~KSSLPrivate() {
00065         delete session;
00066         session = 0L;
00067     }
00068 
00069     bool lastInitTLS;
00070     KSSLCertificate::KSSLValidation m_cert_vfy_res;
00071     QString proxyPeer;
00072 
00073 #ifdef KSSL_HAVE_SSL
00074     SSL *m_ssl;
00075     SSL_CTX *m_ctx;
00076     SSL_METHOD *m_meth;
00077 #endif
00078     KSSLSession *session;
00079     KOSSL *kossl;
00080 };
00081 
00082 
00083 KSSL::KSSL(bool init) {
00084     d = new KSSLPrivate;
00085     m_bInit = false;
00086     m_bAutoReconfig = true;
00087     m_cfg = new KSSLSettings();
00088 #ifdef KSSL_HAVE_SSL  
00089     d->m_ssl = 0L;
00090 #endif  
00091 
00092     if (init)
00093         initialize();
00094 }
00095 
00096 
00097 KSSL::~KSSL() {
00098     close();
00099     delete m_cfg;
00100     delete d;
00101 }
00102 
00103 
00104 int KSSL::seedWithEGD() {
00105 int rc = 0;
00106 #ifdef KSSL_HAVE_SSL
00107     if (m_cfg->useEGD() && !m_cfg->getEGDPath().isEmpty()) {
00108         rc = d->kossl->RAND_egd(m_cfg->getEGDPath().latin1());
00109         if (rc < 0) 
00110             kdDebug(7029) << "KSSL: Error seeding PRNG with the EGD." << endl;
00111         else kdDebug(7029) << "KSSL: PRNG was seeded with " << rc 
00112                    << " bytes from the EGD." << endl;
00113     } else if (m_cfg->useEFile() && !m_cfg->getEGDPath().isEmpty()) {
00114         rc = d->kossl->RAND_load_file(m_cfg->getEGDPath().latin1(), -1);
00115         if (rc < 0) 
00116             kdDebug(7029) << "KSSL: Error seeding PRNG with the entropy file." << endl;
00117         else kdDebug(7029) << "KSSL: PRNG was seeded with " << rc 
00118                    << " bytes from the entropy file." << endl;
00119     }
00120 #endif
00121 return rc;
00122 }
00123 
00124 
00125 bool KSSL::TLSInit() {
00126 #ifdef KSSL_HAVE_SSL
00127 // kdDebug(7029) << "KSSL TLS initialize" << endl;
00128     if (m_bInit)
00129         return false;
00130 
00131     if (m_bAutoReconfig)
00132         m_cfg->load();
00133 
00134     if (!m_cfg->tlsv1())
00135         return false;
00136 
00137     seedWithEGD();
00138     d->m_meth = d->kossl->TLSv1_client_method();
00139     d->lastInitTLS = true;
00140 
00141     m_pi.reset();
00142 
00143     d->m_ctx = d->kossl->SSL_CTX_new(d->m_meth);
00144     if (d->m_ctx == 0L) {
00145         return false;
00146     }
00147 
00148     // set cipher list
00149     QString clist = m_cfg->getCipherList();
00150     //kdDebug(7029) << "Cipher list: " << clist << endl;
00151     if (!clist.isEmpty())
00152         d->kossl->SSL_CTX_set_cipher_list(d->m_ctx, const_cast<char *>(clist.ascii()));
00153 
00154     m_bInit = true;
00155 return true;
00156 #else
00157 return false;
00158 #endif
00159 }
00160 
00161 
00162 bool KSSL::initialize() {
00163 #ifdef KSSL_HAVE_SSL
00164     kdDebug(7029) << "KSSL initialize" << endl;
00165     if (m_bInit)
00166         return false;
00167 
00168     if (m_bAutoReconfig)
00169         m_cfg->load();
00170 
00171     seedWithEGD();
00172     // FIXME: we should be able to force SSL off entirely.
00173     d->lastInitTLS = false;
00174 
00175     m_pi.reset();
00176 
00177     if (!m_cfg->tlsv1() && !m_cfg->sslv3() && m_cfg->sslv2())
00178         d->m_meth = d->kossl->SSLv2_client_method();
00179         else if (m_cfg->tlsv1() && !m_cfg->sslv3() && !m_cfg->sslv2())
00180         d->m_meth = d->kossl->TLSv1_client_method();
00181     else if (!m_cfg->tlsv1() && m_cfg->sslv3() && !m_cfg->sslv2())
00182         d->m_meth = d->kossl->SSLv3_client_method();
00183     else d->m_meth = d->kossl->SSLv23_client_method();
00184 
00185 /*
00186 if (m_cfg->sslv2() && m_cfg->sslv3()) kdDebug(7029) << "Double method" << endl;
00187 else if (m_cfg->sslv2()) kdDebug(7029) << "SSL2 method" << endl;
00188 else if (m_cfg->sslv3()) kdDebug(7029) << "SSL3 method" << endl;
00189 */
00190 
00191     d->m_ctx = d->kossl->SSL_CTX_new(d->m_meth);
00192     if (d->m_ctx == 0L) {
00193         return false;
00194     }
00195 
00196     // set cipher list
00197     QString clist = m_cfg->getCipherList();
00198     kdDebug(7029) << "Cipher list: " << clist << endl;
00199     if (!clist.isEmpty())
00200         d->kossl->SSL_CTX_set_cipher_list(d->m_ctx, const_cast<char *>(clist.ascii()));
00201 
00202     m_bInit = true;
00203 return true;
00204 #else
00205 return false;
00206 #endif
00207 }
00208 
00209 
00210 bool KSSL::setSession(const KSSLSession *session) {
00211 #ifdef KSSL_HAVE_SSL
00212     if (!session) {
00213         delete d->session;
00214         d->session = 0L;
00215         return true;
00216     }
00217 
00218     // Obtain a reference by incrementing the reference count.  Yuck.
00219     static_cast<SSL_SESSION*>(session->_session)->references++;
00220 
00221     d->session = new KSSLSession;
00222     d->session->_session = session->_session;
00223 
00224     return true;
00225 #else
00226     return false;
00227 #endif
00228 }
00229 
00230 
00231 void KSSL::close() {
00232 #ifdef KSSL_HAVE_SSL
00233 //kdDebug(7029) << "KSSL close" << endl;
00234     if (!m_bInit)
00235         return;
00236 
00237     delete d->session;
00238     d->session = 0L;
00239 
00240     if (d->m_ssl) {
00241         d->kossl->SSL_shutdown(d->m_ssl);
00242         d->kossl->SSL_free(d->m_ssl);
00243         d->m_ssl = 0L;
00244     }
00245 
00246     d->kossl->SSL_CTX_free(d->m_ctx);
00247     if (m_cfg->useEFile() && !m_cfg->getEGDPath().isEmpty()) {
00248         d->kossl->RAND_write_file(m_cfg->getEGDPath().latin1());
00249     }
00250 
00251     m_bInit = false;
00252 #endif
00253 }
00254 
00255 
00256 bool KSSL::reInitialize() {
00257     close();
00258 return initialize();
00259 }
00260 
00261 // get the callback file - it's hidden away in here
00262 //#include "ksslcallback.c"
00263 
00264 
00265 bool KSSL::setVerificationLogic() {
00266 #if 0
00267 #ifdef KSSL_HAVE_SSL
00268   //  SSL_set_verify_result(d->m_ssl, X509_V_OK);
00269   //  SSL_CTX_set_verify(d->m_ctx, SSL_VERIFY_PEER, X509Callback);
00270 #endif
00271 #endif
00272 return true;
00273 }
00274 
00275 
00276 int KSSL::accept(int sock) {
00277 #ifdef KSSL_HAVE_SSL
00278 // kdDebug(7029) << "KSSL accept" << endl;
00279 int rc;
00280     if (!m_bInit)
00281         return -1;
00282     d->m_ssl = d->kossl->SSL_new(d->m_ctx);
00283     if (!d->m_ssl)
00284         return -1;
00285 
00286     if (d->session) {
00287         if (static_cast<SSL_SESSION*>(d->session->_session)->sess_cert == 0)
00288         {
00289             kdDebug(7029) << "Can't reuse session, no certificate." << endl;
00290             delete d->session;
00291             d->session = 0;
00292         } else if (1 == d->kossl->SSL_set_session(d->m_ssl,
00293             static_cast<SSL_SESSION*>(d->session->_session))) {
00294             kdDebug(7029) << "Session ID is being reused." << endl;
00295         } else {
00296             kdDebug(7029) << "Error attempting to reuse session." << endl;
00297             delete d->session;
00298             d->session = 0;
00299         }
00300     }
00301 
00302 /*
00303     if (!setVerificationLogic()) {
00304         d->kossl->SSL_shutdown(d->m_ssl);
00305         d->kossl->SSL_free(d->m_ssl);
00306         d->m_ssl = 0;
00307         return -1;
00308     }
00309 */
00310 
00311     int off = SSL_OP_ALL;
00312     if (!d->lastInitTLS && !m_cfg->tlsv1())
00313         off |= SSL_OP_NO_TLSv1;
00314     if (!m_cfg->sslv3())
00315         off |= SSL_OP_NO_SSLv3;
00316     if (!m_cfg->sslv2())
00317         off |= SSL_OP_NO_SSLv2;
00318 
00319     d->kossl->SSL_set_options(d->m_ssl, off);
00320 
00321     rc = d->kossl->SSL_set_fd(d->m_ssl, sock);
00322     if (rc == 0) {
00323         d->kossl->SSL_shutdown(d->m_ssl);
00324         d->kossl->SSL_free(d->m_ssl);
00325         d->m_ssl = 0;
00326         return rc;
00327     }
00328 
00329     rc = d->kossl->SSL_accept(d->m_ssl);
00330     if (rc == 1) {
00331         setConnectionInfo();
00332         setPeerInfo();
00333         kdDebug(7029) << "KSSL connected OK" << endl;
00334     } else {
00335         kdDebug(7029) << "KSSL accept failed - rc = " << rc << endl;
00336         kdDebug(7029) << "                      ERROR = "
00337                   << d->kossl->SSL_get_error(d->m_ssl, rc) << endl;
00338         d->kossl->SSL_shutdown(d->m_ssl);
00339         d->kossl->SSL_free(d->m_ssl);
00340         d->m_ssl = 0;
00341         return -1;
00342     }
00343 
00344     if (!d->kossl->SSL_session_reused(d->m_ssl)) {
00345         if (d->session) {
00346             kdDebug(7029) << "Session reuse failed.  New session used instead." << endl;
00347             delete d->session;
00348             d->session = 0L;
00349         }
00350     }
00351 
00352     if (!d->session) {
00353         SSL_SESSION *sess = d->kossl->SSL_get1_session(d->m_ssl);
00354         if (sess) {
00355             d->session = new KSSLSession;
00356             d->session->_session = sess;
00357         }
00358     }
00359 
00360 return rc;
00361 #else
00362 return -1;
00363 #endif
00364 }
00365 
00366 
00367 int KSSL::connect(int sock) {
00368 #ifdef KSSL_HAVE_SSL
00369 // kdDebug(7029) << "KSSL connect" << endl;
00370 int rc;
00371     if (!m_bInit)
00372         return -1;
00373     d->m_ssl = d->kossl->SSL_new(d->m_ctx);
00374     if (!d->m_ssl)
00375         return -1;
00376 
00377     if (d->session) {
00378         if (static_cast<SSL_SESSION*>(d->session->_session)->sess_cert == 0)
00379         {
00380             kdDebug(7029) << "Can't reuse session, no certificate." << endl;
00381             delete d->session;
00382             d->session = 0;
00383         } else if (1 == d->kossl->SSL_set_session(d->m_ssl,
00384             static_cast<SSL_SESSION*>(d->session->_session))) {
00385             kdDebug(7029) << "Session ID is being reused." << endl;
00386         } else {
00387             kdDebug(7029) << "Error attempting to reuse session." << endl;
00388             delete d->session;
00389             d->session = 0;
00390         }
00391     }
00392 
00393 /*
00394     if (!setVerificationLogic()) {
00395         d->kossl->SSL_shutdown(d->m_ssl);
00396         d->kossl->SSL_free(d->m_ssl);
00397         d->m_ssl = 0;
00398         return -1;
00399     }
00400 */
00401 
00402     int off = SSL_OP_ALL;
00403     if (!d->lastInitTLS && !m_cfg->tlsv1())
00404         off |= SSL_OP_NO_TLSv1;
00405     if (!m_cfg->sslv3())
00406         off |= SSL_OP_NO_SSLv3;
00407     if (!m_cfg->sslv2())
00408         off |= SSL_OP_NO_SSLv2;
00409 
00410     d->kossl->SSL_set_options(d->m_ssl, off);
00411 
00412     rc = d->kossl->SSL_set_fd(d->m_ssl, sock);
00413     if (rc == 0) {
00414         d->kossl->SSL_shutdown(d->m_ssl);
00415         d->kossl->SSL_free(d->m_ssl);
00416         d->m_ssl = 0;
00417         return rc;
00418     }
00419 
00420 connect_again:
00421     rc = d->kossl->SSL_connect(d->m_ssl);
00422     if (rc == 1) {
00423         setConnectionInfo();
00424         setPeerInfo();
00425         kdDebug(7029) << "KSSL connected OK" << endl;
00426     } else {
00427         int err = d->kossl->SSL_get_error(d->m_ssl, rc);
00428         if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
00429             // nonblocking - but we block anyways in connect() :)
00430             goto connect_again;
00431         } else {
00432             kdDebug(7029) << "KSSL connect failed - rc = "
00433                 << rc << endl;
00434             kdDebug(7029) << "                   ERROR = "
00435                 << err << endl;
00436             d->kossl->ERR_print_errors_fp(stderr);
00437             d->kossl->SSL_shutdown(d->m_ssl);
00438             d->kossl->SSL_free(d->m_ssl);
00439             d->m_ssl = 0;
00440             return -1;
00441         }
00442     }
00443 
00444     if (!d->kossl->SSL_session_reused(d->m_ssl)) {
00445         if (d->session) {
00446             kdDebug(7029) << "Session reuse failed.  New session used instead." << endl;
00447             delete d->session;
00448             d->session = 0L;
00449         }
00450     }
00451 
00452     if (!d->session) {
00453         SSL_SESSION *sess = d->kossl->SSL_get1_session(d->m_ssl);
00454         if (sess) {
00455             d->session = new KSSLSession;
00456             d->session->_session = sess;
00457         }
00458     }
00459 
00460 return rc;
00461 #else
00462 return -1;
00463 #endif
00464 }
00465 
00466 
00467 int KSSL::pending() {
00468 #ifdef KSSL_HAVE_SSL
00469     if (!m_bInit)
00470         return -1;
00471 return d->kossl->SSL_pending(d->m_ssl);
00472 #else
00473 return -1;
00474 #endif
00475 }
00476 
00477 
00478 int KSSL::peek(void *buf, int len) {
00479 #ifdef KSSL_HAVE_SSL
00480     if (!m_bInit)
00481         return -1;
00482     // FIXME: enhance to work the way read() does below, handling errors
00483 return d->kossl->SSL_peek(d->m_ssl, buf, len);
00484 #else
00485 return -1;
00486 #endif
00487 }
00488 
00489 
00490 int KSSL::read(void *buf, int len) {
00491 #ifdef KSSL_HAVE_SSL
00492     int rc = 0;
00493     int maxIters = 10;
00494 
00495     if (!m_bInit)
00496         return -1;
00497 
00498 read_again:
00499     rc = d->kossl->SSL_read(d->m_ssl, (char *)buf, len);
00500     if (rc <= 0) {
00501         int err = d->kossl->SSL_get_error(d->m_ssl, rc);
00502 
00503         if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
00504             kdDebug(7029) << "SSL read() returning 0: " << err << endl;
00505             if (maxIters-- > 0) {
00506                 ::usleep(20000); // 20ms sleep
00507                 goto read_again;
00508             }
00509             return 0;
00510         }
00511 
00512         kdDebug(7029) << "SSL READ ERROR: " << err << endl;
00513         if (err != SSL_ERROR_NONE &&
00514             err != SSL_ERROR_ZERO_RETURN && err != SSL_ERROR_SYSCALL) {
00515             rc = -1;      // OpenSSL returns 0 on error too
00516             d->kossl->ERR_print_errors_fp(stderr);
00517         }
00518 
00519 //      else if (err == SSL_ERROR_ZERO_RETURN)
00520 //          rc = 0;
00521     }
00522 return rc;
00523 #else
00524 return -1;
00525 #endif
00526 }
00527 
00528 
00529 int KSSL::write(const void *buf, int len) {
00530 #ifdef KSSL_HAVE_SSL
00531     if (!m_bInit)
00532         return -1;
00533 
00534 write_again:
00535     int rc = d->kossl->SSL_write(d->m_ssl, (const char *)buf, len);
00536     if (rc <= 0) {      // OpenSSL returns 0 on error too
00537         int err = d->kossl->SSL_get_error(d->m_ssl, rc);
00538 
00539         if (err == SSL_ERROR_WANT_WRITE) {
00540             ::usleep(20000); // 20ms sleep
00541             goto write_again;
00542         }
00543 
00544         kdDebug(7029) << "SSL WRITE ERROR: " << err << endl;
00545         if (err != SSL_ERROR_NONE &&
00546             err != SSL_ERROR_ZERO_RETURN && err != SSL_ERROR_SYSCALL)
00547             rc = -1;
00548     }
00549 
00550 return rc;
00551 #else
00552 return -1;
00553 #endif
00554 }
00555 
00556 
00557 bool KSSL::reconfig() {
00558     return reInitialize();
00559 }
00560 
00561 
00562 void KSSL::setAutoReconfig(bool ar) {
00563     m_bAutoReconfig = ar;
00564 }
00565 
00566 
00567 bool KSSL::setSettings(KSSLSettings *settings) {
00568     delete m_cfg;
00569     m_cfg = settings;
00570     return reconfig();
00571 }
00572 
00573 
00574 #ifdef KSSL_HAVE_SSL
00575 bool KSSL::m_bSSLWorks = true;
00576 #else
00577 bool KSSL::m_bSSLWorks = false;
00578 #endif
00579 
00580 bool KSSL::doesSSLWork() {
00581     return m_bSSLWorks;
00582 }
00583 
00584 
00585 void KSSL::setConnectionInfo() {
00586 #ifdef KSSL_HAVE_SSL
00587 SSL_CIPHER *sc;
00588 char buf[1024];
00589 
00590     buf[0] = 0;  // for safety.
00591     sc = d->kossl->SSL_get_current_cipher(d->m_ssl);
00592     if (!sc) {
00593         kdDebug(7029) << "KSSL get current cipher failed - we're probably gonna crash!" << endl;
00594         return;
00595     }
00596 
00597     // set the number of bits, bits used
00598     m_ci.m_iCipherUsedBits = d->kossl->SSL_CIPHER_get_bits(sc, &(m_ci.m_iCipherBits));
00599     // set the cipher version
00600     m_ci.m_cipherVersion = d->kossl->SSL_CIPHER_get_version(sc);
00601     // set the cipher name
00602     m_ci.m_cipherName = d->kossl->SSL_CIPHER_get_name(sc);
00603     // set the cipher description
00604     m_ci.m_cipherDescription = d->kossl->SSL_CIPHER_description(sc, buf, 1023);
00605 
00606 #endif
00607 }
00608 
00609 
00610 void KSSL::setPeerInfo() {
00611 #ifdef KSSL_HAVE_SSL
00612     m_pi.setPeerHost(d->proxyPeer);
00613     m_pi.m_cert.setCert(d->kossl->SSL_get_peer_certificate(d->m_ssl));
00614     STACK_OF(X509) *xs = d->kossl->SSL_get_peer_cert_chain(d->m_ssl);
00615     if (xs)
00616         xs = sk_X509_dup(xs);   // Leak? 
00617     m_pi.m_cert.setChain((void *)xs);
00618 #endif
00619 }
00620 
00621 
00622 KSSLConnectionInfo& KSSL::connectionInfo() {
00623     return m_ci;
00624 }
00625 
00626 
00627 // KDE 4: Make it const QString &
00628 void KSSL::setPeerHost(QString realHost) {
00629     d->proxyPeer = realHost;
00630 }
00631 
00632 // deprecated
00633 void KSSL::setProxyUse(bool, QString, int, QString) {
00634 }
00635 
00636 
00637 KSSLPeerInfo& KSSL::peerInfo() {
00638     return m_pi;
00639 }
00640 
00641 
00642 bool KSSL::setClientCertificate(KSSLPKCS12 *pkcs) {
00643 #ifdef KSSL_HAVE_SSL
00644     if (!pkcs || !pkcs->getCertificate())
00645         return false;
00646 
00647 int rc;
00648 X509 *x = pkcs->getCertificate()->getCert();
00649 EVP_PKEY *k = pkcs->getPrivateKey();
00650 
00651     if (!x || !k) return false;
00652 
00653     if (!pkcs->getCertificate()->x509V3Extensions().certTypeSSLClient())
00654         return false;
00655 
00656     rc = d->kossl->SSL_CTX_use_certificate(d->m_ctx, x);
00657     if (rc <= 0) {
00658         kdDebug(7029) << "KSSL - SSL_CTX_use_certificate failed.  rc = " << rc << endl;
00659         return false;
00660     }
00661 
00662     rc = d->kossl->SSL_CTX_use_PrivateKey(d->m_ctx, k);
00663     if (rc <= 0) {
00664         kdDebug(7029) << "KSSL - SSL_CTX_use_PrivateKey failed.  rc = " << rc << endl;
00665         return false;
00666     }
00667 
00668     return true;
00669 #else
00670     return false;
00671 #endif
00672 }
00673 
00674 #undef sk_dup
00675 
00676 const KSSLSession* KSSL::session() const {
00677     return d->session;
00678 }
00679 
00680 bool KSSL::reusingSession() const {
00681 #ifdef KSSL_HAVE_SSL
00682     return (d->m_ssl && d->kossl->SSL_session_reused(d->m_ssl));
00683 #else
00684     return false;
00685 #endif
00686 }
00687 
00688 

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