summaryrefslogtreecommitdiff
path: root/core/opie-login/qdmdialogimpl.cpp
Unidiff
Diffstat (limited to 'core/opie-login/qdmdialogimpl.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--core/opie-login/qdmdialogimpl.cpp535
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)
60extern "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
81union 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
91static const int ShowClockFreq = 1;
92
93QDM_SHOWNUSERS;
94
95#ifdef QT_QWS_LOGIN_USEPAM
96
97static const char *_PAM_SERVICE = "xdm";
98static const char *PAM_password;
99
100typedef const struct pam_message pam_message_type;
101
102static int PAM_conv( int, pam_message_type **, struct pam_response **, void * );
103
104static struct pam_conv PAM_conversation = {
105 &PAM_conv,
106 NULL
107};
108
109//----------------------------------------------------------------------------
110
111static 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
121static 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
159QDMDialogImpl::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
182QDMDialogImpl::~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
195void QDMDialogImpl::accept () { };
196void QDMDialogImpl::reject () { };
197
198
199void QDMDialogImpl::showTime( void )
200{
201 label_date->setText( QDate::currentDate().toString() );
202 label_time->setText( QTime::currentTime().toString() );
203}
204
205
206void QDMDialogImpl::timerEvent( QTimerEvent * e )
207{
208 if( e->timerId() == clockTimer )
209 showTime();
210}
211
212
213//----------------------------------------------------------------------------
214
215void 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
237void 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
261void 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
272static 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
301static 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
318void 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
347bool 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
474bool 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