summaryrefslogtreecommitdiff
path: root/noncore/securityplugins/pin/pin.cpp
Side-by-side diff
Diffstat (limited to 'noncore/securityplugins/pin/pin.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/securityplugins/pin/pin.cpp342
1 files changed, 342 insertions, 0 deletions
diff --git a/noncore/securityplugins/pin/pin.cpp b/noncore/securityplugins/pin/pin.cpp
new file mode 100644
index 0000000..37dc5be
--- a/dev/null
+++ b/noncore/securityplugins/pin/pin.cpp
@@ -0,0 +1,342 @@
+/**
+ * \note Taken from opie-security and libqpe password.cpp, and modified for Opie multiauth by Clement Seveillac
+ */
+/**********************************************************************
+ ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
+ **
+ ** This file is part of the Qtopia Environment.
+ **
+ ** This file may be distributed and/or modified under the terms of the
+ ** GNU General Public License version 2 as published by the Free Software
+ ** Foundation and appearing in the file LICENSE.GPL included in the
+ ** packaging of this file.
+ **
+ ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ **
+ ** See http://www.trolltech.com/gpl/ for GPL licensing information.
+ **
+ ** Contact info@trolltech.com if any conditions of this licensing are
+ ** not clear to you.
+ **
+ **********************************************************************/
+
+#include "pin.h"
+#include "pinDialogBase.h"
+#include "pinConfigWidget.h"
+/* OPIE */
+#include <opie2/odebug.h>
+#include <opie2/oapplication.h>
+/* QT */
+#include <qpe/config.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qtextview.h>
+#include <qstring.h>
+#include <qdialog.h>
+/* UNIX */
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+
+extern "C" char *crypt(const char *key, const char *salt);
+
+/// set to TRUE when we press the 'Skip' button
+bool isSkip = FALSE;
+
+/// PIN input graphical widget.
+/**
+ * Inherits the PinDialogBase class defined originally in pinDialogBase.ui interface file.
+ * \sa PinDlg and PinDialog (the class generated from the .ui file)
+ * It comes from the original PIN locking code in Opie :
+ * \sa http://dudu.dyn.2-h.org/opiedoxydoc/library_2password_8cpp-source.html
+ */
+class PinDialog : public PinDialogBase
+{
+ Q_OBJECT
+
+ public:
+ PinDialog( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 );
+ ~PinDialog();
+
+ void clear();
+ void setPrompt( const QString& );
+
+signals:
+ /// emitted when we press the Enter button
+ void passwordEntered( const QString& );
+ /// emitted when we press the Skip button
+ void skip();
+
+ protected:
+ bool eventFilter( QObject*, QEvent* );
+
+ private:
+ void input( QString );
+ friend class PinPlugin;
+ QString text;
+};
+
+
+/// Constructs a PinDialog widget, and initializes things
+PinDialog::PinDialog( QWidget* parent, const char* name, WFlags fl )
+ : PinDialogBase( parent, name, fl )
+{
+ QRect desk = oApp->desktop()->geometry();
+
+ if ( desk.width() < 220 ) {
+ QFont f( font() );
+ f.setPointSize( 18 );
+ setFont( f );
+ f.setPointSize( 12 );
+ prompt->setFont( f );
+ }
+
+ button_0->installEventFilter( this );
+ button_1->installEventFilter( this );
+ button_2->installEventFilter( this );
+ button_3->installEventFilter( this );
+ button_4->installEventFilter( this );
+ button_5->installEventFilter( this );
+ button_6->installEventFilter( this );
+ button_7->installEventFilter( this );
+ button_8->installEventFilter( this );
+ button_9->installEventFilter( this );
+ button_Skip->installEventFilter( this );
+ button_OK->installEventFilter( this );
+ setFocus();
+}
+
+/// nothing to do
+PinDialog::~PinDialog()
+{
+ // no need to delete child widgets, Qt does it all for us
+}
+
+/// Record the pressed numbers, and the Skip and Enter commands
+bool PinDialog::eventFilter( QObject*o, QEvent*e )
+{
+ if ( e->type() == QEvent::MouseButtonRelease ) {
+ if ( o == button_OK ) {
+ emit passwordEntered( text );
+ }
+ else if ( o == button_Skip ) {
+ isSkip = TRUE;
+ emit skip();
+ }
+ else {
+ QLabel *l = (QLabel*)o;
+ input(l->text());
+ }
+ }
+ return FALSE;
+}
+
+void PinDialog::input( QString c )
+{
+ text += c;
+ display->setText( text );
+}
+
+void PinDialog::setPrompt( const QString& s )
+{
+ prompt->setText( s );
+}
+
+void PinDialog::clear()
+{
+ text = "";
+ input("");
+}
+
+/// PIN dialog
+/**
+ * Dialog containing the PinDialog widget (which asks for a PIN) and interfacing with its I/O.
+ * \sa PinDialog
+ */
+class PinDlg : public QDialog
+{
+ public:
+ PinDlg( QWidget *parent, const char * name, bool modal, bool fullscreen = FALSE )
+ : QDialog( parent, name, modal, fullscreen ? WStyle_NoBorder | WStyle_Customize | WStyle_StaysOnTop : 0 ),
+ modl(modal)
+ {
+ pinD = new PinDialog( this );
+
+ if ( fullscreen ) {
+ QRect desk = oApp->desktop()->geometry();
+ setGeometry( 0, 0, desk.width(), desk.height() );
+ }
+
+ connect( pinD, SIGNAL(passwordEntered(const QString&)),
+ this, SLOT(accept()) );
+ connect( pinD, SIGNAL(skip()), this, SLOT(accept()) );
+ }
+
+ void resizeEvent( QResizeEvent * )
+ {
+ pinD->resize( size() );
+ }
+
+ void reset()
+ {
+ pinD->clear();
+ }
+
+ /// Slot receiving the Skip or Enter commands, and closing the QDialog
+ void accept()
+ {
+ if ( !modl )
+ oApp->exit_loop();
+ QDialog::accept();
+ }
+
+ PinDialog *pinD;
+ bool modl;
+};
+
+/// generate a fairly random salt and return the PIN hashed by crypt()
+QString PinPlugin::encrypt(const QString& pin)
+{
+ // the salt must begin by "$1$" if we want crypt() to use MD5
+ char salt[] = "$1$........";
+ const char *const seedchars = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ // initialize the random generator
+ srandom(time(0));
+ int i;
+ for(i = 0; i < 8; i++)
+ {
+ // initialize the salt with random()
+ salt[i+3] = seedchars[random() % 64];
+ }
+ return QString::fromLatin1(crypt(pin.latin1(),salt));
+}
+
+/// verify a PIN against its crypt() hash
+/**
+ * \return true if the \a pin matches its \a hash
+ */
+bool PinPlugin::verify(const QString& pin, const QString& hash)
+{
+ // the hash, which contains the salt (8 chars after "$1$"), can be given as the salt
+ return hash.compare( QString::fromLatin1(crypt( pin.latin1(), hash.latin1() )) ) == 0 ? true : false;
+}
+
+/// Displays a PinDialog and returns the typed in PIN
+/**
+ * The returned value is QString::null if the user cancels the operation,
+ * or the empty string if the user enters no password (but confirms the
+ * dialog).
+ */
+QString PinPlugin::getPIN( const QString& prompt )
+{
+ PinDlg pd(0,0,TRUE);
+ pd.pinD->setPrompt( prompt );
+
+ pd.showMaximized();
+ int r = pd.exec();
+
+ if ( r == QDialog::Accepted ) {
+ if (pd.pinD->text.isEmpty())
+ return "";
+ else
+ return pd.pinD->text;
+ }
+ else
+ return QString::null;
+}
+
+/// Displays the PIN dialog and returns a hash of the typed in PIN
+/**
+ * \return the hashed ( =one-way encrypted) PIN typed in by the user
+ * \param prompt the prompt to display in the PinDialog
+ */
+QString PinPlugin::getCryptedPIN( const QString& prompt )
+{
+ return encrypt(getPIN(prompt));
+}
+
+/// Displays the PIN dialog, asks 2 times for a new PIN, saves it if entered two times
+/**
+ * writes nothing if we enter nothing the first time
+ */
+void PinPlugin::changePIN()
+{
+ QString new1, new2;
+ do {
+ new1 = getPIN(QObject::tr("Enter new PIN"));
+ if ( new1.isNull() )
+ return;
+ new2 = getPIN(QObject::tr("Re-enter new PIN"));
+ } while (new1 != new2);
+
+ odebug << "writing new PIN hash in Security.conf" << oendl;
+ Config cfg("Security");
+ cfg.setGroup("PinPlugin");
+ cfg.writeEntry("hashedPIN", encrypt(new1));
+}
+
+/// Removes the PIN hashed value in the config file
+void PinPlugin::clearPIN()
+{
+ Config cfg("Security");
+ cfg.setGroup("PinPlugin");
+ cfg.removeEntry("hashedPIN");
+}
+
+/// Prompt, fullscreen, for the user's PIN and compare it to the stored one.
+/**
+ * \return the result code, as a MultiauthPluginObject::authResult object
+ */
+int PinPlugin::authenticate()
+{
+ // reset skip (if we ran Pin two times in a row, skipping the first time, it must be put to 0 again)
+ isSkip = FALSE;
+ // fetch value in config
+ Config cfg("Security");
+ cfg.setGroup("PinPlugin");
+ QString hashedPin = cfg.readEntry("hashedPIN");
+ if (!hashedPin.isEmpty())
+ {
+ // prompt for the PIN in a fullscreen modal dialog
+ PinDlg pd(0,0,TRUE,TRUE);
+ pd.reset();
+ pd.exec();
+
+ // analyse the result
+ if (isSkip == TRUE)
+ return MultiauthPluginObject::Skip;
+ else if (verify(pd.pinD->text, hashedPin))
+ return MultiauthPluginObject::Success;
+ else
+ return MultiauthPluginObject::Failure;
+ }
+ owarn << "No PIN has been defined! We consider it as a successful authentication though." << oendl;
+ return MultiauthPluginObject::Success;
+}
+
+/// Simply returns the plugin name (PIN plugin)
+QString PinPlugin::pluginName() const {
+ return "PIN Plugin";
+}
+
+QString PinPlugin::pixmapNameWidget() const {
+ return "security/pinplugin";
+}
+
+QString PinPlugin::pixmapNameConfig() const {
+ return "security/pinplugin";
+}
+
+/// returns a PinConfigWidget
+MultiauthConfigWidget * PinPlugin::configWidget(QWidget * parent) {
+ PinConfigWidget * pinw = new PinConfigWidget(parent, "PIN configuration widget");
+
+ connect(pinw->changePIN, SIGNAL( clicked() ), this, SLOT( changePIN() ));
+ connect(pinw->clearPIN, SIGNAL( clicked() ), this, SLOT( clearPIN() ));
+
+ return pinw;
+}
+
+#include "pin.moc"
+