• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • 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 int kdesuDebugArea()
00044 {
00045     static int s_area = KDebug::registerArea("kdesu (kdelibs)");
00046     return s_area;
00047 }
00048 
00049 #ifndef __PATH_SU
00050 #define __PATH_SU "false"
00051 #endif
00052 
00053 #ifndef __PATH_SUDO
00054 #define __PATH_SUDO "false"
00055 #endif
00056 
00057 #ifdef KDESU_USE_SUDO_DEFAULT
00058 #  define DEFAULT_SUPER_USER_COMMAND "sudo"
00059 #else
00060 #  define DEFAULT_SUPER_USER_COMMAND "su"
00061 #endif
00062 
00063 namespace KDESu {
00064 using namespace KDESuPrivate;
00065 
00066 class SuProcess::SuProcessPrivate
00067 {
00068 public:
00069     QString m_superUserCommand;
00070 };
00071 
00072 SuProcess::SuProcess(const QByteArray &user, const QByteArray &command)
00073     : d( new SuProcessPrivate )
00074 {
00075     m_User = user;
00076     m_Command = command;
00077 
00078     KSharedConfig::Ptr config = KGlobal::config();
00079     KConfigGroup group(config, "super-user-command");
00080     d->m_superUserCommand = group.readEntry("super-user-command", DEFAULT_SUPER_USER_COMMAND);
00081 
00082     if ( d->m_superUserCommand != "sudo" && d->m_superUserCommand != "su" ) {
00083       kWarning() << "unknown super user command.";
00084       d->m_superUserCommand = DEFAULT_SUPER_USER_COMMAND;
00085     }
00086 }
00087 
00088 
00089 SuProcess::~SuProcess()
00090 {
00091     delete d;
00092 }
00093 
00094 QString SuProcess::superUserCommand()
00095 {
00096     return d->m_superUserCommand;
00097 }
00098 
00099 bool SuProcess::useUsersOwnPassword()
00100 {
00101     if (superUserCommand() == "sudo" && m_User == "root") {
00102         return true;
00103     }
00104 
00105     KUser user;
00106     return user.loginName() == m_User;
00107 }
00108 
00109 int SuProcess::checkInstall(const char *password)
00110 {
00111     return exec(password, Install);
00112 }
00113 
00114 int SuProcess::checkNeedPassword()
00115 {
00116     return exec(0L, NeedPassword);
00117 }
00118 
00119 /*
00120 * Execute a command with su(1).
00121 */
00122 
00123 int SuProcess::exec(const char *password, int check)
00124 {
00125     if (check)
00126         setTerminal(true);
00127 
00128     // since user may change after constructor (due to setUser())
00129     // we need to override sudo with su for non-root here
00130     if (m_User != "root") {
00131         d->m_superUserCommand = "su";
00132     }
00133 
00134     QList<QByteArray> args;
00135     if (d->m_superUserCommand == "sudo") {
00136         args += "-u";
00137     }
00138 
00139     if ((m_Scheduler != SchedNormal) || (m_Priority > 50))
00140         args += "root";
00141     else
00142         args += m_User;
00143 
00144     if (d->m_superUserCommand == "su") {
00145         args += "-c";
00146     }
00147     args += QByteArray(LIBEXEC_INSTALL_DIR) + "/kdesu_stub";
00148     args += "-"; // krazy:exclude=doublequote_chars (QList, not QString)
00149 
00150     QByteArray command;
00151     if (d->m_superUserCommand == "sudo") {
00152         command = __PATH_SUDO;
00153     } else {
00154         command = __PATH_SU;
00155     }
00156 
00157     if (::access(command, X_OK) != 0)
00158     {
00159         command = QFile::encodeName( KGlobal::dirs()->findExe(d->m_superUserCommand.toLatin1()) );
00160         if (command.isEmpty())
00161             return check ? SuNotFound : -1;
00162     }
00163 
00164     // kDebug(kdesuDebugArea()) << k_lineinfo << "Call StubProcess::exec()";
00165     if (StubProcess::exec(command, args) < 0)
00166     {
00167         return check ? SuNotFound : -1;
00168     }
00169     // kDebug(kdesuDebugArea()) << k_lineinfo << "Done StubProcess::exec()";
00170 
00171     SuErrors ret = (SuErrors) ConverseSU(password);
00172     // kDebug(kdesuDebugArea()) << k_lineinfo << "Conversation returned" << ret;
00173 
00174     if (ret == error)
00175     {
00176         if (!check)
00177             kError(kdesuDebugArea()) << k_lineinfo << "Conversation with su failed.";
00178         return ret;
00179     }
00180     if (check == NeedPassword)
00181     {
00182         if (ret == killme)
00183         {
00184             if ( d->m_superUserCommand == "sudo" ) {
00185             // sudo can not be killed, just return
00186             return ret;
00187         }
00188         if (kill(m_Pid, SIGKILL) < 0) {
00189             kDebug() << "kill < 0";
00190         //FIXME SIGKILL doesn't work for sudo,
00191         //why is this different from su?
00192         //A: because sudo runs as root. Perhaps we could write a Ctrl+C to its stdin, instead?
00193         ret=error;
00194         }
00195             else
00196             {
00197                 int iret = waitForChild();
00198                 if (iret < 0) ret=error;
00199                 else /* nothing */ {} ;
00200             }
00201         }
00202         return ret;
00203     }
00204 
00205     if (m_bErase && password)
00206         memset(const_cast<char *>(password), 0, qstrlen(password));
00207 
00208     if (ret != ok)
00209     {
00210         kill(m_Pid, SIGKILL);
00211         if (d->m_superUserCommand != "sudo") {
00212             waitForChild();
00213         }
00214         return SuIncorrectPassword;
00215     }
00216 
00217     int iret = ConverseStub(check);
00218     if (iret < 0)
00219     {
00220         if (!check)
00221             kError(kdesuDebugArea()) << k_lineinfo << "Conversation with kdesu_stub failed.";
00222         return iret;
00223     }
00224     else if (iret == 1)
00225     {
00226         kill(m_Pid, SIGKILL);
00227         waitForChild();
00228         return SuIncorrectPassword;
00229     }
00230 
00231     if (check == Install)
00232     {
00233         waitForChild();
00234         return 0;
00235     }
00236 
00237     iret = waitForChild();
00238     return iret;
00239 }
00240 
00241 /*
00242 * Conversation with su: feed the password.
00243 * Return values: -1 = error, 0 = ok, 1 = kill me, 2 not authorized
00244 */
00245 
00246 int SuProcess::ConverseSU(const char *password)
00247 {
00248     enum { WaitForPrompt, CheckStar, HandleStub } state = WaitForPrompt;
00249     int colon;
00250     unsigned i, j;
00251     // kDebug(kdesuDebugArea()) << k_lineinfo << "ConverseSU starting.";
00252 
00253     QByteArray line;
00254     while (true)
00255     {
00256         line = readLine();
00257         if (line.isNull())
00258             return ( state == HandleStub ? notauthorized : error);
00259         kDebug(kdesuDebugArea()) << k_lineinfo << "Read line" << line;
00260 
00261         if (line == "kdesu_stub")
00262         {
00263             unreadLine(line);
00264             return ok;
00265         }
00266 
00267         switch (state)
00268         {
00270             case WaitForPrompt:
00271             {
00272                 if (waitMS(fd(),100)>0)
00273                 {
00274                     // There is more output available, so this line
00275                     // couldn't have been a password prompt (the definition
00276                     // of prompt being that  there's a line of output followed
00277                     // by a colon, and then the process waits).
00278                     continue;
00279                 }
00280 
00281                 // Match "Password: " with the regex ^[^:]+:[\w]*$.
00282                 const uint len = line.length();
00283                 for (i=0,j=0,colon=0; i<len; i++)
00284                 {
00285                     if (line[i] == ':')
00286                     {
00287                         j = i; colon++;
00288                         continue;
00289                     }
00290                     if (!isspace(line[i]))
00291                         j++;
00292                 }
00293                 if ((colon == 1) && (line[j] == ':'))
00294                 {
00295                     if (password == 0L)
00296                         return killme;
00297                     if (WaitSlave())
00298                         return error;
00299                     write(fd(), password, strlen(password));
00300                     write(fd(), "\n", 1);
00301                     state = CheckStar;
00302                 }
00303                 break;
00304             }
00306             case CheckStar:
00307             {
00308                 QByteArray s = line.trimmed();
00309                 if (s.isEmpty())
00310                 {
00311                     state=HandleStub;
00312                     break;
00313                 }
00314                 const uint len = line.length();
00315                 for (i=0; i< len; i++)
00316                     {
00317                 if (s[i] != '*')
00318                     return error;
00319                 }
00320                 state=HandleStub;
00321                 break;
00322             }
00324             case HandleStub:
00325                 break;
00327         } // end switch
00328     } // end while (true)
00329     return ok;
00330 }
00331 
00332 void SuProcess::virtual_hook( int id, void* data )
00333 { StubProcess::virtual_hook( id, data ); }
00334 
00335 }

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
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
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