• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdeio/kpasswdserver
 

tdeio/kpasswdserver

  • tdeio
  • kpasswdserver
kpasswdserver.cpp
1 /*
2  This file is part of the KDE Password Server
3 
4  Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
5  Copyright (C) 2005 David Faure (faure@kde.org)
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License
9  version 2 as published by the Free Software Foundation.
10 
11  This software is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this library; see the file COPYING. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 */
21 //----------------------------------------------------------------------------
22 //
23 // KDE Password Server
24 // $Id$
25 
26 #include "kpasswdserver.h"
27 
28 #include <time.h>
29 
30 #include <tqtimer.h>
31 
32 #include <tdeapplication.h>
33 #include <tdelocale.h>
34 #include <tdemessagebox.h>
35 #include <kdebug.h>
36 #include <tdeio/passdlg.h>
37 #include <tdewallet.h>
38 
39 #include "config.h"
40 #ifdef TQ_WS_X11
41 #include <X11/X.h>
42 #include <X11/Xlib.h>
43 #endif
44 
45 extern "C" {
46  TDE_EXPORT KDEDModule *create_kpasswdserver(const TQCString &name)
47  {
48  return new KPasswdServer(name);
49  }
50 }
51 
52 int
53 KPasswdServer::AuthInfoList::compareItems(TQPtrCollection::Item n1, TQPtrCollection::Item n2)
54 {
55  if (!n1 || !n2)
56  return 0;
57 
58  AuthInfo *i1 = (AuthInfo *) n1;
59  AuthInfo *i2 = (AuthInfo *) n2;
60 
61  int l1 = i1->directory.length();
62  int l2 = i2->directory.length();
63 
64  if (l1 > l2)
65  return -1;
66  if (l1 < l2)
67  return 1;
68  return 0;
69 }
70 
71 
72 KPasswdServer::KPasswdServer(const TQCString &name)
73  : KDEDModule(name)
74 {
75  m_authDict.setAutoDelete(true);
76  m_authPending.setAutoDelete(true);
77  m_seqNr = 0;
78  m_wallet = 0;
79  connect(this, TQ_SIGNAL(windowUnregistered(long)),
80  this, TQ_SLOT(removeAuthForWindowId(long)));
81 }
82 
83 KPasswdServer::~KPasswdServer()
84 {
85  delete m_wallet;
86 }
87 
88 // Helper - returns the wallet key to use for read/store/checking for existence.
89 static TQString makeWalletKey( const TQString& key, const TQString& realm )
90 {
91  return realm.isEmpty() ? key : key + '-' + realm;
92 }
93 
94 // Helper for storeInWallet/readFromWallet
95 static TQString makeMapKey( const char* key, int entryNumber )
96 {
97  TQString str = TQString::fromLatin1( key );
98  if ( entryNumber > 1 )
99  str += "-" + TQString::number( entryNumber );
100  return str;
101 }
102 
103 static bool storeInWallet( TDEWallet::Wallet* wallet, const TQString& key, const TDEIO::AuthInfo &info )
104 {
105  if ( !wallet->hasFolder( TDEWallet::Wallet::PasswordFolder() ) )
106  if ( !wallet->createFolder( TDEWallet::Wallet::PasswordFolder() ) )
107  return false;
108  wallet->setFolder( TDEWallet::Wallet::PasswordFolder() );
109  // Before saving, check if there's already an entry with this login.
110  // If so, replace it (with the new password). Otherwise, add a new entry.
111  typedef TQMap<TQString,TQString> Map;
112  int entryNumber = 1;
113  Map map;
114  TQString walletKey = makeWalletKey( key, info.realmValue );
115  kdDebug(130) << "storeInWallet: walletKey=" << walletKey << " reading existing map" << endl;
116  if ( wallet->readMap( walletKey, map ) == 0 ) {
117  Map::ConstIterator end = map.end();
118  Map::ConstIterator it = map.find( "login" );
119  while ( it != end ) {
120  if ( it.data() == info.username ) {
121  break; // OK, overwrite this entry
122  }
123  it = map.find( TQString( "login-" ) + TQString::number( ++entryNumber ) );
124  }
125  // If no entry was found, create a new entry - entryNumber is set already.
126  }
127  const TQString loginKey = makeMapKey( "login", entryNumber );
128  const TQString passwordKey = makeMapKey( "password", entryNumber );
129  kdDebug(130) << "storeInWallet: writing to " << loginKey << "," << passwordKey << endl;
130  // note the overwrite=true by default
131  map.insert( loginKey, info.username );
132  map.insert( passwordKey, info.password );
133  wallet->writeMap( walletKey, map );
134  return true;
135 }
136 
137 
138 static bool readFromWallet( TDEWallet::Wallet* wallet, const TQString& key, const TQString& realm, TQString& username, TQString& password, bool userReadOnly, TQMap<TQString,TQString>& knownLogins )
139 {
140  //kdDebug(130) << "readFromWallet: key=" << key << " username=" << username << " password=" /*<< password*/ << " userReadOnly=" << userReadOnly << " realm=" << realm << endl;
141  if ( wallet->hasFolder( TDEWallet::Wallet::PasswordFolder() ) )
142  {
143  wallet->setFolder( TDEWallet::Wallet::PasswordFolder() );
144 
145  TQMap<TQString,TQString> map;
146  if ( wallet->readMap( makeWalletKey( key, realm ), map ) == 0 )
147  {
148  typedef TQMap<TQString,TQString> Map;
149  int entryNumber = 1;
150  Map::ConstIterator end = map.end();
151  Map::ConstIterator it = map.find( "login" );
152  while ( it != end ) {
153  //kdDebug(130) << "readFromWallet: found " << it.key() << "=" << it.data() << endl;
154  Map::ConstIterator pwdIter = map.find( makeMapKey( "password", entryNumber ) );
155  if ( pwdIter != end ) {
156  if ( it.data() == username )
157  password = pwdIter.data();
158  knownLogins.insert( it.data(), pwdIter.data() );
159  }
160 
161  it = map.find( TQString( "login-" ) + TQString::number( ++entryNumber ) );
162  }
163  //kdDebug(130) << knownLogins.count() << " known logins" << endl;
164 
165  if ( !userReadOnly && !knownLogins.isEmpty() && username.isEmpty() ) {
166  // Pick one, any one...
167  username = knownLogins.begin().key();
168  password = knownLogins.begin().data();
169  //kdDebug(130) << "readFromWallet: picked the first one : " << username << endl;
170  }
171 
172  return true;
173  }
174  }
175  return false;
176 }
177 
178 TDEIO::AuthInfo
179 KPasswdServer::checkAuthInfo(TDEIO::AuthInfo info, long windowId)
180 {
181  return checkAuthInfo(info, windowId, 0);
182 }
183 
184 TDEIO::AuthInfo
185 KPasswdServer::checkAuthInfo(TDEIO::AuthInfo info, long windowId, unsigned long usertime)
186 {
187  kdDebug(130) << "KPasswdServer::checkAuthInfo: User= " << info.username
188  << ", WindowId = " << windowId << endl;
189  if( usertime != 0 )
190  kapp->updateUserTimestamp( usertime );
191 
192  TQString key = createCacheKey(info);
193 
194  Request *request = m_authPending.first();
195  TQString path2 = info.url.directory(false, false);
196  for(; request; request = m_authPending.next())
197  {
198  if (request->key != key)
199  continue;
200 
201  if (info.verifyPath)
202  {
203  TQString path1 = request->info.url.directory(false, false);
204  if (!path2.startsWith(path1))
205  continue;
206  }
207 
208  request = new Request;
209  request->client = callingDcopClient();
210  request->transaction = request->client->beginTransaction();
211  request->key = key;
212  request->info = info;
213  m_authWait.append(request);
214  return info;
215  }
216 
217  const AuthInfo *result = findAuthInfoItem(key, info);
218  if (!result || result->isCanceled)
219  {
220  if (!result &&
221  (info.username.isEmpty() || info.password.isEmpty()) &&
222  !TDEWallet::Wallet::keyDoesNotExist(TDEWallet::Wallet::NetworkWallet(),
223  TDEWallet::Wallet::PasswordFolder(), makeWalletKey(key, info.realmValue)))
224  {
225  TQMap<TQString, TQString> knownLogins;
226  if (openWallet(windowId)) {
227  if (readFromWallet(m_wallet, key, info.realmValue, info.username, info.password,
228  info.readOnly, knownLogins))
229  {
230  info.setModified(true);
231  return info;
232  }
233  }
234  }
235 
236  info.setModified(false);
237  return info;
238  }
239 
240  updateAuthExpire(key, result, windowId, false);
241 
242  return copyAuthInfo(result);
243 }
244 
245 TDEIO::AuthInfo
246 KPasswdServer::queryAuthInfo(TDEIO::AuthInfo info, TQString errorMsg, long windowId, long seqNr)
247 {
248  return queryAuthInfo(info, errorMsg, windowId, seqNr, 0 );
249 }
250 
251 TDEIO::AuthInfo
252 KPasswdServer::queryAuthInfo(TDEIO::AuthInfo info, TQString errorMsg, long windowId, long seqNr, unsigned long usertime)
253 {
254  kdDebug(130) << "KPasswdServer::queryAuthInfo: User= " << info.username
255  << ", Message= " << info.prompt << ", WindowId = " << windowId << endl;
256  if ( !info.password.isEmpty() ) // should we really allow the caller to pre-fill the password?
257  kdDebug(130) << "password was set by caller" << endl;
258  if( usertime != 0 )
259  kapp->updateUserTimestamp( usertime );
260 
261  TQString key = createCacheKey(info);
262  Request *request = new Request;
263  request->client = callingDcopClient();
264  request->transaction = request->client->beginTransaction();
265  request->key = key;
266  request->info = info;
267  request->windowId = windowId;
268  request->seqNr = seqNr;
269  if (errorMsg == "<NoAuthPrompt>")
270  {
271  request->errorMsg = TQString::null;
272  request->prompt = false;
273  }
274  else
275  {
276  request->errorMsg = errorMsg;
277  request->prompt = true;
278  }
279  m_authPending.append(request);
280 
281  if (m_authPending.count() == 1)
282  TQTimer::singleShot(0, this, TQ_SLOT(processRequest()));
283 
284  return info;
285 }
286 
287 void
288 KPasswdServer::addAuthInfo(TDEIO::AuthInfo info, long windowId)
289 {
290  kdDebug(130) << "KPasswdServer::addAuthInfo: User= " << info.username
291  << ", RealmValue= " << info.realmValue << ", WindowId = " << windowId << endl;
292  TQString key = createCacheKey(info);
293 
294  m_seqNr++;
295 
296  addAuthInfoItem(key, info, windowId, m_seqNr, false);
297 }
298 
299 bool
300 KPasswdServer::openWallet( WId windowId )
301 {
302  if ( m_wallet && !m_wallet->isOpen() ) { // forced closed
303  delete m_wallet;
304  m_wallet = 0;
305  }
306  if ( !m_wallet )
307  m_wallet = TDEWallet::Wallet::openWallet(
308  TDEWallet::Wallet::NetworkWallet(), windowId );
309  return m_wallet != 0;
310 }
311 
312 void
313 KPasswdServer::processRequest()
314 {
315  Request *request = m_authPending.first();
316  if (!request)
317  return;
318 
319  TDEIO::AuthInfo &info = request->info;
320 
321  kdDebug(130) << "KPasswdServer::processRequest: User= " << info.username
322  << ", Message= " << info.prompt << endl;
323  const AuthInfo *result = findAuthInfoItem(request->key, request->info);
324 
325  if (result && (request->seqNr < result->seqNr))
326  {
327  kdDebug(130) << "KPasswdServer::processRequest: auto retry!" << endl;
328  if (result->isCanceled)
329  {
330  info.setModified(false);
331  }
332  else
333  {
334  updateAuthExpire(request->key, result, request->windowId, false);
335  info = copyAuthInfo(result);
336  }
337  }
338  else
339  {
340  m_seqNr++;
341  bool askPw = request->prompt;
342  if (result && !info.username.isEmpty() &&
343  !request->errorMsg.isEmpty())
344  {
345  TQString prompt = request->errorMsg;
346  prompt += i18n(" Do you want to retry?");
347  int dlgResult = KMessageBox::warningContinueCancelWId(request->windowId, prompt,
348  i18n("Authentication"), i18n("Retry"));
349  if (dlgResult != KMessageBox::Continue)
350  askPw = false;
351  }
352 
353  int dlgResult = TQDialog::Rejected;
354  if (askPw)
355  {
356  TQString username = info.username;
357  TQString password = info.password;
358  bool hasWalletData = false;
359  TQMap<TQString, TQString> knownLogins;
360 
361  if ( ( username.isEmpty() || password.isEmpty() )
362  && !TDEWallet::Wallet::keyDoesNotExist(TDEWallet::Wallet::NetworkWallet(), TDEWallet::Wallet::PasswordFolder(), makeWalletKey( request->key, info.realmValue )) )
363  {
364  // no login+pass provided, check if tdewallet has one
365  if ( openWallet( request->windowId ) )
366  hasWalletData = readFromWallet( m_wallet, request->key, info.realmValue, username, password, info.readOnly, knownLogins );
367  }
368 
369  TDEIO::PasswordDialog dlg( info.prompt, username, info.keepPassword );
370  if (info.caption.isEmpty())
371  dlg.setPlainCaption( i18n("Authorization Dialog") );
372  else
373  dlg.setPlainCaption( info.caption );
374 
375  if ( !info.comment.isEmpty() )
376  dlg.addCommentLine( info.commentLabel, info.comment );
377 
378  if ( !password.isEmpty() )
379  dlg.setPassword( password );
380 
381  if (info.readOnly)
382  dlg.setUserReadOnly( true );
383  else
384  dlg.setKnownLogins( knownLogins );
385 
386  if (hasWalletData)
387  dlg.setKeepPassword( true );
388 
389 #ifdef TQ_WS_X11
390  XSetTransientForHint( tqt_xdisplay(), dlg.winId(), request->windowId);
391 #endif
392 
393  dlgResult = dlg.exec();
394 
395  if (dlgResult == TQDialog::Accepted)
396  {
397  info.username = dlg.username();
398  info.password = dlg.password();
399  info.keepPassword = dlg.keepPassword();
400 
401  // When the user checks "keep password", that means:
402  // * if the wallet is enabled, store it there for long-term, and in kpasswdserver
403  // only for the duration of the window (#92928)
404  // * otherwise store in kpasswdserver for the duration of the KDE session.
405  if ( info.keepPassword ) {
406  if ( openWallet( request->windowId ) ) {
407  if ( storeInWallet( m_wallet, request->key, info ) )
408  // password is in wallet, don't keep it in memory after window is closed
409  info.keepPassword = false;
410  }
411  }
412  }
413  }
414  if ( dlgResult != TQDialog::Accepted )
415  {
416  addAuthInfoItem(request->key, info, 0, m_seqNr, true);
417  info.setModified( false );
418  }
419  else
420  {
421  addAuthInfoItem(request->key, info, request->windowId, m_seqNr, false);
422  info.setModified( true );
423  }
424  }
425 
426  TQCString replyType;
427  TQByteArray replyData;
428 
429  TQDataStream stream2(replyData, IO_WriteOnly);
430  stream2 << info << m_seqNr;
431  replyType = "TDEIO::AuthInfo";
432  request->client->endTransaction( request->transaction,
433  replyType, replyData);
434 
435  m_authPending.remove((unsigned int) 0);
436 
437  // Check all requests in the wait queue.
438  for(Request *waitRequest = m_authWait.first();
439  waitRequest; )
440  {
441  bool keepQueued = false;
442  TQString key = waitRequest->key;
443 
444  request = m_authPending.first();
445  TQString path2 = waitRequest->info.url.directory(false, false);
446  for(; request; request = m_authPending.next())
447  {
448  if (request->key != key)
449  continue;
450 
451  if (info.verifyPath)
452  {
453  TQString path1 = request->info.url.directory(false, false);
454  if (!path2.startsWith(path1))
455  continue;
456  }
457 
458  keepQueued = true;
459  break;
460  }
461  if (keepQueued)
462  {
463  waitRequest = m_authWait.next();
464  }
465  else
466  {
467  const AuthInfo *result = findAuthInfoItem(waitRequest->key, waitRequest->info);
468 
469  TQCString replyType;
470  TQByteArray replyData;
471 
472  TQDataStream stream2(replyData, IO_WriteOnly);
473 
474  if (!result || result->isCanceled)
475  {
476  waitRequest->info.setModified(false);
477  stream2 << waitRequest->info;
478  }
479  else
480  {
481  updateAuthExpire(waitRequest->key, result, waitRequest->windowId, false);
482  TDEIO::AuthInfo info = copyAuthInfo(result);
483  stream2 << info;
484  }
485 
486  replyType = "TDEIO::AuthInfo";
487  waitRequest->client->endTransaction( waitRequest->transaction,
488  replyType, replyData);
489 
490  m_authWait.remove();
491  waitRequest = m_authWait.current();
492  }
493  }
494 
495  if (m_authPending.count())
496  TQTimer::singleShot(0, this, TQ_SLOT(processRequest()));
497 
498 }
499 
500 TQString KPasswdServer::createCacheKey( const TDEIO::AuthInfo &info )
501 {
502  if( !info.url.isValid() ) {
503  // Note that a null key will break findAuthInfoItem later on...
504  kdWarning(130) << "createCacheKey: invalid URL " << info.url << endl;
505  return TQString::null;
506  }
507 
508  // Generate the basic key sequence.
509  TQString key = info.url.protocol();
510  key += '-';
511  if (!info.url.user().isEmpty())
512  {
513  key += info.url.user();
514  key += "@";
515  }
516  key += info.url.host();
517  int port = info.url.port();
518  if( port )
519  {
520  key += ':';
521  key += TQString::number(port);
522  }
523 
524  return key;
525 }
526 
527 TDEIO::AuthInfo
528 KPasswdServer::copyAuthInfo(const AuthInfo *i)
529 {
530  TDEIO::AuthInfo result;
531  result.url = i->url;
532  result.username = i->username;
533  result.password = i->password;
534  result.realmValue = i->realmValue;
535  result.digestInfo = i->digestInfo;
536  result.setModified(true);
537 
538  return result;
539 }
540 
541 const KPasswdServer::AuthInfo *
542 KPasswdServer::findAuthInfoItem(const TQString &key, const TDEIO::AuthInfo &info)
543 {
544  AuthInfoList *authList = m_authDict.find(key);
545  if (!authList)
546  return 0;
547 
548  TQString path2 = info.url.directory(false, false);
549  for(AuthInfo *current = authList->first();
550  current; )
551  {
552  if ((current->expire == AuthInfo::expTime) &&
553  (difftime(time(0), current->expireTime) > 0))
554  {
555  authList->remove();
556  current = authList->current();
557  continue;
558  }
559 
560  if (info.verifyPath)
561  {
562  TQString path1 = current->directory;
563  if (path2.startsWith(path1) &&
564  (info.username.isEmpty() || info.username == current->username))
565  return current;
566  }
567  else
568  {
569  if (current->realmValue == info.realmValue &&
570  (info.username.isEmpty() || info.username == current->username))
571  return current; // TODO: Update directory info,
572  }
573 
574  current = authList->next();
575  }
576  return 0;
577 }
578 
579 void
580 KPasswdServer::removeAuthInfoItem(const TQString &key, const TDEIO::AuthInfo &info)
581 {
582  AuthInfoList *authList = m_authDict.find(key);
583  if (!authList)
584  return;
585 
586  for(AuthInfo *current = authList->first();
587  current; )
588  {
589  if (current->realmValue == info.realmValue)
590  {
591  authList->remove();
592  current = authList->current();
593  }
594  else
595  {
596  current = authList->next();
597  }
598  }
599  if (authList->isEmpty())
600  {
601  m_authDict.remove(key);
602  }
603 }
604 
605 
606 void
607 KPasswdServer::addAuthInfoItem(const TQString &key, const TDEIO::AuthInfo &info, long windowId, long seqNr, bool canceled)
608 {
609  AuthInfoList *authList = m_authDict.find(key);
610  if (!authList)
611  {
612  authList = new AuthInfoList;
613  m_authDict.insert(key, authList);
614  }
615  AuthInfo *current = authList->first();
616  for(; current; current = authList->next())
617  {
618  if (current->realmValue == info.realmValue)
619  {
620  authList->take();
621  break;
622  }
623  }
624 
625  if (!current)
626  {
627  current = new AuthInfo;
628  current->expire = AuthInfo::expTime;
629  kdDebug(130) << "Creating AuthInfo" << endl;
630  }
631  else
632  {
633  kdDebug(130) << "Updating AuthInfo" << endl;
634  }
635 
636  current->url = info.url;
637  current->directory = info.url.directory(false, false);
638  current->username = info.username;
639  current->password = info.password;
640  current->realmValue = info.realmValue;
641  current->digestInfo = info.digestInfo;
642  current->seqNr = seqNr;
643  current->isCanceled = canceled;
644 
645  updateAuthExpire(key, current, windowId, info.keepPassword && !canceled);
646 
647  // Insert into list, keep the list sorted "longest path" first.
648  authList->inSort(current);
649 }
650 
651 void
652 KPasswdServer::updateAuthExpire(const TQString &key, const AuthInfo *auth, long windowId, bool keep)
653 {
654  AuthInfo *current = const_cast<AuthInfo *>(auth);
655  if (keep)
656  {
657  current->expire = AuthInfo::expNever;
658  }
659  else if (windowId && (current->expire != AuthInfo::expNever))
660  {
661  current->expire = AuthInfo::expWindowClose;
662  if (!current->windowList.contains(windowId))
663  current->windowList.append(windowId);
664  }
665  else if (current->expire == AuthInfo::expTime)
666  {
667  current->expireTime = time(0)+10;
668  }
669 
670  // Update mWindowIdList
671  if (windowId)
672  {
673  TQStringList *keysChanged = mWindowIdList.find(windowId);
674  if (!keysChanged)
675  {
676  keysChanged = new TQStringList;
677  mWindowIdList.insert(windowId, keysChanged);
678  }
679  if (!keysChanged->contains(key))
680  keysChanged->append(key);
681  }
682 }
683 
684 void
685 KPasswdServer::removeAuthForWindowId(long windowId)
686 {
687  TQStringList *keysChanged = mWindowIdList.find(windowId);
688  if (!keysChanged) return;
689 
690  for(TQStringList::ConstIterator it = keysChanged->begin();
691  it != keysChanged->end(); ++it)
692  {
693  TQString key = *it;
694  AuthInfoList *authList = m_authDict.find(key);
695  if (!authList)
696  continue;
697 
698  AuthInfo *current = authList->first();
699  for(; current; )
700  {
701  if (current->expire == AuthInfo::expWindowClose)
702  {
703  if (current->windowList.remove(windowId) && current->windowList.isEmpty())
704  {
705  authList->remove();
706  current = authList->current();
707  continue;
708  }
709  }
710  current = authList->next();
711  }
712  }
713 }
714 
715 #include "kpasswdserver.moc"

tdeio/kpasswdserver

Skip menu "tdeio/kpasswdserver"
  • Main Page
  • File List

tdeio/kpasswdserver

Skip menu "tdeio/kpasswdserver"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeio/kpasswdserver by doxygen 1.9.1
This website is maintained by Timothy Pearson.