• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KDEsu

su.cpp

Go to the documentation of this file.
00001 /* vi: ts=8 sts=4 sw=4
00002 *
00003 * $Id: su.cpp 592501 2006-10-04 23:00:23Z mueller $
00004 *
00005 * This file is part of the KDE project, module kdesu.
00006 * Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org>
00007 * 
00008 * Sudo support added by Jonathan Riddell <jriddell@ ubuntu.com>
00009 * Copyright (C) 2005 Canonical Ltd
00010 *
00011 * This is free software; you can use this library under the GNU Library 
00012 * General Public License, version 2. See the file "COPYING.LIB" for the 
00013 * exact licensing terms.
00014 *
00015 * su.cpp: Execute a program as another user with "class SuProcess".
00016 */
00017 
00018 #include <config.h>
00019 
00020 #include <stdio.h>
00021 #include <stdlib.h>
00022 #include <unistd.h>
00023 #include <fcntl.h>
00024 #include <errno.h>
00025 #include <string.h>
00026 #include <ctype.h>
00027 #include <signal.h>
00028 
00029 #include <sys/types.h>
00030 #include <sys/stat.h>
00031 
00032 #include <qglobal.h>
00033 #include <qcstring.h>
00034 #include <qfile.h>
00035 
00036 #include <kconfig.h>
00037 #include <kdebug.h>
00038 #include <klocale.h>
00039 #include <kstandarddirs.h>
00040 
00041 #include "su.h"
00042 #include "kcookie.h"
00043 
00044 
00045 #ifndef __PATH_SU
00046 #define __PATH_SU "false"
00047 #endif
00048 
00049 #ifndef __PATH_SUDO
00050 #define __PATH_SUDO "false"
00051 #endif
00052 
00053 SuProcess::SuProcess(const QCString &user, const QCString &command)
00054 {
00055     m_User = user;
00056     m_Command = command;
00057 
00058     KConfig* config = KGlobal::config();
00059     config->setGroup("super-user-command");
00060     superUserCommand = config->readEntry("super-user-command", DEFAULT_SUPER_USER_COMMAND);
00061     if ( superUserCommand != "sudo" && superUserCommand != "su" ) {
00062     kdWarning() << "unknown super user command" << endl;
00063     superUserCommand = "su";
00064     }
00065 }
00066 
00067 
00068 SuProcess::~SuProcess()
00069 {
00070 }
00071 
00072 int SuProcess::checkInstall(const char *password)
00073 {
00074     return exec(password, Install);
00075 }
00076 
00077 int SuProcess::checkNeedPassword()
00078 {
00079     return exec(0L, NeedPassword);
00080 }
00081 
00082 /*
00083 * Execute a command with su(1).
00084 */
00085 
00086 int SuProcess::exec(const char *password, int check)
00087 {
00088     if (check)
00089         setTerminal(true);
00090 
00091     // since user may change after constructor (due to setUser())
00092     // we need to override sudo with su for non-root here
00093     if (m_User != "root") {
00094         superUserCommand = "su";
00095     }
00096 
00097     QCStringList args;
00098     if (superUserCommand == "sudo") {
00099         args += "-u";
00100     }
00101 
00102 #ifdef Q_OS_DARWIN
00103     args += "-c";
00104     args += "staff";
00105 #endif
00106 
00107     if ((m_Scheduler != SchedNormal) || (m_Priority > 50))
00108         args += "root";
00109     else
00110         args += m_User;
00111     
00112     if (superUserCommand == "su") {
00113         args += "-c";
00114     }
00115     args += QCString(__KDE_BINDIR) + "/kdesu_stub";
00116 #ifndef Q_OS_DARWIN
00117     args += "-";
00118 #endif
00119 
00122     QCString command;
00123     if (superUserCommand == "sudo") {
00124         command = __PATH_SUDO;
00125     } else {
00126         command = __PATH_SU;
00127     }
00128  
00129     if (::access(command, X_OK) != 0)
00130     {
00132         command = QFile::encodeName( KGlobal::dirs()->findExe(superUserCommand.ascii()) );
00133         if (command.isEmpty())
00134             return check ? SuNotFound : -1;
00135     }
00136 
00137     // kdDebug(900) << k_lineinfo << "Call StubProcess::exec()" << endl;
00138     if (StubProcess::exec(command, args) < 0)
00139     {
00140         return check ? SuNotFound : -1;
00141     }
00142     // kdDebug(900) << k_lineinfo << "Done StubProcess::exec()" << endl;
00143 
00144     SuErrors ret = (SuErrors) ConverseSU(password);
00145     // kdDebug(900) << k_lineinfo << "Conversation returned " << ret << endl;
00146 
00147     if (ret == error)
00148     {
00149         if (!check)
00150             kdError(900) << k_lineinfo << "Conversation with " << superUserCommand << " failed\n";
00151         return ret;
00152     }
00153     if (check == NeedPassword)
00154     {
00155         if (ret == killme)
00156         {
00161             if ( superUserCommand == "sudo" ) {
00162             // sudo can not be killed, just return
00163             return ret;
00164         }
00165         if (kill(m_Pid, SIGKILL) < 0) {
00166             kdDebug() << k_funcinfo << "kill < 0" << endl;
00167         //FIXME SIGKILL doesn't work for sudo,
00168         //why is this different from su?
00169         ret=error;
00170         }
00171             else
00172             {
00173                 int iret = waitForChild();
00174                 if (iret < 0) ret=error;
00175                 else /* nothing */ {} ;
00176             }
00177         }
00178         return ret;
00179     }
00180 
00181     if (m_bErase && password) 
00182     {
00183         char *ptr = const_cast<char *>(password);
00184         const uint plen = strlen(password);
00185         for (unsigned i=0; i < plen; i++)
00186             ptr[i] = '\000';
00187     }
00188 
00189     if (ret == notauthorized)
00190     {
00191         kill(m_Pid, SIGKILL);
00192         if (superUserCommand != "sudo") {
00193             waitForChild();
00194         }
00195         return SuIncorrectPassword;
00196     }
00197 
00198     int iret = ConverseStub(check);
00199     if (iret < 0)
00200     {
00201         if (!check)
00202             kdError(900) << k_lineinfo << "Converstation with kdesu_stub failed\n";
00203         return iret;
00204     }
00205     else if (iret == 1)
00206     {
00207         kill(m_Pid, SIGKILL);
00208         waitForChild();
00209         return SuIncorrectPassword;
00210     }
00211 
00212     if (check == Install)
00213     {
00214         waitForChild();
00215         return 0;
00216     }
00217 
00218     iret = waitForChild();
00219     return iret;
00220 }
00221 
00222 /*
00223 * Conversation with su: feed the password.
00224 * Return values: -1 = error, 0 = ok, 1 = kill me, 2 not authorized
00225 */
00226 
00227 int SuProcess::ConverseSU(const char *password)
00228 {   
00229     enum { WaitForPrompt, CheckStar, HandleStub } state = WaitForPrompt;
00230     int colon;
00231     unsigned i, j;
00232     // kdDebug(900) << k_lineinfo << "ConverseSU starting." << endl;
00233 
00234     QCString line;
00235     while (true)
00236     {
00237         line = readLine();
00238         if (line.isNull())
00239             return ( state == HandleStub ? notauthorized : error);
00240         kdDebug(900) << k_lineinfo << "Read line <" << line << ">" << endl;
00241 
00242         switch (state) 
00243         {
00245             case WaitForPrompt:
00246             {
00247                 // In case no password is needed.
00248                 if (line == "kdesu_stub")
00249                 {
00250                     unreadLine(line);
00251                     return ok;
00252                 }
00253     
00254                 while(waitMS(m_Fd,100)>0)
00255                 {
00256                     // There is more output available, so the previous line
00257                     // couldn't have been a password prompt (the definition
00258                     // of prompt being that  there's a line of output followed 
00259                     // by a colon, and then the process waits).
00260                     QCString more = readLine();
00261                     if (more.isEmpty())
00262                         break;
00263     
00264                     line = more;
00265                     kdDebug(900) << k_lineinfo << "Read line <" << more << ">" << endl;
00266                 }
00267     
00268                 // Match "Password: " with the regex ^[^:]+:[\w]*$.
00269                 const uint len = line.length();
00270                 for (i=0,j=0,colon=0; i<len; i++) 
00271                 {
00272                     if (line[i] == ':') 
00273                     {
00274                         j = i; colon++;
00275                         continue;
00276                     }
00277                     if (!isspace(line[i]))
00278                         j++;
00279                 }
00280                 if ((colon == 1) && (line[j] == ':')) 
00281                 {
00282                     if (password == 0L)
00283                         return killme;
00284                     if (!checkPid(m_Pid))
00285                     {
00286                         kdError(900) << superUserCommand << " has exited while waiting for pwd." << endl;
00287                         return error;
00288                     }
00289                     if ((WaitSlave() == 0) && checkPid(m_Pid))
00290                     {
00291                         write(m_Fd, password, strlen(password));
00292                         write(m_Fd, "\n", 1);
00293                         state=CheckStar;
00294                     }
00295                     else
00296                     {
00297                         return error;
00298                     }
00299                 }
00300                 break;
00301             }
00303             case CheckStar:
00304             {
00305                 QCString s = line.stripWhiteSpace();
00306                 if (s.isEmpty()) 
00307                 {
00308                     state=HandleStub;
00309                     break;
00310                 }
00311                 const uint len = line.length();
00312                 for (i=0; i< len; i++)
00313                     {
00314                 if (s[i] != '*')
00315                     return error;
00316                 }
00317                 state=HandleStub;
00318                 break;
00319             }
00321             case HandleStub:
00322                 // Read till we get "kdesu_stub"
00323                 if (line == "kdesu_stub")
00324                 {
00325                     unreadLine(line);
00326                     return ok;
00327             } else if (superUserCommand == "sudo") {
00328                 // sudo gives a "sorry" line so reaches here
00329                 // with the wrong password
00330                 return notauthorized;
00331                 }
00332                 break;
00334         } // end switch
00335     } // end while (true)
00336     return ok;
00337 }
00338 
00339 void SuProcess::virtual_hook( int id, void* data )
00340 { StubProcess::virtual_hook( id, data ); }
00341 
00342 

KDEsu

Skip menu "KDEsu"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal