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

KDEsu

su.cpp

Go to the documentation of this file.
00001 /* vi: ts=8 sts=4 sw=4
00002 *
00003 * This file is part of the KDE project, module kdesu.
00004 * Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org>
00005 *
00006 * Sudo support added by Jonathan Riddell <jriddell@ ubuntu.com>
00007 * Copyright (C) 2005 Canonical Ltd  // krazy:exclude=copyright (no email)
00008 *
00009 * This is free software; you can use this library under the GNU Library
00010 * General Public License, version 2. See the file "COPYING.LIB" for the
00011 * exact licensing terms.
00012 *
00013 * su.cpp: Execute a program as another user with "class SuProcess".
00014 */
00015 
00016 #include "su.h"
00017 #include "kcookie.h"
00018 
00019 #include <config.h>
00020 #include <config-prefix.h> // for LIBEXEC_INSTALL_DIR
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 * Execute a command with su(1).
00116 */
00117 
00118 int SuProcess::exec(const char *password, int check)
00119 {
00120     if (check)
00121         setTerminal(true);
00122 
00123     // since user may change after constructor (due to setUser())
00124     // we need to override sudo with su for non-root here
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 += "-"; // krazy:exclude=doublequote_chars (QList, not QString)
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     // kDebug(900) << k_lineinfo << "Call StubProcess::exec()";
00160     if (StubProcess::exec(command, args) < 0)
00161     {
00162         return check ? SuNotFound : -1;
00163     }
00164     // kDebug(900) << k_lineinfo << "Done StubProcess::exec()";
00165 
00166     SuErrors ret = (SuErrors) ConverseSU(password);
00167     // kDebug(900) << k_lineinfo << "Conversation returned " << ret;
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             // sudo can not be killed, just return
00181             return ret;
00182         }
00183         if (kill(m_Pid, SIGKILL) < 0) {
00184             kDebug() << "kill < 0";
00185         //FIXME SIGKILL doesn't work for sudo,
00186         //why is this different from su?
00187         //A: because sudo runs as root. Perhaps we could write a Ctrl+C to its stdin, instead?
00188         ret=error;
00189         }
00190             else
00191             {
00192                 int iret = waitForChild();
00193                 if (iret < 0) ret=error;
00194                 else /* nothing */ {} ;
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 * Conversation with su: feed the password.
00238 * Return values: -1 = error, 0 = ok, 1 = kill me, 2 not authorized
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     // kDebug(900) << k_lineinfo << "ConverseSU starting.";
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                 // In case no password is needed.
00262                 if (line == "kdesu_stub")
00263                 {
00264                     unreadLine(line);
00265                     return ok;
00266                 }
00267 
00268                 while(waitMS(fd(),100)>0)
00269                 {
00270                     // There is more output available, so the previous line
00271                     // couldn't have been a password prompt (the definition
00272                     // of prompt being that  there's a line of output followed 
00273                     // by a colon, and then the process waits).
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                 // Match "Password: " with the regex ^[^:]+:[\w]*$.
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                 // Read till we get "kdesu_stub"
00337                 if (line == "kdesu_stub")
00338                 {
00339                     unreadLine(line);
00340                     return ok;
00341                 } else if (!line.isEmpty ()) {
00342                     // if we read anything else, it's probably a
00343                     // sorry, wrong password.
00344                     return notauthorized;
00345                 }
00346                 break;
00348         } // end switch
00349     } // end while (true)
00350     return ok;
00351 }
00352 
00353 void SuProcess::virtual_hook( int id, void* data )
00354 { StubProcess::virtual_hook( id, data ); }
00355 
00356 }

KDEsu

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
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