su.cpp00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include <config.h>
00016
00017 #include <stdio.h>
00018 #include <stdlib.h>
00019 #include <unistd.h>
00020 #include <fcntl.h>
00021 #include <errno.h>
00022 #include <string.h>
00023 #include <ctype.h>
00024 #include <signal.h>
00025
00026 #include <sys/types.h>
00027 #include <sys/stat.h>
00028
00029 #include <qglobal.h>
00030 #include <qcstring.h>
00031 #include <qfile.h>
00032
00033 #include <kdebug.h>
00034 #include <klocale.h>
00035 #include <kstandarddirs.h>
00036
00037 #include "su.h"
00038 #include "kcookie.h"
00039
00040
00041 #ifndef __PATH_SU
00042 #define __PATH_SU "false"
00043 #endif
00044
00045
00046 SuProcess::SuProcess(const QCString &user, const QCString &command)
00047 {
00048 m_User = user;
00049 m_Command = command;
00050 }
00051
00052
00053 SuProcess::~SuProcess()
00054 {
00055 }
00056
00057 int SuProcess::checkInstall(const char *password)
00058 {
00059 return exec(password, Install);
00060 }
00061
00062 int SuProcess::checkNeedPassword()
00063 {
00064 return exec(0L, NeedPassword);
00065 }
00066
00067
00068
00069
00070
00071 int SuProcess::exec(const char *password, int check)
00072 {
00073 if (check)
00074 setTerminal(true);
00075
00076 QCStringList args;
00077
00078 #ifdef Q_OS_DARWIN
00079 args += "-c";
00080 args += "staff";
00081 #endif
00082
00083 if ((m_Scheduler != SchedNormal) || (m_Priority > 50))
00084 args += "root";
00085 else
00086 args += m_User;
00087
00088 args += "-c";
00089 args += QCString(__KDE_BINDIR) + "/kdesu_stub";
00090 #ifndef Q_OS_DARWIN
00091 args += "-";
00092 #endif
00093
00094 QCString command = __PATH_SU;
00095 if (::access(__PATH_SU, X_OK) != 0)
00096 {
00097 command = QFile::encodeName(KGlobal::dirs()->findExe("su"));
00098 if (command.isEmpty())
00099 return check ? SuNotFound : -1;
00100 }
00101
00102
00103 if (StubProcess::exec(command, args) < 0)
00104 {
00105 return check ? SuNotFound : -1;
00106 }
00107
00108
00109 SuErrors ret = (SuErrors) ConverseSU(password);
00110
00111
00112 if (ret == error)
00113 {
00114 if (!check)
00115 kdError(900) << k_lineinfo << "Conversation with su failed\n";
00116 return ret;
00117 }
00118 if (check == NeedPassword)
00119 {
00120 if (ret == killme)
00121 {
00122 if (kill(m_Pid, SIGKILL) < 0)
00123 {
00124 ret=error;
00125 }
00126 else
00127 {
00128 int iret = waitForChild();
00129 if (iret < 0) ret=error;
00130 else {} ;
00131 }
00132 }
00133 return ret;
00134 }
00135
00136 if (m_bErase && password)
00137 {
00138 char *ptr = const_cast<char *>(password);
00139 const uint plen = strlen(password);
00140 for (unsigned i=0; i < plen; i++)
00141 ptr[i] = '\000';
00142 }
00143
00144 if (ret == notauthorized)
00145 {
00146 kill(m_Pid, SIGKILL);
00147 waitForChild();
00148 return SuIncorrectPassword;
00149 }
00150
00151 int iret = ConverseStub(check);
00152 if (iret < 0)
00153 {
00154 if (!check)
00155 kdError(900) << k_lineinfo << "Converstation with kdesu_stub failed\n";
00156 return iret;
00157 }
00158 else if (iret == 1)
00159 {
00160 kill(m_Pid, SIGKILL);
00161 waitForChild();
00162 return SuIncorrectPassword;
00163 }
00164
00165 if (check == Install)
00166 {
00167 waitForChild();
00168 return 0;
00169 }
00170
00171 iret = waitForChild();
00172 return iret;
00173 }
00174
00175
00176
00177
00178
00179
00180 int SuProcess::ConverseSU(const char *password)
00181 {
00182 enum { WaitForPrompt, CheckStar, HandleStub } state = WaitForPrompt;
00183 int colon;
00184 unsigned i, j;
00185
00186
00187 QCString line;
00188 while (true)
00189 {
00190 line = readLine();
00191 if (line.isNull())
00192 return ( state == HandleStub ? notauthorized : error);
00193 kdDebug(900) << k_lineinfo << "Read line <" << line << ">" << endl;
00194
00195 switch (state)
00196 {
00198 case WaitForPrompt:
00199 {
00200
00201 if (line == "kdesu_stub")
00202 {
00203 unreadLine(line);
00204 return ok;
00205 }
00206
00207 while(waitMS(m_Fd,100)>0)
00208 {
00209
00210
00211
00212
00213 QCString more = readLine();
00214 if (more.isEmpty())
00215 break;
00216
00217 line = more;
00218 kdDebug(900) << k_lineinfo << "Read line <" << more << ">" << endl;
00219 }
00220
00221
00222 const uint len = line.length();
00223 for (i=0,j=0,colon=0; i<len; i++)
00224 {
00225 if (line[i] == ':')
00226 {
00227 j = i; colon++;
00228 continue;
00229 }
00230 if (!isspace(line[i]))
00231 j++;
00232 }
00233 if ((colon == 1) && (line[j] == ':'))
00234 {
00235 if (password == 0L)
00236 return killme;
00237 if (!checkPid(m_Pid))
00238 {
00239 kdError(900) << "su has exited while waiting for pwd." << endl;
00240 return error;
00241 }
00242 if ((WaitSlave() == 0) && checkPid(m_Pid))
00243 {
00244 write(m_Fd, password, strlen(password));
00245 write(m_Fd, "\n", 1);
00246 state=CheckStar;
00247 }
00248 else
00249 {
00250 return error;
00251 }
00252 }
00253 break;
00254 }
00256 case CheckStar:
00257 {
00258 QCString s = line.stripWhiteSpace();
00259 if (s.isEmpty())
00260 {
00261 state=HandleStub;
00262 break;
00263 }
00264 const uint len = line.length();
00265 for (i=0; i< len; i++)
00266 {
00267 if (s[i] != '*')
00268 return error;
00269 }
00270 state=HandleStub;
00271 break;
00272 }
00274 case HandleStub:
00275
00276 if (line == "kdesu_stub")
00277 {
00278 unreadLine(line);
00279 return ok;
00280 }
00281 break;
00283 }
00284 }
00285 return ok;
00286 }
00287
00288 void SuProcess::virtual_hook( int id, void* data )
00289 { StubProcess::virtual_hook( id, data ); }
00290
00291
|