Diffstat (limited to 'noncore/securityplugins/pin/pin.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | noncore/securityplugins/pin/pin.cpp | 342 |
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 | |||
42 | extern "C" char *crypt(const char *key, const char *salt); | ||
43 | |||
44 | /// set to TRUE when we press the 'Skip' button | ||
45 | bool 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 | */ | ||
54 | class 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 | |||
65 | signals: | ||
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 | ||
82 | PinDialog::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 | ||
111 | PinDialog::~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 | ||
117 | bool 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 | |||
135 | void PinDialog::input( QString c ) | ||
136 | { | ||
137 | text += c; | ||
138 | display->setText( text ); | ||
139 | } | ||
140 | |||
141 | void PinDialog::setPrompt( const QString& s ) | ||
142 | { | ||
143 | prompt->setText( s ); | ||
144 | } | ||
145 | |||
146 | void 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 | */ | ||
157 | class 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() | ||
199 | QString 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 | */ | ||
219 | bool 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 | */ | ||
231 | QString 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 | */ | ||
254 | QString 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 | */ | ||
263 | void 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 | ||
280 | void 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 | */ | ||
291 | int 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) | ||
319 | QString PinPlugin::pluginName() const { | ||
320 | return "PIN Plugin"; | ||
321 | } | ||
322 | |||
323 | QString PinPlugin::pixmapNameWidget() const { | ||
324 | return "security/pinplugin"; | ||
325 | } | ||
326 | |||
327 | QString PinPlugin::pixmapNameConfig() const { | ||
328 | return "security/pinplugin"; | ||
329 | } | ||
330 | |||
331 | /// returns a PinConfigWidget | ||
332 | MultiauthConfigWidget * 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 | |||