00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "loginapplication.h"
00029
00030
00031 #include <opie2/odebug.h>
00032
00033
00034
00035
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:
00078 return PAM_CONV_ERR;
00079
00080 case PAM_PROMPT_ECHO_OFF:
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++;
00089 break;
00090
00091 case PAM_TEXT_INFO:
00092 break;
00093
00094 default:
00095
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
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
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 }