summaryrefslogtreecommitdiff
path: root/noncore/securityplugins/pin/pin.cpp
Unidiff
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 @@
1/**
2 * \note Taken from opie-security and libqpe password.cpp, and modified for Opie multiauth by Clement Seveillac
3 */
4/**********************************************************************
5 ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
6 **
7 ** This file is part of the Qtopia Environment.
8 **
9 ** This file may be distributed and/or modified under the terms of the
10 ** GNU General Public License version 2 as published by the Free Software
11 ** Foundation and appearing in the file LICENSE.GPL included in the
12 ** packaging of this file.
13 **
14 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
15 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 **
17 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
18 **
19 ** Contact info@trolltech.com if any conditions of this licensing are
20 ** not clear to you.
21 **
22 **********************************************************************/
23
24#include "pin.h"
25#include "pinDialogBase.h"
26#include "pinConfigWidget.h"
27/* OPIE */
28#include <opie2/odebug.h>
29#include <opie2/oapplication.h>
30/* QT */
31#include <qpe/config.h>
32#include <qlabel.h>
33#include <qlineedit.h>
34#include <qtextview.h>
35#include <qstring.h>
36#include <qdialog.h>
37/* UNIX */
38#include <unistd.h>
39#include <stdlib.h>
40#include <time.h>
41
42extern "C" char *crypt(const char *key, const char *salt);
43
44/// set to TRUE when we press the 'Skip' button
45bool isSkip = FALSE;
46
47/// PIN input graphical widget.
48/**
49 * Inherits the PinDialogBase class defined originally in pinDialogBase.ui interface file.
50 * \sa PinDlg and PinDialog (the class generated from the .ui file)
51 * It comes from the original PIN locking code in Opie :
52 * \sa http://dudu.dyn.2-h.org/opiedoxydoc/library_2password_8cpp-source.html
53 */
54class PinDialog : public PinDialogBase
55{
56 Q_OBJECT
57
58 public:
59 PinDialog( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 );
60 ~PinDialog();
61
62 void clear();
63 void setPrompt( const QString& );
64
65signals:
66 /// emitted when we press the Enter button
67 void passwordEntered( const QString& );
68 /// emitted when we press the Skip button
69 void skip();
70
71 protected:
72 bool eventFilter( QObject*, QEvent* );
73
74 private:
75 void input( QString );
76 friend class PinPlugin;
77 QString text;
78};
79
80
81/// Constructs a PinDialog widget, and initializes things
82PinDialog::PinDialog( QWidget* parent, const char* name, WFlags fl )
83 : PinDialogBase( parent, name, fl )
84{
85 QRect desk = oApp->desktop()->geometry();
86
87 if ( desk.width() < 220 ) {
88 QFont f( font() );
89 f.setPointSize( 18 );
90 setFont( f );
91 f.setPointSize( 12 );
92 prompt->setFont( f );
93 }
94
95 button_0->installEventFilter( this );
96 button_1->installEventFilter( this );
97 button_2->installEventFilter( this );
98 button_3->installEventFilter( this );
99 button_4->installEventFilter( this );
100 button_5->installEventFilter( this );
101 button_6->installEventFilter( this );
102 button_7->installEventFilter( this );
103 button_8->installEventFilter( this );
104 button_9->installEventFilter( this );
105 button_Skip->installEventFilter( this );
106 button_OK->installEventFilter( this );
107 setFocus();
108}
109
110/// nothing to do
111PinDialog::~PinDialog()
112{
113 // no need to delete child widgets, Qt does it all for us
114}
115
116/// Record the pressed numbers, and the Skip and Enter commands
117bool PinDialog::eventFilter( QObject*o, QEvent*e )
118{
119 if ( e->type() == QEvent::MouseButtonRelease ) {
120 if ( o == button_OK ) {
121 emit passwordEntered( text );
122 }
123 else if ( o == button_Skip ) {
124 isSkip = TRUE;
125 emit skip();
126 }
127 else {
128 QLabel *l = (QLabel*)o;
129 input(l->text());
130 }
131 }
132 return FALSE;
133}
134
135void PinDialog::input( QString c )
136{
137 text += c;
138 display->setText( text );
139}
140
141void PinDialog::setPrompt( const QString& s )
142{
143 prompt->setText( s );
144}
145
146void PinDialog::clear()
147{
148 text = "";
149 input("");
150}
151
152/// PIN dialog
153/**
154 * Dialog containing the PinDialog widget (which asks for a PIN) and interfacing with its I/O.
155 * \sa PinDialog
156 */
157class PinDlg : public QDialog
158{
159 public:
160 PinDlg( QWidget *parent, const char * name, bool modal, bool fullscreen = FALSE )
161 : QDialog( parent, name, modal, fullscreen ? WStyle_NoBorder | WStyle_Customize | WStyle_StaysOnTop : 0 ),
162 modl(modal)
163 {
164 pinD = new PinDialog( this );
165
166 if ( fullscreen ) {
167 QRect desk = oApp->desktop()->geometry();
168 setGeometry( 0, 0, desk.width(), desk.height() );
169 }
170
171 connect( pinD, SIGNAL(passwordEntered(const QString&)),
172 this, SLOT(accept()) );
173 connect( pinD, SIGNAL(skip()), this, SLOT(accept()) );
174 }
175
176 void resizeEvent( QResizeEvent * )
177 {
178 pinD->resize( size() );
179 }
180
181 void reset()
182 {
183 pinD->clear();
184 }
185
186 /// Slot receiving the Skip or Enter commands, and closing the QDialog
187 void accept()
188 {
189 if ( !modl )
190 oApp->exit_loop();
191 QDialog::accept();
192 }
193
194 PinDialog *pinD;
195 bool modl;
196};
197
198/// generate a fairly random salt and return the PIN hashed by crypt()
199QString PinPlugin::encrypt(const QString& pin)
200{
201 // the salt must begin by "$1$" if we want crypt() to use MD5
202 char salt[] = "$1$........";
203 const char *const seedchars = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
204 // initialize the random generator
205 srandom(time(0));
206 int i;
207 for(i = 0; i < 8; i++)
208 {
209 // initialize the salt with random()
210 salt[i+3] = seedchars[random() % 64];
211 }
212 return QString::fromLatin1(crypt(pin.latin1(),salt));
213}
214
215/// verify a PIN against its crypt() hash
216/**
217 * \return true if the \a pin matches its \a hash
218 */
219bool PinPlugin::verify(const QString& pin, const QString& hash)
220{
221 // the hash, which contains the salt (8 chars after "$1$"), can be given as the salt
222 return hash.compare( QString::fromLatin1(crypt( pin.latin1(), hash.latin1() )) ) == 0 ? true : false;
223}
224
225/// Displays a PinDialog and returns the typed in PIN
226/**
227 * The returned value is QString::null if the user cancels the operation,
228 * or the empty string if the user enters no password (but confirms the
229 * dialog).
230 */
231QString PinPlugin::getPIN( const QString& prompt )
232{
233 PinDlg pd(0,0,TRUE);
234 pd.pinD->setPrompt( prompt );
235
236 pd.showMaximized();
237 int r = pd.exec();
238
239 if ( r == QDialog::Accepted ) {
240 if (pd.pinD->text.isEmpty())
241 return "";
242 else
243 return pd.pinD->text;
244 }
245 else
246 return QString::null;
247}
248
249/// Displays the PIN dialog and returns a hash of the typed in PIN
250/**
251 * \return the hashed ( =one-way encrypted) PIN typed in by the user
252 * \param prompt the prompt to display in the PinDialog
253 */
254QString PinPlugin::getCryptedPIN( const QString& prompt )
255{
256 return encrypt(getPIN(prompt));
257}
258
259/// Displays the PIN dialog, asks 2 times for a new PIN, saves it if entered two times
260/**
261 * writes nothing if we enter nothing the first time
262 */
263void PinPlugin::changePIN()
264{
265 QString new1, new2;
266 do {
267 new1 = getPIN(QObject::tr("Enter new PIN"));
268 if ( new1.isNull() )
269 return;
270 new2 = getPIN(QObject::tr("Re-enter new PIN"));
271 } while (new1 != new2);
272
273 odebug << "writing new PIN hash in Security.conf" << oendl;
274 Config cfg("Security");
275 cfg.setGroup("PinPlugin");
276 cfg.writeEntry("hashedPIN", encrypt(new1));
277}
278
279/// Removes the PIN hashed value in the config file
280void PinPlugin::clearPIN()
281{
282 Config cfg("Security");
283 cfg.setGroup("PinPlugin");
284 cfg.removeEntry("hashedPIN");
285}
286
287/// Prompt, fullscreen, for the user's PIN and compare it to the stored one.
288/**
289 * \return the result code, as a MultiauthPluginObject::authResult object
290 */
291int PinPlugin::authenticate()
292{
293 // reset skip (if we ran Pin two times in a row, skipping the first time, it must be put to 0 again)
294 isSkip = FALSE;
295 // fetch value in config
296 Config cfg("Security");
297 cfg.setGroup("PinPlugin");
298 QString hashedPin = cfg.readEntry("hashedPIN");
299 if (!hashedPin.isEmpty())
300 {
301 // prompt for the PIN in a fullscreen modal dialog
302 PinDlg pd(0,0,TRUE,TRUE);
303 pd.reset();
304 pd.exec();
305
306 // analyse the result
307 if (isSkip == TRUE)
308 return MultiauthPluginObject::Skip;
309 else if (verify(pd.pinD->text, hashedPin))
310 return MultiauthPluginObject::Success;
311 else
312 return MultiauthPluginObject::Failure;
313 }
314 owarn << "No PIN has been defined! We consider it as a successful authentication though." << oendl;
315 return MultiauthPluginObject::Success;
316}
317
318/// Simply returns the plugin name (PIN plugin)
319QString PinPlugin::pluginName() const {
320 return "PIN Plugin";
321}
322
323QString PinPlugin::pixmapNameWidget() const {
324 return "security/pinplugin";
325}
326
327QString PinPlugin::pixmapNameConfig() const {
328 return "security/pinplugin";
329}
330
331/// returns a PinConfigWidget
332MultiauthConfigWidget * PinPlugin::configWidget(QWidget * parent) {
333 PinConfigWidget * pinw = new PinConfigWidget(parent, "PIN configuration widget");
334
335 connect(pinw->changePIN, SIGNAL( clicked() ), this, SLOT( changePIN() ));
336 connect(pinw->clearPIN, SIGNAL( clicked() ), this, SLOT( clearPIN() ));
337
338 return pinw;
339}
340
341#include "pin.moc"
342