-rw-r--r-- | core/opie-login/.cvsignore | 2 | ||||
-rw-r--r-- | core/opie-login/loginwindowimpl.cpp | 14 | ||||
-rw-r--r-- | core/opie-login/loginwindowimpl.h | 5 | ||||
-rw-r--r-- | core/opie-login/opie-login.pro | 8 | ||||
-rw-r--r-- | core/opie-login/passworddialog.ui | 225 | ||||
-rw-r--r-- | core/opie-login/passworddialogimpl.cpp | 232 | ||||
-rw-r--r-- | core/opie-login/passworddialogimpl.h | 65 |
7 files changed, 545 insertions, 6 deletions
diff --git a/core/opie-login/.cvsignore b/core/opie-login/.cvsignore index 0c3cc62..b80bdc4 100644 --- a/core/opie-login/.cvsignore +++ b/core/opie-login/.cvsignore @@ -1,7 +1,9 @@ *.moc Makefile* loginwindow.cpp loginwindow.h +passworddialog.h +passworddialog.cpp moc_* .moc .obj diff --git a/core/opie-login/loginwindowimpl.cpp b/core/opie-login/loginwindowimpl.cpp index 32f98f3..73c2cbe 100644 --- a/core/opie-login/loginwindowimpl.cpp +++ b/core/opie-login/loginwindowimpl.cpp @@ -34,32 +34,33 @@ #include <qpopupmenu.h> #include <qmessagebox.h> #if QT_VERSION < 300 #include <qgfx_qws.h> #endif #include <qwindowsystem_qws.h> #include <qpe/resource.h> #include <qpe/qcopenvelope_qws.h> #include <qpe/config.h> #include <opie2/odevice.h> #include <stdio.h> #include <stdlib.h> +#include "passworddialogimpl.h" #include "loginwindowimpl.h" #include "loginapplication.h" #include "inputmethods.h" using namespace Opie::Core; LoginWindowImpl::LoginWindowImpl ( ) : LoginWindow ( 0, "LOGIN-WINDOW", WStyle_Customize | WStyle_NoBorder | WDestructiveClose ) { QPopupMenu *pop = new QPopupMenu ( this ); pop-> insertItem ( tr( "Restart" ), this, SLOT( restart())); pop-> insertItem ( tr( "Quit" ), this, SLOT( quit())); m_menu-> setPopup ( pop ); QCopChannel *channel = new QCopChannel ( "QPE/TaskBar", this ); connect ( channel, SIGNAL( received(const QCString&,const QByteArray&)), this, SLOT( receive(const QCString&,const QByteArray&))); @@ -77,42 +78,47 @@ LoginWindowImpl::LoginWindowImpl ( ) : LoginWindow ( 0, "LOGIN-WINDOW", WStyle_C //there is no point in displaying the IM for a zaurus if (ODevice::inst ( )-> series ( ) != Model_Zaurus){ QTimer::singleShot ( 0, this, SLOT( showIM())); } QString opiedir = ::getenv ( "OPIEDIR" ); QPixmap bgpix ( opiedir + "/pics/launcher/opie-background.jpg" ); if ( !bgpix. isNull ( )) { setBackgroundPixmap ( bgpix ); m_caption-> setBackgroundPixmap ( bgpix); TextLabel1-> setBackgroundPixmap ( bgpix); TextLabel2-> setBackgroundPixmap ( bgpix); } - m_caption-> setText ( tr("<center>Welcome to OPIE %1</center><center>& %2 %3</center>"). arg(QPE_VERSION). arg ( ODevice::inst ( )-> systemString ( )). arg ( ODevice::inst ( )-> systemVersionString ( ))); +// m_caption-> setText ( tr("<center>Welcome to OPIE %1</center><center>& %2 %3</center>"). arg(QPE_VERSION). arg ( ODevice::inst ( )-> systemString ( )). arg ( ODevice::inst ( )-> systemVersionString ( ))); Config cfg ( "opie-login" ); cfg. setGroup ( "General" ); QString last = cfg. readEntry ( "LastLogin" ); if ( !last. isEmpty ( )) m_user-> setEditText ( last ); calcMaxWindowRect ( ); + + if ( PasswordDialogImpl::needDialog() ) + QTimer::singleShot(10, this, SLOT(showPasswordDialog()) ); + + } LoginWindowImpl::~LoginWindowImpl ( ) { } void LoginWindowImpl::receive ( const QCString &msg, const QByteArray &data ) { QDataStream stream ( data, IO_ReadOnly ); if ( msg == "hideInputMethod()" ) m_input-> hideInputMethod ( ); else if ( msg == "showInputMethod()" ) m_input-> showInputMethod ( ); else if ( msg == "reloadInputMethods()" ) @@ -235,16 +241,22 @@ void LoginWindowImpl::login ( ) cfg. setGroup ( "General" ); cfg. writeEntry ( "LastLogin", user ); cfg. write ( ); lApp-> setLoginAs ( user ); // Draw a big wait icon, the image can be altered in later revisions m_input-> hideInputMethod ( ); new WaitLogo ( ); // WaitLogo::showEvent() calls qApp-> quit() } else { QMessageBox::warning ( this, tr( "Wrong password" ), tr( "The given password is incorrect." )); m_password-> clear ( ); } } + +void LoginWindowImpl::showPasswordDialog() { + PasswordDialogImpl dia( this ); + dia.showMaximized(); + dia.exec(); +} diff --git a/core/opie-login/loginwindowimpl.h b/core/opie-login/loginwindowimpl.h index df8dbbb..1de212c 100644 --- a/core/opie-login/loginwindowimpl.h +++ b/core/opie-login/loginwindowimpl.h @@ -21,43 +21,44 @@ -_. . . )=. = see the file COPYING. If not, write to the -- :-=` Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __OPIE_LOGINWINDOW_IMPL_H__ #define __OPIE_LOGINWINDOW_IMPL_H__ #include "loginwindow.h" class InputMethods; class LoginWindowImpl : public LoginWindow { Q_OBJECT - + public: LoginWindowImpl ( ); - virtual ~LoginWindowImpl ( ); + virtual ~LoginWindowImpl ( ); protected slots: void restart ( ); void quit ( ); void showIM ( ); void suspend ( ); void backlight ( ); void login ( ); void toggleEchoMode ( bool ); void calcMaxWindowRect ( ); void receive ( const QCString &, const QByteArray & ); + void showPasswordDialog(); protected: virtual void keyPressEvent ( QKeyEvent *e ); QStringList getAllUsers ( ); bool changeIdentity ( const char *user ); private: InputMethods *m_input; }; #endif diff --git a/core/opie-login/opie-login.pro b/core/opie-login/opie-login.pro index 63d4481..175d0b6 100644 --- a/core/opie-login/opie-login.pro +++ b/core/opie-login/opie-login.pro @@ -1,28 +1,30 @@ TEMPLATE = app CONFIG = qt warn_on usepam -HEADERS = loginwindowimpl.h \ +HEADERS = loginwindowimpl.h \ loginapplication.h \ + passworddialogimpl.h \ ../launcher/inputmethods.h \ ../apps/calibrate/calibrate.h -SOURCES = loginwindowimpl.cpp \ +SOURCES = loginwindowimpl.cpp \ loginapplication.cpp \ + passworddialogimpl.cpp \ ../launcher/inputmethods.cpp \ ../apps/calibrate/calibrate.cpp \ main.cpp -INTERFACES = loginwindow.ui +INTERFACES = loginwindow.ui passworddialog.ui INCLUDEPATH += $(OPIEDIR)/include ../launcher ../apps/calibrate DEPENDPATH += $(OPIEDIR)/include ../launcher ../apps/calibrate LIBS += -lqpe -lopiecore2 usepam:LIBS += -lpam usepam:DEFINES += USEPAM DESTDIR = $(OPIEDIR)/bin TARGET = opie-login include ( $(OPIEDIR)/include.pro ) diff --git a/core/opie-login/passworddialog.ui b/core/opie-login/passworddialog.ui new file mode 100644 index 0000000..f2b2c88 --- a/dev/null +++ b/core/opie-login/passworddialog.ui @@ -0,0 +1,225 @@ +<!DOCTYPE UI><UI> +<class>PasswordDialog</class> +<widget> + <class>QDialog</class> + <property stdset="1"> + <name>name</name> + <cstring>PasswordDialog</cstring> + </property> + <property stdset="1"> + <name>geometry</name> + <rect> + <x>0</x> + <y>0</y> + <width>625</width> + <height>277</height> + </rect> + </property> + <property stdset="1"> + <name>caption</name> + <string>Set Password</string> + <comment>Caption of the password dialog</comment> + </property> + <property> + <name>layoutMargin</name> + </property> + <property> + <name>layoutSpacing</name> + </property> + <grid> + <property stdset="1"> + <name>margin</name> + <number>4</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>4</number> + </property> + <widget row="0" column="0" > + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>m_header</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string><qt><h2>Please set a password for the Superuser.</h2></qt></string> + </property> + </widget> + <widget row="1" column="0" > + <class>QLayoutWidget</class> + <property stdset="1"> + <name>name</name> + <cstring>Layout5</cstring> + </property> + <grid> + <property stdset="1"> + <name>margin</name> + <number>0</number> + </property> + <property stdset="1"> + <name>spacing</name> + <number>6</number> + </property> + <widget row="0" column="1" > + <class>QLineEdit</class> + <property stdset="1"> + <name>name</name> + <cstring>m_pass</cstring> + </property> + <property stdset="1"> + <name>echoMode</name> + <enum>Password</enum> + </property> + </widget> + <widget row="0" column="0" > + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>m_passLabel</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string><b>Password:</b></string> + </property> + <property> + <name>buddy</name> + <cstring>m_pass</cstring> + </property> + </widget> + <widget row="0" column="2" > + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>ToolButton3</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string></string> + </property> + <property stdset="1"> + <name>pixmap</name> + <pixmap>image0</pixmap> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + <property stdset="1"> + <name>toggleButton</name> + <bool>true</bool> + </property> + </widget> + <widget row="1" column="3" > + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>ToolButton1_2</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string></string> + </property> + <property stdset="1"> + <name>pixmap</name> + <pixmap>image1</pixmap> + </property> + </widget> + <widget row="1" column="1" > + <class>QLineEdit</class> + <property stdset="1"> + <name>name</name> + <cstring>m_confirm</cstring> + </property> + <property stdset="1"> + <name>echoMode</name> + <enum>Password</enum> + </property> + </widget> + <widget row="0" column="3" > + <class>QToolButton</class> + <property stdset="1"> + <name>name</name> + <cstring>ToolButton1</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string></string> + </property> + <property stdset="1"> + <name>pixmap</name> + <pixmap>image1</pixmap> + </property> + </widget> + <widget row="1" column="0" > + <class>QLabel</class> + <property stdset="1"> + <name>name</name> + <cstring>m_confirmLbl</cstring> + </property> + <property stdset="1"> + <name>text</name> + <string><b>Confirm:</b></string> + </property> + </widget> + </grid> + </widget> + <spacer row="2" column="0" > + <property> + <name>name</name> + <cstring>Spacer2</cstring> + </property> + <property stdset="1"> + <name>orientation</name> + <enum>Vertical</enum> + </property> + <property stdset="1"> + <name>sizeType</name> + <enum>Expanding</enum> + </property> + <property> + <name>sizeHint</name> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> +</widget> +<images> + <image> + <name>image0</name> + <data format="XPM.GZ" length="394">789cd3d7528808f055d0d2e72a2e492cc94c5648ce482c52d04a29cdcdad8c8eb5ade6523234530022230543251d2e253d856405bffcbc54105b19c856360003b0141a808a2983b03284848a298304c108240e15033141045829580cac07ac4e590f5d0c22a4876caf32d45898797a48044caf32c22948e629c39d0457a78ce60f65b8f104ec50d6c366af1e865eb4b0aab5e602008bcd444d</data> + </image> + <image> + <name>image1</name> + <data format="XPM.GZ" length="341">789c558fcd0a02310c84ef7d8ad0b915c9bae84d7c04c5a3201e4275d1c32ab8eb41c477b73fa96e43a1f30d4d266d1ced771b728d194619af9efc451ee44ecfbe7f1d8eebb7b1ed92c259506b67c63279dade6fe7a81134e6a9224ac4ae2bc85565075004901c8820731069a648b490effc26eac4a25dcc195373c94231b87a8349fabf894b7a3d27a76af8cf01eb0e534757d70da1bf8a933f2bf30509e84b68</data> + </image> +</images> +<connections> + <connection> + <sender>ToolButton3</sender> + <signal>toggled(bool)</signal> + <receiver>PasswordDialog</receiver> + <slot>slotToggleEcho(bool)</slot> + </connection> + <connection> + <sender>ToolButton1</sender> + <signal>clicked()</signal> + <receiver>m_pass</receiver> + <slot>clear()</slot> + </connection> + <connection> + <sender>ToolButton1_2</sender> + <signal>clicked()</signal> + <receiver>m_confirm</receiver> + <slot>clear()</slot> + </connection> + <slot access="protected">slotToggleEcho(bool)</slot> +</connections> +<tabstops> + <tabstop>m_pass</tabstop> + <tabstop>m_confirm</tabstop> +</tabstops> +</UI> diff --git a/core/opie-login/passworddialogimpl.cpp b/core/opie-login/passworddialogimpl.cpp new file mode 100644 index 0000000..aeb7516 --- a/dev/null +++ b/core/opie-login/passworddialogimpl.cpp @@ -0,0 +1,232 @@ +/* + =. This file is part of the OPIE Project + .=l. Copyright (c) 2004 Holger Hans Peter Freyther <zecke@handhelds.org> + .>+-= + _;:, .> :=|. This file is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This file is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU General +..}^=.= = ; Public License for more details. +++= -. .` .: + : = ...= . :.=- You should have received a copy of the GNU + -. .:....=;==+<; General Public License along with this file; + -_. . . )=. = see the file COPYING. If not, write to the + -- :-=` Free Software Foundation, Inc., + 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + + +#include <qlayout.h> +#include <qlabel.h> +#include <qlineedit.h> +#include <qvalidator.h> +#include <qmessagebox.h> +#include <qhbox.h> +#include <qtoolbutton.h> + +#include <sys/types.h> +#include <pwd.h> +#include <shadow.h> +#include <stdio.h> +#include <time.h> +#include <unistd.h> + + +#include "passworddialogimpl.h" + + +// This function is taken from 'busybox'. +static int i64c(int i) { + if (i <= 0) + return ('.'); + if (i == 1) + return ('/'); + if (i >= 2 && i < 12) + return ('0' - 2 + i); + if (i >= 12 && i < 38) + return ('A' - 12 + i); + if (i >= 38 && i < 63) + return ('a' - 38 + i); + return ('z'); +} + +// This function is taken from 'busybox'. +static char *crypt_make_salt() { + time_t now; + static unsigned long x; + static char result[3]; + + ::time(&now); + x += now + getpid() + clock(); + result[0] = i64c(((x >> 18) ^ (x >> 6)) & 077); + result[1] = i64c(((x >> 12) ^ x) & 077); + result[2] = '\0'; + return result; +} + +/* + * Modal dialog to force root password. It is quite hard as it only leave + * when a password is set. + * Also it prevalidates the password... + */ +PasswordDialogImpl::PasswordDialogImpl( QWidget* parent ) + : PasswordDialog( parent, 0, true ), m_isSet( PasswordDialogImpl::needDialog() ) { +} + +PasswordDialogImpl::~PasswordDialogImpl() { + /* qt does the stuff for us */ +} + +void PasswordDialogImpl::done(int res) { + m_isSet = true; + + /* + * The user hit 'Ok' see if we can safe the file + * if not an error will be raised and m_isSet altered. + * On cancel we will see if it is now ok... + */ + if ( res == Accepted ) + writePassword(); + else if(PasswordDialogImpl::needDialog() ) { + switch( QMessageBox::warning(this,tr("Trying to leave without password set") , + tr("<qt>No password was set. This could lead to you not beeing" + "able to remotely connect to your machine." + "Do you want to continue not setting a password?</qt>" ), + QMessageBox::Ok, QMessageBox::Cancel ) ) { + case QMessageBox::Cancel: + m_isSet = false; + break; + case QMessageBox::Ok: + default: + break; + } + + } + + if(m_isSet) + PasswordDialog::done( res ); +} + +/* + * Lets see if we can write either shadow + * + */ +/** + * CRYPT the password and then tries to write it either to the shadow password + * or to the plain /etc/passwd + */ +void PasswordDialogImpl::writePassword() { + /* + * Check if both texts are the same + */ + if ( m_pass->text() != m_confirm->text() ) + return error( tr("Passwords don't match"), + tr("<qt>The two passwords don't match. Please try again.</qt>") ); + + + /* + * Now crypt the password so we can write it later + */ + char* password = ::crypt( m_pass->text().latin1(), crypt_make_salt() ); + + if ( !password ) + return error( tr("Password not legal" ), + tr("<qt>The entered password is not a valid password." + "Please try entering a valid password.</qt>" ) ); + + /* rewind and rewrite the password file */ + ::setpwent(); + + FILE* file = ::fopen( "/etc/passwd.new", "w" ); + struct passwd* pass; + while ( (pass = ::getpwent()) != 0l ) { + /* no shadow password support */ + if ( pass->pw_uid == 0 ) + pass->pw_passwd = password; + + ::putpwent( pass, file ); + } + + ::fclose( file ); + ::endpwent(); + ::unlink("/etc/passwd"); + ::rename("/etc/passwd.new","/etc/passwd" ); + + /* should be done now */ +#ifdef OPIE_LOGIN_SHADOW_PW + #error "Can't write Shadow Passwords fixme" +#endif +} + +/** + * Raise an error. Delete input and set the focus after showing + * the error to the user + */ +void PasswordDialogImpl::error( const QString& caption, const QString& text ) { + m_isSet = false; + QMessageBox::critical(this,caption, text, + QMessageBox::Ok, QMessageBox::NoButton ); + + m_pass->setText(""); + m_pass->setFocus(); + + m_confirm->setText(""); +} + +void PasswordDialogImpl::slotToggleEcho( bool b ) { + m_pass-> setEchoMode( b ? QLineEdit::Normal : QLineEdit::Password ); + m_confirm->setEchoMode( b ? QLineEdit::Normal : QLineEdit::Password ); +} + +///////////////////////// +/// static functions +/// + +/** + * Ask whether or not we need to show the dialog. It returns true if + * no root password is set so that the user will be able to set one. + */ +bool PasswordDialogImpl::needDialog() { + /* + * This can cope with no password and shadow passwords + * Let us go through the user database until we find 'root' and then + * see if it is 'shadow' and see if shadow is empty or see if the password is empty + */ + bool need = false; + struct passwd *pwd; + ::setpwent(); + + while((pwd = ::getpwent() ) ) { + /* found root */ + if( pwd->pw_uid == 0 ) { + QString str = QString::fromLatin1(pwd->pw_passwd ); + + /* + * If str is really empty it is passwordless anyway... + * else it is shadow based + */ + if(str.isEmpty() ) + need = true; + else if ( str == '*' || str == 'x' ) +#ifdef OPIE_LOGIN_SHADOW_PW + need = QString::fromLatin1( ::getspnam( pwd->pw_name )->sp_pwdp ).isEmpty(); +#else + ; +#endif + break; + } + } + ::endpwent(); + + return need; +} diff --git a/core/opie-login/passworddialogimpl.h b/core/opie-login/passworddialogimpl.h new file mode 100644 index 0000000..f8953dd --- a/dev/null +++ b/core/opie-login/passworddialogimpl.h @@ -0,0 +1,65 @@ +/* + =. This file is part of the OPIE Project + .=l. Copyright (c) 2004 Holger Hans Peter Freyther <zecke@handhelds.org> + .>+-= + _;:, .> :=|. This file is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This file is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU General +..}^=.= = ; Public License for more details. +++= -. .` .: + : = ...= . :.=- You should have received a copy of the GNU + -. .:....=;==+<; General Public License along with this file; + -_. . . )=. = see the file COPYING. If not, write to the + -- :-=` Free Software Foundation, Inc., + 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + + +#ifndef OPIE_LOGIN_PASSWORDIMPL_DIALOG_H +#define OPIE_LOGIN_PASSWORDIMPL_DIALOG_H + +#include "passworddialog.h" + + +class QLineEdit; +/** + * Small Dialog and Class to set the root password if it + * is not empty. + * \code + * if(PasswordDialogImpl::needDialog()) { + * PasswordDialogImpl *dia = new PasswordDialogImpl() + * dia->exec(); + * dia->delete(); + * } + */ +class PasswordDialogImpl : public PasswordDialog { + Q_OBJECT +public: + PasswordDialogImpl( QWidget *parent ); + ~PasswordDialogImpl(); + static bool needDialog(); + +protected slots: + void done( int ); + void slotToggleEcho( bool ); + +private: + void writePassword(); + void writeShadow(); + void error( const QString&, const QString& ); + bool m_isSet : 1; +}; + + +#endif |