summaryrefslogtreecommitdiffstats
path: root/tdesu/su.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tdesu/su.cpp')
-rw-r--r--tdesu/su.cpp342
1 files changed, 342 insertions, 0 deletions
diff --git a/tdesu/su.cpp b/tdesu/su.cpp
new file mode 100644
index 000000000..0739c29c3
--- /dev/null
+++ b/tdesu/su.cpp
@@ -0,0 +1,342 @@
+/* vi: ts=8 sts=4 sw=4
+*
+* $Id$
+*
+* This file is part of the KDE project, module tdesu.
+* Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org>
+*
+* Sudo support added by Jonathan Riddell <jriddell@ ubuntu.com>
+* Copyright (C) 2005 Canonical Ltd
+*
+* This is free software; you can use this library under the GNU Library
+* General Public License, version 2. See the file "COPYING.LIB" for the
+* exact licensing terms.
+*
+* su.cpp: Execute a program as another user with "class SuProcess".
+*/
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <tqglobal.h>
+#include <tqcstring.h>
+#include <tqfile.h>
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+#include "su.h"
+#include "kcookie.h"
+
+
+#ifndef __PATH_SU
+#define __PATH_SU "false"
+#endif
+
+#ifndef __PATH_SUDO
+#define __PATH_SUDO "false"
+#endif
+
+SuProcess::SuProcess(const TQCString &user, const TQCString &command)
+{
+ m_User = user;
+ m_Command = command;
+
+ KConfig* config = KGlobal::config();
+ config->setGroup("super-user-command");
+ superUserCommand = config->readEntry("super-user-command", DEFAULT_SUPER_USER_COMMAND);
+ if ( superUserCommand != "sudo" && superUserCommand != "su" ) {
+ kdWarning() << "unknown super user command" << endl;
+ superUserCommand = "su";
+ }
+}
+
+
+SuProcess::~SuProcess()
+{
+}
+
+int SuProcess::checkInstall(const char *password)
+{
+ return exec(password, Install);
+}
+
+int SuProcess::checkNeedPassword()
+{
+ return exec(0L, NeedPassword);
+}
+
+/*
+* Execute a command with su(1).
+*/
+
+int SuProcess::exec(const char *password, int check)
+{
+ if (check)
+ setTerminal(true);
+
+ // since user may change after constructor (due to setUser())
+ // we need to override sudo with su for non-root here
+ if (m_User != "root") {
+ superUserCommand = "su";
+ }
+
+ QCStringList args;
+ if (superUserCommand == "sudo") {
+ args += "-u";
+ }
+
+#ifdef Q_OS_DARWIN
+ args += "-c";
+ args += "staff";
+#endif
+
+ if ((m_Scheduler != SchedNormal) || (m_Priority > 50))
+ args += "root";
+ else
+ args += m_User;
+
+ if (superUserCommand == "su") {
+ args += "-c";
+ }
+ args += TQCString(__KDE_BINDIR) + "/tdesu_stub";
+#ifndef Q_OS_DARWIN
+ args += "-";
+#endif
+
+ /// TQCString command = __PATH_SU;
+ /// if (::access(__PATH_SU, X_OK) != 0)
+ TQCString command;
+ if (superUserCommand == "sudo") {
+ command = __PATH_SUDO;
+ } else {
+ command = __PATH_SU;
+ }
+
+ if (::access(command, X_OK) != 0)
+ {
+ /// command = TQFile::encodeName(KGlobal::dirs()->findExe("su"));
+ command = TQFile::encodeName( KGlobal::dirs()->findExe(superUserCommand.ascii()) );
+ if (command.isEmpty())
+ return check ? SuNotFound : -1;
+ }
+
+ // kdDebug(900) << k_lineinfo << "Call StubProcess::exec()" << endl;
+ if (StubProcess::exec(command, args) < 0)
+ {
+ return check ? SuNotFound : -1;
+ }
+ // kdDebug(900) << k_lineinfo << "Done StubProcess::exec()" << endl;
+
+ SuErrors ret = (SuErrors) ConverseSU(password);
+ // kdDebug(900) << k_lineinfo << "Conversation returned " << ret << endl;
+
+ if (ret == error)
+ {
+ if (!check)
+ kdError(900) << k_lineinfo << "Conversation with " << superUserCommand << " failed\n";
+ return ret;
+ }
+ if (check == NeedPassword)
+ {
+ if (ret == killme)
+ {
+ /// if (kill(m_Pid, SIGKILL) < 0)
+ /// {
+ /// ret=error;
+ /// }
+ if ( superUserCommand == "sudo" ) {
+ // sudo can not be killed, just return
+ return ret;
+ }
+ if (kill(m_Pid, SIGKILL) < 0) {
+ kdDebug() << k_funcinfo << "kill < 0" << endl;
+ //FIXME SIGKILL doesn't work for sudo,
+ //why is this different from su?
+ ret=error;
+ }
+ else
+ {
+ int iret = waitForChild();
+ if (iret < 0) ret=error;
+ else /* nothing */ {} ;
+ }
+ }
+ return ret;
+ }
+
+ if (m_bErase && password)
+ {
+ char *ptr = const_cast<char *>(password);
+ const uint plen = strlen(password);
+ for (unsigned i=0; i < plen; i++)
+ ptr[i] = '\000';
+ }
+
+ if (ret == notauthorized)
+ {
+ kill(m_Pid, SIGKILL);
+ if (superUserCommand != "sudo") {
+ waitForChild();
+ }
+ return SuIncorrectPassword;
+ }
+
+ int iret = ConverseStub(check);
+ if (iret < 0)
+ {
+ if (!check)
+ kdError(900) << k_lineinfo << "Converstation with tdesu_stub failed\n";
+ return iret;
+ }
+ else if (iret == 1)
+ {
+ kill(m_Pid, SIGKILL);
+ waitForChild();
+ return SuIncorrectPassword;
+ }
+
+ if (check == Install)
+ {
+ waitForChild();
+ return 0;
+ }
+
+ iret = waitForChild();
+ return iret;
+}
+
+/*
+* Conversation with su: feed the password.
+* Return values: -1 = error, 0 = ok, 1 = kill me, 2 not authorized
+*/
+
+int SuProcess::ConverseSU(const char *password)
+{
+ enum { WaitForPrompt, CheckStar, HandleStub } state = WaitForPrompt;
+ int colon;
+ unsigned i, j;
+ // kdDebug(900) << k_lineinfo << "ConverseSU starting." << endl;
+
+ TQCString line;
+ while (true)
+ {
+ line = readLine();
+ if (line.isNull())
+ return ( state == HandleStub ? notauthorized : error);
+ kdDebug(900) << k_lineinfo << "Read line <" << line << ">" << endl;
+
+ switch (state)
+ {
+ //////////////////////////////////////////////////////////////////////////
+ case WaitForPrompt:
+ {
+ // In case no password is needed.
+ if (line == "tdesu_stub")
+ {
+ unreadLine(line);
+ return ok;
+ }
+
+ while(waitMS(m_Fd,100)>0)
+ {
+ // There is more output available, so the previous line
+ // couldn't have been a password prompt (the definition
+ // of prompt being that there's a line of output followed
+ // by a colon, and then the process waits).
+ TQCString more = readLine();
+ if (more.isEmpty())
+ break;
+
+ line = more;
+ kdDebug(900) << k_lineinfo << "Read line <" << more << ">" << endl;
+ }
+
+ // Match "Password: " with the regex ^[^:]+:[\w]*$.
+ const uint len = line.length();
+ for (i=0,j=0,colon=0; i<len; i++)
+ {
+ if (line[i] == ':')
+ {
+ j = i; colon++;
+ continue;
+ }
+ if (!isspace(line[i]))
+ j++;
+ }
+ if ((colon == 1) && (line[j] == ':'))
+ {
+ if (password == 0L)
+ return killme;
+ if (!checkPid(m_Pid))
+ {
+ kdError(900) << superUserCommand << " has exited while waiting for pwd." << endl;
+ return error;
+ }
+ if ((WaitSlave() == 0) && checkPid(m_Pid))
+ {
+ write(m_Fd, password, strlen(password));
+ write(m_Fd, "\n", 1);
+ state=CheckStar;
+ }
+ else
+ {
+ return error;
+ }
+ }
+ break;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ case CheckStar:
+ {
+ TQCString s = line.stripWhiteSpace();
+ if (s.isEmpty())
+ {
+ state=HandleStub;
+ break;
+ }
+ const uint len = line.length();
+ for (i=0; i< len; i++)
+ {
+ if (s[i] != '*')
+ return error;
+ }
+ state=HandleStub;
+ break;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ case HandleStub:
+ // Read till we get "tdesu_stub"
+ if (line == "tdesu_stub")
+ {
+ unreadLine(line);
+ return ok;
+ } else if (superUserCommand == "sudo") {
+ // sudo gives a "sorry" line so reaches here
+ // with the wrong password
+ return notauthorized;
+ }
+ break;
+ //////////////////////////////////////////////////////////////////////////
+ } // end switch
+ } // end while (true)
+ return ok;
+}
+
+void SuProcess::virtual_hook( int id, void* data )
+{ StubProcess::virtual_hook( id, data ); }
+
+