mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-23 18:32:49 +00:00
generic: replace kdesu with kdesudo
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
parent
31ce3fef82
commit
7419f793b0
42 changed files with 865 additions and 3205 deletions
|
@ -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 )
|
||||
|
|
|
@ -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]
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -419,14 +419,9 @@ install(
|
|||
KWebView
|
||||
KWebPluginFactory
|
||||
KWebWallet
|
||||
KDEsuClient
|
||||
KPty
|
||||
KPtyDevice
|
||||
KPtyProcess
|
||||
PtyProcess
|
||||
SshProcess
|
||||
StubProcess
|
||||
SuProcess
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/KDE
|
||||
COMPONENT Devel
|
||||
)
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
#include "../kdesu/client.h"
|
|
@ -1 +0,0 @@
|
|||
#include "../kdesu/process.h"
|
|
@ -1 +0,0 @@
|
|||
#include "../kdesu/ssh.h"
|
|
@ -1 +0,0 @@
|
|||
#include "../kdesu/stub.h"
|
|
@ -1 +0,0 @@
|
|||
#include "../kdesu/su.h"
|
|
@ -61,8 +61,7 @@
|
|||
1201 konqtree
|
||||
1203 libkonq
|
||||
1204 plasma
|
||||
1205 kdesud
|
||||
1206 kdesu
|
||||
1205 kdesudo
|
||||
1207 krunner
|
||||
1208 kcontrol
|
||||
1209 libplasma
|
||||
|
|
|
@ -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
|
||||
)
|
13
kdesu/README
13
kdesu/README
|
@ -1,13 +0,0 @@
|
|||
Maintainer: Adriaan de Groot <groot@kde.org>
|
||||
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 <jansen@kde.org>
|
||||
|
||||
Distributed under the GNU Library General Public License, version 2.
|
438
kdesu/client.cpp
438
kdesu/client.cpp
|
@ -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 <jansen@kde.org>
|
||||
*
|
||||
* 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 <config.h>
|
||||
#include <config-kdesu.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <pwd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <qplatformdefs.h>
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QRegExp>
|
||||
|
||||
#include <kdebug.h>
|
||||
#include <kstandarddirs.h>
|
||||
#include <ktoolinvocation.h>
|
||||
#include <kde_file.h>
|
||||
|
||||
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<QByteArray> &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<QByteArray> KDEsuClient::getKeys(const QByteArray &group)
|
||||
{
|
||||
QByteArray cmd = "GETK ";
|
||||
cmd += escape(group);
|
||||
cmd += '\n';
|
||||
QByteArray reply;
|
||||
command(cmd, &reply);
|
||||
int index=0, pos;
|
||||
QList<QByteArray> 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;
|
||||
}
|
||||
|
||||
}
|
204
kdesu/client.h
204
kdesu/client.h
|
@ -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 <jansen@kde.org>
|
||||
*
|
||||
* 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 <QtCore/qglobal.h>
|
||||
#include <QtCore/QList>
|
||||
#include <kdesu/kdesu_export.h>
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
|
||||
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<QByteArray> &env=QList<QByteArray>());
|
||||
|
||||
/**
|
||||
* 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<QByteArray> 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__
|
|
@ -1,7 +0,0 @@
|
|||
|
||||
#cmakedefine HAVE_STRUCT_UCRED 1
|
||||
|
||||
#cmakedefine HAVE_SETPRIORITY 1
|
||||
|
||||
#cmakedefine HAVE_GETPEEREID 1
|
||||
|
|
@ -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 <jansen@kde.org>
|
||||
*
|
||||
* 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
|
|
@ -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 <jansen@kde.org>
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/qprocess.h>
|
||||
|
||||
#include <kdebug.h>
|
||||
|
||||
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<QByteArray> 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
|
||||
}
|
||||
|
||||
}}
|
|
@ -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 <jansen@kde.org>
|
||||
*
|
||||
* 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 <QtCore/qbytearray.h>
|
||||
|
||||
|
||||
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__
|
|
@ -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 <jansen@kde.org>
|
||||
*
|
||||
* 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 <config.h>
|
||||
#include <config-kdesu.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <termios.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef HAVE_INITGROUPS
|
||||
#include <grp.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#ifdef POSIX1B_SCHEDULING
|
||||
#include <sched.h>
|
||||
#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; i<P_LAST; i++)
|
||||
{
|
||||
printf("%s\n", params[i].name);
|
||||
fflush(stdout);
|
||||
if (fgets(buf, BUFSIZE, stdin) == 0L)
|
||||
{
|
||||
printf("end\n"); fflush(stdout);
|
||||
perror("kdesu_stub: fgets()");
|
||||
exit(1);
|
||||
}
|
||||
params[i].value = xstrdup(buf);
|
||||
/* Installation check? */
|
||||
if ((i == 0) && !strcmp(params[i].value, "stop"))
|
||||
{
|
||||
printf("end\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
printf("environment\n");
|
||||
fflush(stdout);
|
||||
for(;;)
|
||||
{
|
||||
char* tmp;
|
||||
if (fgets(buf, BUFSIZE, stdin) == 0L)
|
||||
{
|
||||
printf("end\n"); fflush(stdout);
|
||||
perror("kdesu_stub: fgets()");
|
||||
exit(1);
|
||||
}
|
||||
dequote(buf);
|
||||
tmp = xstrdup( buf );
|
||||
if( tmp[ 0 ] == '\0' ) /* terminator */
|
||||
break;
|
||||
putenv(tmp);
|
||||
}
|
||||
|
||||
printf("end\n");
|
||||
fflush(stdout);
|
||||
|
||||
xsetenv("PATH", params[P_PATH].value);
|
||||
xsetenv("DESKTOP_STARTUP_ID", params[P_APP_STARTUP_ID].value);
|
||||
|
||||
kdesu_lc_all = getenv( "KDESU_LC_ALL" );
|
||||
if( kdesu_lc_all != NULL )
|
||||
xsetenv("LC_ALL",kdesu_lc_all);
|
||||
else
|
||||
unsetenv("LC_ALL");
|
||||
|
||||
/* Do we need to change uid? */
|
||||
|
||||
pw = getpwnam(params[P_USER].value);
|
||||
if (pw == 0L)
|
||||
{
|
||||
printf("kdesu_stub: user %s does not exist!\n", params[P_USER].value);
|
||||
exit(1);
|
||||
}
|
||||
xsetenv("HOME", pw->pw_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);
|
||||
}
|
||||
}
|
|
@ -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 <jansen@kde.org>
|
||||
*
|
||||
* This file contains code from TEShell.C of the KDE konsole.
|
||||
* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
|
||||
*
|
||||
* 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 <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
#include <sys/select.h> // Needed on some systems.
|
||||
#endif
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/QFile>
|
||||
|
||||
#include <ksharedconfig.h>
|
||||
#include <kconfiggroup.h>
|
||||
#include <kdebug.h>
|
||||
#include <kstandarddirs.h>
|
||||
#include <kde_file.h>
|
||||
|
||||
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<QByteArray> 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<QByteArray> &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<QByteArray> 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<QByteArray> &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<char *>(d->env.at(i).constData()));
|
||||
}
|
||||
unsetenv("KDE_FULL_SESSION");
|
||||
// for : Qt: Session management error
|
||||
unsetenv("SESSION_MANAGER");
|
||||
// QMutex::lock , deadlocks without that.
|
||||
// <thiago> 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<char **>(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;
|
||||
}
|
||||
|
||||
}
|
201
kdesu/process.h
201
kdesu/process.h
|
@ -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 <jansen@kde.org>
|
||||
*
|
||||
* 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 <sys/types.h>
|
||||
|
||||
#include <QtCore/qbytearray.h>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QList>
|
||||
|
||||
#include <kdesu/kdesu_export.h>
|
||||
|
||||
#include <kpty.h>
|
||||
|
||||
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<QByteArray> &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<QByteArray> &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<QByteArray> 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
|
259
kdesu/ssh.cpp
259
kdesu/ssh.cpp
|
@ -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 <jansen@kde.org>
|
||||
*
|
||||
* 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 <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#include <kdebug.h>
|
||||
#include <klocale.h>
|
||||
#include <kstandarddirs.h>
|
||||
|
||||
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<QByteArray> 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<char *>(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; i<len; ++i)
|
||||
{
|
||||
if (line[i] == ':')
|
||||
{
|
||||
j = i; colon++;
|
||||
continue;
|
||||
}
|
||||
if (!isspace(line[i]))
|
||||
j++;
|
||||
}
|
||||
if ((colon == 1) && (line[j] == ':'))
|
||||
{
|
||||
if (check == 2)
|
||||
{
|
||||
d->m_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";
|
||||
}
|
||||
|
||||
}
|
81
kdesu/ssh.h
81
kdesu/ssh.h
|
@ -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 <jansen@kde.org>
|
||||
*
|
||||
* 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 <kdesu/kdesu_export.h>
|
||||
|
||||
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
|
222
kdesu/stub.cpp
222
kdesu/stub.cpp
|
@ -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 <jansen@kde.org>
|
||||
*
|
||||
* 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 <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#include <kdebug.h>
|
||||
|
||||
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<int T> 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<QByteArray> 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<sizeof(pid_t)>::PID_t)(getpid()));
|
||||
writeLine(tmp);
|
||||
} else if (line == "environment") { // additional env vars
|
||||
QList<QByteArray> 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
|
||||
|
||||
|
||||
}
|
106
kdesu/stub.h
106
kdesu/stub.h
|
@ -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 <jansen@kde.org>
|
||||
*
|
||||
* 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 <QtCore/qbytearray.h>
|
||||
#include <QtCore/QList>
|
||||
|
||||
#include "process.h"
|
||||
|
||||
#include <kdesu/kdesu_export.h>
|
||||
|
||||
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__
|
329
kdesu/su.cpp
329
kdesu/su.cpp
|
@ -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 <jansen@kde.org>
|
||||
*
|
||||
* Sudo support added by Jonathan Riddell <jriddell@ ubuntu.com>
|
||||
* 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 <config.h>
|
||||
#include <config-prefix.h> // for LIBEXEC_INSTALL_DIR
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <QtCore/QFile>
|
||||
|
||||
#include <kconfig.h>
|
||||
#include <kconfiggroup.h>
|
||||
#include <kdebug.h>
|
||||
#include <klocale.h>
|
||||
#include <kstandarddirs.h>
|
||||
#include <kuser.h>
|
||||
|
||||
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<QByteArray> 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<char *>(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<len; ++i)
|
||||
{
|
||||
if (line[i] == ':')
|
||||
{
|
||||
j = i; colon++;
|
||||
continue;
|
||||
}
|
||||
if (!isspace(line[i]))
|
||||
j++;
|
||||
}
|
||||
if ((colon == 1) && (line[j] == ':'))
|
||||
{
|
||||
if (password == 0L)
|
||||
return killme;
|
||||
if (WaitSlave())
|
||||
return error;
|
||||
write(fd(), password, strlen(password));
|
||||
write(fd(), "\n", 1);
|
||||
state = CheckStar;
|
||||
}
|
||||
break;
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
case CheckStar:
|
||||
{
|
||||
QByteArray s = line.trimmed();
|
||||
if (s.isEmpty())
|
||||
{
|
||||
state=HandleStub;
|
||||
break;
|
||||
}
|
||||
const uint len = line.length();
|
||||
for (i=0; i< len; ++i)
|
||||
{
|
||||
if (s[i] != '*')
|
||||
return error;
|
||||
}
|
||||
state=HandleStub;
|
||||
break;
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
case HandleStub:
|
||||
break;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
} // end switch
|
||||
} // end while (true)
|
||||
return ok;
|
||||
}
|
||||
|
||||
}
|
74
kdesu/su.h
74
kdesu/su.h
|
@ -1,74 +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 <jansen@kde.org>
|
||||
*
|
||||
* 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 <kdesu/kdesu_export.h>
|
||||
|
||||
#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
|
20
kdesudo/CMakeLists.txt
Normal file
20
kdesudo/CMakeLists.txt
Normal file
|
@ -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}
|
||||
)
|
2
kdesudo/Messages.sh
Executable file
2
kdesudo/Messages.sh
Executable file
|
@ -0,0 +1,2 @@
|
|||
#! /usr/bin/env bash
|
||||
$XGETTEXT `find . -name \*.cpp` -o $podir/kdesudo.pot
|
2
kdesudo/config.h.cmake
Normal file
2
kdesudo/config.h.cmake
Normal file
|
@ -0,0 +1,2 @@
|
|||
#cmakedefine01 HAVE_SYS_PRCTL_H
|
||||
#cmakedefine01 HAVE_PR_SET_DUMPABLE
|
105
kdesudo/kcookie.cpp
Normal file
105
kdesudo/kcookie.cpp
Normal file
|
@ -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 <jansen@kde.org>
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QBool>
|
||||
#include <QtCore/Q_PID>
|
||||
|
||||
#include <kdebug.h>
|
||||
|
||||
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<QByteArray> 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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
57
kdesudo/kcookie.h
Normal file
57
kdesudo/kcookie.h
Normal file
|
@ -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 <jansen@kde.org>
|
||||
*
|
||||
* 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 <QtCore/QByteRef>
|
||||
|
||||
|
||||
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__
|
387
kdesudo/kdesudo.cpp
Normal file
387
kdesudo/kdesudo.cpp
Normal file
|
@ -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
|
||||
<rgruber@users.sourceforge.net>
|
||||
(C) 2007 by Martin Böhm <martin.bohm@kubuntu.org>
|
||||
Anthony Mercatante <tonio@kubuntu.org>
|
||||
Canonical Ltd (Jonathan Riddell
|
||||
<jriddell@ubuntu.com>)
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* 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 <QtCore/QDataStream>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QProcess>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QTemporaryFile>
|
||||
#include <QtCore/QTextCodec>
|
||||
|
||||
#include <KApplication>
|
||||
#include <KCmdLineArgs>
|
||||
#include <KDebug>
|
||||
#include <KLocale>
|
||||
#include <KMessageBox>
|
||||
#include <KPasswordDialog>
|
||||
#include <KPushButton>
|
||||
#include <KShell>
|
||||
#include <KStandardDirs>
|
||||
#include <KWindowSystem>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <csignal>
|
||||
|
||||
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 <runas>] <command>\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 = "<b>%1</b> " + i18n("needs administrative privileges. ");
|
||||
|
||||
if (runas.isEmpty() || runas == "root") {
|
||||
defaultComment += i18n("Please enter your password.");
|
||||
} else {
|
||||
defaultComment += i18n("Please enter password for <b>%1</b>.", 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("<b>Warning: </b>"), i18n("<b>Incorrect password, please try again.</b>"));
|
||||
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;
|
||||
}
|
94
kdesudo/kdesudo.h
Normal file
94
kdesudo/kdesudo.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
/***************************************************************************
|
||||
kdesudo.cpp - description
|
||||
-------------------
|
||||
begin : Sam Feb 15 15:42:12 CET 2003
|
||||
copyright : (C) 2003 by Robert Gruber <rgruber@users.sourceforge.net>
|
||||
(C) 2007 by Martin Böhm <martin.bohm@kubuntu.org>
|
||||
Anthony Mercatante <tonio@kubuntu.org>
|
||||
Canonical Ltd (Jonathan Riddell <jriddell@ubuntu.com>)
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* 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 <config.h>
|
||||
#endif
|
||||
|
||||
#include <QtGui/QWidget>
|
||||
#include <QtCore/QString>
|
||||
|
||||
#include <QProcess>
|
||||
#include <KPasswordDialog>
|
||||
#include <knewpassworddialog.h>
|
||||
|
||||
#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
|
160
kdesudo/main.cpp
Normal file
160
kdesudo/main.cpp
Normal file
|
@ -0,0 +1,160 @@
|
|||
/***************************************************************************
|
||||
kdesudo.cpp - description
|
||||
-------------------
|
||||
begin : Sam Feb 15 15:42:12 CET 2003
|
||||
copyright : (C) 2003 by Robert Gruber
|
||||
<rgruber@users.sourceforge.net>
|
||||
(C) 2007 by Martin Böhm <martin.bohm@kubuntu.org>
|
||||
Anthony Mercatante <tonio@kubuntu.org>
|
||||
Canonical Ltd (Jonathan Riddell
|
||||
<jriddell@ubuntu.com>)
|
||||
(C) 2009-2015 by Harald Sitter <sitter@kde.org>
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* 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 <KCmdLineArgs>
|
||||
#include <KAboutData>
|
||||
#include <KLocale>
|
||||
#include <KMessageBox>
|
||||
#include <KDesktopFile>
|
||||
#include <KIconLoader>
|
||||
#include <KIconTheme>
|
||||
#include <KGlobal>
|
||||
#include <KStandardDirs>
|
||||
#include <KProcess>
|
||||
#include <KDebug>
|
||||
#include <KApplication>
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if HAVE_SYS_PRCTL_H
|
||||
#include <sys/prctl.h>
|
||||
#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 <runas>", ki18n("sets a runas user"));
|
||||
options.add("c <command>", ki18n("The command to execute"));
|
||||
options.add("s", ki18n("Fake option for compatibility"));
|
||||
options.add("i <icon name>", 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 <priority>", ki18n("Process priority, between 0 and 100,"
|
||||
" 0 the lowest [50]"));
|
||||
options.add("r", ki18n("Use realtime scheduling"));
|
||||
options.add("f <file>", ki18n("Use target UID if <file> 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 <dialog text>", ki18n("The comment that should be "
|
||||
"displayed in the dialog"));
|
||||
options.add("noignorebutton", ki18n("Do not display « ignore » button"));
|
||||
options.add("attach <winid>", ki18n("Makes the dialog transient for an X app specified by winid"));
|
||||
options.add("desktop <desktop file>", 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();
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -350,6 +350,7 @@ void KCMultiDialog::slotHelpClicked()
|
|||
}
|
||||
}
|
||||
|
||||
#warning this can make use of KToolInvocation::invokeHelp()
|
||||
KUrl docUrl( KUrl( "help:/" ), docPath );
|
||||
KToolInvocation::invokeBrowser( docUrl.url() );
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue