KDEsu
su.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "su.h"
00017 #include "kcookie.h"
00018
00019 #include <config.h>
00020 #include <config-prefix.h>
00021
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <unistd.h>
00025 #include <fcntl.h>
00026 #include <errno.h>
00027 #include <string.h>
00028 #include <ctype.h>
00029 #include <signal.h>
00030
00031 #include <sys/types.h>
00032 #include <sys/stat.h>
00033
00034 #include <QtCore/QFile>
00035
00036 #include <kconfig.h>
00037 #include <kconfiggroup.h>
00038 #include <kdebug.h>
00039 #include <klocale.h>
00040 #include <kstandarddirs.h>
00041 #include <kuser.h>
00042
00043
00044 #ifndef __PATH_SU
00045 #define __PATH_SU "false"
00046 #endif
00047
00048 #ifndef __PATH_SUDO
00049 #define __PATH_SUDO "false"
00050 #endif
00051
00052 #ifdef KDESU_USE_SUDO_DEFAULT
00053 # define DEFAULT_SUPER_USER_COMMAND "sudo"
00054 #else
00055 # define DEFAULT_SUPER_USER_COMMAND "su"
00056 #endif
00057
00058 namespace KDESu {
00059 using namespace KDESuPrivate;
00060
00061 class SuProcess::SuProcessPrivate
00062 {
00063 public:
00064 QString m_superUserCommand;
00065 };
00066
00067 SuProcess::SuProcess(const QByteArray &user, const QByteArray &command)
00068 : d( new SuProcessPrivate )
00069 {
00070 m_User = user;
00071 m_Command = command;
00072
00073 KSharedConfig::Ptr config = KGlobal::config();
00074 KConfigGroup group(config, "super-user-command");
00075 d->m_superUserCommand = group.readEntry("super-user-command", DEFAULT_SUPER_USER_COMMAND);
00076
00077 if ( d->m_superUserCommand != "sudo" && d->m_superUserCommand != "su" ) {
00078 kWarning() << "unknown super user command";
00079 d->m_superUserCommand = DEFAULT_SUPER_USER_COMMAND;
00080 }
00081 }
00082
00083
00084 SuProcess::~SuProcess()
00085 {
00086 delete d;
00087 }
00088
00089 QString SuProcess::superUserCommand()
00090 {
00091 return d->m_superUserCommand;
00092 }
00093
00094 bool SuProcess::useUsersOwnPassword()
00095 {
00096 if (superUserCommand() == "sudo" && m_User == "root") {
00097 return true;
00098 }
00099
00100 KUser user;
00101 return user.loginName() == m_User;
00102 }
00103
00104 int SuProcess::checkInstall(const char *password)
00105 {
00106 return exec(password, Install);
00107 }
00108
00109 int SuProcess::checkNeedPassword()
00110 {
00111 return exec(0L, NeedPassword);
00112 }
00113
00114
00115
00116
00117
00118 int SuProcess::exec(const char *password, int check)
00119 {
00120 if (check)
00121 setTerminal(true);
00122
00123
00124
00125 if (m_User != "root") {
00126 d->m_superUserCommand = "su";
00127 }
00128
00129 QList<QByteArray> args;
00130 if (d->m_superUserCommand == "sudo") {
00131 args += "-u";
00132 }
00133
00134 if ((m_Scheduler != SchedNormal) || (m_Priority > 50))
00135 args += "root";
00136 else
00137 args += m_User;
00138
00139 if (d->m_superUserCommand == "su") {
00140 args += "-c";
00141 }
00142 args += QByteArray(LIBEXEC_INSTALL_DIR) + "/kdesu_stub";
00143 args += "-";
00144
00145 QByteArray command;
00146 if (d->m_superUserCommand == "sudo") {
00147 command = __PATH_SUDO;
00148 } else {
00149 command = __PATH_SU;
00150 }
00151
00152 if (::access(command, X_OK) != 0)
00153 {
00154 command = QFile::encodeName( KGlobal::dirs()->findExe(d->m_superUserCommand.toLatin1()) );
00155 if (command.isEmpty())
00156 return check ? SuNotFound : -1;
00157 }
00158
00159
00160 if (StubProcess::exec(command, args) < 0)
00161 {
00162 return check ? SuNotFound : -1;
00163 }
00164
00165
00166 SuErrors ret = (SuErrors) ConverseSU(password);
00167
00168
00169 if (ret == error)
00170 {
00171 if (!check)
00172 kError(900) << k_lineinfo << "Conversation with su failed\n";
00173 return ret;
00174 }
00175 if (check == NeedPassword)
00176 {
00177 if (ret == killme)
00178 {
00179 if ( d->m_superUserCommand == "sudo" ) {
00180
00181 return ret;
00182 }
00183 if (kill(m_Pid, SIGKILL) < 0) {
00184 kDebug() << "kill < 0";
00185
00186
00187
00188 ret=error;
00189 }
00190 else
00191 {
00192 int iret = waitForChild();
00193 if (iret < 0) ret=error;
00194 else {} ;
00195 }
00196 }
00197 return ret;
00198 }
00199
00200 if (m_bErase && password)
00201 memset(const_cast<char *>(password), 0, qstrlen(password));
00202
00203 if (ret != ok)
00204 {
00205 kill(m_Pid, SIGKILL);
00206 if (d->m_superUserCommand != "sudo") {
00207 waitForChild();
00208 }
00209 return SuIncorrectPassword;
00210 }
00211
00212 int iret = ConverseStub(check);
00213 if (iret < 0)
00214 {
00215 if (!check)
00216 kError(900) << k_lineinfo << "Conversation with kdesu_stub failed\n";
00217 return iret;
00218 }
00219 else if (iret == 1)
00220 {
00221 kill(m_Pid, SIGKILL);
00222 waitForChild();
00223 return SuIncorrectPassword;
00224 }
00225
00226 if (check == Install)
00227 {
00228 waitForChild();
00229 return 0;
00230 }
00231
00232 iret = waitForChild();
00233 return iret;
00234 }
00235
00236
00237
00238
00239
00240
00241 int SuProcess::ConverseSU(const char *password)
00242 {
00243 enum { WaitForPrompt, CheckStar, HandleStub } state = WaitForPrompt;
00244 int colon;
00245 unsigned i, j;
00246
00247
00248 QByteArray line;
00249 while (true)
00250 {
00251 line = readLine();
00252 if (line.isNull())
00253 return ( state == HandleStub ? notauthorized : error);
00254 kDebug(900) << k_lineinfo << "Read line <" << line << ">";
00255
00256 switch (state)
00257 {
00259 case WaitForPrompt:
00260 {
00261
00262 if (line == "kdesu_stub")
00263 {
00264 unreadLine(line);
00265 return ok;
00266 }
00267
00268 while(waitMS(fd(),100)>0)
00269 {
00270
00271
00272
00273
00274 QByteArray more = readLine();
00275 if (more.isEmpty())
00276 break;
00277
00278 line = more;
00279 kDebug(900) << k_lineinfo << "Read line <" << more << ">";
00280 }
00281
00282
00283 const uint len = line.length();
00284 for (i=0,j=0,colon=0; i<len; i++)
00285 {
00286 if (line[i] == ':')
00287 {
00288 j = i; colon++;
00289 continue;
00290 }
00291 if (!isspace(line[i]))
00292 j++;
00293 }
00294 if ((colon == 1) && (line[j] == ':'))
00295 {
00296 if (password == 0L)
00297 return killme;
00298 if (!checkPid(m_Pid))
00299 {
00300 kError(900) << "su has exited while waiting for pwd." << endl;
00301 return error;
00302 }
00303 if ((WaitSlave() == 0) && checkPid(m_Pid))
00304 {
00305 write(fd(), password, strlen(password));
00306 write(fd(), "\n", 1);
00307 state=CheckStar;
00308 }
00309 else
00310 {
00311 return error;
00312 }
00313 }
00314 break;
00315 }
00317 case CheckStar:
00318 {
00319 QByteArray s = line.trimmed();
00320 if (s.isEmpty())
00321 {
00322 state=HandleStub;
00323 break;
00324 }
00325 const uint len = line.length();
00326 for (i=0; i< len; i++)
00327 {
00328 if (s[i] != '*')
00329 return error;
00330 }
00331 state=HandleStub;
00332 break;
00333 }
00335 case HandleStub:
00336
00337 if (line == "kdesu_stub")
00338 {
00339 unreadLine(line);
00340 return ok;
00341 } else if (!line.isEmpty ()) {
00342
00343
00344 return notauthorized;
00345 }
00346 break;
00348 }
00349 }
00350 return ok;
00351 }
00352
00353 void SuProcess::virtual_hook( int id, void* data )
00354 { StubProcess::virtual_hook( id, data ); }
00355
00356 }