Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

loginapplication.cpp

Go to the documentation of this file.
00001 /*
00002                =.            This file is part of the OPIE Project
00003              .=l.            Copyright (c)  2002 Robert Griebl <sandman@handhelds.org>
00004            .>+-=
00005  _;:,     .>    :=|.         This file is free software; you can
00006 .> <`_,   >  .   <=          redistribute it and/or modify it under
00007 :`=1 )Y*s>-.--   :           the terms of the GNU General Public
00008 .="- .-=="i,     .._         License as published by the Free Software
00009  - .   .-<_>     .<>         Foundation; either version 2 of the License,
00010      ._= =}       :          or (at your option) any later version.
00011     .%`+i>       _;_.
00012     .i_,=:_.      -<s.       This file is distributed in the hope that
00013      +  .  -:.       =       it will be useful, but WITHOUT ANY WARRANTY;
00014     : ..    .:,     . . .    without even the implied warranty of
00015     =_        +     =;=|`    MERCHANTABILITY or FITNESS FOR A
00016   _.=:.       :    :=>`:     PARTICULAR PURPOSE. See the GNU General
00017 ..}^=.=       =       ;      Public License for more details.
00018 ++=   -.     .`     .:
00019  :     =  ...= . :.=-        You should have received a copy of the GNU
00020  -.   .:....=;==+<;          General Public License along with this file;
00021   -_. . .   )=.  =           see the file COPYING. If not, write to the
00022     --        :-=`           Free Software Foundation, Inc.,
00023                              59 Temple Place - Suite 330,
00024                              Boston, MA 02111-1307, USA.
00025 
00026 */
00027 
00028 #include "loginapplication.h"
00029 
00030 /* OPIE */
00031 #include <opie2/odebug.h>
00032 
00033 /* QT */
00034 
00035 /* STD */
00036 #include <pwd.h>
00037 #include <grp.h>
00038 #include <unistd.h>
00039 #include <stdlib.h>
00040 #include <signal.h>
00041 #include <sys/stat.h>
00042 #include <sys/wait.h>
00043 
00044 #ifdef USEPAM
00045 extern "C" {
00046 #include <security/pam_appl.h>
00047 }
00048 #else
00049 #include <crypt.h>
00050 #include <shadow.h>
00051 #endif
00052 
00053 
00054 LoginApplication *lApp;
00055 
00056 LoginApplication::LoginApplication ( int &argc, char **argv, pid_t parentpid )
00057     : QPEApplication ( argc, argv, GuiServer )
00058 {
00059     lApp = this;
00060     m_parentpid = parentpid;
00061 }
00062 
00063 const char *LoginApplication::s_username = 0;
00064 
00065 #ifdef USEPAM
00066 
00067 const char *LoginApplication::s_pam_password = 0;
00068 
00069 int LoginApplication::pam_helper ( int num_msg, const struct pam_message **msg, struct pam_response **resp, void * )
00070 {
00071     int replies = 0;
00072     struct pam_response *reply = 0;
00073     int size = sizeof( struct pam_response );
00074 
00075     for ( int i = 0; i < num_msg; i++ ) {
00076         switch ( msg [i]-> msg_style ) {
00077             case PAM_PROMPT_ECHO_ON: // user name given to PAM already
00078                 return PAM_CONV_ERR;
00079 
00080             case PAM_PROMPT_ECHO_OFF: // wants password
00081                 reply = (struct pam_response *) ::realloc ( reply, size );
00082                 if ( !reply )
00083                     return PAM_CONV_ERR;
00084                 size += sizeof( struct pam_response );
00085 
00086                 reply [replies]. resp_retcode = PAM_SUCCESS;
00087                 reply [replies]. resp = ::strdup ( s_pam_password );
00088                 replies++; // PAM frees resp
00089                 break;
00090 
00091             case PAM_TEXT_INFO:
00092                 break;
00093 
00094             default:
00095                 /* unknown or PAM_ERROR_MSG */
00096                 if ( reply )
00097                     ::free ( reply );
00098                 return PAM_CONV_ERR;
00099         }
00100     }
00101     if ( reply )
00102         *resp = reply;
00103     return PAM_SUCCESS;
00104 }
00105 
00106 
00107 bool LoginApplication::checkPassword ( const char *user, const char *pass )
00108 {
00109     static struct pam_conv conv = { &LoginApplication::pam_helper, 0 };
00110 
00111     int pam_error;
00112     pam_handle_t *pamh = 0;
00113 
00114     pam_error = ::pam_start( "xdm", user, &conv, &pamh );
00115     if ( pam_error == PAM_SUCCESS ) {
00116         s_pam_password = pass;
00117         pam_error = ::pam_authenticate ( pamh, 0 );
00118         s_pam_password = 0;
00119     }
00120     ::pam_end ( pamh, pam_error );
00121     return ( pam_error == PAM_SUCCESS );
00122 }
00123 
00124 #else
00125 
00126 bool LoginApplication::checkPassword ( const char *user, const char *pass )
00127 {
00128     char *encrypted, *correct;
00129     struct passwd *pw;
00130 
00131     if ( !user || !pass )
00132         return false;
00133 
00134     pw = ::getpwnam ( user );
00135 
00136     if ( !pw )
00137         return false;
00138 
00139     if (( ::strcmp ( pw-> pw_passwd, "x" ) == 0 ) || ( ::strcmp ( pw-> pw_passwd, "*" ) == 0 )) {
00140         struct spwd *sp = ::getspnam ( pw-> pw_name );
00141 
00142         if ( !sp )
00143             return false;
00144 
00145         correct = sp-> sp_pwdp;
00146     }
00147     else
00148         correct = pw-> pw_passwd;
00149 
00150     if ( correct == 0 || correct[0] == '\0' )
00151         return true;
00152 
00153     encrypted = ::crypt ( pass, correct );
00154     return ( ::strcmp ( encrypted, correct ) == 0 );
00155 }
00156 
00157 #endif
00158 
00159 bool LoginApplication::changeIdentity ( )
00160 {
00161     const char *DEFAULT_LOGIN_PATH      = "/bin:/usr/bin";
00162     const char *DEFAULT_ROOT_LOGIN_PATH = "/usr/sbin:/bin:/usr/bin:/sbin";
00163 
00164     if ( !s_username )
00165         return false;
00166     struct passwd *pw = ::getpwnam ( s_username );
00167     if ( !pw )
00168         return false;
00169 
00170     // we are still root at this point - try to run the pre-session script
00171     if ( !runRootScript ( "OPIEDIR", "share/opie-login/pre-session", s_username ))
00172         owarn << "failed to run $OPIEDIR/share/opie-login/pre-session" << oendl;
00173 
00174     bool fail = false;
00175     fail |= ( ::initgroups ( pw-> pw_name, pw-> pw_gid ));
00176     ::endgrent ( );
00177     fail |= ( ::setgid ( pw-> pw_gid ));
00178     fail |= ( ::setuid ( pw-> pw_uid ));
00179 
00180     fail |= ( ::chdir ( pw-> pw_dir ) && ::chdir ( "/" ));
00181 
00182     fail |= ( ::setenv ( "HOME",    pw-> pw_dir, 1 ));
00183     fail |= ( ::setenv ( "SHELL",   pw-> pw_shell, 1 ));
00184     fail |= ( ::setenv ( "USER",    pw-> pw_name, 1 ));
00185     fail |= ( ::setenv ( "LOGNAME", pw-> pw_name, 1 ));
00186     fail |= ( ::setenv ( "PATH",    ( pw-> pw_uid ? DEFAULT_LOGIN_PATH : DEFAULT_ROOT_LOGIN_PATH ), 1 ));
00187 
00188     return !fail;
00189 }
00190 
00191 bool LoginApplication::login ( )
00192 {
00193     execUserScript ( "HOME", ".opie-session" );
00194     execUserScript ( "OPIEDIR", "share/opie-login/opie-session" );
00195     execUserScript ( "OPIEDIR", "bin/qpe" );
00196 
00197     owarn << "failed to start an Opie session" << oendl;
00198     return false;
00199 }
00200 
00201 void LoginApplication::logout ( )
00202 {
00203     // we are now root again - try to run the post-session script
00204     if ( !runRootScript ( "OPIEDIR", "share/opie-login/post-session" ))
00205         owarn << "failed to run $OPIEDIR/scripts/post-session" << oendl;
00206 }
00207 
00208 
00209 static char *buildarg ( const char *base, const char *script )
00210 {
00211     const char *dir = base ? ::getenv ( base ) : "/";
00212     char *arg = new char [::strlen ( dir ) + ::strlen ( script ) + 2];
00213 
00214     ::strcpy ( arg, dir );
00215     ::strcat ( arg, "/" );
00216     ::strcat ( arg, script );
00217 
00218     return arg;
00219 }
00220 
00221 bool LoginApplication::runRootScript ( const char *base, const char *script, const char *param )
00222 {
00223     bool res = false;
00224     char *arg = buildarg ( base, script );
00225 
00226     struct stat st;
00227     if (( ::stat ( arg, &st ) == 0 ) && ( st. st_uid == 0 )) {
00228         pid_t child = ::fork ( );
00229 
00230         if ( child == 0 ) {
00231             ::execl ( "/bin/sh", "-sh", arg, param, 0 );
00232             ::_exit ( -1 );
00233         }
00234         else if ( child > 0 ) {
00235             int status = 0;
00236 
00237             while ( ::waitpid ( child, &status, 0 ) < 0 ) { }
00238             res = ( WIFEXITED( status )) && ( WEXITSTATUS( status ) == 0 );
00239         }
00240     }
00241 
00242     delete [] arg;
00243     return res;
00244 }
00245 
00246 void LoginApplication::execUserScript ( const char *base, const char *script )
00247 {
00248     char *arg = buildarg ( base, script );
00249 
00250     struct stat st;
00251     if ( ::stat ( arg, &st ) == 0 ) {
00252         if ( st. st_mode & S_IXUSR )
00253             ::execl ( "/bin/sh", "-sh", "-c", arg, 0 );
00254         else
00255             ::execl ( "/bin/sh", "-sh", arg, 0 );
00256     }
00257 }
00258 
00259 const char *LoginApplication::loginAs ( )
00260 {
00261     return s_username;
00262 }
00263 
00264 void LoginApplication::setLoginAs ( const char *name )
00265 {
00266     s_username = name;
00267 }
00268 
00269 QStringList LoginApplication::allUsers ( )
00270 {
00271     struct passwd *pwd;
00272     QStringList sl;
00273 
00274     while (( pwd = ::getpwent ( ))) {
00275         if (( pwd-> pw_uid == 0 ) || ( pwd-> pw_uid >= 500 && pwd-> pw_uid < 65534 ))
00276             sl << QString ( pwd-> pw_name );
00277     }
00278 
00279     ::endpwent ( );
00280 
00281     return sl;
00282 }
00283 
00284 void LoginApplication::quitToConsole ( )
00285 {
00286     QPEApplication::quit ( );
00287     ::kill ( m_parentpid, SIGTERM );
00288 }

Generated on Sat Nov 5 16:15:45 2005 for OPIE by  doxygen 1.4.2