• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kio/kio
 

kio/kio

  • kio
  • kio
tcpslavebase.cpp
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2000 Alex Zepeda <zipzippy@sonic.net
5  * Copyright (C) 2001-2003 George Staikos <staikos@kde.org>
6  * Copyright (C) 2001 Dawit Alemayehu <adawit@kde.org>
7  *
8  * This file is part of the KDE project
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB. If not, write to
22  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  */
25 
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29 
30 #include <sys/types.h>
31 #include <sys/uio.h>
32 #include <sys/time.h>
33 #include <sys/socket.h>
34 
35 #include <netinet/in.h>
36 
37 #include <time.h>
38 #include <netdb.h>
39 #include <unistd.h>
40 #include <errno.h>
41 
42 #include <ksocks.h>
43 #include <kdebug.h>
44 #include <ksslall.h>
45 #include <ksslcertdlg.h>
46 #include <kmessagebox.h>
47 #ifndef Q_WS_WIN //temporary
48 #include <kresolver.h>
49 #endif
50 
51 #include <klocale.h>
52 #include <dcopclient.h>
53 #include <tqcstring.h>
54 #include <tqdatastream.h>
55 
56 #include <kapplication.h>
57 
58 #include <kprotocolmanager.h>
59 #include <kde_file.h>
60 
61 #include "kio/tcpslavebase.h"
62 
63 using namespace KIO;
64 
65 class TCPSlaveBase::TcpSlaveBasePrivate
66 {
67 public:
68 
69  TcpSlaveBasePrivate() : rblockSz(256), militantSSL(false), userAborted(false) {}
70  ~TcpSlaveBasePrivate() {}
71 
72  KSSL *kssl;
73  bool usingTLS;
74  KSSLCertificateCache *cc;
75  TQString host;
76  TQString realHost;
77  TQString ip;
78  DCOPClient *dcc;
79  KSSLPKCS12 *pkcs;
80 
81  int status;
82  int timeout;
83  int rblockSz; // Size for reading blocks in readLine()
84  bool block;
85  bool useSSLTunneling;
86  bool needSSLHandShake;
87  bool militantSSL; // If true, we just drop a connection silently
88  // if SSL certificate check fails in any way.
89  bool userAborted;
90  MetaData savedMetaData;
91 };
92 
93 
94 TCPSlaveBase::TCPSlaveBase(unsigned short int defaultPort,
95  const TQCString &protocol,
96  const TQCString &poolSocket,
97  const TQCString &appSocket)
98  :SlaveBase (protocol, poolSocket, appSocket),
99  m_iSock(-1),
100  m_iDefaultPort(defaultPort),
101  m_sServiceName(protocol),
102  fp(0)
103 {
104  // We have to have two constructors, so don't add anything
105  // else in here. Put it in doConstructorStuff() instead.
106  doConstructorStuff();
107  m_bIsSSL = false;
108 }
109 
110 TCPSlaveBase::TCPSlaveBase(unsigned short int defaultPort,
111  const TQCString &protocol,
112  const TQCString &poolSocket,
113  const TQCString &appSocket,
114  bool useSSL)
115  :SlaveBase (protocol, poolSocket, appSocket),
116  m_iSock(-1),
117  m_bIsSSL(useSSL),
118  m_iDefaultPort(defaultPort),
119  m_sServiceName(protocol),
120  fp(0)
121 {
122  doConstructorStuff();
123  if (useSSL)
124  m_bIsSSL = initializeSSL();
125 }
126 
127 // The constructor procedures go here now.
128 void TCPSlaveBase::doConstructorStuff()
129 {
130  d = new TcpSlaveBasePrivate;
131  d->kssl = 0L;
132  d->ip = "";
133  d->cc = 0L;
134  d->usingTLS = false;
135  d->dcc = 0L;
136  d->pkcs = 0L;
137  d->status = -1;
138  d->timeout = KProtocolManager::connectTimeout();
139  d->block = false;
140  d->useSSLTunneling = false;
141 }
142 
143 TCPSlaveBase::~TCPSlaveBase()
144 {
145  cleanSSL();
146  if (d->usingTLS) delete d->kssl;
147  if (d->dcc) delete d->dcc;
148  if (d->pkcs) delete d->pkcs;
149  delete d;
150 }
151 
152 ssize_t TCPSlaveBase::write(const void *data, ssize_t len)
153 {
154 #ifdef Q_OS_UNIX
155  if ( (m_bIsSSL || d->usingTLS) && !d->useSSLTunneling )
156  {
157  if ( d->needSSLHandShake )
158  (void) doSSLHandShake( true );
159  return d->kssl->write(data, len);
160  }
161  return KSocks::self()->write(m_iSock, data, len);
162 #else
163  return 0;
164 #endif
165 }
166 
167 ssize_t TCPSlaveBase::read(void *data, ssize_t len)
168 {
169 #ifdef Q_OS_UNIX
170  if ( (m_bIsSSL || d->usingTLS) && !d->useSSLTunneling )
171  {
172  if ( d->needSSLHandShake )
173  (void) doSSLHandShake( true );
174  return d->kssl->read(data, len);
175  }
176  return KSocks::self()->read(m_iSock, data, len);
177 #else
178  return 0;
179 #endif
180 }
181 
182 
183 void TCPSlaveBase::setBlockSize(int sz)
184 {
185  if (sz <= 0)
186  sz = 1;
187 
188  d->rblockSz = sz;
189 }
190 
191 
192 ssize_t TCPSlaveBase::readLine(char *data, ssize_t len)
193 {
194 // Optimization:
195 // It's small, but it probably results in a gain on very high
196 // speed connections. I moved 3 if statements out of the while loop
197 // so that the while loop is as small as possible. (GS)
198 
199  // let's not segfault!
200  if (!data)
201  return -1;
202 
203  char tmpbuf[1024]; // 1kb temporary buffer for peeking
204  *data = 0;
205  ssize_t clen = 0;
206  char *buf = data;
207  int rc = 0;
208 
209 if ((m_bIsSSL || d->usingTLS) && !d->useSSLTunneling) { // SSL CASE
210  if ( d->needSSLHandShake )
211  (void) doSSLHandShake( true );
212 
213  while (clen < len-1) {
214  rc = d->kssl->pending();
215  if (rc > 0) { // Read a chunk
216  int bytes = rc;
217  if (bytes > d->rblockSz)
218  bytes = d->rblockSz;
219 
220  rc = d->kssl->peek(tmpbuf, bytes);
221  if (rc <= 0) {
222  // FIXME: this doesn't cover rc == 0 case
223  return -1;
224  }
225 
226  bytes = rc; // in case it contains no \n
227  for (int i = 0; i < rc; i++) {
228  if (tmpbuf[i] == '\n') {
229  bytes = i+1;
230  break;
231  }
232  }
233 
234  if (bytes+clen >= len) // don't read too much!
235  bytes = len - clen - 1;
236 
237  rc = d->kssl->read(buf, bytes);
238  if (rc > 0) {
239  clen += rc;
240  buf += (rc-1);
241  if (*buf++ == '\n')
242  break;
243  } else {
244  // FIXME: different case if rc == 0;
245  return -1;
246  }
247  } else { // Read a byte
248  rc = d->kssl->read(buf, 1);
249  if (rc <= 0) {
250  return -1;
251  // hm rc = 0 then
252  // SSL_read says to call SSL_get_error to see if
253  // this was an error. FIXME
254  } else {
255  clen++;
256  if (*buf++ == '\n')
257  break;
258  }
259  }
260  }
261 } else { // NON SSL CASE
262  while (clen < len-1) {
263 #ifdef Q_OS_UNIX
264  rc = KSocks::self()->read(m_iSock, buf, 1);
265 #else
266  rc = 0;
267 #endif
268  if (rc <= 0) {
269  // FIXME: this doesn't cover rc == 0 case
270  return -1;
271  } else {
272  clen++;
273  if (*buf++ == '\n')
274  break;
275  }
276  }
277 }
278 
279  // Both cases fall through to here
280  *buf = 0;
281 return clen;
282 }
283 
284 unsigned short int TCPSlaveBase::port(unsigned short int _p)
285 {
286  unsigned short int p = _p;
287 
288  if (_p <= 0)
289  {
290  p = m_iDefaultPort;
291  }
292 
293  return p;
294 }
295 
296 // This function is simply a wrapper to establish the connection
297 // to the server. It's a bit more complicated than ::connect
298 // because we first have to check to see if the user specified
299 // a port, and if so use it, otherwise we check to see if there
300 // is a port specified in /etc/services, and if so use that
301 // otherwise as a last resort use the supplied default port.
302 bool TCPSlaveBase::connectToHost( const TQString &host,
303  unsigned int _port,
304  bool sendError )
305 {
306 #ifdef Q_OS_UNIX
307  unsigned short int p;
308  KExtendedSocket ks;
309 
310  d->userAborted = false;
311 
312  // - leaving SSL - warn before we even connect
313  if (metaData("main_frame_request") == "TRUE" &&
314  metaData("ssl_activate_warnings") == "TRUE" &&
315  metaData("ssl_was_in_use") == "TRUE" &&
316  !m_bIsSSL) {
317  KSSLSettings kss;
318  if (kss.warnOnLeave()) {
319  int result = messageBox( i18n("You are about to leave secure "
320  "mode. Transmissions will no "
321  "longer be encrypted.\nThis "
322  "means that a third party could "
323  "observe your data in transit."),
324  WarningContinueCancel,
325  i18n("Security Information"),
326  i18n("C&ontinue Loading"), TQString::null,
327  "WarnOnLeaveSSLMode" );
328 
329  // Move this setting into KSSL instead
330  KConfig *config = new KConfig("kioslaverc");
331  config->setGroup("Notification Messages");
332 
333  if (!config->readBoolEntry("WarnOnLeaveSSLMode", true)) {
334  config->deleteEntry("WarnOnLeaveSSLMode");
335  config->sync();
336  kss.setWarnOnLeave(false);
337  kss.save();
338  }
339  delete config;
340 
341  if ( result == KMessageBox::Cancel ) {
342  d->userAborted = true;
343  return false;
344  }
345  }
346  }
347 
348  d->status = -1;
349  d->host = host;
350  d->needSSLHandShake = m_bIsSSL;
351  p = port(_port);
352  ks.setAddress(host, p);
353  if ( d->timeout > -1 )
354  ks.setTimeout( d->timeout );
355 
356  if (ks.connect() < 0)
357  {
358  d->status = ks.status();
359  if ( sendError )
360  {
361  if (d->status == IO_LookupError)
362  error( ERR_UNKNOWN_HOST, host);
363  else if ( d->status != -1 )
364  error( ERR_COULD_NOT_CONNECT, host);
365  }
366  return false;
367  }
368 
369  m_iSock = ks.fd();
370 
371  // store the IP for later
372  const KSocketAddress *sa = ks.peerAddress();
373  if (sa)
374  d->ip = sa->nodeName();
375  else
376  d->ip = "";
377 
378  ks.release(); // KExtendedSocket no longer applicable
379 
380  if ( d->block != ks.blockingMode() )
381  ks.setBlockingMode( d->block );
382 
383  m_iPort=p;
384 
385  if (m_bIsSSL && !d->useSSLTunneling) {
386  if ( !doSSLHandShake( sendError ) )
387  return false;
388  }
389  else
390  setMetaData("ssl_in_use", "FALSE");
391 
392  // Since we want to use stdio on the socket,
393  // we must fdopen it to get a file pointer,
394  // if it fails, close everything up
395  if ((fp = KDE_fdopen(m_iSock, "w+")) == 0) {
396  closeDescriptor();
397  return false;
398  }
399 
400  return true;
401 #else
402  return false;
403 #endif //Q_OS_UNIX
404 }
405 
406 void TCPSlaveBase::closeDescriptor()
407 {
408  stopTLS();
409  if (fp) {
410  fclose(fp);
411  fp=0;
412  m_iSock=-1;
413  if (m_bIsSSL)
414  d->kssl->close();
415  }
416  if (m_iSock != -1) {
417  close(m_iSock);
418  m_iSock=-1;
419  }
420  d->ip = "";
421  d->host = "";
422 }
423 
424 bool TCPSlaveBase::initializeSSL()
425 {
426  if (m_bIsSSL) {
427  if (KSSL::doesSSLWork()) {
428  d->kssl = new KSSL;
429  return true;
430  }
431  }
432 return false;
433 }
434 
435 void TCPSlaveBase::cleanSSL()
436 {
437  delete d->cc;
438 
439  if (m_bIsSSL) {
440  delete d->kssl;
441  d->kssl = 0;
442  }
443  d->militantSSL = false;
444 }
445 
446 bool TCPSlaveBase::atEnd()
447 {
448  return feof(fp);
449 }
450 
451 int TCPSlaveBase::startTLS()
452 {
453  if (d->usingTLS || d->useSSLTunneling || m_bIsSSL || !KSSL::doesSSLWork())
454  return false;
455 
456  d->kssl = new KSSL(false);
457  if (!d->kssl->TLSInit()) {
458  delete d->kssl;
459  return -1;
460  }
461 
462  if ( !d->realHost.isEmpty() )
463  {
464  kdDebug(7029) << "Setting real hostname: " << d->realHost << endl;
465  d->kssl->setPeerHost(d->realHost);
466  } else {
467  kdDebug(7029) << "Setting real hostname: " << d->host << endl;
468  d->kssl->setPeerHost(d->host);
469  }
470 
471  if (hasMetaData("ssl_session_id")) {
472  KSSLSession *s = KSSLSession::fromString(metaData("ssl_session_id"));
473  if (s) {
474  d->kssl->setSession(s);
475  delete s;
476  }
477  }
478  certificatePrompt();
479 
480  int rc = d->kssl->connect(m_iSock);
481  if (rc < 0) {
482  delete d->kssl;
483  return -2;
484  }
485 
486  setMetaData("ssl_session_id", d->kssl->session()->toString());
487 
488  d->usingTLS = true;
489  setMetaData("ssl_in_use", "TRUE");
490 
491  if (!d->kssl->reusingSession()) {
492  rc = verifyCertificate();
493  if (rc != 1) {
494  setMetaData("ssl_in_use", "FALSE");
495  d->usingTLS = false;
496  delete d->kssl;
497  return -3;
498  }
499  }
500 
501  d->savedMetaData = mOutgoingMetaData;
502  return (d->usingTLS ? 1 : 0);
503 }
504 
505 
506 void TCPSlaveBase::stopTLS()
507 {
508  if (d->usingTLS) {
509  delete d->kssl;
510  d->usingTLS = false;
511  setMetaData("ssl_in_use", "FALSE");
512  }
513 }
514 
515 
516 void TCPSlaveBase::setSSLMetaData() {
517  if (!(d->usingTLS || d->useSSLTunneling || m_bIsSSL))
518  return;
519 
520  mOutgoingMetaData = d->savedMetaData;
521 }
522 
523 
524 bool TCPSlaveBase::canUseTLS()
525 {
526  if (m_bIsSSL || d->needSSLHandShake || !KSSL::doesSSLWork())
527  return false;
528 
529  KSSLSettings kss;
530  return kss.tlsv1();
531 }
532 
533 
534 void TCPSlaveBase::certificatePrompt()
535 {
536 TQString certname; // the cert to use this session
537 bool send = false, prompt = false, save = false, forcePrompt = false;
538 KSSLCertificateHome::KSSLAuthAction aa;
539 
540  setMetaData("ssl_using_client_cert", "FALSE"); // we change this if needed
541 
542  if (metaData("ssl_no_client_cert") == "TRUE") return;
543  forcePrompt = (metaData("ssl_force_cert_prompt") == "TRUE");
544 
545  // Delete the old cert since we're certainly done with it now
546  if (d->pkcs) {
547  delete d->pkcs;
548  d->pkcs = NULL;
549  }
550 
551  if (!d->kssl) return;
552 
553  // Look for a general certificate
554  if (!forcePrompt) {
555  certname = KSSLCertificateHome::getDefaultCertificateName(&aa);
556  switch(aa) {
557  case KSSLCertificateHome::AuthSend:
558  send = true; prompt = false;
559  break;
560  case KSSLCertificateHome::AuthDont:
561  send = false; prompt = false;
562  certname = TQString::null;
563  break;
564  case KSSLCertificateHome::AuthPrompt:
565  send = false; prompt = true;
566  break;
567  default:
568  break;
569  }
570  }
571 
572  TQString ourHost;
573  if (!d->realHost.isEmpty()) {
574  ourHost = d->realHost;
575  } else {
576  ourHost = d->host;
577  }
578 
579  // Look for a certificate on a per-host basis as an override
580  TQString tmpcn = KSSLCertificateHome::getDefaultCertificateName(ourHost, &aa);
581  if (aa != KSSLCertificateHome::AuthNone) { // we must override
582  switch (aa) {
583  case KSSLCertificateHome::AuthSend:
584  send = true;
585  prompt = false;
586  certname = tmpcn;
587  break;
588  case KSSLCertificateHome::AuthDont:
589  send = false;
590  prompt = false;
591  certname = TQString::null;
592  break;
593  case KSSLCertificateHome::AuthPrompt:
594  send = false;
595  prompt = true;
596  certname = tmpcn;
597  break;
598  default:
599  break;
600  }
601  }
602 
603  // Finally, we allow the application to override anything.
604  if (hasMetaData("ssl_demand_certificate")) {
605  certname = metaData("ssl_demand_certificate");
606  if (!certname.isEmpty()) {
607  forcePrompt = false;
608  prompt = false;
609  send = true;
610  }
611  }
612 
613  if (certname.isEmpty() && !prompt && !forcePrompt) return;
614 
615  // Ok, we're supposed to prompt the user....
616  if (prompt || forcePrompt) {
617  TQStringList certs = KSSLCertificateHome::getCertificateList();
618 
619  for (TQStringList::Iterator it = certs.begin(); it != certs.end(); ++it) {
620  KSSLPKCS12 *pkcs = KSSLCertificateHome::getCertificateByName(*it);
621  if (pkcs && (!pkcs->getCertificate() ||
622  !pkcs->getCertificate()->x509V3Extensions().certTypeSSLClient())) {
623  certs.remove(*it);
624  }
625  delete pkcs;
626  }
627 
628  if (certs.isEmpty()) return; // we had nothing else, and prompt failed
629 
630  if (!d->dcc) {
631  d->dcc = new DCOPClient;
632  d->dcc->attach();
633  if (!d->dcc->isApplicationRegistered("kio_uiserver")) {
634  KApplication::startServiceByDesktopPath("kio_uiserver.desktop",
635  TQStringList() );
636  }
637  }
638 
639  TQByteArray data, retval;
640  TQCString rettype;
641  TQDataStream arg(data, IO_WriteOnly);
642  arg << ourHost;
643  arg << certs;
644  arg << metaData("window-id").toInt();
645  bool rc = d->dcc->call("kio_uiserver", "UIServer",
646  "showSSLCertDialog(TQString, TQStringList,int)",
647  data, rettype, retval);
648 
649  if (rc && rettype == "KSSLCertDlgRet") {
650  TQDataStream retStream(retval, IO_ReadOnly);
651  KSSLCertDlgRet drc;
652  retStream >> drc;
653  if (drc.ok) {
654  send = drc.send;
655  save = drc.save;
656  certname = drc.choice;
657  }
658  }
659  }
660 
661  // The user may have said to not send the certificate,
662  // but to save the choice
663  if (!send) {
664  if (save) {
665  KSSLCertificateHome::setDefaultCertificate(certname, ourHost,
666  false, false);
667  }
668  return;
669  }
670 
671  // We're almost committed. If we can read the cert, we'll send it now.
672  KSSLPKCS12 *pkcs = KSSLCertificateHome::getCertificateByName(certname);
673  if (!pkcs && KSSLCertificateHome::hasCertificateByName(certname)) { // We need the password
674  KIO::AuthInfo ai;
675  bool first = true;
676  do {
677  ai.prompt = i18n("Enter the certificate password:");
678  ai.caption = i18n("SSL Certificate Password");
679  ai.url.setProtocol("kssl");
680  ai.url.setHost(certname);
681  ai.username = certname;
682  ai.keepPassword = true;
683 
684  bool showprompt;
685  if (first)
686  showprompt = !checkCachedAuthentication(ai);
687  else
688  showprompt = true;
689  if (showprompt) {
690  if (!openPassDlg(ai, first ? TQString::null :
691  i18n("Unable to open the certificate. Try a new password?")))
692  break;
693  }
694 
695  first = false;
696  pkcs = KSSLCertificateHome::getCertificateByName(certname, ai.password);
697  } while (!pkcs);
698 
699  }
700 
701  // If we could open the certificate, let's send it
702  if (pkcs) {
703  if (!d->kssl->setClientCertificate(pkcs)) {
704  messageBox(Information, i18n("The procedure to set the "
705  "client certificate for the session "
706  "failed."), i18n("SSL"));
707  delete pkcs; // we don't need this anymore
708  pkcs = 0L;
709  } else {
710  kdDebug(7029) << "Client SSL certificate is being used." << endl;
711  setMetaData("ssl_using_client_cert", "TRUE");
712  if (save) {
713  KSSLCertificateHome::setDefaultCertificate(certname, ourHost,
714  true, false);
715  }
716  }
717  d->pkcs = pkcs;
718  }
719 }
720 
721 
722 
723 bool TCPSlaveBase::usingTLS() const
724 {
725  return d->usingTLS;
726 }
727 
728 // ### remove this for KDE4 (misses const):
729 bool TCPSlaveBase::usingTLS()
730 {
731  return d->usingTLS;
732 }
733 
734 
735 // Returns 0 for failed verification, -1 for rejected cert and 1 for ok
736 int TCPSlaveBase::verifyCertificate()
737 {
738  int rc = 0;
739  bool permacache = false;
740  bool isChild = false;
741  bool _IPmatchesCN = false;
742  int result;
743  bool doAddHost = false;
744  TQString ourHost;
745 
746  if (!d->realHost.isEmpty())
747  ourHost = d->realHost;
748  else ourHost = d->host;
749 
750  TQString theurl = TQString(m_sServiceName)+"://"+ourHost+":"+TQString::number(m_iPort);
751 
752  if (!hasMetaData("ssl_militant") || metaData("ssl_militant") == "FALSE")
753  d->militantSSL = false;
754  else if (metaData("ssl_militant") == "TRUE")
755  d->militantSSL = true;
756 
757  if (!d->cc) d->cc = new KSSLCertificateCache;
758 
759  KSSLCertificate& pc = d->kssl->peerInfo().getPeerCertificate();
760 
761  KSSLCertificate::KSSLValidationList ksvl = pc.validateVerbose(KSSLCertificate::SSLServer);
762 
763  _IPmatchesCN = d->kssl->peerInfo().certMatchesAddress();
764  if (!_IPmatchesCN) {
765 #ifndef Q_WS_WIN //temporary
766  KNetwork::KResolverResults res = KNetwork::KResolver::resolve(d->kssl->peerInfo().peerHost(), "80", KNetwork::KResolver::CanonName);
767  if (!res.isEmpty()) {
768  TQString old = d->kssl->peerInfo().peerHost();
769  d->kssl->peerInfo().setPeerHost(res[0].canonicalName());
770  _IPmatchesCN = d->kssl->peerInfo().certMatchesAddress();
771  if (!_IPmatchesCN) {
772  d->kssl->peerInfo().setPeerHost(old);
773  }
774  }
775 #endif
776  if (!_IPmatchesCN && !d->militantSSL) { // force this if the user wants it
777  if (d->cc->getHostList(pc).contains(ourHost)) {
778  _IPmatchesCN = true;
779  }
780  }
781  }
782 
783  if (!_IPmatchesCN) {
784  ksvl << KSSLCertificate::InvalidHost;
785  }
786 
787  KSSLCertificate::KSSLValidation ksv = KSSLCertificate::Ok;
788  if (!ksvl.isEmpty())
789  ksv = ksvl.first();
790 
791  /* Setting the various bits of meta-info that will be needed. */
792  setMetaData("ssl_cipher", d->kssl->connectionInfo().getCipher());
793  setMetaData("ssl_cipher_desc",
794  d->kssl->connectionInfo().getCipherDescription());
795  setMetaData("ssl_cipher_version",
796  d->kssl->connectionInfo().getCipherVersion());
797  setMetaData("ssl_cipher_used_bits",
798  TQString::number(d->kssl->connectionInfo().getCipherUsedBits()));
799  setMetaData("ssl_cipher_bits",
800  TQString::number(d->kssl->connectionInfo().getCipherBits()));
801  setMetaData("ssl_peer_ip", d->ip);
802  if (!d->realHost.isEmpty()) {
803  setMetaData("ssl_proxied", "true");
804  }
805 
806  TQString errorStr;
807  for(KSSLCertificate::KSSLValidationList::ConstIterator it = ksvl.begin();
808  it != ksvl.end(); ++it)
809  {
810  errorStr += TQString::number(*it)+":";
811  }
812  setMetaData("ssl_cert_errors", errorStr);
813  setMetaData("ssl_peer_certificate", pc.toString());
814 
815  if (pc.chain().isValid() && pc.chain().depth() > 1) {
816  TQString theChain;
817  TQPtrList<KSSLCertificate> chain = pc.chain().getChain();
818  chain.setAutoDelete(true);
819  for (KSSLCertificate *c = chain.first(); c; c = chain.next()) {
820  theChain += c->toString();
821  theChain += "\n";
822  }
823  setMetaData("ssl_peer_chain", theChain);
824  } else setMetaData("ssl_peer_chain", "");
825 
826  setMetaData("ssl_cert_state", TQString::number(ksv));
827 
828  if (ksv == KSSLCertificate::Ok) {
829  rc = 1;
830  setMetaData("ssl_action", "accept");
831  }
832 
833  kdDebug(7029) << "SSL HTTP frame the parent? " << metaData("main_frame_request") << endl;
834  if (!hasMetaData("main_frame_request") || metaData("main_frame_request") == "TRUE") {
835  // Since we're the parent, we need to teach the child.
836  setMetaData("ssl_parent_ip", d->ip);
837  setMetaData("ssl_parent_cert", pc.toString());
838  // - Read from cache and see if there is a policy for this
839  KSSLCertificateCache::KSSLCertificatePolicy cp =
840  d->cc->getPolicyByCertificate(pc);
841 
842  // - validation code
843  if (ksv != KSSLCertificate::Ok) {
844  if (d->militantSSL) {
845  return -1;
846  }
847 
848  if (cp == KSSLCertificateCache::Unknown ||
849  cp == KSSLCertificateCache::Ambiguous) {
850  cp = KSSLCertificateCache::Prompt;
851  } else {
852  // A policy was already set so let's honor that.
853  permacache = d->cc->isPermanent(pc);
854  }
855 
856 /*
857  if (!_IPmatchesCN && cp == KSSLCertificateCache::Accept) {
858  cp = KSSLCertificateCache::Prompt;
859 // ksv = KSSLCertificate::Ok;
860  }
861 */
862 
863  // Precondition: cp is one of Reject, Accept or Prompt
864  switch (cp) {
865  case KSSLCertificateCache::Accept:
866  rc = 1;
867  setMetaData("ssl_action", "accept");
868  break;
869  case KSSLCertificateCache::Reject:
870  rc = -1;
871  setMetaData("ssl_action", "reject");
872  break;
873  case KSSLCertificateCache::Prompt:
874  {
875  do {
876  if (ksv == KSSLCertificate::InvalidHost) {
877  TQString msg = i18n("The IP address of the host %1 "
878  "does not match the one the "
879  "certificate was issued to.");
880  result = messageBox( WarningYesNoCancel,
881  msg.arg(ourHost),
882  i18n("Server Authentication"),
883  i18n("&Details"),
884  i18n("Co&ntinue") );
885  } else {
886  TQString msg = i18n("The server certificate failed the "
887  "authenticity test (%1).");
888  result = messageBox( WarningYesNoCancel,
889  msg.arg(ourHost),
890  i18n("Server Authentication"),
891  i18n("&Details"),
892  i18n("Co&ntinue") );
893  }
894 
895  if (result == KMessageBox::Yes) {
896  if (!d->dcc) {
897  d->dcc = new DCOPClient;
898  d->dcc->attach();
899  if (!d->dcc->isApplicationRegistered("kio_uiserver")) {
900  KApplication::startServiceByDesktopPath("kio_uiserver.desktop",
901  TQStringList() );
902  }
903 
904  }
905  TQByteArray data, ignore;
906  TQCString ignoretype;
907  TQDataStream arg(data, IO_WriteOnly);
908  arg << theurl << mOutgoingMetaData;
909  arg << metaData("window-id").toInt();
910  d->dcc->call("kio_uiserver", "UIServer",
911  "showSSLInfoDialog(TQString,KIO::MetaData,int)",
912  data, ignoretype, ignore);
913  }
914  } while (result == KMessageBox::Yes);
915 
916  if (result == KMessageBox::No) {
917  setMetaData("ssl_action", "accept");
918  rc = 1;
919  cp = KSSLCertificateCache::Accept;
920  doAddHost = true;
921  result = messageBox( WarningYesNo,
922  i18n("Would you like to accept this "
923  "certificate forever without "
924  "being prompted?"),
925  i18n("Server Authentication"),
926  i18n("&Forever"),
927  i18n("&Current Sessions Only"));
928  if (result == KMessageBox::Yes)
929  permacache = true;
930  else
931  permacache = false;
932  } else {
933  setMetaData("ssl_action", "reject");
934  rc = -1;
935  cp = KSSLCertificateCache::Prompt;
936  }
937  break;
938  }
939  default:
940  kdDebug(7029) << "TCPSlaveBase/SSL error in cert code."
941  << "Please report this to kfm-devel@kde.org."
942  << endl;
943  break;
944  }
945  }
946 
947 
948  // - cache the results
949  d->cc->addCertificate(pc, cp, permacache);
950  if (doAddHost) d->cc->addHost(pc, ourHost);
951  } else { // Child frame
952  // - Read from cache and see if there is a policy for this
953  KSSLCertificateCache::KSSLCertificatePolicy cp =
954  d->cc->getPolicyByCertificate(pc);
955  isChild = true;
956 
957  // Check the cert and IP to make sure they're the same
958  // as the parent frame
959  bool certAndIPTheSame = (d->ip == metaData("ssl_parent_ip") &&
960  pc.toString() == metaData("ssl_parent_cert"));
961 
962  if (ksv == KSSLCertificate::Ok) {
963  if (certAndIPTheSame) { // success
964  rc = 1;
965  setMetaData("ssl_action", "accept");
966  } else {
967  /*
968  if (d->militantSSL) {
969  return -1;
970  }
971  result = messageBox(WarningYesNo,
972  i18n("The certificate is valid but does not appear to have been assigned to this server. Do you wish to continue loading?"),
973  i18n("Server Authentication"));
974  if (result == KMessageBox::Yes) { // success
975  rc = 1;
976  setMetaData("ssl_action", "accept");
977  } else { // fail
978  rc = -1;
979  setMetaData("ssl_action", "reject");
980  }
981  */
982  setMetaData("ssl_action", "accept");
983  rc = 1; // Let's accept this now. It's bad, but at least the user
984  // will see potential attacks in KDE3 with the pseudo-lock
985  // icon on the toolbar, and can investigate with the RMB
986  }
987  } else {
988  if (d->militantSSL) {
989  return -1;
990  }
991 
992  if (cp == KSSLCertificateCache::Accept) {
993  if (certAndIPTheSame) { // success
994  rc = 1;
995  setMetaData("ssl_action", "accept");
996  } else { // fail
997  result = messageBox(WarningYesNo,
998  i18n("You have indicated that you wish to accept this certificate, but it is not issued to the server who is presenting it. Do you wish to continue loading?"),
999  i18n("Server Authentication"));
1000  if (result == KMessageBox::Yes) {
1001  rc = 1;
1002  setMetaData("ssl_action", "accept");
1003  d->cc->addHost(pc, ourHost);
1004  } else {
1005  rc = -1;
1006  setMetaData("ssl_action", "reject");
1007  }
1008  }
1009  } else if (cp == KSSLCertificateCache::Reject) { // fail
1010  messageBox(Information, i18n("SSL certificate is being rejected as requested. You can disable this in the KDE Control Center."),
1011  i18n("Server Authentication"));
1012  rc = -1;
1013  setMetaData("ssl_action", "reject");
1014  } else {
1015  do {
1016  TQString msg = i18n("The server certificate failed the "
1017  "authenticity test (%1).");
1018  result = messageBox(WarningYesNoCancel,
1019  msg.arg(ourHost),
1020  i18n("Server Authentication"),
1021  i18n("&Details"),
1022  i18n("Co&nnect"));
1023  if (result == KMessageBox::Yes) {
1024  if (!d->dcc) {
1025  d->dcc = new DCOPClient;
1026  d->dcc->attach();
1027  if (!d->dcc->isApplicationRegistered("kio_uiserver")) {
1028  KApplication::startServiceByDesktopPath("kio_uiserver.desktop",
1029  TQStringList() );
1030  }
1031  }
1032  TQByteArray data, ignore;
1033  TQCString ignoretype;
1034  TQDataStream arg(data, IO_WriteOnly);
1035  arg << theurl << mOutgoingMetaData;
1036  arg << metaData("window-id").toInt();
1037  d->dcc->call("kio_uiserver", "UIServer",
1038  "showSSLInfoDialog(TQString,KIO::MetaData,int)",
1039  data, ignoretype, ignore);
1040  }
1041  } while (result == KMessageBox::Yes);
1042 
1043  if (result == KMessageBox::No) {
1044  setMetaData("ssl_action", "accept");
1045  rc = 1;
1046  cp = KSSLCertificateCache::Accept;
1047  result = messageBox(WarningYesNo,
1048  i18n("Would you like to accept this "
1049  "certificate forever without "
1050  "being prompted?"),
1051  i18n("Server Authentication"),
1052  i18n("&Forever"),
1053  i18n("&Current Sessions Only"));
1054  permacache = (result == KMessageBox::Yes);
1055  d->cc->addCertificate(pc, cp, permacache);
1056  d->cc->addHost(pc, ourHost);
1057  } else {
1058  setMetaData("ssl_action", "reject");
1059  rc = -1;
1060  cp = KSSLCertificateCache::Prompt;
1061  d->cc->addCertificate(pc, cp, permacache);
1062  }
1063  }
1064  }
1065  }
1066 
1067 
1068  if (rc == -1) {
1069  return rc;
1070  }
1071 
1072  if (metaData("ssl_activate_warnings") == "TRUE") {
1073  // - entering SSL
1074  if (!isChild && metaData("ssl_was_in_use") == "FALSE" &&
1075  d->kssl->settings()->warnOnEnter()) {
1076  int result;
1077  do {
1078  result = messageBox( i18n("You are about to "
1079  "enter secure mode. "
1080  "All transmissions "
1081  "will be encrypted "
1082  "unless otherwise "
1083  "noted.\nThis means "
1084  "that no third party "
1085  "will be able to "
1086  "easily observe your "
1087  "data in transit."),
1088  WarningYesNo,
1089  i18n("Security Information"),
1090  i18n("Display SSL "
1091  "&Information"),
1092  i18n("C&onnect"),
1093  "WarnOnEnterSSLMode" );
1094  // Move this setting into KSSL instead
1095  KConfig *config = new KConfig("kioslaverc");
1096  config->setGroup("Notification Messages");
1097 
1098  if (!config->readBoolEntry("WarnOnEnterSSLMode", true)) {
1099  config->deleteEntry("WarnOnEnterSSLMode");
1100  config->sync();
1101  d->kssl->settings()->setWarnOnEnter(false);
1102  d->kssl->settings()->save();
1103  }
1104  delete config;
1105 
1106  if ( result == KMessageBox::Yes )
1107  {
1108  if (!d->dcc) {
1109  d->dcc = new DCOPClient;
1110  d->dcc->attach();
1111  if (!d->dcc->isApplicationRegistered("kio_uiserver")) {
1112  KApplication::startServiceByDesktopPath("kio_uiserver.desktop",
1113  TQStringList() );
1114  }
1115  }
1116  TQByteArray data, ignore;
1117  TQCString ignoretype;
1118  TQDataStream arg(data, IO_WriteOnly);
1119  arg << theurl << mOutgoingMetaData;
1120  arg << metaData("window-id").toInt();
1121  d->dcc->call("kio_uiserver", "UIServer",
1122  "showSSLInfoDialog(TQString,KIO::MetaData,int)",
1123  data, ignoretype, ignore);
1124  }
1125  } while (result != KMessageBox::No);
1126  }
1127 
1128  } // if ssl_activate_warnings
1129 
1130 
1131  kdDebug(7029) << "SSL connection information follows:" << endl
1132  << "+-----------------------------------------------" << endl
1133  << "| Cipher: " << d->kssl->connectionInfo().getCipher() << endl
1134  << "| Description: " << d->kssl->connectionInfo().getCipherDescription() << endl
1135  << "| Version: " << d->kssl->connectionInfo().getCipherVersion() << endl
1136  << "| Strength: " << d->kssl->connectionInfo().getCipherUsedBits()
1137  << " of " << d->kssl->connectionInfo().getCipherBits()
1138  << " bits used." << endl
1139  << "| PEER:" << endl
1140  << "| Subject: " << d->kssl->peerInfo().getPeerCertificate().getSubject() << endl
1141  << "| Issuer: " << d->kssl->peerInfo().getPeerCertificate().getIssuer() << endl
1142  << "| Validation: " << (int)ksv << endl
1143  << "| Certificate matches IP: " << _IPmatchesCN << endl
1144  << "+-----------------------------------------------"
1145  << endl;
1146 
1147  // sendMetaData(); Do not call this function!!
1148  return rc;
1149 }
1150 
1151 
1152 bool TCPSlaveBase::isConnectionValid()
1153 {
1154  if ( m_iSock == -1 )
1155  return false;
1156 
1157  fd_set rdfs;
1158  FD_ZERO(&rdfs);
1159  FD_SET(m_iSock , &rdfs);
1160 
1161  struct timeval tv;
1162  tv.tv_usec = 0;
1163  tv.tv_sec = 0;
1164  int retval;
1165 #ifdef Q_OS_UNIX
1166  do {
1167  retval = KSocks::self()->select(m_iSock+1, &rdfs, NULL, NULL, &tv);
1168  if (wasKilled())
1169  return false; // Beam us out of here
1170  } while ((retval == -1) && (errno == EAGAIN));
1171 #else
1172  retval = -1;
1173 #endif
1174  // retval == -1 ==> Error
1175  // retval == 0 ==> Connection Idle
1176  // retval >= 1 ==> Connection Active
1177  //kdDebug(7029) << "TCPSlaveBase::isConnectionValid: select returned: "
1178  // << retval << endl;
1179 
1180  if (retval == -1)
1181  return false;
1182 
1183  if (retval == 0)
1184  return true;
1185 
1186  // Connection is active, check if it has closed.
1187  char buffer[100];
1188 #ifdef Q_OS_UNIX
1189  do {
1190  retval = KSocks::self()->recv(m_iSock, buffer, 80, MSG_PEEK);
1191 
1192  } while ((retval == -1) && (errno == EAGAIN));
1193 #else
1194  retval = -1;
1195 #endif
1196  //kdDebug(7029) << "TCPSlaveBase::isConnectionValid: recv returned: "
1197  // << retval << endl;
1198  if (retval <= 0)
1199  return false; // Error or connection closed.
1200 
1201  return true; // Connection still valid.
1202 }
1203 
1204 
1205 bool TCPSlaveBase::waitForResponse( int t )
1206 {
1207  fd_set rd;
1208  struct timeval timeout;
1209 
1210  if ( (m_bIsSSL || d->usingTLS) && !d->useSSLTunneling && d->kssl )
1211  if (d->kssl->pending() > 0)
1212  return true;
1213 
1214  FD_ZERO(&rd);
1215  FD_SET(m_iSock, &rd);
1216 
1217  timeout.tv_usec = 0;
1218  timeout.tv_sec = t;
1219  time_t startTime;
1220 
1221  int rc;
1222  int n = t;
1223 
1224 reSelect:
1225  startTime = time(NULL);
1226 #ifdef Q_OS_UNIX
1227  rc = KSocks::self()->select(m_iSock+1, &rd, NULL, NULL, &timeout);
1228 #else
1229  rc = -1;
1230 #endif
1231  if (wasKilled())
1232  return false; // We're dead.
1233 
1234  if (rc == -1)
1235  return false;
1236 
1237  if (FD_ISSET(m_iSock, &rd))
1238  return true;
1239 
1240  // Well it returned but it wasn't set. Let's see if it
1241  // returned too early (perhaps from an errant signal) and
1242  // start over with the remaining time
1243  int timeDone = time(NULL) - startTime;
1244  if (timeDone < n)
1245  {
1246  n -= timeDone;
1247  timeout.tv_sec = n;
1248  goto reSelect;
1249  }
1250 
1251  return false; // Timed out!
1252 }
1253 
1254 int TCPSlaveBase::connectResult()
1255 {
1256  return d->status;
1257 }
1258 
1259 void TCPSlaveBase::setBlockConnection( bool b )
1260 {
1261  d->block = b;
1262 }
1263 
1264 void TCPSlaveBase::setConnectTimeout( int t )
1265 {
1266  d->timeout = t;
1267 }
1268 
1269 bool TCPSlaveBase::isSSLTunnelEnabled()
1270 {
1271  return d->useSSLTunneling;
1272 }
1273 
1274 void TCPSlaveBase::setEnableSSLTunnel( bool enable )
1275 {
1276  d->useSSLTunneling = enable;
1277 }
1278 
1279 void TCPSlaveBase::setRealHost( const TQString& realHost )
1280 {
1281  d->realHost = realHost;
1282 }
1283 
1284 bool TCPSlaveBase::doSSLHandShake( bool sendError )
1285 {
1286  kdDebug(7029) << "TCPSlaveBase::doSSLHandShake: " << endl;
1287  TQString msgHost = d->host;
1288 
1289  d->kssl->reInitialize();
1290 
1291  if (hasMetaData("ssl_session_id")) {
1292  KSSLSession *s = KSSLSession::fromString(metaData("ssl_session_id"));
1293  if (s) {
1294  d->kssl->setSession(s);
1295  delete s;
1296  }
1297  }
1298  certificatePrompt();
1299 
1300  if ( !d->realHost.isEmpty() )
1301  {
1302  msgHost = d->realHost;
1303  }
1304 
1305  kdDebug(7029) << "Setting real hostname: " << msgHost << endl;
1306  d->kssl->setPeerHost(msgHost);
1307 
1308  d->status = d->kssl->connect(m_iSock);
1309  if (d->status < 0)
1310  {
1311  closeDescriptor();
1312  if ( sendError )
1313  error( ERR_COULD_NOT_CONNECT, msgHost);
1314  return false;
1315  }
1316 
1317  setMetaData("ssl_session_id", d->kssl->session()->toString());
1318  setMetaData("ssl_in_use", "TRUE");
1319 
1320  if (!d->kssl->reusingSession()) {
1321  int rc = verifyCertificate();
1322  if ( rc != 1 ) {
1323  d->status = -1;
1324  closeDescriptor();
1325  if ( sendError )
1326  error( ERR_COULD_NOT_CONNECT, msgHost);
1327  return false;
1328  }
1329  }
1330 
1331  d->needSSLHandShake = false;
1332 
1333  d->savedMetaData = mOutgoingMetaData;
1334  return true;
1335 }
1336 
1337 
1338 bool TCPSlaveBase::userAborted() const
1339 {
1340  return d->userAborted;
1341 }
1342 
1343 void TCPSlaveBase::virtual_hook( int id, void* data )
1344 { SlaveBase::virtual_hook( id, data ); }
1345 

kio/kio

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

kio/kio

Skip menu "kio/kio"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kio/kio by doxygen 1.8.3.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |