From 7419f793b02e2ad21768dd7ddd7a51c81f64e6d5 Mon Sep 17 00:00:00 2001 From: Ivailo Monev Date: Sun, 15 May 2016 02:06:56 +0000 Subject: [PATCH] generic: replace kdesu with kdesudo Signed-off-by: Ivailo Monev --- CMakeLists.txt | 10 +- ConfigureChecks.cmake | 26 +- cmake/modules/FindKDE4Internal.cmake | 2 - includes/CMakeLists.txt | 5 - includes/KDEsuClient | 1 - includes/PtyProcess | 1 - includes/SshProcess | 1 - includes/StubProcess | 1 - includes/SuProcess | 1 - kdecore/kdebug.areas | 3 +- kdesu/CMakeLists.txt | 80 ---- kdesu/README | 13 - kdesu/client.cpp | 438 --------------------- kdesu/client.h | 204 ---------- kdesu/config-kdesu.h.cmake | 7 - kdesu/defaults.h | 22 -- kdesu/kcookie.cpp | 107 ------ kdesu/kcookie.h | 54 --- kdesu/kdesu_stub.c | 414 -------------------- kdesu/process.cpp | 552 --------------------------- kdesu/process.h | 201 ---------- kdesu/ssh.cpp | 259 ------------- kdesu/ssh.h | 81 ---- kdesu/stub.cpp | 222 ----------- kdesu/stub.h | 106 ----- kdesu/su.cpp | 329 ---------------- kdesu/su.h | 74 ---- kdesudo/CMakeLists.txt | 20 + kdesudo/Messages.sh | 2 + kdesudo/config.h.cmake | 2 + kdesudo/kcookie.cpp | 105 +++++ kdesudo/kcookie.h | 57 +++ kdesudo/kdesudo.cpp | 387 +++++++++++++++++++ kdesudo/kdesudo.h | 94 +++++ kdesudo/main.cpp | 160 ++++++++ kdeui/kernel/kstartupinfo.cpp | 2 +- kinit/kinit.cpp | 8 +- kio/kfile/kfilesharedialog.cpp | 2 +- kio/kio/krun.cpp | 6 +- kio/tests/krununittest.cpp | 8 +- kutils/kcmoduleproxy.cpp | 2 +- kutils/kcmultidialog.cpp | 1 + 42 files changed, 865 insertions(+), 3205 deletions(-) delete mode 100644 includes/KDEsuClient delete mode 100644 includes/PtyProcess delete mode 100644 includes/SshProcess delete mode 100644 includes/StubProcess delete mode 100644 includes/SuProcess delete mode 100644 kdesu/CMakeLists.txt delete mode 100644 kdesu/README delete mode 100644 kdesu/client.cpp delete mode 100644 kdesu/client.h delete mode 100644 kdesu/config-kdesu.h.cmake delete mode 100644 kdesu/defaults.h delete mode 100644 kdesu/kcookie.cpp delete mode 100644 kdesu/kcookie.h delete mode 100644 kdesu/kdesu_stub.c delete mode 100644 kdesu/process.cpp delete mode 100644 kdesu/process.h delete mode 100644 kdesu/ssh.cpp delete mode 100644 kdesu/ssh.h delete mode 100644 kdesu/stub.cpp delete mode 100644 kdesu/stub.h delete mode 100644 kdesu/su.cpp delete mode 100644 kdesu/su.h create mode 100644 kdesudo/CMakeLists.txt create mode 100755 kdesudo/Messages.sh create mode 100644 kdesudo/config.h.cmake create mode 100644 kdesudo/kcookie.cpp create mode 100644 kdesudo/kcookie.h create mode 100644 kdesudo/kdesudo.cpp create mode 100644 kdesudo/kdesudo.h create mode 100644 kdesudo/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c04880d3..1cbd1e02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,14 @@ set_package_properties(Perl PROPERTIES PURPOSE "Needed for KIO fileshareset and KDEUI preparetips scripts" ) +find_package(Sudo) +set_package_properties(Sudo PROPERTIES + DESCRIPTION "Sudo allows a system administrator to delegate authority to give certain users" + URL "http://www.sudo.ws/" + TYPE RUNTIME + PURPOSE "Needed for kdesudo to operate" +) + find_package(ZLIB) set_package_properties(ZLIB PROPERTIES DESCRIPTION "Support for gzip compressed files and data streams" @@ -266,7 +274,7 @@ add_subdirectory( kdcraw ) add_subdirectory( kdeclarative ) add_subdirectory( kdecore ) add_subdirectory( kded ) -add_subdirectory( kdesu ) +add_subdirectory( kdesudo ) add_subdirectory( kdeui ) if(QT_QTWEBKIT_FOUND) add_subdirectory( kdewebkit ) diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index a14c9699..0f3bfdfc 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -69,7 +69,7 @@ macro_bool_to_01(X11_Xrender_FOUND HAVE_XRENDER) # kio check_symbol_exists(strtoll "stdlib.h" HAVE_STRTOLL) # kioslave check_symbol_exists(S_ISSOCK "sys/stat.h" HAVE_S_ISSOCK) # config.h check_symbol_exists(vsnprintf "stdio.h" HAVE_VSNPRINTF) # config.h -check_symbol_exists(getgrouplist "unistd.h;grp.h" HAVE_GETGROUPLIST)# kdecore/fakes.c +check_symbol_exists(getgrouplist "unistd.h;grp.h" HAVE_GETGROUPLIST)# kdecore/fakes.cpp check_function_exists(backtrace HAVE_BACKTRACE) # kdecore, kio check_function_exists(fdatasync HAVE_FDATASYNC) # kdecore, kate @@ -94,7 +94,7 @@ check_library_exists(socket connect "" HAVE_SOCKET_LIBRARY) if (UNIX) - # for kdecore (kpty) & kdesu + # for kpty check_include_files("sys/types.h;libutil.h" HAVE_LIBUTIL_H) check_include_files(util.h HAVE_UTIL_H) @@ -182,19 +182,19 @@ if (UNIX) endif (UNIX) check_function_exists(getmntinfo HAVE_GETMNTINFO) # kdecore, kio -check_function_exists(initgroups HAVE_INITGROUPS) # kde3support/k3process, kdesu -check_function_exists(mkstemps HAVE_MKSTEMPS) # dcop, kdecore/fakes.c -check_function_exists(mkstemp HAVE_MKSTEMP) # kdecore/fakes.c -check_function_exists(mkdtemp HAVE_MKDTEMP) # kdecore/fakes.c -check_function_exists(strlcpy HAVE_STRLCPY) # kdecore/fakes.c -check_function_exists(strlcat HAVE_STRLCAT) # kdecore/fakes.c -check_function_exists(strcasestr HAVE_STRCASESTR) # kdecore/fakes.c +check_function_exists(initgroups HAVE_INITGROUPS) # kdecore/fakes.cpp +check_function_exists(mkstemps HAVE_MKSTEMPS) # dcop, kdecore/fakes.cpp +check_function_exists(mkstemp HAVE_MKSTEMP) # kdecore/fakes.cpp +check_function_exists(mkdtemp HAVE_MKDTEMP) # kdecore/fakes.cpp +check_function_exists(strlcpy HAVE_STRLCPY) # kdecore/fakes.cpp +check_function_exists(strlcat HAVE_STRLCAT) # kdecore/fakes.cpp +check_function_exists(strcasestr HAVE_STRCASESTR) # kdecore/fakes.cpp check_symbol_exists(strcasestr string.h HAVE_STRCASESTR_PROTO) -check_function_exists(setenv HAVE_SETENV) # kdecore/fakes.c -check_function_exists(seteuid HAVE_SETEUID) # kdecore/fakes.c +check_function_exists(setenv HAVE_SETENV) # kdecore/fakes.cpp +check_function_exists(seteuid HAVE_SETEUID) # kdecore/fakes.cpp check_function_exists(setmntent HAVE_SETMNTENT) # solid, kio, kdecore -check_function_exists(unsetenv HAVE_UNSETENV) # kdecore/fakes.c -check_function_exists(usleep HAVE_USLEEP) # kdecore/fakes.c, kdeui/qxembed +check_function_exists(unsetenv HAVE_UNSETENV) # kdecore/fakes.cpp +check_function_exists(usleep HAVE_USLEEP) # kdecore/fakes.cpp, kdeui/qxembed # check for prototypes [for functions provided by kdefakes when not available] diff --git a/cmake/modules/FindKDE4Internal.cmake b/cmake/modules/FindKDE4Internal.cmake index d8fad10b..6eca2c2d 100644 --- a/cmake/modules/FindKDE4Internal.cmake +++ b/cmake/modules/FindKDE4Internal.cmake @@ -78,7 +78,6 @@ # KDE4_KPRINTUTILS_LIBS - the kprintutils library and all depending libraries # KDE4_KFILE_LIBS - the kfile library and all depending libraries # KDE4_KDNSSD_LIBS - the kdnssd library and all depending libraries -# KDE4_KDESU_LIBS - the kdesu library and all depending libraries # KDE4_KPTY_LIBS - the kpty library and all depending libraries # KDE4_THREADWEAVER_LIBS - the threadweaver library and all depending libraries # KDE4_SOLID_LIBS - the solid library and all depending libraries @@ -406,7 +405,6 @@ set(_kde_libraries kdcraw kdeclarative kdecore - kdesu kdeui kdewebkit kdnssd diff --git a/includes/CMakeLists.txt b/includes/CMakeLists.txt index 15b12cc2..7204b7b5 100644 --- a/includes/CMakeLists.txt +++ b/includes/CMakeLists.txt @@ -419,14 +419,9 @@ install( KWebView KWebPluginFactory KWebWallet - KDEsuClient KPty KPtyDevice KPtyProcess - PtyProcess - SshProcess - StubProcess - SuProcess DESTINATION ${INCLUDE_INSTALL_DIR}/KDE COMPONENT Devel ) diff --git a/includes/KDEsuClient b/includes/KDEsuClient deleted file mode 100644 index 489f90cd..00000000 --- a/includes/KDEsuClient +++ /dev/null @@ -1 +0,0 @@ -#include "../kdesu/client.h" diff --git a/includes/PtyProcess b/includes/PtyProcess deleted file mode 100644 index 347e0da8..00000000 --- a/includes/PtyProcess +++ /dev/null @@ -1 +0,0 @@ -#include "../kdesu/process.h" diff --git a/includes/SshProcess b/includes/SshProcess deleted file mode 100644 index 300ebc80..00000000 --- a/includes/SshProcess +++ /dev/null @@ -1 +0,0 @@ -#include "../kdesu/ssh.h" diff --git a/includes/StubProcess b/includes/StubProcess deleted file mode 100644 index 75602d7d..00000000 --- a/includes/StubProcess +++ /dev/null @@ -1 +0,0 @@ -#include "../kdesu/stub.h" diff --git a/includes/SuProcess b/includes/SuProcess deleted file mode 100644 index fb530244..00000000 --- a/includes/SuProcess +++ /dev/null @@ -1 +0,0 @@ -#include "../kdesu/su.h" diff --git a/kdecore/kdebug.areas b/kdecore/kdebug.areas index 75123f78..1373d7be 100644 --- a/kdecore/kdebug.areas +++ b/kdecore/kdebug.areas @@ -61,8 +61,7 @@ 1201 konqtree 1203 libkonq 1204 plasma -1205 kdesud -1206 kdesu +1205 kdesudo 1207 krunner 1208 kcontrol 1209 libplasma diff --git a/kdesu/CMakeLists.txt b/kdesu/CMakeLists.txt deleted file mode 100644 index 607d034c..00000000 --- a/kdesu/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -project(kdesu) - -include_directories(${KDE4_KPTY_INCLUDES}) - -check_function_exists(setpriority HAVE_SETPRIORITY) -check_function_exists(getpeereid HAVE_GETPEEREID) - -set(CMAKE_EXTRA_INCLUDE_FILES sys/socket.h) -# defines HAVE_STRUCT_UCRED (bool) and STRUCT_UCRED (size, unused) -check_type_size("struct ucred" STRUCT_UCRED) -# reset CMAKE_EXTRA_INCLUDE_FILES -set(CMAKE_EXTRA_INCLUDE_FILES) - -configure_file( - config-kdesu.h.cmake - ${CMAKE_CURRENT_BINARY_DIR}/config-kdesu.h -) - -find_package(Sudo) -set_package_properties(Sudo PROPERTIES - DESCRIPTION "Sudo allows a system administrator to delegate authority to give certain users" - URL "http://www.sudo.ws/" - PURPOSE "Needed for password caching in kdesu" -) - -########### next target ############### - -set(kdesu_LIB_SRCS - client.cpp - process.cpp - kcookie.cpp - su.cpp - ssh.cpp - stub.cpp -) - -add_library(kdesu ${LIBRARY_TYPE} ${kdesu_LIB_SRCS}) - -target_link_libraries(kdesu PRIVATE ${KDE4_KPTY_LIBS}) -target_link_libraries(kdesu PUBLIC ${QT_QTCORE_LIBRARY}) - -if(SUDO_FOUND) - add_definitions(-DKDESU_USE_SUDO_DEFAULT) -endif() - -set_target_properties(kdesu PROPERTIES - VERSION ${GENERIC_LIB_VERSION} - SOVERSION ${GENERIC_LIB_SOVERSION} -) - -install( - TARGETS kdesu - EXPORT kdelibsLibraryTargets - ${INSTALL_TARGETS_DEFAULT_ARGS} -) - -########### next target ############### - -set(kdesu_stub_SRCS kdesu_stub.c ) - -add_executable(kdesu_stub ${kdesu_stub_SRCS}) - -install(TARGETS kdesu_stub DESTINATION ${LIBEXEC_INSTALL_DIR}) - -########### install files ############### - -generate_export_header(kdesu) - -install( - FILES - ${CMAKE_CURRENT_BINARY_DIR}/kdesu_export.h - client.h - process.h - su.h - ssh.h - stub.h - defaults.h - DESTINATION ${INCLUDE_INSTALL_DIR}/kdesu - COMPONENT Devel -) diff --git a/kdesu/README b/kdesu/README deleted file mode 100644 index 0a6acd9d..00000000 --- a/kdesu/README +++ /dev/null @@ -1,13 +0,0 @@ -Maintainer: Adriaan de Groot -Maintainer: kdesu was maintained by Alan Eldridge until his - death in 2003. - -README for libkdesu. - -Libkdesu provides functionality for building GUI front ends for -(password asking) console mode programs. For example, kdesu and -kdessh use it to interface with su and ssh respectively. - -libkdesu is Copyright (c) 1999,2000 Geert Jansen - -Distributed under the GNU Library General Public License, version 2. diff --git a/kdesu/client.cpp b/kdesu/client.cpp deleted file mode 100644 index 4fbeffe7..00000000 --- a/kdesu/client.cpp +++ /dev/null @@ -1,438 +0,0 @@ -/* vi: ts=8 sts=4 sw=4 - * - * This file is part of the KDE project, module kdesu. - * Copyright (C) 1999,2000 Geert Jansen - * - * 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. - * - * client.cpp: A client for kdesud. - */ - -#include "client.h" - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -extern int kdesuDebugArea(); - -namespace KDESu { - -class KDEsuClient::KDEsuClientPrivate { -public: - KDEsuClientPrivate() : sockfd(-1) {} - QString daemon; - int sockfd; - QByteArray sock; -}; - -#ifndef SUN_LEN -#define SUN_LEN(ptr) ((QT_SOCKLEN_T) (((struct sockaddr_un *) 0)->sun_path) \ - + strlen ((ptr)->sun_path)) -#endif - -KDEsuClient::KDEsuClient() - :d(new KDEsuClientPrivate) -{ -#ifdef Q_WS_X11 - QString display = QString::fromLatin1(qgetenv("DISPLAY")); - if (display.isEmpty()) - { - kWarning(kdesuDebugArea()) << "$DISPLAY is not set."; - return; - } - - // strip the screen number from the display - display.remove(QRegExp("\\.[0-9]+$")); -#elif defined(Q_WS_QWS) - QByteArray display("QWS"); -#else - QByteArray display("NODISPLAY"); -#endif - - d->sock = QFile::encodeName( KStandardDirs::locateLocal("socket", - QString("kdesud_").append(display))); - connect(); -} - - -KDEsuClient::~KDEsuClient() -{ - if (d->sockfd >= 0) - close(d->sockfd); - delete d; -} - -int KDEsuClient::connect() -{ - if (d->sockfd >= 0) - close(d->sockfd); - if (access(d->sock, R_OK|W_OK)) - { - d->sockfd = -1; - return -1; - } - - d->sockfd = socket(PF_UNIX, SOCK_STREAM, 0); - if (d->sockfd < 0) - { - kWarning(kdesuDebugArea()) << "socket():" << perror; - return -1; - } - struct sockaddr_un addr; - addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, d->sock); - - if (::connect(d->sockfd, (struct sockaddr *) &addr, SUN_LEN(&addr)) < 0) - { - kWarning(kdesuDebugArea()) << "connect():" << perror; - close(d->sockfd); d->sockfd = -1; - return -1; - } - -#if !defined(SO_PEERCRED) || !defined(HAVE_STRUCT_UCRED) -# if defined(HAVE_GETPEEREID) - uid_t euid; - gid_t egid; - // Security: if socket exists, we must own it - if (getpeereid(d->sockfd, &euid, &egid) == 0) - { - if (euid != getuid()) - { - kWarning(kdesuDebugArea()) << "socket not owned by me! socket uid =" << euid; - close(d->sockfd); d->sockfd = -1; - return -1; - } - } -# else -# ifdef __GNUC__ -# warning "Using sloppy security checks" -# endif - // We check the owner of the socket after we have connected. - // If the socket was somehow not ours an attacker will be able - // to delete it after we connect but shouldn't be able to - // create a socket that is owned by us. - KDE_struct_stat s; - if (KDE_lstat(d->sock, &s)!=0) - { - kWarning(kdesuDebugArea()) << "stat failed (" << d->sock << ")"; - close(d->sockfd); d->sockfd = -1; - return -1; - } - if (s.st_uid != getuid()) - { - kWarning(kdesuDebugArea()) << "socket not owned by me! socket uid =" << s.st_uid; - close(d->sockfd); d->sockfd = -1; - return -1; - } - if (!S_ISSOCK(s.st_mode)) - { - kWarning(kdesuDebugArea()) << "socket is not a socket (" << d->sock << ")"; - close(d->sockfd); d->sockfd = -1; - return -1; - } -# endif -#else - struct ucred cred; - QT_SOCKLEN_T siz = sizeof(cred); - - // Security: if socket exists, we must own it - if (getsockopt(d->sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &siz) == 0) - { - if (cred.uid != getuid()) - { - kWarning(kdesuDebugArea()) << "socket not owned by me! socket uid =" << cred.uid; - close(d->sockfd); d->sockfd = -1; - return -1; - } - } -#endif - - return 0; -} - -QByteArray KDEsuClient::escape(const QByteArray &str) -{ - QByteArray copy; - copy.reserve(str.size() + 4); - copy.append('"'); - for (int i = 0; i < str.size(); i++) { - uchar c = str.at(i); - if (c < 32) { - copy.append('\\'); - copy.append('^'); - copy.append(c + '@'); - } else { - if (c == '\\' || c == '"') - copy.append('\\'); - copy.append(c); - } - } - copy.append('"'); - return copy; -} - -int KDEsuClient::command(const QByteArray &cmd, QByteArray *result) -{ - if (d->sockfd < 0) - return -1; - - if (send(d->sockfd, cmd, cmd.length(), 0) != (int) cmd.length()) - return -1; - - char buf[1024]; - int nbytes = recv(d->sockfd, buf, 1023, 0); - if (nbytes <= 0) - { - kWarning(kdesuDebugArea()) << "no reply from daemon."; - return -1; - } - buf[nbytes] = '\000'; - - QByteArray reply = buf; - if (reply.left(2) != "OK") - return -1; - - if (result) - *result = reply.mid(3, reply.length()-4); - return 0; -} - -int KDEsuClient::setPass(const char *pass, int timeout) -{ - QByteArray cmd = "PASS "; - cmd += escape(pass); - cmd += ' '; - cmd += QByteArray().setNum(timeout); - cmd += '\n'; - return command(cmd); -} - -int KDEsuClient::exec(const QByteArray &prog, const QByteArray &user, const QByteArray &options, const QList &env) -{ - QByteArray cmd; - cmd = "EXEC "; - cmd += escape(prog); - cmd += ' '; - cmd += escape(user); - if (!options.isEmpty() || !env.isEmpty()) - { - cmd += ' '; - cmd += escape(options); - for (int i = 0; i < env.count(); ++i) - { - cmd += ' '; - cmd += escape(env.at(i)); - } - } - cmd += '\n'; - return command(cmd); -} - -int KDEsuClient::setHost(const QByteArray &host) -{ - QByteArray cmd = "HOST "; - cmd += escape(host); - cmd += '\n'; - return command(cmd); -} - -int KDEsuClient::setPriority(int prio) -{ - QByteArray cmd; - cmd += "PRIO "; - cmd += QByteArray::number(prio); - cmd += '\n'; - return command(cmd); -} - -int KDEsuClient::setScheduler(int sched) -{ - QByteArray cmd; - cmd += "SCHD "; - cmd += QByteArray::number(sched); - cmd += '\n'; - return command(cmd); -} - -int KDEsuClient::delCommand(const QByteArray &key, const QByteArray &user) -{ - QByteArray cmd = "DEL "; - cmd += escape(key); - cmd += ' '; - cmd += escape(user); - cmd += '\n'; - return command(cmd); -} -int KDEsuClient::setVar(const QByteArray &key, const QByteArray &value, int timeout, - const QByteArray &group) -{ - QByteArray cmd = "SET "; - cmd += escape(key); - cmd += ' '; - cmd += escape(value); - cmd += ' '; - cmd += escape(group); - cmd += ' '; - cmd += QByteArray().setNum(timeout); - cmd += '\n'; - return command(cmd); -} - -QByteArray KDEsuClient::getVar(const QByteArray &key) -{ - QByteArray cmd = "GET "; - cmd += escape(key); - cmd += '\n'; - QByteArray reply; - command(cmd, &reply); - return reply; -} - -QList KDEsuClient::getKeys(const QByteArray &group) -{ - QByteArray cmd = "GETK "; - cmd += escape(group); - cmd += '\n'; - QByteArray reply; - command(cmd, &reply); - int index=0, pos; - QList list; - if( !reply.isEmpty() ) - { - // kDebug(kdesuDebugArea()) << "Found a matching entry:" << reply; - while (1) - { - pos = reply.indexOf( '\007', index ); - if( pos == -1 ) - { - if( index == 0 ) - list.append( reply ); - else - list.append( reply.mid(index) ); - break; - } - else - { - list.append( reply.mid(index, pos-index) ); - } - index = pos+1; - } - } - return list; -} - -bool KDEsuClient::findGroup(const QByteArray &group) -{ - QByteArray cmd = "CHKG "; - cmd += escape(group); - cmd += '\n'; - if( command(cmd) == -1 ) - return false; - return true; -} - -int KDEsuClient::delVar(const QByteArray &key) -{ - QByteArray cmd = "DELV "; - cmd += escape(key); - cmd += '\n'; - return command(cmd); -} - -int KDEsuClient::delGroup(const QByteArray &group) -{ - QByteArray cmd = "DELG "; - cmd += escape(group); - cmd += '\n'; - return command(cmd); -} - -int KDEsuClient::delVars(const QByteArray &special_key) -{ - QByteArray cmd = "DELS "; - cmd += escape(special_key); - cmd += '\n'; - return command(cmd); -} - -int KDEsuClient::ping() -{ - return command("PING\n"); -} - -int KDEsuClient::exitCode() -{ - QByteArray result; - if (command("EXIT\n", &result) != 0) - return -1; - - return result.toInt(); -} - -int KDEsuClient::stopServer() -{ - return command("STOP\n"); -} - -bool KDEsuClient::isServerSGID() -{ - d->daemon = KStandardDirs::locate("exe", "kdesud"); - if (d->daemon.isEmpty()) { - kWarning(kdesuDebugArea()) << "daemon not found."; - return false; - } - - QT_STATBUF sbuf; - if (QT_STAT(QFile::encodeName(d->daemon), &sbuf) < 0) - { - kWarning(kdesuDebugArea()) << "stat():" << perror; - return false; - } - return (sbuf.st_mode & S_ISGID); -} - -int KDEsuClient::startServer() -{ - d->daemon = KStandardDirs::locate("exe", "kdesud"); - if (d->daemon.isEmpty()) { - kWarning(kdesuDebugArea()) << "daemon not found."; - return -1; - } - - if (!isServerSGID()) { - kWarning(kdesuDebugArea()) << "kdesud not setgid!"; - } - - // kdesud only forks to the background after it is accepting - // connections. - // We start it via kdeinit to make sure that it doesn't inherit - // any fd's from the parent process. - int ret = KToolInvocation::kdeinitExecWait(d->daemon); - connect(); - return ret; -} - -} diff --git a/kdesu/client.h b/kdesu/client.h deleted file mode 100644 index 6ef1b650..00000000 --- a/kdesu/client.h +++ /dev/null @@ -1,204 +0,0 @@ -/* vi: ts=8 sts=4 sw=4 - * - * This file is part of the KDE project, module kdesu. - * Copyright (C) 1999,2000 Geert Jansen - * - * 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. - * - * client.h: client to access kdesud. - */ - -#ifndef __KDE_su_Client_h_Included__ -#define __KDE_su_Client_h_Included__ - -#include -#include -#include - -#ifdef Q_OS_UNIX - -#include -#include -#include - -#include - -namespace KDESu { - -/** \class KDEsuClient client.h kdesu/client.h - * A client class to access kdesud, the KDE su daemon. Kdesud can assist in - * password caching in two ways: - * - * @li For high security passwords, like for su and ssh, it executes the - * password requesting command for you. It feeds the password to the - * command, without ever returning it to you, the user. The daemon should - * be installed setgid nogroup, in order to be able to act as an inaccessible, - * trusted 3rd party. - * See exec, setPass, delCommand. - * - * @li For lower security passwords, like web and ftp passwords, it can act - * as a persistent storage for string variables. These variables are - * returned to the user, and the daemon doesn't need to be setgid nogroup - * for this. - * See setVar, delVar, delGroup. - */ - -class KDESU_EXPORT KDEsuClient { -public: - KDEsuClient(); - ~KDEsuClient(); - - /** - * Lets kdesud execute a command. If the daemon does not have a password - * for this command, this will fail and you need to call setPass(). - * - * @param command The command to execute. - * @param user The user to run the command as. - * @param options Extra options. - * @param env Extra environment variables. - * @return Zero on success, -1 on failure. - */ - int exec(const QByteArray &command, const QByteArray &user, const QByteArray &options=0, const QList &env=QList()); - - /** - * Wait for the last command to exit and return the exit code. - * @return Exit code of last command, -1 on failure. - */ - int exitCode(); - - /** - * Set root's password, lasts one session. - * - * @param pass Root's password. - * @param timeout The time that a password will live. - * @return Zero on success, -1 on failure. - */ - int setPass(const char *pass, int timeout); - - /** - * Set the target host (optional). - */ - int setHost(const QByteArray &host); - - /** - * Set the desired priority (optional), see StubProcess. - */ - int setPriority(int priority); - - /** - * Set the desired scheduler (optional), see StubProcess. - */ - int setScheduler(int scheduler); - - /** - * Remove a password for a user/command. - * @param command The command. - * @param user The user. - * @return zero on success, -1 on an error - */ - int delCommand(const QByteArray &command, const QByteArray &user); - - /** - * Set a persistent variable. - * @param key The name of the variable. - * @param value Its value. - * @param timeout The timeout in seconds for this key. Zero means - * no timeout. - * @param group Make the key part of a group. See delGroup. - * @return zero on success, -1 on failure. - */ - int setVar(const QByteArray &key, const QByteArray &value, int timeout=0, const QByteArray &group=0); - - /** - * Get a persistent variable. - * @param key The name of the variable. - * @return Its value. - */ - QByteArray getVar(const QByteArray &key); - - /** - * Gets all the keys that are membes of the given group. - * @param group the group name of the variables. - * @return a list of the keys in the group. - */ - QList getKeys(const QByteArray &group); - - /** - * Returns true if the specified group exists is - * cached. - * - * @param group the group key - * @return true if the group is found - */ - bool findGroup(const QByteArray &group); - - /** - * Delete a persistent variable. - * @param key The name of the variable. - * @return zero on success, -1 on failure. - */ - int delVar(const QByteArray &key); - - /** - * Delete all persistent variables with the given key. - * - * A specicalized variant of delVar(QByteArray) that removes all - * subsets of the cached varaibles given by @p key. In order for all - * cached variables related to this key to be deleted properly, the - * value given to the @p group argument when the setVar function - * was called, must be a subset of the argument given here and the key - * - * @note Simply supplying the group key here WILL not necessarily - * work. If you only have a group key, then use delGroup instead. - * - * @param special_key the name of the variable. - * @return zero on success, -1 on failure. - */ - int delVars(const QByteArray &special_key); - - /** - * Delete all persistent variables in a group. - * - * @param group the group name. See setVar. - * @return - */ - int delGroup(const QByteArray &group); - - /** - * Ping kdesud. This can be used for diagnostics. - * @return Zero on success, -1 on failure - */ - int ping(); - - /** - * Stop the daemon. - */ - int stopServer(); - - /** - * Try to start up kdesud - */ - int startServer(); - - /** - * Returns true if the server is safe (installed setgid), false otherwise. - */ - bool isServerSGID(); - -private: - int connect(); - - int command(const QByteArray &cmd, QByteArray *result=0L); - QByteArray escape(const QByteArray &str); - - class KDEsuClientPrivate; - KDEsuClientPrivate* const d; -}; - -} //END namespace KDESu - -#endif //Q_OS_UNIX - -#endif //__KDE_su_Client_h_Included__ diff --git a/kdesu/config-kdesu.h.cmake b/kdesu/config-kdesu.h.cmake deleted file mode 100644 index 2600f13f..00000000 --- a/kdesu/config-kdesu.h.cmake +++ /dev/null @@ -1,7 +0,0 @@ - -#cmakedefine HAVE_STRUCT_UCRED 1 - -#cmakedefine HAVE_SETPRIORITY 1 - -#cmakedefine HAVE_GETPEEREID 1 - diff --git a/kdesu/defaults.h b/kdesu/defaults.h deleted file mode 100644 index 706a088c..00000000 --- a/kdesu/defaults.h +++ /dev/null @@ -1,22 +0,0 @@ -/* vi: ts=8 sts=4 sw=4 - * - * This file is part of the KDE project, module kdesu. - * Copyright (C) 1999,2000 Geert Jansen - * - * 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. - */ - -#ifndef __Defaults_h_included__ -#define __Defaults_h_included__ - -namespace KDESu { - -const int defTimeout = 120*60; -const int defEchoMode = 0; -const bool defKeep = false; - -} - -#endif diff --git a/kdesu/kcookie.cpp b/kdesu/kcookie.cpp deleted file mode 100644 index 0527de4d..00000000 --- a/kdesu/kcookie.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* vi: ts=8 sts=4 sw=4 - * - * This file is part of the KDE project, module kdesu. - * Copyright (C) 1999,2000 Geert Jansen - * - * 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. - * - * kcookie.cpp: KDE authentication cookies. - */ - -#include "kcookie.h" - -#include - -#include -#include -#include -#include - -#include - -extern int kdesuDebugArea(); - -namespace KDESu { -namespace KDESuPrivate { - -class KCookie::KCookiePrivate -{ -public: - QByteArray m_Display; -#ifdef Q_WS_X11 - QByteArray m_DisplayAuth; -#endif -}; - - - -KCookie::KCookie() - : d( new KCookiePrivate ) -{ -#ifdef Q_WS_X11 - getXCookie(); -#endif -} - -KCookie::~KCookie() -{ - delete d; -} - -QByteArray KCookie::display() const -{ - return d->m_Display; -} - -#ifdef Q_WS_X11 -QByteArray KCookie::displayAuth() const -{ - return d->m_DisplayAuth; -} -#endif - -void KCookie::getXCookie() -{ -#ifdef Q_WS_X11 - d->m_Display = qgetenv("DISPLAY"); -#else - d->m_Display = qgetenv("QWS_DISPLAY"); -#endif - if (d->m_Display.isEmpty()) - { - kError(kdesuDebugArea()) << "$DISPLAY is not set."; - return; - } -#ifdef Q_WS_X11 // No need to mess with X Auth stuff - QByteArray disp = d->m_Display; - if (disp.startsWith("localhost:")) // krazy:exclude=strings - disp.remove(0, 9); - - QProcess proc; - proc.start("xauth", QStringList() << "list" << disp); - if (!proc.waitForStarted()) - { - kError(kdesuDebugArea()) << "Could not run xauth."; - return; - } - proc.waitForReadyRead(100); - QByteArray output = proc.readLine().simplified(); - if (output.isEmpty()) - { - kWarning(kdesuDebugArea()) << "No X authentication info set for display" << d->m_Display; - return; - } - QList lst = output.split(' '); - if (lst.count() != 3) - { - kError(kdesuDebugArea()) << "parse error."; - return; - } - d->m_DisplayAuth = (lst[1] + ' ' + lst[2]); - proc.waitForFinished(100); // give QProcess a chance to clean up gracefully -#endif -} - -}} diff --git a/kdesu/kcookie.h b/kdesu/kcookie.h deleted file mode 100644 index f6814fce..00000000 --- a/kdesu/kcookie.h +++ /dev/null @@ -1,54 +0,0 @@ -/* vi: ts=8 sts=4 sw=4 - * - * This file is part of the KDE project, module kdesu - * Copyright (C) 1999,2000 Geert Jansen - * - * 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. - */ - -#ifndef __KCookie_h_Included__ -#define __KCookie_h_Included__ - -#include - - -namespace KDESu { - -namespace KDESuPrivate { - -/** - * Utility class to access the authentication tokens needed to run a KDE - * program (X11 cookies on X11, for instance). - * @internal - */ - -class KCookie -{ -public: - KCookie(); - ~KCookie(); - - /** - * Returns the X11 display. - */ - QByteArray display() const; - -#ifdef Q_WS_X11 - /** - * Returns the X11 magic cookie, if available. - */ - QByteArray displayAuth() const; -#endif - -private: - void getXCookie(); - - class KCookiePrivate; - KCookiePrivate * const d; -}; - -}} - -#endif // __KCookie_h_Included__ diff --git a/kdesu/kdesu_stub.c b/kdesu/kdesu_stub.c deleted file mode 100644 index b7e20250..00000000 --- a/kdesu/kdesu_stub.c +++ /dev/null @@ -1,414 +0,0 @@ -/* vi: ts=8 sts=4 sw=4 - * - * kdesu_stub.c: KDE su executes this stub through su or ssh. This stub in turn - * executes the target program. Before that, startup parameters - * are sent through stdin. - * - * This file is part of the KDE project, module kdesu. - * Copyright (C) 1999,2000 Geert Jansen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * - * Available parameters: - * - * Parameter Description Format (csl = comma separated list) - * - * - kdesu_stub Header "ok" | "stop" - * - display X11 display string - * - display_auth X11 authentication "type cookie" pair - * - command Command to run string - * - path PATH env. var string - * - build_sycoca Rebuild sycoca? "yes" | "no" - * - user Target user string - * - priority Process priority 0 <= int <= 100 - * - scheduler Process scheduler "fifo" | "normal" - * - app_startup_id DESKTOP_STARTUP_ID string - * - environment Additional envvars strings, last one is empty - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_INITGROUPS -#include -#endif - -#include -#include -#include -#include -#include - -#ifdef POSIX1B_SCHEDULING -#include -#endif - -/** - * Params sent by the peer. - */ - -struct param_struct -{ - const char *name; - char *value; -}; - -struct param_struct params[] = -{ - { "kdesu_stub", 0L }, - { "display", 0L }, - { "display_auth", 0L }, - { "command", 0L }, - { "path", 0L }, - { "xwindows_only", 0L }, - { "user", 0L }, - { "priority", 0L }, - { "scheduler", 0L }, -/* obsoleted by app_startup_id { "app_start_pid", 0L } */ - { "app_startup_id", 0L } -}; - -#define P_HEADER 0 -#define P_DISPLAY 1 -#define P_DISPLAY_AUTH 2 -#define P_COMMAND 3 -#define P_PATH 4 -#define P_XWIN_ONLY 5 -#define P_USER 6 -#define P_PRIORITY 7 -#define P_SCHEDULER 8 -#define P_APP_STARTUP_ID 9 -#define P_LAST 10 - -/** - * Safe malloc functions. - */ -char *xmalloc(size_t size) -{ - char *ptr = malloc(size); - if (ptr) return ptr; - perror("malloc()"); - exit(1); -} - - -char **xrealloc(char **ptr, int size) -{ - ptr = realloc(ptr, size); - if (ptr) return ptr; - perror("realloc()"); - exit(1); -} - - -/** - * Solaris does not have a setenv()... - */ -int xsetenv(const char *name, const char *value) -{ - char *s = malloc(strlen(name)+strlen(value)+2); - if (!s) return -1; - strcpy(s, name); - strcat(s, "="); - strcat(s, value); - return putenv(s); /* yes: no free()! */ -} - -/** - * Safe strdup and strip newline - */ -char *xstrdup(char *src) -{ - int len = strlen(src); - char *dst = xmalloc(len+1); - strcpy(dst, src); - if (dst[len-1] == '\n') - dst[len-1] = '\000'; - return dst; -} - -/** - * Split comma separated list. - */ -char **xstrsep(char *str) -{ - int i = 0, size = 10; - char **list = (char **) xmalloc(size * sizeof(char *)); - char *ptr = str, *nptr; - while ((nptr = strchr(ptr, ',')) != 0L) - { - if (i > size-2) - list = xrealloc(list, (size *= 2) * sizeof(char *)); - *nptr = '\000'; - list[i++] = ptr; - ptr = nptr+1; - } - if (*ptr != '\000') - list[i++] = ptr; - list[i] = 0L; - return list; -} - -#define BUFSIZE 8192 - -static void dequote(char *buf) -{ - char *in, *out; - for (in = buf, out = buf; *in; in++, out++) { - char c = *in; - if (c == '\\') { - c = *++in; - if (c == '/') - *out = '\\'; - else - *out = c - '@'; - } else { - *out = c; - } - } - *out = 0; -} - -/** - * The main program - */ - -int main() -{ - char buf[BUFSIZE+1]; -#ifndef QWS - char xauthority[200]; -#endif - int i/*, res, sycoca*/; - pid_t pid; - struct passwd *pw; - const char* kdesu_lc_all; - - xauthority[0] = '\0'; - - /* Get startup parameters. */ - - for (i=0; ipw_dir); - - /* New user won't be able to connect it anyway. */ - unsetenv("DBUS_SESSION_BUS_ADDRESS"); - - /* Set scheduling/priority */ -#if defined(POSIX1B_SCHEDULING) || defined(HAVE_SETPRIORITY) - double prio = (double) atoi(params[P_PRIORITY].value); -#endif - if (!strcmp(params[P_SCHEDULER].value, "realtime")) { -#ifdef POSIX1B_SCHEDULING - struct sched_param sched; - int min = sched_get_priority_min(SCHED_FIFO); - int max = sched_get_priority_max(SCHED_FIFO); - sched.sched_priority = min + (int) (prio * (max - min) / 100 + 0.5); - sched_setscheduler(0, SCHED_FIFO, &sched); -#else - printf("kdesu_stub: realtime scheduling not supported\n"); -#endif -#ifdef HAVE_SETPRIORITY - } else { - int val = 20 - (int) (prio * 40 / 100 + 0.5); - setpriority(PRIO_PROCESS, getpid(), val); -#endif - } - - /* Drop privileges (this is permanent) */ - - if (getuid() != pw->pw_uid) - { - if (setgid(pw->pw_gid) == -1) - { - perror("kdesu_stub: setgid()"); - exit(1); - } -#ifdef HAVE_INITGROUPS - if (initgroups(pw->pw_name, pw->pw_gid) == -1) - { - perror("kdesu_stub: initgroups()"); - exit(1); - } -#endif - if (setuid(pw->pw_uid) == -1) - { - perror("kdesu_stub: setuid()"); - exit(1); - } - xsetenv("HOME", pw->pw_dir); - } - - /* Handle display */ - - if (strcmp(params[P_DISPLAY].value, "no")) - { -#ifndef QWS - xsetenv("DISPLAY", params[P_DISPLAY].value); - if (params[P_DISPLAY_AUTH].value[0]) - { - int fd2; - /* - ** save umask and set to 077, so we create those files only - ** readable for root. (if someone else could read them, we - ** are in deep shit). - */ - int oldumask = umask(077); - const char *disp = params[P_DISPLAY].value; - if (strncmp(disp, "localhost:", 10) == 0) - disp += 9; - - strcpy(xauthority, "/tmp/xauth.XXXXXXXXXX"); - fd2 = mkstemp(xauthority); - umask(oldumask); - - if (fd2 == -1) { - perror("kdesu_stub: mkstemp()"); - exit(1); - } else - close(fd2); - xsetenv("XAUTHORITY", xauthority); - - FILE *fout = popen("xauth >/dev/null 2>&1","w"); - if (fout == NULL) - { - perror("kdesu_stub: popen(xauth)"); - exit(1); - } - fprintf(fout, "add %s %s\n", disp, - params[P_DISPLAY_AUTH].value); - pclose(fout); - } -#else - xsetenv("DISPLAY", params[P_DISPLAY].value); -#endif - } - - /* Rebuild the sycoca and start kdeinit? */ - - if (strcmp(params[P_XWIN_ONLY].value, "no")) - { - system("kdeinit4 --suicide"); - } - - /* Execute the command */ - - pid = fork(); - if (pid == -1) - { - perror("kdesu_stub: fork()"); - exit(1); - } - if (pid) - { - /* Parent: wait for child, delete tempfiles and return. */ - int xit = 1; - while (1) - { - int state; - int ret = waitpid(pid, &state, 0); - if (ret == -1) - { - if (errno == EINTR) - continue; - if (errno != ECHILD) - perror("kdesu_stub: waitpid()"); - break; - } - if (WIFEXITED(state)) - xit = WEXITSTATUS(state); - } - -#ifndef QWS - if (*xauthority) - unlink(xauthority); -#endif - exit(xit); - } else - { - setsid(); - /* Child: exec command. */ - sprintf(buf, "%s", params[P_COMMAND].value); - dequote(buf); - execl("/bin/sh", "sh", "-c", buf, (void *)0); - perror("kdesu_stub: exec()"); - _exit(1); - } -} diff --git a/kdesu/process.cpp b/kdesu/process.cpp deleted file mode 100644 index df4187dc..00000000 --- a/kdesu/process.cpp +++ /dev/null @@ -1,552 +0,0 @@ -/* vi: ts=8 sts=4 sw=4 - * - * This file is part of the KDE project, module kdesu. - * Copyright (C) 1999,2000 Geert Jansen - * - * This file contains code from TEShell.C of the KDE konsole. - * Copyright (c) 1997,1998 by Lars Doelle - * - * 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. - * - * process.cpp: Functionality to build a front end to password asking - * terminal programs. - */ - -#include "process.h" -#include "kcookie.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_SELECT_H -#include // Needed on some systems. -#endif - -#include -#include - -#include -#include -#include -#include -#include - -extern int kdesuDebugArea(); - -namespace KDESu { - -using namespace KDESuPrivate; - -/* -** Wait for @p ms miliseconds -** @param fd file descriptor -** @param ms time to wait in miliseconds -** @return -*/ -int PtyProcess::waitMS(int fd,int ms) -{ - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 1000*ms; - - fd_set fds; - FD_ZERO(&fds); - FD_SET(fd,&fds); - return select(fd+1, &fds, 0L, 0L, &tv); -} - -// XXX this function is nonsense: -// - for our child, we could use waitpid(). -// - the configurability at this place it *complete* braindamage -/* -** Basic check for the existence of @p pid. -** Returns true iff @p pid is an extant process. -*/ -bool PtyProcess::checkPid(pid_t pid) -{ - KSharedConfig::Ptr config = KGlobal::config(); - KConfigGroup cg(config, "super-user-command"); - QString superUserCommand = cg.readEntry("super-user-command", "sudo"); - //sudo does not accept signals from user so we except it - if (superUserCommand == "sudo") { - return true; - } else { - return kill(pid, 0) == 0; - } -} - -/* -** Check process exit status for process @p pid. -** On error (no child, no exit), return Error (-1). -** If child @p pid has exited, return its exit status, -** (which may be zero). -** If child @p has not exited, return NotExited (-2). -*/ - -int PtyProcess::checkPidExited(pid_t pid) -{ - int state, ret; - ret = waitpid(pid, &state, WNOHANG); - - if (ret < 0) - { - kError(kdesuDebugArea()) << "waitpid():" << perror; - return Error; - } - if (ret == pid) - { - if (WIFEXITED(state)) - return WEXITSTATUS(state); - return Killed; - } - - return NotExited; -} - - -class PtyProcess::PtyProcessPrivate -{ -public: - PtyProcessPrivate() : m_pPTY(0L) {} - ~PtyProcessPrivate() - { - delete m_pPTY; - } - QList env; - KPty *m_pPTY; - QByteArray m_Inbuf; -}; - - -PtyProcess::PtyProcess() - :d(new PtyProcessPrivate) -{ - m_bTerminal = false; - m_bErase = false; -} - - -int PtyProcess::init() -{ - delete d->m_pPTY; - d->m_pPTY = new KPty(); - if (!d->m_pPTY->open()) - { - kError(kdesuDebugArea()) << "Failed to open PTY."; - return -1; - } - d->m_Inbuf.resize(0); - return 0; -} - - -PtyProcess::~PtyProcess() -{ - delete d; -} - -/** Set additional environment variables. */ -void PtyProcess::setEnvironment( const QList &env ) -{ - d->env = env; -} - -int PtyProcess::fd() const -{ - return d->m_pPTY ? d->m_pPTY->masterFd() : -1; -} - -int PtyProcess::pid() const -{ - return m_Pid; -} - -/** Returns the additional environment variables set by setEnvironment() */ -QList PtyProcess::environment() const -{ - return d->env; -} - - -QByteArray PtyProcess::readAll(bool block) -{ - QByteArray ret; - if (!d->m_Inbuf.isEmpty()) - { - // if there is still something in the buffer, we need not block. - // we should still try to read any further output, from the fd, though. - block = false; - ret = d->m_Inbuf; - d->m_Inbuf.resize(0); - } - - int flags = fcntl(fd(), F_GETFL); - if (flags < 0) - { - kError(kdesuDebugArea()) << "fcntl(F_GETFL):" << perror; - return ret; - } - int oflags = flags; - if (block) - flags &= ~O_NONBLOCK; - else - flags |= O_NONBLOCK; - - if ((flags != oflags) && (fcntl(fd(), F_SETFL, flags) < 0)) - { - // We get an error here when the child process has closed - // the file descriptor already. - return ret; - } - - while (1) - { - ret.reserve(ret.size() + 0x8000); - int nbytes = read(fd(), ret.data() + ret.size(), 0x8000); - if (nbytes == -1) - { - if (errno == EINTR) - continue; - else break; - } - if (nbytes == 0) - break; // nothing available / eof - - ret.resize(ret.size() + nbytes); - break; - } - - return ret; -} - - -QByteArray PtyProcess::readLine(bool block) -{ - d->m_Inbuf = readAll(block); - - QByteArray ret; - if (!d->m_Inbuf.isEmpty()) - { - int pos = d->m_Inbuf.indexOf('\n'); - if (pos == -1) - { - // NOTE: this means we return something even if there in no full line! - ret = d->m_Inbuf; - d->m_Inbuf.resize(0); - } else - { - ret = d->m_Inbuf.left(pos); - d->m_Inbuf.remove(0, pos+1); - } - } - - return ret; -} - - -void PtyProcess::writeLine(const QByteArray &line, bool addnl) -{ - if (!line.isEmpty()) - write(fd(), line, line.length()); - if (addnl) - write(fd(), "\n", 1); -} - - -void PtyProcess::unreadLine(const QByteArray &line, bool addnl) -{ - QByteArray tmp = line; - if (addnl) - tmp += '\n'; - if (!tmp.isEmpty()) - d->m_Inbuf.prepend(tmp); -} - -void PtyProcess::setExitString(const QByteArray &exit) -{ - m_Exit = exit; -} - -/* - * Fork and execute the command. This returns in the parent. - */ - -int PtyProcess::exec(const QByteArray &command, const QList &args) -{ - kDebug(kdesuDebugArea()) << "Running" << command; - - if (init() < 0) - return -1; - - if ((m_Pid = fork()) == -1) - { - kError(kdesuDebugArea()) << "fork():" << perror; - return -1; - } - - // Parent - if (m_Pid) - { - d->m_pPTY->closeSlave(); - return 0; - } - - // Child - if (setupTTY() < 0) - _exit(1); - - for (int i = 0; i < d->env.count(); ++i) - { - putenv(const_cast(d->env.at(i).constData())); - } - unsetenv("KDE_FULL_SESSION"); - // for : Qt: Session management error - unsetenv("SESSION_MANAGER"); - // QMutex::lock , deadlocks without that. - // you cannot connect to the user's session bus from another UID - unsetenv("DBUS_SESSION_BUS_ADDRESS"); - - // set temporarily LC_ALL to C, for su (to be able to parse "Password:") - const QByteArray old_lc_all = qgetenv( "LC_ALL" ); - if( !old_lc_all.isEmpty() ) - qputenv( "KDESU_LC_ALL", old_lc_all ); - else - unsetenv( "KDESU_LC_ALL" ); - qputenv("LC_ALL", "C"); - - // From now on, terminal output goes through the tty. - - QByteArray path; - if (command.contains('/')) { - path = command; - } else { - QString file = KStandardDirs::findExe(command); - if (file.isEmpty()) { - kError(kdesuDebugArea()) << command << "not found."; - _exit(1); - } - path = QFile::encodeName(file); - } - - const char **argp = (const char **)malloc((args.count()+2)*sizeof(char *)); - int i = 1; - argp[i] = path; - foreach (QByteArray it, args) { - argp[i] = it; - i++; - } - argp[i] = NULL; - - execv(path, const_cast(argp)); - free(argp); - - kError(kdesuDebugArea()) << "execv(" << path << "):" << perror; - _exit(1); - return -1; // Shut up compiler. Never reached. -} - - -/* - * Wait until the terminal is set into no echo mode. At least one su - * (RH6 w/ Linux-PAM patches) sets noecho mode AFTER writing the Password: - * prompt, using TCSAFLUSH. This flushes the terminal I/O queues, possibly - * taking the password with it. So we wait until no echo mode is set - * before writing the password. - * Note that this is done on the slave fd. While Linux allows tcgetattr() on - * the master side, Solaris doesn't. - */ - -int PtyProcess::WaitSlave() -{ - kDebug(kdesuDebugArea()) << "Child pid" << m_Pid; - - struct termios tio; - while (1) - { - if (!checkPid(m_Pid)) - { - kError(kdesuDebugArea()) << "process has exited while waiting for password."; - return -1; - } - if (!d->m_pPTY->tcGetAttr(&tio)) - { - kError(kdesuDebugArea()) << "tcgetattr():" << perror; - return -1; - } - if (tio.c_lflag & ECHO) - { - kDebug(kdesuDebugArea()) << "Echo mode still on."; - usleep(10000); - continue; - } - break; - } - return 0; -} - - -int PtyProcess::enableLocalEcho(bool enable) -{ - return d->m_pPTY->setEcho(enable) ? 0 : -1; -} - - -void PtyProcess::setTerminal(bool terminal) -{ - m_bTerminal = terminal; -} - -void PtyProcess::setErase(bool erase) -{ - m_bErase = erase; -} - -/* - * Copy output to stdout until the child process exits, or a line of output - * matches `m_Exit'. - * We have to use waitpid() to test for exit. Merely waiting for EOF on the - * pty does not work, because the target process may have children still - * attached to the terminal. - */ - -int PtyProcess::waitForChild() -{ - fd_set fds; - FD_ZERO(&fds); - QByteArray remainder; - - while (1) - { - FD_SET(fd(), &fds); - - // specify timeout to make sure select() does not block, even if the - // process is dead / non-responsive. It does not matter if we abort too - // early. In that case 0 is returned, and we'll try again in the next - // iteration. (As long as we don't consitently time out in each iteration) - timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 100000; - int ret = select(fd()+1, &fds, 0L, 0L, &timeout); - if (ret == -1) - { - if (errno != EINTR) - { - kError(kdesuDebugArea()) << "select():" << perror; - return -1; - } - ret = 0; - } - - if (ret) - { - forever { - QByteArray output = readAll(false); - if (output.isEmpty()) - break; - if (m_bTerminal) - { - fwrite(output.constData(), output.size(), 1, stdout); - fflush(stdout); - } - if (!m_Exit.isEmpty()) - { - // match exit string only at line starts - remainder += output; - while (remainder.length() >= m_Exit.length()) { - if (remainder.startsWith(m_Exit)) { - kill(m_Pid, SIGTERM); - remainder.remove(0, m_Exit.length()); - } - int off = remainder.indexOf('\n'); - if (off < 0) - break; - remainder.remove(0, off + 1); - } - } - } - } - - ret = checkPidExited(m_Pid); - if (ret == Error) - { - if (errno == ECHILD) return 0; - else return 1; - } - else if (ret == Killed) - { - return 0; - } - else if (ret == NotExited) - { - // keep checking - } - else - { - return ret; - } - } -} - -/* - * SetupTTY: Creates a new session. The filedescriptor "fd" should be - * connected to the tty. It is closed after the tty is reopened to make it - * our controlling terminal. This way the tty is always opened at least once - * so we'll never get EIO when reading from it. - */ - -int PtyProcess::setupTTY() -{ - // Reset signal handlers - for (int sig = 1; sig < NSIG; sig++) - KDE_signal(sig, SIG_DFL); - KDE_signal(SIGHUP, SIG_IGN); - - d->m_pPTY->setCTty(); - - // Connect stdin, stdout and stderr - int slave = d->m_pPTY->slaveFd(); - dup2(slave, 0); dup2(slave, 1); dup2(slave, 2); - - // Close all file handles - // XXX this caused problems in KProcess - not sure why anymore. -- ??? - // Because it will close the start notification pipe. -- ossi - struct rlimit rlp; - getrlimit(RLIMIT_NOFILE, &rlp); - for (int i = 3; i < (int)rlp.rlim_cur; i++) - close(i); - - // Disable OPOST processing. Otherwise, '\n' are (on Linux at least) - // translated to '\r\n'. - struct ::termios tio; - if (tcgetattr(0, &tio) < 0) - { - kError(kdesuDebugArea()) << "tcgetattr():" << perror; - return -1; - } - tio.c_oflag &= ~OPOST; - if (tcsetattr(0, TCSANOW, &tio) < 0) - { - kError(kdesuDebugArea()) << "tcsetattr():" << perror; - return -1; - } - - return 0; -} - -} diff --git a/kdesu/process.h b/kdesu/process.h deleted file mode 100644 index d8b56598..00000000 --- a/kdesu/process.h +++ /dev/null @@ -1,201 +0,0 @@ -///////// XXX migrate it to kprocess ///////////////// - -/* vi: ts=8 sts=4 sw=4 - * - * This file is part of the KDE project, module kdesu. - * Copyright (C) 1999,2000 Geert Jansen - * - * 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. - */ - -#ifndef __Process_h_Included__ -#define __Process_h_Included__ - -#include - -#include -#include -#include -#include - -#include - -#include - -namespace KDESu { - -/** \class PtyProcess process.h kdesu/process.h - * Synchronous communication with tty programs. - * - * PtyProcess provides synchronous communication with tty based programs. - * The communications channel used is a pseudo tty (as opposed to a pipe) - * This means that programs which require a terminal will work. - */ - -class KDESU_EXPORT PtyProcess -{ -public: - PtyProcess(); - virtual ~PtyProcess(); - - /** - * Forks off and execute a command. The command's standard in and output - * are connected to the pseudo tty. They are accessible with readLine - * and writeLine. - * @param command The command to execute. - * @param args The arguments to the command. - * @return 0 on success, -1 on error. errno might give more information then. - */ - int exec(const QByteArray &command, const QList &args); - - /** - * Reads a line from the program's standard out. Depending on the @em block - * parameter, this call blocks until something was read. - * Note that in some situations this function will return less than a full - * line of output, but never more. Newline characters are stripped. - * @param block Block until a full line is read? - * @return The output string. - */ - QByteArray readLine(bool block=true); - - /** - * Read all available output from the program's standard out. - * @param block If no output is in the buffer, should the function block - * (else it will return an empty QByteArray)? - * @return The output. - */ - QByteArray readAll(bool block=true); - - /** - * Writes a line of text to the program's standard in. - * @param line The text to write. - * @param addNewline Adds a '\n' to the line. - */ - void writeLine(const QByteArray &line, bool addNewline=true); - - /** - * Puts back a line of input. - * @param line The line to put back. - * @param addNewline Adds a '\n' to the line. - */ - void unreadLine(const QByteArray &line, bool addNewline=true); - - /** - * Sets the exit string. If a line of program output matches this, - * waitForChild() will terminate the program and return. - */ - void setExitString(const QByteArray &exit); - - /** - * Waits for the child to exit. See also setExitString. - */ - int waitForChild(); - - /** - * Waits until the pty has cleared the ECHO flag. This is useful - * when programs write a password prompt before they disable ECHO. - * Disabling it might flush any input that was written. - */ - int WaitSlave(); - - /** - * Enables/disables local echo on the pseudo tty. - */ - int enableLocalEcho(bool enable=true); - - /** - * Enables/disables terminal output. Relevant only to some subclasses. - */ - void setTerminal(bool terminal); - - /** - * Overwrites the password as soon as it is used. Relevant only to - * some subclasses. - */ - void setErase(bool erase); - - /** - * Set additinal environment variables. - */ - void setEnvironment( const QList &env ); - - /** - * Returns the filedescriptor of the process. - */ - int fd() const; - - /** - * Returns the pid of the process. - */ - int pid() const; - -public /* static */: - /* - ** This is a collection of static functions that can be - ** used for process control inside kdesu. I'd suggest - ** against using this publicly. There are probably - ** nicer Qt based ways to do what you want. - */ - - /** - ** Wait @p ms miliseconds (ie. 1/10th of a second is 100ms), - ** using @p fd as a filedescriptor to wait on. Returns - ** select(2)'s result, which is -1 on error, 0 on timeout, - ** or positive if there is data on one of the selected fd's. - ** - ** @p ms must be in the range 0..999 (i.e. the maximum wait - ** duration is 999ms, almost one second). - */ - static int waitMS(int fd,int ms); - - - /** - ** Basic check for the existence of @p pid. - ** Returns true iff @p pid is an extant process, - ** (one you could kill - see man kill(2) for signal 0). - */ - static bool checkPid(pid_t pid); - - - /** Error return values for checkPidExited() */ - enum checkPidStatus { Error=-1, /**< No child */ - NotExited=-2, /**< Child hasn't exited */ - Killed=-3 /**< Child terminated by signal */ - } ; - - /** - ** Check process exit status for process @p pid. - ** If child @p pid has exited, return its exit status, - ** (which may be zero). - ** On error (no child, no exit), return -1. - ** If child @p has not exited, return -2. - */ - static int checkPidExited(pid_t pid); - - -protected: - QList environment() const; - - bool m_bErase, /**< @see setErase() */ - m_bTerminal; /**< Indicates running in a terminal, causes additional - newlines to be printed after output. Set to @c false - in constructor. @see setTerminal() */ - int m_Pid; /**< PID of child process */ - QByteArray m_Command, /**< Unused */ - m_Exit; /**< String to scan for in output that indicates - child has exited. */ - -private: - int init(); - int setupTTY(); - -private: - class PtyProcessPrivate; - PtyProcessPrivate* const d; -}; - -} - -#endif diff --git a/kdesu/ssh.cpp b/kdesu/ssh.cpp deleted file mode 100644 index f9769139..00000000 --- a/kdesu/ssh.cpp +++ /dev/null @@ -1,259 +0,0 @@ -/* vi: ts=8 sts=4 sw=4 -* -* This file is part of the KDE project, module kdesu. -* Copyright (C) 2000 Geert Jansen -* -* 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. -* -* ssh.cpp: Execute a program on a remote machine using ssh. -*/ - -#include "ssh.h" -#include "kcookie.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include - -extern int kdesuDebugArea(); - -namespace KDESu { - -using namespace KDESuPrivate; - -class SshProcess::SshProcessPrivate -{ -public: - SshProcessPrivate(const QByteArray &host) - : m_Host( host ) - , m_Stub( "kdesu_stub" ) - {} - QByteArray m_Prompt; - QByteArray m_Host; - QByteArray m_Error; - QByteArray m_Stub; -}; - - -SshProcess::SshProcess(const QByteArray &host, const QByteArray &user, const QByteArray &command) - : d( new SshProcessPrivate(host) ) -{ - m_User = user; - m_Command = command; - srand(time(0L)); -} - - -SshProcess::~SshProcess() -{ - delete d; -} - -void SshProcess::setHost(const QByteArray &host) -{ - d->m_Host = host; -} - - -void SshProcess::setStub(const QByteArray &stub) -{ - d->m_Stub = stub; -} - - -int SshProcess::checkInstall(const char *password) -{ - return exec(password, 1); -} - - -int SshProcess::checkNeedPassword() -{ - return exec(0L, 2); -} - - -int SshProcess::exec(const char *password, int check) -{ - if (check) - setTerminal(true); - - QList args; - args += "-l"; args += m_User; - args += "-o"; args += "StrictHostKeyChecking=no"; - args += d->m_Host; args += d->m_Stub; - - if (StubProcess::exec("ssh", args) < 0) - { - return check ? SshNotFound : -1; - } - - int ret = ConverseSsh(password, check); - if (ret < 0) - { - if (!check) - kError(kdesuDebugArea()) << "Conversation with ssh failed."; - return ret; - } - if (check == 2) - { - if (ret == 1) - { - kill(m_Pid, SIGTERM); - waitForChild(); - } - return ret; - } - - if (m_bErase && password) - memset(const_cast(password), 0, qstrlen(password)); - - ret = ConverseStub(check); - if (ret < 0) - { - if (!check) - kError(kdesuDebugArea()) << "Conversation with kdesu_stub failed."; - return ret; - } - else if (ret == 1) - { - kill(m_Pid, SIGTERM); - waitForChild(); - ret = SshIncorrectPassword; - } - - if (check == 1) - { - waitForChild(); - return 0; - } - - setExitString("Waiting for forwarded connections to terminate"); - ret = waitForChild(); - return ret; -} - -QByteArray SshProcess::prompt() const -{ - return d->m_Prompt; -} - -QByteArray SshProcess::error() const -{ - return d->m_Error; -} - - -/* -* Conversation with ssh. -* If check is 0, this waits for either a "Password: " prompt, -* or the header of the stub. If a prompt is received, the password is -* written back. Used for running a command. -* If check is 1, operation is the same as 0 except that if a stub header is -* received, the stub is stopped with the "stop" command. This is used for -* checking a password. -* If check is 2, operation is the same as 1, except that no password is -* written. The prompt is saved to m_Prompt. Used for checking the need for -* a password. -*/ - -int SshProcess::ConverseSsh(const char *password, int check) -{ - unsigned i, j, colon; - - QByteArray line; - int state = 0; - - while (state < 2) - { - line = readLine(); - const uint len = line.length(); - if (line.isNull()) - return -1; - - switch (state) { - case 0: - // Check for "kdesu_stub" header. - if (line == "kdesu_stub") - { - unreadLine(line); - return 0; - } - - // Match "Password: " with the regex ^[^:]+:[\w]*$. - for (i=0,j=0,colon=0; im_Prompt = line; - return SshNeedsPassword; - } - if (WaitSlave()) - return -1; - write(fd(), password, strlen(password)); - write(fd(), "\n", 1); - state++; - break; - } - - // Warning/error message. - d->m_Error += line; d->m_Error += '\n'; - if (m_bTerminal) - fprintf(stderr, "ssh: %s\n", line.constData()); - break; - - case 1: - if (line.isEmpty()) - { - state++; - break; - } - return -1; - } - } - return 0; -} - - -// Display redirection is handled by ssh natively. -QByteArray SshProcess::display() -{ - return "no"; -} - - -QByteArray SshProcess::displayAuth() -{ - return "no"; -} - -} diff --git a/kdesu/ssh.h b/kdesu/ssh.h deleted file mode 100644 index e954cbc1..00000000 --- a/kdesu/ssh.h +++ /dev/null @@ -1,81 +0,0 @@ -/* vi: ts=8 sts=4 sw=4 - * - * This file is part of the KDE project, module kdesu. - * Copyright (C) 2000 Geert Jansen - * - * 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. - */ - -#ifndef __SSH_h_Included__ -#define __SSH_h_Included__ - -#include "stub.h" - -#include - -namespace KDESu { - -/** \class SshProcess ssh.h kdesu/ssh.h - * Executes a remote command, using ssh. - */ - -class KDESU_EXPORT SshProcess: public StubProcess -{ -public: - explicit SshProcess(const QByteArray &host = QByteArray(), - const QByteArray &user = QByteArray(), - const QByteArray &command = QByteArray()); - ~SshProcess(); - - enum Errors { SshNotFound=1, SshNeedsPassword, SshIncorrectPassword }; - - /** - * Sets the target host. - */ - void setHost(const QByteArray &host); - - /** - * Sets the localtion of the remote stub. - */ - void setStub(const QByteArray &stub); - - /** - * Checks if the current user\@host needs a password. - * @return The prompt for the password if a password is required. A null - * string otherwise. - * - * @todo The return doc is so obviously wrong that the C code needs to be checked. - */ - int checkNeedPassword(); - - /** - * Checks if the stub is installed and if the password is correct. - * @return Zero if everything is correct, nonzero otherwise. - */ - int checkInstall(const char *password); - - /** - * Executes the command. - */ - int exec(const char *password, int check=0); - - QByteArray prompt() const; - QByteArray error() const; - -protected: - virtual QByteArray display(); - virtual QByteArray displayAuth(); - -private: - int ConverseSsh(const char *password, int check); - -private: - class SshProcessPrivate; - SshProcessPrivate * const d; -}; - -} - -#endif diff --git a/kdesu/stub.cpp b/kdesu/stub.cpp deleted file mode 100644 index 9b81b661..00000000 --- a/kdesu/stub.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/* vi: ts=8 sts=4 sw=4 - * - * This file is part of the KDE project, module kdesu. - * Copyright (C) 1999,2000 Geert Jansen - * - * 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. - * - * stub.cpp: Conversation with kdesu_stub. - */ - -#include "stub.h" -#include "kcookie.h" - -#include -#include -#include - -#include - -#include - -extern int kdesuDebugArea(); - -namespace KDESu { - -using namespace KDESuPrivate; - -StubProcess::StubProcess() - : d(0) -{ - m_User = "root"; - m_Scheduler = SchedNormal; - m_Priority = 50; - m_pCookie = new KCookie; - m_bXOnly = true; -} - - -StubProcess::~StubProcess() -{ - delete m_pCookie; -} - - -void StubProcess::setCommand(const QByteArray &command) -{ - m_Command = command; -} - - -void StubProcess::setUser(const QByteArray &user) -{ - m_User = user; -} - - -void StubProcess::setXOnly(bool xonly) -{ - m_bXOnly = xonly; -} - - -void StubProcess::setPriority(int prio) -{ - if (prio > 100) - m_Priority = 100; - else if (prio < 0) - m_Priority = 0; - else - m_Priority = prio; -} - - -void StubProcess::setScheduler(int sched) -{ - m_Scheduler = sched; -} - -void StubProcess::writeString(const QByteArray &str) -{ - QByteArray out; - out.reserve(str.size() + 8); - for (int i = 0; i < str.size(); i++) { - uchar c = str.at(i); - if (c < 32) { - out.append('\\'); - out.append(c + '@'); - } else if (c == '\\') { - out.append('\\'); - out.append('/'); - } else { - out.append(c); - } - } - writeLine(out); -} - -/* - * Map pid_t to a signed integer type that makes sense for QByteArray; - * only the most common sizes 16 bit and 32 bit are special-cased. - */ -template struct PIDType { typedef pid_t PID_t; } ; -template<> struct PIDType<2> { typedef qint16 PID_t; } ; -template<> struct PIDType<4> { typedef qint32 PID_t; } ; - -/* - * Conversation with kdesu_stub. This is how we pass the authentication - * tokens (X11) and other stuff to kdesu_stub. - * return values: -1 = error, 0 = ok, 1 = kill me - */ - -int StubProcess::ConverseStub(int check) -{ - QByteArray line, tmp; - - while (1) - { - line = readLine(); - if (line.isNull()) - return -1; - - if (line == "kdesu_stub") - { - // This makes parsing a lot easier. - enableLocalEcho(false); - if (check) writeLine("stop"); - else writeLine("ok"); - break; - } - } - - while (1) - { - line = readLine(); - if (line.isNull()) - return -1; - - if (line == "display") { - writeLine(display()); - } else if (line == "display_auth") { -#ifdef Q_WS_X11 - writeLine(displayAuth()); -#else - writeLine(""); -#endif - } else if (line == "command") { - writeString(m_Command); - } else if (line == "path") { - QByteArray path = qgetenv("PATH"); - if (!path.isEmpty() && path[0] == ':') - path = path.mid(1); - if (m_User == "root") { - if (!path.isEmpty()) - path = "/sbin:/bin:/usr/sbin:/usr/bin:" + path; - else - path = "/sbin:/bin:/usr/sbin:/usr/bin"; - } - writeLine(path); - } else if (line == "user") { - writeLine(m_User); - } else if (line == "priority") { - tmp.setNum(m_Priority); - writeLine(tmp); - } else if (line == "scheduler") { - if (m_Scheduler == SchedRealtime) writeLine("realtime"); - else writeLine("normal"); - } else if (line == "xwindows_only") { - if (m_bXOnly) writeLine("no"); - else writeLine("yes"); - } else if (line == "app_startup_id") { - QList env = environment(); - QByteArray tmp; - for(int i = 0; i < env.count(); ++i) - { - const char startup_env[] = "DESKTOP_STARTUP_ID="; - if (env.at(i).startsWith(startup_env)) - tmp = env.at(i).mid(sizeof(startup_env) - 1); - } - if( tmp.isEmpty()) - tmp = "0"; // krazy:exclude=doublequote_chars - writeLine(tmp); - } else if (line == "app_start_pid") { // obsolete - // Force the pid_t returned from getpid() into - // something QByteArray understands; avoids ambiguity - // between short and unsigned short in particular. - tmp.setNum((PIDType::PID_t)(getpid())); - writeLine(tmp); - } else if (line == "environment") { // additional env vars - QList env = environment(); - for (int i = 0; i < env.count(); ++i) - writeString(env.at(i)); - writeLine( "" ); - } else if (line == "end") { - return 0; - } else - { - kWarning(kdesuDebugArea()) << "Unknown request:" << line; - return 1; - } - } - - return 0; -} - - -QByteArray StubProcess::display() -{ - return m_pCookie->display(); -} - - -#ifdef Q_WS_X11 -QByteArray StubProcess::displayAuth() -{ - return m_pCookie->displayAuth(); -} -#endif - - -} diff --git a/kdesu/stub.h b/kdesu/stub.h deleted file mode 100644 index 12975f99..00000000 --- a/kdesu/stub.h +++ /dev/null @@ -1,106 +0,0 @@ -/* vi: ts=8 sts=4 sw=4 - * - * This file is part of the KDE project, module kdesu. - * Copyright (C) 1999,2000 Geert Jansen - * - * 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. - */ - -#ifndef __Stub_h_Included__ -#define __Stub_h_Included__ - -#include -#include - -#include "process.h" - -#include - -namespace KDESu { - -namespace KDESuPrivate { class KCookie; } - - -/** \class StubProcess stub.h kdesu/stub.h - * Chat with kdesu_stub. - * - * StubProcess extends PtyProcess with functionality to chat with kdesu_stub. - */ - -class KDESU_EXPORT StubProcess: public PtyProcess -{ -public: - StubProcess(); - ~StubProcess(); - - /** - * Set the command. - */ - void setCommand(const QByteArray &command); - - /** - * Set the target user. - */ - void setUser(const QByteArray &user); - - /** - * Set to "X only mode": Sycoca is not built and kdeinit is not launched. - */ - void setXOnly(bool xonly); - - /** - * Set the priority of the process. The priority value must be between 0 - * and 100, 0 being the lowest priority. This value is mapped to the - * scheduler and system dependent priority range of the OS. - */ - void setPriority(int prio); - - /** - * Different schedulers. SchedNormal is the normal Unix timesharing - * scheduler, while SchedRealtime is a POSIX.1b realtime scheduler. - */ - enum Scheduler { SchedNormal, SchedRealtime }; - - /** - * Set the scheduler type. - */ - void setScheduler(int sched); - -protected: - - /** - * Exchange all parameters with kdesu_stub. - */ - int ConverseStub(int check); - - /** - * This virtual function can be overloaded when special behavior is - * desired. By default, it returns the value returned by KCookie. - */ - virtual QByteArray display(); -#ifdef Q_WS_X11 - /** - * See display. - */ - virtual QByteArray displayAuth(); -#endif - bool m_bXOnly; - int m_Priority; - int m_Scheduler; - QByteArray m_Command; - QByteArray m_User; - KDESuPrivate::KCookie *m_pCookie; - -private: - void writeString(const QByteArray &str); - -private: - class StubProcessPrivate; - StubProcessPrivate * const d; -}; - -} - -#endif // __Stub_h_Included__ diff --git a/kdesu/su.cpp b/kdesu/su.cpp deleted file mode 100644 index 9d5189e0..00000000 --- a/kdesu/su.cpp +++ /dev/null @@ -1,329 +0,0 @@ -/* vi: ts=8 sts=4 sw=4 -* -* This file is part of the KDE project, module kdesu. -* Copyright (C) 1999,2000 Geert Jansen -* -* Sudo support added by Jonathan Riddell -* Copyright (C) 2005 Canonical Ltd // krazy:exclude=copyright (no email) -* -* 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 "su.h" -#include "kcookie.h" - -#include -#include // for LIBEXEC_INSTALL_DIR - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -int kdesuDebugArea() -{ - static int s_area = KDebug::registerArea("kdesu (kdelibs)"); - return s_area; -} - -#ifndef __PATH_SU -#define __PATH_SU "false" -#endif - -#ifndef __PATH_SUDO -#define __PATH_SUDO "false" -#endif - -#ifdef KDESU_USE_SUDO_DEFAULT -# define DEFAULT_SUPER_USER_COMMAND "sudo" -#else -# define DEFAULT_SUPER_USER_COMMAND "su" -#endif - -namespace KDESu { -using namespace KDESuPrivate; - -class SuProcess::SuProcessPrivate -{ -public: - QString m_superUserCommand; -}; - -SuProcess::SuProcess(const QByteArray &user, const QByteArray &command) - : d( new SuProcessPrivate ) -{ - m_User = user; - m_Command = command; - - KSharedConfig::Ptr config = KGlobal::config(); - KConfigGroup group(config, "super-user-command"); - d->m_superUserCommand = group.readEntry("super-user-command", DEFAULT_SUPER_USER_COMMAND); - - if ( d->m_superUserCommand != "sudo" && d->m_superUserCommand != "su" ) { - kWarning() << "unknown super user command."; - d->m_superUserCommand = DEFAULT_SUPER_USER_COMMAND; - } -} - - -SuProcess::~SuProcess() -{ - delete d; -} - -QString SuProcess::superUserCommand() -{ - return d->m_superUserCommand; -} - -bool SuProcess::useUsersOwnPassword() -{ - if (superUserCommand() == "sudo" && m_User == "root") { - return true; - } - - KUser user; - return user.loginName() == m_User; -} - -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") { - d->m_superUserCommand = "su"; - } - - QList args; - if (d->m_superUserCommand == "sudo") { - args += "-u"; - } - - if ((m_Scheduler != SchedNormal) || (m_Priority > 50)) - args += "root"; - else - args += m_User; - - if (d->m_superUserCommand == "su") { - args += "-c"; - } - args += QByteArray(LIBEXEC_INSTALL_DIR) + "/kdesu_stub"; - args += "-"; // krazy:exclude=doublequote_chars (QList, not QString) - - QByteArray command; - if (d->m_superUserCommand == "sudo") { - command = __PATH_SUDO; - } else { - command = __PATH_SU; - } - - if (::access(command, X_OK) != 0) - { - command = QFile::encodeName( KGlobal::dirs()->findExe(d->m_superUserCommand.toLatin1()) ); - if (command.isEmpty()) - return check ? SuNotFound : -1; - } - - // kDebug(kdesuDebugArea()) << "Call StubProcess::exec()"; - if (StubProcess::exec(command, args) < 0) - { - return check ? SuNotFound : -1; - } - // kDebug(kdesuDebugArea()) << "Done StubProcess::exec()"; - - SuErrors ret = (SuErrors) ConverseSU(password); - // kDebug(kdesuDebugArea()) << "Conversation returned" << ret; - - if (ret == error) - { - if (!check) - kError(kdesuDebugArea()) << "Conversation with su failed."; - return ret; - } - if (check == NeedPassword) - { - if (ret == killme) - { - if (kill(m_Pid, SIGKILL) < 0) { - // SIGKILL doesn't work for sudo - if (kill(m_Pid, SIGINT) < 0) { - kDebug() << "kill < 0"; - ret=error; - } - } - else - { - int iret = waitForChild(); - if (iret < 0) ret=error; - else /* nothing */ {} ; - } - } - return ret; - } - - if (m_bErase && password) - memset(const_cast(password), 0, qstrlen(password)); - - if (ret != ok) - { - kill(m_Pid, SIGKILL); - kill(m_Pid, SIGINT); - waitForChild(); - return SuIncorrectPassword; - } - - int iret = ConverseStub(check); - if (iret < 0) - { - if (!check) - kError(kdesuDebugArea()) << "Conversation with kdesu_stub failed."; - return iret; - } - else if (iret == 1) - { - kill(m_Pid, SIGKILL); - kill(m_Pid, SIGINT); - 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; - // kDebug(kdesuDebugArea()) << "ConverseSU starting."; - - QByteArray line; - while (true) - { - line = readLine(); - // close your eyes for a sec and use that scroll button - if (line.isNull() || line == "Sorry, try again.") - return ( state == HandleStub ? notauthorized : error); - kDebug(kdesuDebugArea()) << "Read line" << line; - - if (line == "kdesu_stub") - { - unreadLine(line); - return ok; - } - - switch (state) - { - ////////////////////////////////////////////////////////////////////////// - case WaitForPrompt: - { - if (waitMS(fd(),100)>0) - { - // There is more output available, so this 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). - continue; - } - - // Match "Password: " with the regex ^[^:]+:[\w]*$. - const uint len = line.length(); - for (i=0,j=0,colon=0; i - * - * 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. - */ - -#ifndef __SU_h_Included__ -#define __SU_h_Included__ - -#include - -#include "stub.h" - - -namespace KDESu { - -/** \class SuProcess su.h kdesu/su.h - * Executes a command under elevated privileges, using su. - */ - -class KDESU_EXPORT SuProcess: public StubProcess -{ -public: - explicit SuProcess(const QByteArray &user=0, const QByteArray &command=0); - ~SuProcess(); - - enum Errors { SuNotFound=1, SuNotAllowed, SuIncorrectPassword }; - - /** - * Executes the command. This will wait for the command to finish. - */ - enum checkMode { NoCheck=0, Install=1, NeedPassword=2 } ; - int exec(const char *password, int check=NoCheck); - - /** - * Checks if the stub is installed and the password is correct. - * @return Zero if everything is correct, nonzero otherwise. - */ - int checkInstall(const char *password); - - /** - * Checks if a password is needed. - */ - int checkNeedPassword(); - - /** - * Checks what the default super user command is, e.g. sudo, su, etc - * @return the default super user command - */ - QString superUserCommand(); - - /** - * Checks whether or not the user's password is being asked for or another - * user's password. Due to usage of systems such as sudo, even when attempting - * to switch to another user one may need to enter their own password. - */ - bool useUsersOwnPassword(); - -private: - enum SuErrors { error=-1, ok=0, killme=1, notauthorized=2 } ; - int ConverseSU(const char *password); - -private: - class SuProcessPrivate; - SuProcessPrivate * const d; -}; - -} - -#endif diff --git a/kdesudo/CMakeLists.txt b/kdesudo/CMakeLists.txt new file mode 100644 index 00000000..e9266d45 --- /dev/null +++ b/kdesudo/CMakeLists.txt @@ -0,0 +1,20 @@ +check_include_files("sys/prctl.h" HAVE_SYS_PRCTL_H) +check_symbol_exists(PR_SET_DUMPABLE "sys/prctl.h" HAVE_PR_SET_DUMPABLE) +add_feature_info("prctl-dumpable" HAVE_PR_SET_DUMPABLE "Used to disallow ptracing") + +configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) + +# set(kt4_SRC app.cpp mainwindow.cpp core.cpp view.cpp viewmodel.cpp main.cpp) +set(KDESUDO_SRC + main.cpp + kdesudo.cpp + kcookie.cpp +) + +add_executable(kdesudo ${KDESUDO_SRC}) + +target_link_libraries(kdesudo ${KDE4_KDEUI_LIBS}) +install( + TARGETS kdesudo + ${INSTALL_TARGETS_DEFAULT_ARGS} +) diff --git a/kdesudo/Messages.sh b/kdesudo/Messages.sh new file mode 100755 index 00000000..c0ed512d --- /dev/null +++ b/kdesudo/Messages.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +$XGETTEXT `find . -name \*.cpp` -o $podir/kdesudo.pot diff --git a/kdesudo/config.h.cmake b/kdesudo/config.h.cmake new file mode 100644 index 00000000..800cd57f --- /dev/null +++ b/kdesudo/config.h.cmake @@ -0,0 +1,2 @@ +#cmakedefine01 HAVE_SYS_PRCTL_H +#cmakedefine01 HAVE_PR_SET_DUMPABLE diff --git a/kdesudo/kcookie.cpp b/kdesudo/kcookie.cpp new file mode 100644 index 00000000..c75c13af --- /dev/null +++ b/kdesudo/kcookie.cpp @@ -0,0 +1,105 @@ +/* vi: ts=8 sts=4 sw=4 + * + * This file is part of the KDE project, module kdesu. + * Copyright (C) 1999,2000 Geert Jansen + * + * 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. + * + * kcookie.cpp: KDE authentication cookies. + */ + +#include "kcookie.h" + +#include + +#include +#include +#include +#include + +#include + +namespace KDESu +{ + namespace KDESuPrivate + { + + class KCookie::KCookiePrivate + { + public: + QByteArray m_Display; +#ifdef Q_WS_X11 + QByteArray m_DisplayAuth; +#endif + }; + + + + KCookie::KCookie() + : d(new KCookiePrivate) + { +#ifdef Q_WS_X11 + getXCookie(); +#endif + } + + KCookie::~KCookie() + { + delete d; + } + + QByteArray KCookie::display() const + { + return d->m_Display; + } + +#ifdef Q_WS_X11 + QByteArray KCookie::displayAuth() const + { + return d->m_DisplayAuth; + } +#endif + + void KCookie::getXCookie() + { +#ifdef Q_WS_X11 + d->m_Display = getenv("DISPLAY"); +#else + d->m_Display = getenv("QWS_DISPLAY"); +#endif + if (d->m_Display.isEmpty()) { + kError(900) << "$DISPLAY is not set.\n"; + return; + } +#ifdef Q_WS_X11 // No need to mess with X Auth stuff + QByteArray disp = d->m_Display; + if (disp.startsWith("localhost:")) { + disp.remove(0, 9); + } + + QProcess proc; + proc.start("xauth", QStringList() << "list" << disp); + if (!proc.waitForStarted()) { + kError(900) << "Could not run xauth.\n"; + return; + } + proc.waitForReadyRead(100); + QByteArray output = proc.readLine().simplified(); + if (output.isEmpty()) { + kWarning(900) << "No X authentication info set for display " << + d->m_Display << endl; return; + } + QList lst = output.split(' '); + if (lst.count() != 3) { + kError(900) << "parse error.\n"; + return; + } + d->m_DisplayAuth = (lst[1] + ' ' + lst[2]); + proc.waitForFinished(100); // give QProcess a chance to clean up gracefully +#endif + } + + } +} diff --git a/kdesudo/kcookie.h b/kdesudo/kcookie.h new file mode 100644 index 00000000..62aae0fe --- /dev/null +++ b/kdesudo/kcookie.h @@ -0,0 +1,57 @@ +/* vi: ts=8 sts=4 sw=4 + * + * This file is part of the KDE project, module kdesu + * Copyright (C) 1999,2000 Geert Jansen + * + * 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. + */ + +#ifndef __KCookie_h_Included__ +#define __KCookie_h_Included__ + +#include + + +namespace KDESu +{ + + namespace KDESuPrivate + { + + /** + * Utility class to access the authentication tokens needed to run a KDE + * program (X11 cookies on X11, for instance). + * @internal + */ + + class KCookie + { + public: + KCookie(); + ~KCookie(); + + /** + * Returns the X11 display. + */ + QByteArray display() const; + +#ifdef Q_WS_X11 + /** + * Returns the X11 magic cookie, if available. + */ + QByteArray displayAuth() const; +#endif + + private: + void getXCookie(); + + class KCookiePrivate; + KCookiePrivate *const d; + }; + + } +} + +#endif // __KCookie_h_Included__ diff --git a/kdesudo/kdesudo.cpp b/kdesudo/kdesudo.cpp new file mode 100644 index 00000000..26564d61 --- /dev/null +++ b/kdesudo/kdesudo.cpp @@ -0,0 +1,387 @@ +/*************************************************************************** + kdesudo.cpp - the implementation of the + admin granting sudo widget + ------------------- + begin : Sam Feb 15 15:42:12 CET 2003 + copyright : (C) 2003 by Robert Gruber + + (C) 2007 by Martin Böhm + Anthony Mercatante + Canonical Ltd (Jonathan Riddell + ) + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "kdesudo.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +KdeSudo::KdeSudo(const QString &icon, const QString &appname) : + QObject(), + m_process(0), + m_error(false), + m_pCookie(new KDESu::KDESuPrivate::KCookie) +{ + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + bool realtime = args->isSet("r"); + bool priority = args->isSet("p"); + bool showCommand = (!args->isSet("d")); + bool changeUID = true; + bool noExec = false; + QString runas = args->getOption("u"); + QString cmd; + int winid = -1; + bool attach = args->isSet("attach"); + + m_dialog = new KPasswordDialog; + m_dialog->setDefaultButton(KDialog::Ok); + + if (attach) { + winid = args->getOption("attach").toInt(&attach, 0); + KWindowSystem::setMainWindow(m_dialog, (WId)winid); + } + + if (!args->isSet("c") && !args->count()) { + KMessageBox::information(0, i18n("No command arguments supplied!\n" + "Usage: kdesudo [-u ] \n" + "KdeSudo will now exit...") + ); + noExec = true; + } + + m_process = new QProcess; + + /* load the icon */ + m_dialog->setPixmap(icon); + + // Parsins args + + /* Get the comment out of cli args */ + QByteArray commentBytes = args->getOption("comment").toUtf8(); + QTextCodec *tCodecConv = QTextCodec::codecForLocale(); + QString comment = tCodecConv->toUnicode(commentBytes, commentBytes.size()); + + if (args->isSet("f")) { + // If file is writeable, do not change uid + QString file = args->getOption("f"); + if (!file.isEmpty()) { + if (file.at(0) != '/') { + KStandardDirs dirs; + file = dirs.findResource("config", file); + if (file.isEmpty()) { + kWarning(1206) << "Config file not found: " << file << "\n"; + exit(1); + } + } + QFileInfo fi(file); + if (!fi.exists()) { + kWarning(1206) << "File does not exist: " << file << "\n"; + exit(1); + } + if (fi.isWritable()) { + changeUID = false; + } + } + } + + connect(m_process, SIGNAL(readyReadStandardOutput()), + this, SLOT(parseOutput())); + + connect(m_process, SIGNAL(readyReadStandardError()), + this, SLOT(parseOutput())); + + connect(m_process, SIGNAL(finished(int)), + this, SLOT(procExited(int))); + + connect(m_dialog, SIGNAL(gotPassword(const QString & , bool)), + this, SLOT(pushPassword(const QString &))); + + connect(m_dialog, SIGNAL(rejected()), + this, SLOT(slotCancel())); + + // Generate the xauth cookie and put it in a tempfile + // set the environment variables to reflect that. + // Default cookie-timeout is 60 sec. . + // 'man xauth' for more info on xauth cookies. + + QTemporaryFile *tmpFile = new QTemporaryFile("/tmp/kdesudo-XXXXXX-xauth"); + tmpFile->open(); + QString m_tmpName = tmpFile->fileName(); + delete tmpFile; + + QByteArray disp = m_pCookie->display(); + + // Create two processes, one for each xauth call + QProcess xauth_ext; + QProcess xauth_merge; + + // This makes "xauth extract - $DISPLAY | xauth -f /tmp/kdesudo-... merge -" + xauth_ext.setStandardOutputProcess(&xauth_merge); + + // Start the first + xauth_ext.start("xauth", QStringList() << "extract" << "-" << QString::fromLocal8Bit(disp), QIODevice::ReadOnly); + if (!xauth_ext.waitForStarted()) { + return; + } + + // Start the second + xauth_merge.start("xauth", QStringList() << "-f" << m_tmpName << "merge" << "-", QIODevice::WriteOnly); + if (!xauth_merge.waitForStarted()) { + return; + } + + // If they ended, close it all + if (!xauth_merge.waitForFinished()) { + return; + } + xauth_merge.close(); + + if (!xauth_ext.waitForFinished()) { + return; + } + xauth_ext.close(); + + // non root users need to be able to read the xauth file. + // the xauth file is deleted when kdesudo exits. security? + QFile tf; + tf.setFileName(m_tmpName); + + if (!runas.isEmpty() && runas != "root" && tf.exists()) { + chmod(QFile::encodeName(m_tmpName), 0644); + } + + QProcessEnvironment processEnv = QProcessEnvironment::systemEnvironment(); + processEnv.insert("DISPLAY", disp); + processEnv.insert("XAUTHORITY", m_tmpName); + m_process->setProcessEnvironment(processEnv); + + QStringList processArgs; + { + // Do not cache credentials to avoid security risks caused by the fact + // that kdesudo could be invoked from anyting inside the user session + // potentially in such a way that it uses the cached credentials of a + // previously kdesudo run in that same scope. + processArgs << "-k"; + if (changeUID) { + processArgs << "-H" << "-S" << "-p" << "passprompt"; + + if (!runas.isEmpty()) { + processArgs << "-u" << runas; + } + processArgs << "--"; + } + + if (realtime) { + processArgs << "nice" << "-n" << "10"; + m_dialog->addCommentLine(i18n("Priority:"), i18n("realtime:") + + QChar(' ') + QString("50/100")); + processArgs << "--"; + } else if (priority) { + QString n = args->getOption("p"); + int intn = atoi(n.toUtf8()); + intn = (intn * 40 / 100) - (20 + 0.5); + + QString strn; + strn.sprintf("%d", intn); + + processArgs << "nice" << "-n" << strn; + m_dialog->addCommentLine(i18n("Priority:"), n + QString("/100")); + processArgs << "--"; + } + + + + if (args->isSet("c")) { + QString command = args->getOption("c"); + cmd += command; + processArgs << "sh"; + processArgs << "-c"; + processArgs << command; + } + + else if (args->count()) { + for (int i = 0; i < args->count(); i++) { + if ((!args->isSet("c")) && (i == 0)) { + QStringList argsSplit = KShell::splitArgs(args->arg(i)); + for (int j = 0; j < argsSplit.count(); j++) { + processArgs << validArg(argsSplit[j]); + if (j == 0) { + cmd += validArg(argsSplit[j]) + QChar(' '); + } else { + cmd += KShell::quoteArg(validArg(argsSplit[j])) + QChar(' '); + } + } + } else { + processArgs << validArg(args->arg(i)); + cmd += validArg(args->arg(i)) + QChar(' '); + } + } + } + // strcmd needs to be defined + if (showCommand && !cmd.isEmpty()) { + m_dialog->addCommentLine(i18n("Command:"), cmd); + } + } + + if (comment.isEmpty()) { + QString defaultComment = "%1 " + i18n("needs administrative privileges. "); + + if (runas.isEmpty() || runas == "root") { + defaultComment += i18n("Please enter your password."); + } else { + defaultComment += i18n("Please enter password for %1.", runas); + } + + if (!appname.isEmpty()) { + m_dialog->setPrompt(defaultComment.arg(appname)); + } else { + m_dialog->setPrompt(defaultComment.arg(cmd)); + } + } else { + m_dialog->setPrompt(comment); + } + + m_process->setProcessChannelMode(QProcess::MergedChannels); + + if (noExec) { + exit(0); + } else { + m_process->start("sudo", processArgs); + } +} + +KdeSudo::~KdeSudo() +{ + delete m_dialog; +} + +void KdeSudo::error(const QString &msg) +{ + m_error = true; + KMessageBox::error(0, msg); + KApplication::kApplication()->exit(1); +} + +void KdeSudo::parseOutput() +{ + QString strOut = m_process->readAllStandardOutput(); + + static int badpass = 0; + + if (strOut.contains("try again")) { + badpass++; + if (badpass == 1) { + m_dialog->addCommentLine(i18n("Warning: "), i18n("Incorrect password, please try again.")); + m_dialog->show(); + } else if (badpass == 2) { + m_dialog->show(); + } else { + error(i18n("Wrong password! Exiting...")); + } + + } else if (strOut.contains("command not found")) { + error(i18n("Command not found!")); + } else if (strOut.contains("is not in the sudoers file")) { + error(i18n("Your username is unknown to sudo!")); + } else if (strOut.contains("is not allowed to execute")) { + error(i18n("Your user is not allowed to run the specified command!")); + } else if (strOut.contains("is not allowed to run sudo on")) { + error(i18n("Your user is not allowed to run sudo on this host!")); + } else if (strOut.contains("may not run sudo on")) { + error(i18n("Your user is not allowed to run sudo on this host!")); + } else if ((strOut.contains("passprompt")) || (strOut.contains("PIN (CHV2)"))) { + m_dialog->setPassword(QString()); + m_dialog->show(); + } else { + fprintf(stdout, "%s", strOut.toLocal8Bit().constData()); + } +} + +void KdeSudo::procExited(int exitCode) +{ + if (!m_error) { + if (!m_tmpName.isEmpty()) { + QFile::remove(m_tmpName); + } + } + KApplication::kApplication()->exit(exitCode); +} + +void KdeSudo::pushPassword(const QString &pwd) +{ + m_process->write(pwd.toLocal8Bit() + "\n"); +} + +void KdeSudo::slotCancel() +{ + KApplication::kApplication()->exit(1); +} + +void KdeSudo::slotUser1() +{ + m_dialog->done(AsUser); +} + +void KdeSudo::blockSigChild() +{ + sigset_t sset; + sigemptyset(&sset); + sigaddset(&sset, SIGCHLD); + sigprocmask(SIG_BLOCK, &sset, 0L); +} + +void KdeSudo::unblockSigChild() +{ + sigset_t sset; + sigemptyset(&sset); + sigaddset(&sset, SIGCHLD); + sigprocmask(SIG_UNBLOCK, &sset, 0L); +} + + +QString KdeSudo::validArg(QString arg) +{ + QChar firstChar = arg.at(0); + QChar lastChar = arg.at(arg.length() - 1); + + if ((firstChar == '"' && lastChar == '"') || (firstChar == '\'' && lastChar == '\'')) { + arg = arg.remove(0, 1); + arg = arg.remove(arg.length() - 1, 1); + } + return arg; +} diff --git a/kdesudo/kdesudo.h b/kdesudo/kdesudo.h new file mode 100644 index 00000000..be2fc26f --- /dev/null +++ b/kdesudo/kdesudo.h @@ -0,0 +1,94 @@ +/*************************************************************************** + kdesudo.cpp - description + ------------------- + begin : Sam Feb 15 15:42:12 CET 2003 + copyright : (C) 2003 by Robert Gruber + (C) 2007 by Martin Böhm + Anthony Mercatante + Canonical Ltd (Jonathan Riddell ) + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef KDESUDO_H +#define KDESUDO_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include + +#include "kcookie.h" +/* +* KdeSudo is the base class of the project +* +* @version 3.1 +*/ + +/* buffer is used when reading from the QProcess child */ +#define BUFSIZE 1024 + +class KdeSudo : QObject +{ + Q_OBJECT +public: + KdeSudo(const QString &icon = QString(), const QString &generic = QString()); + ~KdeSudo(); + + enum ResultCodes { + AsUser = 10 + }; + +private slots: + /** + * This slot gets executed if sudo creates some output + * -- well, in theory it should. Even though the code + * seems to be doing what the API says, it doesn't + * yet do what we need. + **/ + void parseOutput(); + + /** + * This slot gets exectuted when sudo exits + **/ + void procExited(int exitCode); + + /** + * This slot overrides the slot from KPasswordDialog + * @see KPasswordDialog + **/ + void pushPassword(const QString &); + void slotCancel(); + void slotUser1(); + QString validArg(QString arg); + +private: + void error(const QString &); + QProcess *m_process; + bool m_error; + bool useTerm; + bool noExec; + QString m_tmpName; + QString iceauthorityFile; + KDESu::KDESuPrivate::KCookie *m_pCookie; + void blockSigChild(); + void unblockSigChild(); + + KPasswordDialog *m_dialog; +}; + +#endif // KDESUDO_H diff --git a/kdesudo/main.cpp b/kdesudo/main.cpp new file mode 100644 index 00000000..433a50b9 --- /dev/null +++ b/kdesudo/main.cpp @@ -0,0 +1,160 @@ +/*************************************************************************** + kdesudo.cpp - description + ------------------- + begin : Sam Feb 15 15:42:12 CET 2003 + copyright : (C) 2003 by Robert Gruber + + (C) 2007 by Martin Böhm + Anthony Mercatante + Canonical Ltd (Jonathan Riddell + ) + (C) 2009-2015 by Harald Sitter + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if HAVE_SYS_PRCTL_H +#include +#endif + +#include "kdesudo.h" + +int main(int argc, char **argv) +{ + // Disable ptrace to prevent arbitrary apps reading password out of memory. +#if HAVE_PR_SET_DUMPABLE + prctl(PR_SET_DUMPABLE, 0); +#endif + + KAboutData about( + "kdesudo", 0, ki18n("KdeSudo"), + "3.4.2.3", ki18n("Sudo frontend for KDE"), + KAboutData::License_GPL, + ki18n("(C) 2007 - 2008 Anthony Mercatante"), + KLocalizedString(), + "https://code.launchpad.net/kdesudo/"); + + about.setBugAddress("https://launchpad.net/kdesudo/+filebug"); + + about.addAuthor(ki18n("Robert Gruber"), KLocalizedString(), + "rgruber@users.sourceforge.net", "http://test.com"); + about.addAuthor(ki18n("Anthony Mercatante"), KLocalizedString(), + "tonio@ubuntu.com"); + about.addAuthor(ki18n("Martin Böhm"), KLocalizedString(), + "martin.bohm@kubuntu.org"); + about.addAuthor(ki18n("Jonathan Riddell"), KLocalizedString(), + "jriddell@ubuntu.com"); + about.addAuthor(ki18n("Harald Sitter"), KLocalizedString(), + "apachelogger@ubuntu.com"); + + KCmdLineArgs::init(argc, argv, &about); + + KCmdLineOptions options; + options.add("u ", ki18n("sets a runas user")); + options.add("c ", ki18n("The command to execute")); + options.add("s", ki18n("Fake option for compatibility")); + options.add("i ", ki18n("Specify icon to use in the password" + " dialog")); + options.add("d", ki18n("Do not show the command to be run in the dialog")); + options.add("p ", ki18n("Process priority, between 0 and 100," + " 0 the lowest [50]")); + options.add("r", ki18n("Use realtime scheduling")); + options.add("f ", ki18n("Use target UID if is not writeable")); + options.add("t", ki18n("Fake option for KDE's KdeSu compatibility")); + options.add("n", ki18n("Fake option for compatibility")); + options.add("nonewdcop", ki18n("Use existing DCOP server")); + options.add("comment ", ki18n("The comment that should be " + "displayed in the dialog")); + options.add("noignorebutton", ki18n("Do not display « ignore » button")); + options.add("attach ", ki18n("Makes the dialog transient for an X app specified by winid")); + options.add("desktop ", ki18n("Manual override for " + "automatic desktop file detection")); + + options.add("+command", ki18n("The command to execute")); + + KCmdLineArgs::addCmdLineOptions(options); + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + KApplication a; + + QString executable, arg, command, icon; + QStringList executableList, commandlist; + KDesktopFile *desktopFile; + + if (args->isSet("c")) { + executable = args->getOption("c"); + } + + if (args->count() && executable.isEmpty()) { + command = args->arg(0); + commandlist = command.split(" "); + executable = commandlist[0]; + } + + /* We have to make sure the executable is only the binary name */ + executableList = executable.split(" "); + executable = executableList[0]; + + executableList = executable.split("/"); + executable = executableList[executableList.count() - 1]; + + /* Kubuntu has a bug in it - this is a workaround for it */ + KGlobal::dirs()->addResourceDir("apps", "/usr/share/applications/kde"); + KGlobal::dirs()->addResourceDir("apps", "/usr/share/applications/kde4"); + KGlobal::dirs()->addResourceDir("apps", "/usr/share/kde/services"); + KGlobal::dirs()->addResourceDir("apps", "/usr/share/kde4/services"); + KGlobal::dirs()->addResourceDir("apps", "/usr/share/applications"); + KGlobal::dirs()->addResourceDir("apps", "/usr/share/applnk"); + + QString path = getenv("PATH"); + QStringList pathList = path.split(":"); + for (int i = 0; i < pathList.count(); i++) { + executable.remove(pathList[i]); + } + + if (args->isSet("desktop")) { + desktopFile = new KDesktopFile(args->getOption("desktop")); + } else { + desktopFile = new KDesktopFile(executable + ".desktop"); + } + + /* icon parsing */ + if (args->isSet("i")) { + icon = args->getOption("i"); + } else { + QString iconName = desktopFile->readIcon(); + KIconLoader *loader = KIconLoader::global(); + icon = loader->iconPath(iconName, -1 * KIconLoader::StdSizes( + KIconLoader::SizeHuge), true); + } + + /* generic name parsing */ + QString name = desktopFile->readName(); + + a.setQuitOnLastWindowClosed(false); + KdeSudo kdesudo(icon, name); + return a.exec(); +} diff --git a/kdeui/kernel/kstartupinfo.cpp b/kdeui/kernel/kstartupinfo.cpp index e86a1036..2b7fd2a8 100644 --- a/kdeui/kernel/kstartupinfo.cpp +++ b/kdeui/kernel/kstartupinfo.cpp @@ -63,7 +63,7 @@ DEALINGS IN THE SOFTWARE. static const char* const NET_STARTUP_MSG = "_NET_STARTUP_INFO"; static const char* const NET_STARTUP_WINDOW = "_NET_STARTUP_ID"; // DESKTOP_STARTUP_ID is used also in kinit/wrapper.c , -// kdesu in both kdelibs and kdebase and who knows where else +// kdesudo in both kdelibs and kdebase and who knows where else static const char* const NET_STARTUP_ENV = "DESKTOP_STARTUP_ID"; static bool auto_app_started_sending = true; diff --git a/kinit/kinit.cpp b/kinit/kinit.cpp index 77c18ef1..b8e35034 100644 --- a/kinit/kinit.cpp +++ b/kinit/kinit.cpp @@ -1420,15 +1420,15 @@ static void setupX() XSetIOErrorHandler(kdeinit_xio_errhandler); XSetErrorHandler(kdeinit_x_errhandler); /* - Handle the tricky case of running via kdesu/su/sudo/etc. There the usual case - is that kdesu (etc.) creates a file with xauth information, sets XAUTHORITY, + Handle the tricky case of running via kdesudo/su/sudo/etc. There the usual case + is that kdesudo (etc.) creates a file with xauth information, sets XAUTHORITY, runs the command and removes the xauth file after the command finishes. However, dbus and kdeinit daemon currently don't clean up properly and keeping running. - Which means that running a KDE app via kdesu the second time talks to kdeinit + Which means that running a KDE app via kdesudo the second time talks to kdeinit with obsolete xauth information, which makes it unable to connect to X or launch any X11 applications. Even fixing the cleanup probably wouldn't be sufficient, since it'd be possible to - launch one kdesu session, another one, exit the first one and the app from the second + launch one kdesudo session, another one, exit the first one and the app from the second session would be using kdeinit from the first one. So the trick here is to duplicate the xauth file to another file in KDE's tmp location, make the file have a consistent name so that future sessions will use it diff --git a/kio/kfile/kfilesharedialog.cpp b/kio/kfile/kfilesharedialog.cpp index eea785ec..fc77049f 100644 --- a/kio/kfile/kfilesharedialog.cpp +++ b/kio/kfile/kfilesharedialog.cpp @@ -199,7 +199,7 @@ void KFileSharePropsPlugin::slotConfigureFileSharing() if (d->m_configProc) return; d->m_configProc = new QProcess(this); - if (!d->m_configProc->startDetached(KStandardDirs::findExe("kdesu"), QStringList() << "kcmshell4" << "fileshare")) + if (!d->m_configProc->startDetached(KStandardDirs::findExe("kdesudo"), QStringList() << "kcmshell4" << "fileshare")) { delete d->m_configProc; d->m_configProc = 0; diff --git a/kio/kio/krun.cpp b/kio/kio/krun.cpp index 308fda71..47d39990 100644 --- a/kio/kio/krun.cpp +++ b/kio/kio/krun.cpp @@ -440,8 +440,8 @@ QStringList KRun::processDesktopExec(const KService &_service, const KUrl::List& 2 << split(term) << "-e" << split(cmd) 3 << split(term) << "-e" << "sh" << "-c" << cmd - 4 << "kdesu" << "-u" << user << "-c" << cmd - 5 << "kdesu" << "-u" << user << "-c" << ("sh -c " + quote(cmd)) + 4 << "kdesudo" << "-u" << user << "-c" << cmd + 5 << "kdesudo" << "-u" << user << "-c" << ("sh -c " + quote(cmd)) 6 << split(term) << "-e" << "su" << user << "-c" << cmd 7 << split(term) << "-e" << "su" << user << "-c" << ("sh -c " + quote(cmd)) @@ -484,7 +484,7 @@ QStringList KRun::processDesktopExec(const KService &_service, const KUrl::List& result << "su"; } else { - result << KStandardDirs::findExe("kdesu") << "-u"; + result << KStandardDirs::findExe("kdesudo") << "-u"; } result << _service.username() << "-c"; diff --git a/kio/tests/krununittest.cpp b/kio/tests/krununittest.cpp index c795db54..b18a18a1 100644 --- a/kio/tests/krununittest.cpp +++ b/kio/tests/krununittest.cpp @@ -111,8 +111,8 @@ void KRunUnitTest::testProcessDesktopExec() "/bin/sh -c 'echo $PWD '", // 1 "x-term -T ' - just_a_test' -e /bin/date -u", // 2 "x-term -T ' - just_a_test' -e /bin/sh -c 'echo $PWD '", // 3 - /* kdesu */ " -u sprallo -c '/bin/date -u'", // 4 - /* kdesu */ " -u sprallo -c '/bin/sh -c '\\''echo $PWD '\\'''", // 5 + /* kdesudo */ " -u sprallo -c '/bin/date -u'", // 4 + /* kdesudo */ " -u sprallo -c '/bin/sh -c '\\''echo $PWD '\\'''", // 5 "x-term -T ' - just_a_test' -e su sprallo -c '/bin/date -u'", // 6 "x-term -T ' - just_a_test' -e su sprallo -c '/bin/sh -c '\\''echo $PWD '\\'''", // 7 }; @@ -131,9 +131,9 @@ void KRunUnitTest::testProcessDesktopExec() int pt = ex+te*2+su*4; QString exe; if (pt == 4 || pt == 5) { - exe = KStandardDirs::findExe("kdesu"); + exe = KStandardDirs::findExe("kdesudo"); if (exe.isEmpty()) { - qWarning() << "kdesu not found, skipping test"; + qWarning() << "kdesudo not found, skipping test"; continue; } } diff --git a/kutils/kcmoduleproxy.cpp b/kutils/kcmoduleproxy.cpp index aa5436e1..d4fbd83c 100644 --- a/kutils/kcmoduleproxy.cpp +++ b/kutils/kcmoduleproxy.cpp @@ -46,7 +46,7 @@ - Two Layout problems in runAsRoot: * lblBusy doesn't show * d->kcm/d->rootInfo doesn't get it right when the user - presses cancel in the kdesu dialog + presses cancel in the kdesudo dialog - Resizing horizontally is contrained; minimum size is set somewhere. It appears to be somehow derived from the module's size. diff --git a/kutils/kcmultidialog.cpp b/kutils/kcmultidialog.cpp index 636322c2..bbf60877 100644 --- a/kutils/kcmultidialog.cpp +++ b/kutils/kcmultidialog.cpp @@ -350,6 +350,7 @@ void KCMultiDialog::slotHelpClicked() } } +#warning this can make use of KToolInvocation::invokeHelp() KUrl docUrl( KUrl( "help:/" ), docPath ); KToolInvocation::invokeBrowser( docUrl.url() ); }