• 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
45extern "C" {
46 TDE_EXPORT KDEDModule *create_kpasswdserver(const TQCString &name)
47 {
48 return new KPasswdServer(name);
49 }
50}
51
52int
53KPasswdServer::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
72KPasswdServer::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
83KPasswdServer::~KPasswdServer()
84{
85 delete m_wallet;
86}
87
88// Helper - returns the wallet key to use for read/store/checking for existence.
89static TQString makeWalletKey( const TQString& key, const TQString& realm )
90{
91 return realm.isEmpty() ? key : key + '-' + realm;
92}
93
94// Helper for storeInWallet/readFromWallet
95static 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
103static 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
138static 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
178TDEIO::AuthInfo
179KPasswdServer::checkAuthInfo(TDEIO::AuthInfo info, long windowId)
180{
181 return checkAuthInfo(info, windowId, 0);
182}
183
184TDEIO::AuthInfo
185KPasswdServer::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 tdeApp->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
245TDEIO::AuthInfo
246KPasswdServer::queryAuthInfo(TDEIO::AuthInfo info, TQString errorMsg, long windowId, long seqNr)
247{
248 return queryAuthInfo(info, errorMsg, windowId, seqNr, 0 );
249}
250
251TDEIO::AuthInfo
252KPasswdServer::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 tdeApp->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
287void
288KPasswdServer::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
299bool
300KPasswdServer::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
312void
313KPasswdServer::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
500TQString 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
527TDEIO::AuthInfo
528KPasswdServer::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
541const KPasswdServer::AuthInfo *
542KPasswdServer::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
579void
580KPasswdServer::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
606void
607KPasswdServer::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
651void
652KPasswdServer::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
684void
685KPasswdServer::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.4
This website is maintained by Timothy Pearson.