35 #include "config-kdesud.h"
36 #include <config-kdesu.h>
37 #include <ksud_debug.h>
50 #include <sys/resource.h>
51 #include <sys/socket.h>
54 #include <sys/types.h>
57 #ifdef HAVE_SYS_SELECT_H
58 #include <sys/select.h>
64 #include <sys/syscall.h>
68 #include <QCommandLineParser>
70 #include <QRegularExpression>
71 #include <QStandardPaths>
75 #include <KLocalizedString>
88 #define SUN_LEN(ptr) ((socklen_t)(offsetof(struct sockaddr_un, sun_path) + strlen((ptr)->sun_path)))
91 #define ERR strerror(errno)
93 using namespace KDESu;
95 static int closeExtraFds()
98 const int res = close_range(4, ~0U, 0);
103 if (errno != ENOSYS) {
106 #elif defined(SYS_close_range)
107 const int res = syscall(SYS_close_range, 4, ~0U, 0);
112 if (errno != ENOSYS) {
117 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) // /proc, /dev are Linux only
120 qCDebug(KSUD_LOG) <<
"close_range function/syscall isn't available, falling back to iterarting "
121 "over '/dev/fd' and closing the file descriptors manually.\n";
123 std::unique_ptr<DIR, int (*)(DIR *)> dirPtr(opendir(
"/dev/fd"), closedir);
129 const int dirFd = dirfd(dirPtr.get());
130 while (
struct dirent *dirEnt = readdir(dirPtr.get())) {
131 const int currFd = std::atoi(dirEnt->d_name);
132 if (currFd > 3 && currFd != dirFd) {
133 closeRes =
close(currFd);
134 if (closeRes == -1) {
155 void kdesud_cleanup()
163 extern "C" int xio_errhandler(Display *);
165 int xio_errhandler(Display *)
167 qCCritical(KSUD_LOG) <<
"Fatal IO error, exiting...\n";
173 int initXconnection()
175 x11Display = XOpenDisplay(
nullptr);
176 if (x11Display !=
nullptr) {
177 XSetIOErrorHandler(xio_errhandler);
179 XCreateSimpleWindow(x11Display,
180 DefaultRootWindow(x11Display),
182 BlackPixelOfScreen(DefaultScreenOfDisplay(x11Display)),
183 BlackPixelOfScreen(DefaultScreenOfDisplay(x11Display)));
185 return XConnectionNumber(x11Display);
187 qCWarning(KSUD_LOG) <<
"Can't connect to the X Server.\n";
188 qCWarning(KSUD_LOG) <<
"Might not terminate at end of session.\n";
195 void signal_exit(
int);
196 void sigchld_handler(
int);
199 void signal_exit(
int sig)
201 qCDebug(KSUD_LOG) <<
"Exiting on signal " << sig <<
"\n";
206 void sigchld_handler(
int)
209 write(pipeOfDeath[1], &c, 1);
223 if (display.isEmpty()) {
224 qCWarning(KSUD_LOG) <<
"$DISPLAY is not set\n";
233 if (!stat_err && S_ISLNK(s.st_mode)) {
234 qCWarning(KSUD_LOG) <<
"Someone is running a symlink attack on you\n";
236 qCWarning(KSUD_LOG) <<
"Could not delete symlink\n";
243 if (client.ping() == -1) {
244 qCWarning(KSUD_LOG) <<
"stale socket exists\n";
246 qCWarning(KSUD_LOG) <<
"Could not delete stale socket\n";
250 qCWarning(KSUD_LOG) <<
"kdesud is already running\n";
255 sockfd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
257 qCCritical(KSUD_LOG) <<
"socket(): " << ERR <<
"\n";
262 struct fd_ScopeGuard {
263 fd_ScopeGuard(
int fd)
273 fd_ScopeGuard(
const fd_ScopeGuard &) =
delete;
274 fd_ScopeGuard &operator=(
const fd_ScopeGuard &) =
delete;
282 struct sockaddr_un addr;
283 addr.sun_family = AF_UNIX;
284 strncpy(addr.sun_path, sock.
constData(),
sizeof(addr.sun_path) - 1);
285 addr.sun_path[
sizeof(addr.sun_path) - 1] =
'\000';
286 addrlen = SUN_LEN(&addr);
287 if (bind(sockfd, (
struct sockaddr *)&addr, addrlen) < 0) {
288 qCCritical(KSUD_LOG) <<
"bind(): " << ERR <<
"\n";
293 lin.l_onoff = lin.l_linger = 0;
294 if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (
char *)&lin,
sizeof(linger)) < 0) {
295 qCCritical(KSUD_LOG) <<
"setsockopt(SO_LINGER): " << ERR <<
"\n";
300 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (
char *)&opt,
sizeof(opt)) < 0) {
301 qCCritical(KSUD_LOG) <<
"setsockopt(SO_REUSEADDR): " << ERR <<
"\n";
305 if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (
char *)&opt,
sizeof(opt)) < 0) {
306 qCCritical(KSUD_LOG) <<
"setsockopt(SO_KEEPALIVE): " << ERR <<
"\n";
318 int main(
int argc,
char *argv[])
321 KAboutData aboutData(QStringLiteral(
"kdesud") ,
322 i18n(
"KDE su daemon"),
324 i18n(
"Daemon used by kdesu"),
326 i18n(
"Copyright (c) 1999,2000 Geert Jansen"));
327 aboutData.addAuthor(
i18n(
"Geert Jansen"),
i18n(
"Author"), QStringLiteral(
"[email protected]"), QStringLiteral(
"http://www.stack.nl/~geertj/"));
331 aboutData.setupCommandLine(&parser);
333 aboutData.processCommandLine(&parser);
337 rlim.rlim_cur = rlim.rlim_max = 0;
338 if (setrlimit(RLIMIT_CORE, &rlim) < 0) {
339 qCCritical(KSUD_LOG) <<
"setrlimit(): " << ERR <<
"\n";
344 int sockfd = create_socket();
348 if (
listen(sockfd, 10) < 0) {
349 qCCritical(KSUD_LOG) <<
"listen(): " << ERR <<
"\n";
355 sockfd = dup3(sockfd, 3, O_CLOEXEC);
358 qCCritical(KSUD_LOG) <<
"Failed to set sockfd to fd 3" << ERR <<
"\n";
365 if (closeExtraFds() < 0) {
366 qCCritical(KSUD_LOG) <<
"Failed to close file descriptors higher than 3, with error:" << ERR <<
"\n";
374 qCCritical(KSUD_LOG) <<
"fork():" << ERR <<
"\n";
384 int x11Fd = initXconnection();
385 maxfd = qMax(maxfd, x11Fd);
391 pipe2(pipeOfDeath, O_CLOEXEC);
392 maxfd = qMax(maxfd, pipeOfDeath[0]);
396 sa.sa_handler = signal_exit;
397 sigemptyset(&sa.sa_mask);
399 sigaction(SIGHUP, &sa,
nullptr);
400 sigaction(SIGINT, &sa,
nullptr);
401 sigaction(SIGTERM, &sa,
nullptr);
402 sigaction(SIGQUIT, &sa,
nullptr);
404 sa.sa_handler = sigchld_handler;
405 sa.sa_flags = SA_NOCLDSTOP;
406 sigaction(SIGCHLD, &sa,
nullptr);
407 sa.sa_handler = SIG_IGN;
408 sigaction(SIGPIPE, &sa,
nullptr);
413 struct sockaddr_un clientname;
417 FD_ZERO(&active_fds);
418 FD_SET(sockfd, &active_fds);
419 FD_SET(pipeOfDeath[0], &active_fds);
422 FD_SET(x11Fd, &active_fds);
427 tmp_fds = active_fds;
433 if (select(maxfd + 1, &tmp_fds,
nullptr,
nullptr,
nullptr) < 0) {
434 if (errno == EINTR) {
438 qCCritical(KSUD_LOG) <<
"select(): " << ERR <<
"\n";
442 for (
int i = 0; i <= maxfd; i++) {
443 if (!FD_ISSET(i, &tmp_fds)) {
447 if (i == pipeOfDeath[0]) {
449 read(pipeOfDeath[0], buf, 100);
453 result = waitpid((pid_t)-1, &status, WNOHANG);
455 for (
int j = handler.
size(); j--;) {
456 if (handler[j] && (handler[j]->m_pid == result)) {
457 handler[j]->m_exitCode = WEXITSTATUS(status);
458 handler[j]->m_hasExitCode =
true;
459 handler[j]->sendExitCode();
460 handler[j]->m_pid = 0;
465 }
while (result > 0);
473 while (XPending(x11Display)) {
474 XNextEvent(x11Display, &event_return);
485 fd = accept(sockfd, (
struct sockaddr *)&clientname, &addrlen);
487 qCCritical(KSUD_LOG) <<
"accept():" << ERR <<
"\n";
490 while (fd + 1 > (
int)handler.
size()) {
495 maxfd = qMax(maxfd, fd);
496 FD_SET(fd, &active_fds);
497 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
502 if (handler[i] && handler[i]->handle() < 0) {
504 handler[i] =
nullptr;
505 FD_CLR(i, &active_fds);
509 qCWarning(KSUD_LOG) <<
"???\n";