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 if ((m_Scheduler != SchedNormal) || (m_Priority > 50))
00079 args += "root";
00080 else
00081 args += m_User;
00082
00083 args += "-c";
00084 args += QCString(__KDE_BINDIR) + "/kdesu_stub";
00085 args += "-";
00086
00087 QCString command = __PATH_SU;
00088 if (::access(__PATH_SU, X_OK) != 0)
00089 {
00090 command = QFile::encodeName(KGlobal::dirs()->findExe("su"));
00091 if (command.isEmpty())
00092 return check ? SuNotFound : -1;
00093 }
00094
00095
00096 if (StubProcess::exec(command, args) < 0)
00097 {
00098 return check ? SuNotFound : -1;
00099 }
00100
00101
00102 SuErrors ret = (SuErrors) ConverseSU(password);
00103
00104
00105 if (ret == error)
00106 {
00107 if (!check)
00108 kdError(900) << k_lineinfo << "Conversation with su failed\n";
00109 return ret;
00110 }
00111 if (check == NeedPassword)
00112 {
00113 if (ret == killme)
00114 {
00115 if (kill(m_Pid, SIGKILL) < 0)
00116 {
00117 ret=error;
00118 }
00119 else
00120 {
00121 int iret = waitForChild();
00122 if (iret < 0) ret=error;
00123 else {} ;
00124 }
00125 }
00126 return ret;
00127 }
00128
00129 if (m_bErase && password)
00130 {
00131 char *ptr = const_cast<char *>(password);
00132 const uint plen = strlen(password);
00133 for (unsigned i=0; i < plen; i++)
00134 ptr[i] = '\000';
00135 }
00136
00137 if (ret == notauthorized)
00138 {
00139 kill(m_Pid, SIGKILL);
00140 waitForChild();
00141 return SuIncorrectPassword;
00142 }
00143
00144 int iret = ConverseStub(check);
00145 if (iret < 0)
00146 {
00147 if (!check)
00148 kdError(900) << k_lineinfo << "Converstation with kdesu_stub failed\n";
00149 return iret;
00150 }
00151 else if (iret == 1)
00152 {
00153 kill(m_Pid, SIGKILL);
00154 waitForChild();
00155 return SuIncorrectPassword;
00156 }
00157
00158 if (check == Install)
00159 {
00160 waitForChild();
00161 return 0;
00162 }
00163
00164 iret = waitForChild();
00165 return iret;
00166 }
00167
00168
00169
00170
00171
00172
00173 int SuProcess::ConverseSU(const char *password)
00174 {
00175 enum { WaitForPrompt, CheckStar, HandleStub } state = WaitForPrompt;
00176 int colon;
00177 unsigned i, j;
00178
00179
00180 QCString line;
00181 while (true)
00182 {
00183 line = readLine();
00184 if (line.isNull())
00185 return ( state == HandleStub ? notauthorized : error);
00186 kdDebug(900) << k_lineinfo << "Read line <" << line << ">" << endl;
00187
00188 switch (state)
00189 {
00191 case WaitForPrompt:
00192 {
00193
00194 if (line == "kdesu_stub")
00195 {
00196 unreadLine(line);
00197 return ok;
00198 }
00199
00200 while(waitMS(m_Fd,100)>0)
00201 {
00202
00203
00204
00205
00206 QCString more = readLine();
00207 if (more.isEmpty())
00208 break;
00209
00210 line = more;
00211 kdDebug(900) << k_lineinfo << "Read line <" << more << ">" << endl;
00212 }
00213
00214
00215 const uint len = line.length();
00216 for (i=0,j=0,colon=0; i<len; i++)
00217 {
00218 if (line[i] == ':')
00219 {
00220 j = i; colon++;
00221 continue;
00222 }
00223 if (!isspace(line[i]))
00224 j++;
00225 }
00226 if ((colon == 1) && (line[j] == ':'))
00227 {
00228 if (password == 0L)
00229 return killme;
00230 if (!checkPid(m_Pid))
00231 {
00232 kdError(900) << "su has exited while waiting for pwd." << endl;
00233 return error;
00234 }
00235 if ((WaitSlave() == 0) && checkPid(m_Pid))
00236 {
00237 write(m_Fd, password, strlen(password));
00238 write(m_Fd, "\n", 1);
00239 state=CheckStar;
00240 }
00241 else
00242 {
00243 return error;
00244 }
00245 }
00246 break;
00247 }
00249 case CheckStar:
00250 {
00251 QCString s = line.stripWhiteSpace();
00252 if (s.isEmpty())
00253 {
00254 state=HandleStub;
00255 break;
00256 }
00257 const uint len = line.length();
00258 for (i=0; i< len; i++)
00259 {
00260 if (s[i] != '*')
00261 return error;
00262 }
00263 state=HandleStub;
00264 break;
00265 }
00267 case HandleStub:
00268
00269 if (line == "kdesu_stub")
00270 {
00271 unreadLine(line);
00272 return ok;
00273 }
00274 break;
00276 }
00277 }
00278 return ok;
00279 }
00280
00281 void SuProcess::virtual_hook( int id, void* data )
00282 { StubProcess::virtual_hook( id, data ); }
00283
00284
|