Diffstat (limited to 'core/opie-login/qdmdialogimpl.cpp') (more/less context) (show whitespace changes)
-rw-r--r-- | core/opie-login/qdmdialogimpl.cpp | 535 |
1 files changed, 535 insertions, 0 deletions
diff --git a/core/opie-login/qdmdialogimpl.cpp b/core/opie-login/qdmdialogimpl.cpp new file mode 100644 index 0000000..bb1b453 --- a/dev/null +++ b/core/opie-login/qdmdialogimpl.cpp | |||
@@ -0,0 +1,535 @@ | |||
1 | /********************************************************************** | ||
2 | ** Copyright (C) 2001 LISA Systems | ||
3 | ** | ||
4 | ** This file is an additional part of Qtopia Environment. | ||
5 | ** | ||
6 | ** This file may be distributed and/or modified under the terms of the | ||
7 | ** GNU General Public License version 2 as published by the Free Software | ||
8 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
9 | ** packaging of this file. | ||
10 | ** | ||
11 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
13 | ** | ||
14 | ** For further information contact info@lisa.de | ||
15 | ** | ||
16 | **********************************************************************/ | ||
17 | |||
18 | /* | ||
19 | * AUTHOR: Christian Rahn | ||
20 | * EMAIL: cdr@lisa.de | ||
21 | * | ||
22 | * $Id$ | ||
23 | */ | ||
24 | |||
25 | #include "qdm_config.h" | ||
26 | |||
27 | #ifdef QT_QWS_LOGIN | ||
28 | |||
29 | #include <pwd.h> | ||
30 | #include <unistd.h> | ||
31 | #include <stdlib.h> | ||
32 | #include <iostream.h> | ||
33 | #include <assert.h> | ||
34 | |||
35 | #include <qlabel.h> | ||
36 | #include <qregexp.h> | ||
37 | #include <qdatetime.h> | ||
38 | #include <qmessagebox.h> | ||
39 | #include <qcombobox.h> | ||
40 | #include <qlineedit.h> | ||
41 | #include <qtranslator.h> | ||
42 | #include <qpeapplication.h> | ||
43 | |||
44 | #include <qwsdisplay_qws.h> | ||
45 | |||
46 | #include <string.h> | ||
47 | #include <stdio.h> | ||
48 | #include <errno.h> | ||
49 | #include <unistd.h> | ||
50 | |||
51 | #include <sys/types.h> | ||
52 | #include <sys/stat.h> | ||
53 | #include <sys/sem.h> | ||
54 | #include <sys/shm.h> | ||
55 | #include <sys/ipc.h> | ||
56 | |||
57 | #include <global.h> | ||
58 | |||
59 | #if defined(QT_QWS_LOGIN_USEPAM) | ||
60 | extern "C" { | ||
61 | #include <security/pam_appl.h> | ||
62 | } | ||
63 | #else | ||
64 | #define _XOPEN_SOURCE | ||
65 | #include <unistd.h> | ||
66 | #include <crypt.h> | ||
67 | #endif | ||
68 | |||
69 | |||
70 | #include "qdmdialogimpl.h" | ||
71 | #include "../taskbar/inputmethods.h" | ||
72 | |||
73 | |||
74 | //---------------------------------------------------------------------------- | ||
75 | |||
76 | //-- taken from semctl man page | ||
77 | #if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) | ||
78 | //-- union semun is defined by including <sys/sem.h> | ||
79 | #else | ||
80 | //-- according to X/OPEN we have to define it ourselves | ||
81 | union semun { | ||
82 | int val; // value for SETVAL | ||
83 | struct semid_ds *buf; // buffer for IPC_STAT, IPC_SET | ||
84 | unsigned short int *array; // array for GETALL, SETALL | ||
85 | struct seminfo *__buf; // buffer for IPC_INFO | ||
86 | }; | ||
87 | #endif | ||
88 | |||
89 | //---------------------------------------------------------------------------- | ||
90 | |||
91 | static const int ShowClockFreq = 1; | ||
92 | |||
93 | QDM_SHOWNUSERS; | ||
94 | |||
95 | #ifdef QT_QWS_LOGIN_USEPAM | ||
96 | |||
97 | static const char *_PAM_SERVICE = "xdm"; | ||
98 | static const char *PAM_password; | ||
99 | |||
100 | typedef const struct pam_message pam_message_type; | ||
101 | |||
102 | static int PAM_conv( int, pam_message_type **, struct pam_response **, void * ); | ||
103 | |||
104 | static struct pam_conv PAM_conversation = { | ||
105 | &PAM_conv, | ||
106 | NULL | ||
107 | }; | ||
108 | |||
109 | //---------------------------------------------------------------------------- | ||
110 | |||
111 | static char *COPY_STRING( const char * s ) { | ||
112 | return (s) ? strdup(s) : (char *)NULL; | ||
113 | } | ||
114 | |||
115 | #define GET_MEM if (reply) realloc(reply, size);\ | ||
116 | else reply = (struct pam_response *)malloc(size); \ | ||
117 | if (!reply) return PAM_CONV_ERR; \ | ||
118 | size += sizeof(struct pam_response) | ||
119 | |||
120 | |||
121 | static int PAM_conv( int num_msg, pam_message_type **msg, | ||
122 | struct pam_response **resp, void *) | ||
123 | { | ||
124 | int count = 0, replies = 0; | ||
125 | struct pam_response *reply = NULL; | ||
126 | int size = sizeof(struct pam_response); | ||
127 | |||
128 | for( count = 0; count < num_msg; count++ ) { | ||
129 | switch (msg[count]->msg_style) { | ||
130 | case PAM_PROMPT_ECHO_ON: | ||
131 | /* user name given to PAM already */ | ||
132 | return PAM_CONV_ERR; | ||
133 | |||
134 | case PAM_PROMPT_ECHO_OFF: | ||
135 | /* wants password */ | ||
136 | GET_MEM; | ||
137 | reply[replies].resp_retcode = PAM_SUCCESS; | ||
138 | reply[replies].resp = COPY_STRING(PAM_password); | ||
139 | replies++; | ||
140 | /* PAM frees resp */ | ||
141 | break; | ||
142 | case PAM_TEXT_INFO: | ||
143 | break; | ||
144 | default: | ||
145 | /* unknown or PAM_ERROR_MSG */ | ||
146 | if (reply) free (reply); | ||
147 | return PAM_CONV_ERR; | ||
148 | } | ||
149 | } | ||
150 | if (reply) *resp = reply; | ||
151 | return PAM_SUCCESS; | ||
152 | } | ||
153 | |||
154 | #endif | ||
155 | |||
156 | |||
157 | //---------------------------------------------------------------------------- | ||
158 | |||
159 | QDMDialogImpl::QDMDialogImpl( QWidget* parent, const char* name, bool modal, WFlags f ) | ||
160 | : QDMDialog( parent, name, modal, f ) | ||
161 | { | ||
162 | showTime(); | ||
163 | clockTimer = startTimer( ShowClockFreq * 1000 );//-- call timer evry min. | ||
164 | setActiveWindow(); | ||
165 | setFocus(); | ||
166 | |||
167 | input = new InputMethods( this ); | ||
168 | input->resize( input->sizeHint() ); | ||
169 | input->move( 0, height() - input->height() ); | ||
170 | |||
171 | for( int i=0; Shown_Users[i]; ++i ) { | ||
172 | input_user->insertItem( Shown_Users[i] ); | ||
173 | } | ||
174 | input_user->clearEdit(); | ||
175 | |||
176 | label_welcome->setText( QDM_WELCOME_STRING ); | ||
177 | |||
178 | }; | ||
179 | |||
180 | |||
181 | |||
182 | QDMDialogImpl::~QDMDialogImpl() | ||
183 | { | ||
184 | input->lower(); | ||
185 | input->close( false ); | ||
186 | input->hide(); | ||
187 | delete input; | ||
188 | input = 0; | ||
189 | if( parent() ) { | ||
190 | ((QWidget*)parent())->repaint(true); | ||
191 | } | ||
192 | }; | ||
193 | |||
194 | |||
195 | void QDMDialogImpl::accept () { }; | ||
196 | void QDMDialogImpl::reject () { }; | ||
197 | |||
198 | |||
199 | void QDMDialogImpl::showTime( void ) | ||
200 | { | ||
201 | label_date->setText( QDate::currentDate().toString() ); | ||
202 | label_time->setText( QTime::currentTime().toString() ); | ||
203 | } | ||
204 | |||
205 | |||
206 | void QDMDialogImpl::timerEvent( QTimerEvent * e ) | ||
207 | { | ||
208 | if( e->timerId() == clockTimer ) | ||
209 | showTime(); | ||
210 | } | ||
211 | |||
212 | |||
213 | //---------------------------------------------------------------------------- | ||
214 | |||
215 | void QDMDialogImpl::slot_sleepmode() | ||
216 | { | ||
217 | const int button = QMessageBox::warning( this, "Shutdown", tr( "Do you really want to go\nto sleep mode now?" ), | ||
218 | QString::null, tr( "Cancel" ), QString::null,0,1 ); | ||
219 | switch( button ) { | ||
220 | case 0: | ||
221 | done( Rejected ); | ||
222 | // Global::execute( cmd_shutdown ); | ||
223 | if( vfork() == 0 ) { | ||
224 | execl( QDM_CMD_SLEEP, 0 ); | ||
225 | cerr << "Sleepmode: " << strerror( errno ) << endl; | ||
226 | } | ||
227 | break; | ||
228 | |||
229 | default: | ||
230 | break; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | |||
235 | //---------------------------------------------------------------------------- | ||
236 | |||
237 | void QDMDialogImpl::slot_shutdown() | ||
238 | { | ||
239 | const int button = QMessageBox::warning( this, "Shutdown", tr("Do you really want to shut\nthe system down now?"), | ||
240 | QString::null, tr("Cancel"), QString::null,0,1 ); | ||
241 | switch( button ) { | ||
242 | case 0: | ||
243 | done( Rejected ); | ||
244 | // Global::execute( cmd_shutdown ); | ||
245 | if( vfork() == 0 ) { | ||
246 | execl( QDM_CMD_SHUTDOWN, 0 ); | ||
247 | cerr << "Shutdown: " << strerror( errno ) << endl; | ||
248 | } | ||
249 | break; | ||
250 | |||
251 | default: | ||
252 | break; | ||
253 | } | ||
254 | } | ||
255 | |||
256 | |||
257 | |||
258 | |||
259 | //---------------------------------------------------------------------------- | ||
260 | |||
261 | void QDMDialogImpl::informBadPassword() | ||
262 | { | ||
263 | QMessageBox::warning( this, tr("Password wrong"), | ||
264 | tr("The given password is incorrect") ); | ||
265 | } | ||
266 | |||
267 | |||
268 | //---------------------------------------------------------------------------- | ||
269 | |||
270 | #if defined(QT_QWS_LOGIN_USEPAM) | ||
271 | |||
272 | static bool pwcheck_PAM( const char *user, const char *password ) | ||
273 | { | ||
274 | bool pw_correct = false; | ||
275 | int pam_error; | ||
276 | int pam_return = 0; | ||
277 | pam_handle_t *pamh = 0; | ||
278 | PAM_password = password.latin1(); | ||
279 | |||
280 | pam_error = pam_start( _PAM_SERVICE, user, &PAM_conversation, &pamh ); | ||
281 | if( pam_error == PAM_SUCCESS ) { | ||
282 | pam_error = pam_authenticate( pamh, 0 ); | ||
283 | if( pam_error == PAM_SUCCESS ) { | ||
284 | //-- password correct | ||
285 | pw_correct = true; | ||
286 | pam_return = PAM_SUCCESS; | ||
287 | } else { | ||
288 | pam_return = pam_error; | ||
289 | } | ||
290 | } else { | ||
291 | // cerr << "PAM error: " << pam_strerror( pamh, pam_error ) << endl; | ||
292 | } | ||
293 | pam_end( pamh, pam_return ); | ||
294 | return pw_correct; | ||
295 | } | ||
296 | |||
297 | #else | ||
298 | |||
299 | //---------------------------------------------------------------------------- | ||
300 | |||
301 | static bool pwcheck_Unix( const char *user, const char *password ) | ||
302 | { | ||
303 | struct passwd * pword = getpwnam( user ); | ||
304 | if( pword ) { | ||
305 | if( strcmp( crypt(password, password), pword->pw_passwd) == 0 ) { | ||
306 | return true; | ||
307 | } | ||
308 | } | ||
309 | return false; | ||
310 | } | ||
311 | |||
312 | #endif | ||
313 | |||
314 | |||
315 | |||
316 | //---------------------------------------------------------------------------- | ||
317 | |||
318 | void QDMDialogImpl::slot_login() | ||
319 | { | ||
320 | bool pw_correct = false; | ||
321 | const char *username = input_user->currentText().latin1(); | ||
322 | const char *password = input_password->text().latin1(); | ||
323 | |||
324 | assert( username ); | ||
325 | |||
326 | #if defined(QT_QWS_LOGIN_USEPAM) | ||
327 | pw_correct = pwcheck_PAM( username, password ); | ||
328 | #else | ||
329 | pw_correct = pwcheck_Unix( username, password ); | ||
330 | #endif | ||
331 | |||
332 | if( pw_correct ) { | ||
333 | if( changePersona( username ) ) { | ||
334 | // cerr << "Password correct" << endl; | ||
335 | done( Accepted ); | ||
336 | return; | ||
337 | } | ||
338 | } else { | ||
339 | // cerr << "Password incorrect" << endl; | ||
340 | } | ||
341 | informBadPassword(); | ||
342 | } | ||
343 | |||
344 | |||
345 | //---------------------------------------------------------------------------- | ||
346 | |||
347 | bool QDMDialogImpl::changePersona( const char *username ) | ||
348 | { | ||
349 | int err; | ||
350 | |||
351 | //-- get some info on user <username> | ||
352 | struct passwd * pword; | ||
353 | pword = getpwnam( username ); | ||
354 | |||
355 | if( pword == 0 ) | ||
356 | return false; | ||
357 | |||
358 | gid_t gid = pword->pw_gid; | ||
359 | uid_t uid = pword->pw_uid; | ||
360 | |||
361 | //-- some very dirty hacks following | ||
362 | // extern int qws_display_id; | ||
363 | extern QString qws_qtePipeFilename(); | ||
364 | extern QString qws_dataDir(); | ||
365 | |||
366 | |||
367 | const QString QTEdataDir = qws_dataDir(); | ||
368 | QString QTEdataDirNew = QTEdataDir; | ||
369 | QTEdataDirNew.replace( QRegExp("root"), username ); | ||
370 | |||
371 | const char *qws_display_str = getenv("QWS_DISPLAY"); | ||
372 | |||
373 | //-- get name of semaphore and lock | ||
374 | QString pipe = qws_qtePipeFilename(); | ||
375 | |||
376 | //-- change owner of semaphore | ||
377 | key_t semkey = ftok( pipe.latin1(), 'd' ); | ||
378 | int semid = semget( semkey, 0, 0 ); | ||
379 | if( semid < 0 ) | ||
380 | cerr << "error: semget, " << strerror( errno ) << endl; | ||
381 | |||
382 | struct shmid_ds shminfo; | ||
383 | semun arg; | ||
384 | semid_ds semidds; | ||
385 | arg.buf = & semidds; | ||
386 | |||
387 | if( semctl( semid, 0, IPC_STAT, arg ) < 0 ) | ||
388 | cerr << "error: semctl stat, " << strerror( errno ) << endl; | ||
389 | |||
390 | arg.buf->sem_perm.uid = uid; | ||
391 | arg.buf->sem_perm.gid = gid; | ||
392 | |||
393 | if( semctl( semid, 0, IPC_SET, arg ) < 0 ) | ||
394 | cerr << "error: semctl set, " << strerror( errno ) << endl; | ||
395 | |||
396 | //-- change owner of shared memory | ||
397 | key_t memkey = ftok( pipe.latin1(), 'm' ); | ||
398 | int ramid = shmget( memkey, 0, 0 ); | ||
399 | if( ramid < 0 ) cerr << "error: shmget, " << strerror( errno ) << endl; | ||
400 | |||
401 | if( shmctl( ramid, IPC_STAT, &shminfo ) < 0 ) | ||
402 | cerr << "error: shmctl stat, " << strerror( errno ) << endl; | ||
403 | |||
404 | shminfo.shm_perm.uid = uid; | ||
405 | shminfo.shm_perm.gid = gid; | ||
406 | |||
407 | if( shmctl( ramid, IPC_SET, &shminfo ) < 0 ) | ||
408 | cerr << "error: shmctl set, " << strerror( errno ) << endl; | ||
409 | |||
410 | //-- change owner of region manager | ||
411 | memkey = ftok( pipe.latin1(), 'r' ); | ||
412 | int regionid = shmget( memkey, 0, 0 ); | ||
413 | if( regionid < 0 ) | ||
414 | cerr << "error: shmget, " << strerror( errno ) << endl; | ||
415 | |||
416 | if( shmctl( regionid, IPC_STAT, &shminfo ) < 0 ) | ||
417 | cerr << "error: shmctl stat, " << strerror( errno ) << endl; | ||
418 | |||
419 | shminfo.shm_perm.uid = uid; | ||
420 | shminfo.shm_perm.gid = gid; | ||
421 | |||
422 | if( shmctl( regionid, IPC_SET, &shminfo ) < 0 ) | ||
423 | cerr << "error: shmctl set, " << strerror( errno ) << endl; | ||
424 | |||
425 | // cerr << "ungrabbing qws display: " << qws_display_id << " on lock " << pipe << endl; | ||
426 | // QWSDisplay::ungrab(); | ||
427 | |||
428 | //-- presenting socket-file to new user | ||
429 | chown( pipe.latin1(), uid, gid ); | ||
430 | chown( QTEdataDir.latin1(), uid, gid ); | ||
431 | |||
432 | |||
433 | //-- another dirty hack - force framebuffer to be writeable... | ||
434 | struct stat devstat; | ||
435 | if( ! stat( "/dev/fb0", &devstat ) ) { | ||
436 | if( chmod( "/dev/fb0", devstat.st_mode |S_IWOTH |S_IWUSR |S_IWGRP ) ) { | ||
437 | cerr << "chmod error: " << strerror( errno ) << endl; | ||
438 | } | ||
439 | } | ||
440 | |||
441 | err = rename( QTEdataDir, QTEdataDirNew ) ; | ||
442 | if( err < 0 ) cerr << "error: rename " << strerror(errno) | ||
443 | << " , " << QTEdataDir << " -> " << QTEdataDirNew << endl; | ||
444 | |||
445 | // | ||
446 | //-- actually change uid and gid | ||
447 | // | ||
448 | // cerr << "changing persona, uid: " << uid << " gid: " << gid << endl; | ||
449 | |||
450 | err = setgid( gid ); | ||
451 | if( err != 0 ) cerr << "error: gid changePersona " << err << endl; | ||
452 | |||
453 | err = setuid( uid ); | ||
454 | if( err != 0 ) cerr << "error: uid changePersona " << err << endl; | ||
455 | |||
456 | |||
457 | //-- set some environment | ||
458 | setenv( "QWS_DISPLAY", qws_display_str, true ); | ||
459 | setenv( "LOGNAME", username, true ); | ||
460 | setenv( "USER", username, true ); | ||
461 | setenv( "HOME", pword->pw_dir, true ); | ||
462 | |||
463 | // cout << "QTE data dir: " << qws_dataDir() << endl; | ||
464 | |||
465 | //-- I am reborn | ||
466 | |||
467 | return true; | ||
468 | } | ||
469 | |||
470 | |||
471 | |||
472 | //---------------------------------------------------------------------------- | ||
473 | |||
474 | bool QDMDialogImpl::login( QWidget *parent ) | ||
475 | { | ||
476 | //-- only when called as 'root' do login-box | ||
477 | if( getuid() != 0 ) | ||
478 | return true; | ||
479 | |||
480 | |||
481 | //-- are we coming from a 'restart' ? | ||
482 | if( getenv("QDM_STARTED") ) | ||
483 | return true; | ||
484 | else | ||
485 | unsetenv("QDM_STARTED"); | ||
486 | |||
487 | |||
488 | #ifndef QT_NO_TRANSLATION | ||
489 | QString lang = getenv( "LANG" ); | ||
490 | |||
491 | QTranslator * trans = new QTranslator(qApp); | ||
492 | QString tfn = QPEApplication::qpeDir()+"/i18n/"+lang+"/login.qm"; | ||
493 | if ( trans->load( tfn )) | ||
494 | qApp->installTranslator( trans ); | ||
495 | else { | ||
496 | delete trans; | ||
497 | trans = 0; | ||
498 | } | ||
499 | #endif | ||
500 | |||
501 | if( parent ) parent->erase(); | ||
502 | |||
503 | QDMDialog *dialog = new QDMDialogImpl( parent, "Login", true //); | ||
504 | ,WStyle_NoBorder | WStyle_Customize ); | ||
505 | |||
506 | #if QT_VERSION >= 300 | ||
507 | Q_CHECK_PTR( dialog ); | ||
508 | #else | ||
509 | CHECK_PTR( dialog ); | ||
510 | #endif | ||
511 | int result = dialog->exec(); | ||
512 | delete dialog; | ||
513 | |||
514 | if( parent ) parent->erase(); | ||
515 | |||
516 | #ifndef QT_NO_TRANSLATION | ||
517 | if( trans ) { | ||
518 | qApp->removeTranslator( trans ); | ||
519 | delete trans; | ||
520 | trans = 0; | ||
521 | } | ||
522 | #endif | ||
523 | |||
524 | setenv( "QDM_STARTED", "", true ); | ||
525 | |||
526 | // if( parent ) parent->erase(); | ||
527 | |||
528 | //-- get all configs going | ||
529 | Global::restart(); | ||
530 | |||
531 | return result; | ||
532 | } | ||
533 | |||
534 | |||
535 | #endif //-- QT_QWS_LOGIN | ||