From 4aed2c8219774f5d797760606b8489a92ddc5163 Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- kdesu/kdesud/kdesud.cpp | 415 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 415 insertions(+) create mode 100644 kdesu/kdesud/kdesud.cpp (limited to 'kdesu/kdesud/kdesud.cpp') diff --git a/kdesu/kdesud/kdesud.cpp b/kdesu/kdesud/kdesud.cpp new file mode 100644 index 000000000..d81b6a0c9 --- /dev/null +++ b/kdesu/kdesud/kdesud.cpp @@ -0,0 +1,415 @@ +/* vi: ts=8 sts=4 sw=4 + * + * This file is part of the KDE project, module kdesu. + * Copyright (C) 1999,2000 Geert Jansen + * + * + * kdesud.cpp: KDE su daemon. Offers "keep password" functionality to kde su. + * + * The socket $KDEHOME/socket-$(HOSTNAME)/kdesud_$(display) is used for communication with + * client programs. + * + * The protocol: Client initiates the connection. All commands and responses + * are terminated by a newline. + * + * Client Server Description + * ------ ------ ----------- + * + * PASS OK Set password for commands in + * this session. Password is + * valid for seconds. + * + * USER OK Set the target user [required] + * + * EXEC OK Execute command . If + * NO has been executed + * before (< timeout) no PASS + * command is needed. + * + * DEL OK Delete password for command + * NO . + * + * PING OK Ping the server (diagnostics). + */ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_SELECT_H +#include // Needed on some systems. +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "repo.h" +#include "handler.h" + +#include +#include + +#ifndef SUN_LEN +#define SUN_LEN(ptr) ((kde_socklen_t) (((struct sockaddr_un *) 0)->sun_path) \ + + strlen ((ptr)->sun_path)) +#endif + +#define ERR strerror(errno) + +// Globals + +Repository *repo; +const char *Version = "1.01"; +QCString sock; +Display *x11Display; +int pipeOfDeath[2]; + + +void kdesud_cleanup() +{ + unlink(sock); +} + + +// Borrowed from kdebase/kaudio/kaudioserver.cpp + +extern "C" int xio_errhandler(Display *); + +int xio_errhandler(Display *) +{ + kdError(1205) << "Fatal IO error, exiting...\n"; + kdesud_cleanup(); + exit(1); + return 1; //silence compilers +} + +int initXconnection() +{ + x11Display = XOpenDisplay(NULL); + if (x11Display != 0L) + { + XSetIOErrorHandler(xio_errhandler); + XCreateSimpleWindow(x11Display, DefaultRootWindow(x11Display), + 0, 0, 1, 1, 0, + BlackPixelOfScreen(DefaultScreenOfDisplay(x11Display)), + BlackPixelOfScreen(DefaultScreenOfDisplay(x11Display))); + return XConnectionNumber(x11Display); + } else + { + kdWarning(1205) << "Can't connect to the X Server.\n"; + kdWarning(1205) << "Might not terminate at end of session.\n"; + return -1; + } +} + +extern "C" { + void signal_exit(int); + void sigchld_handler(int); +} + +void signal_exit(int sig) +{ + kdDebug(1205) << "Exiting on signal " << sig << "\n"; + kdesud_cleanup(); + exit(1); +} + +void sigchld_handler(int) +{ + char c = ' '; + write(pipeOfDeath[1], &c, 1); +} + +/** + * Creates an AF_UNIX socket in socket resource, mode 0600. + */ + +int create_socket() +{ + int sockfd; + ksocklen_t addrlen; + struct stat s; + + QCString display(getenv("DISPLAY")); + if (display.isEmpty()) + { + kdWarning(1205) << "$DISPLAY is not set\n"; + return -1; + } + + // strip the screen number from the display + display.replace(QRegExp("\\.[0-9]+$"), ""); + + sock = QFile::encodeName(locateLocal("socket", QString("kdesud_%1").arg(display))); + int stat_err=lstat(sock, &s); + if(!stat_err && S_ISLNK(s.st_mode)) { + kdWarning(1205) << "Someone is running a symlink attack on you\n"; + if(unlink(sock)) { + kdWarning(1205) << "Could not delete symlink\n"; + return -1; + } + } + + if (!access(sock, R_OK|W_OK)) + { + KDEsuClient client; + if (client.ping() == -1) + { + kdWarning(1205) << "stale socket exists\n"; + if (unlink(sock)) + { + kdWarning(1205) << "Could not delete stale socket\n"; + return -1; + } + } else + { + kdWarning(1205) << "kdesud is already running\n"; + return -1; + } + + } + + sockfd = socket(PF_UNIX, SOCK_STREAM, 0); + if (sockfd < 0) + { + kdError(1205) << "socket(): " << ERR << "\n"; + return -1; + } + + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, sock, sizeof(addr.sun_path)-1); + addr.sun_path[sizeof(addr.sun_path)-1] = '\000'; + addrlen = SUN_LEN(&addr); + if (bind(sockfd, (struct sockaddr *)&addr, addrlen) < 0) + { + kdError(1205) << "bind(): " << ERR << "\n"; + return -1; + } + + struct linger lin; + lin.l_onoff = lin.l_linger = 0; + if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (char *) &lin, + sizeof(linger)) < 0) + { + kdError(1205) << "setsockopt(SO_LINGER): " << ERR << "\n"; + return -1; + } + + int opt = 1; + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, + sizeof(opt)) < 0) + { + kdError(1205) << "setsockopt(SO_REUSEADDR): " << ERR << "\n"; + return -1; + } + opt = 1; + if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, + sizeof(opt)) < 0) + { + kdError(1205) << "setsockopt(SO_KEEPALIVE): " << ERR << "\n"; + return -1; + } + chmod(sock, 0600); + return sockfd; +} + + +/** + * Main program + */ + +int main(int argc, char *argv[]) +{ + KAboutData aboutData("kdesud", I18N_NOOP("KDE su daemon"), + Version, I18N_NOOP("Daemon used by kdesu"), + KAboutData::License_Artistic, + "Copyright (c) 1999,2000 Geert Jansen"); + aboutData.addAuthor("Geert Jansen", I18N_NOOP("Author"), + "jansen@kde.org", "http://www.stack.nl/~geertj/"); + KCmdLineArgs::init(argc, argv, &aboutData); + KInstance instance(&aboutData); + + // Set core dump size to 0 + struct rlimit rlim; + rlim.rlim_cur = rlim.rlim_max = 0; + if (setrlimit(RLIMIT_CORE, &rlim) < 0) + { + kdError(1205) << "setrlimit(): " << ERR << "\n"; + exit(1); + } + + // Create the Unix socket. + int sockfd = create_socket(); + if (sockfd < 0) + exit(1); + if (listen(sockfd, 1) < 0) + { + kdError(1205) << "listen(): " << ERR << "\n"; + kdesud_cleanup(); + exit(1); + } + int maxfd = sockfd; + + // Ok, we're accepting connections. Fork to the background. + pid_t pid = fork(); + if (pid == -1) + { + kdError(1205) << "fork():" << ERR << "\n"; + kdesud_cleanup(); + exit(1); + } + if (pid) + exit(0); + + // Make sure we exit when the display gets closed. + int x11Fd = initXconnection(); + maxfd = QMAX(maxfd, x11Fd); + + repo = new Repository; + QPtrVector handler; + handler.setAutoDelete(true); + + pipe(pipeOfDeath); + maxfd = QMAX(maxfd, pipeOfDeath[0]); + + // Signal handlers + struct sigaction sa; + sa.sa_handler = signal_exit; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(SIGHUP, &sa, 0L); + sigaction(SIGINT, &sa, 0L); + sigaction(SIGTERM, &sa, 0L); + sigaction(SIGQUIT, &sa, 0L); + + sa.sa_handler = sigchld_handler; + sa.sa_flags = SA_NOCLDSTOP; + sigaction(SIGCHLD, &sa, 0L); + sa.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &sa, 0L); + + // Main execution loop + + ksocklen_t addrlen; + struct sockaddr_un clientname; + + fd_set tmp_fds, active_fds; + FD_ZERO(&active_fds); + FD_SET(sockfd, &active_fds); + FD_SET(pipeOfDeath[0], &active_fds); + if (x11Fd != -1) + FD_SET(x11Fd, &active_fds); + + while (1) + { + tmp_fds = active_fds; + if(x11Display) + XFlush(x11Display); + if (select(maxfd+1, &tmp_fds, 0L, 0L, 0L) < 0) + { + if (errno == EINTR) continue; + + kdError(1205) << "select(): " << ERR << "\n"; + exit(1); + } + repo->expire(); + for (int i=0; i<=maxfd; i++) + { + if (!FD_ISSET(i, &tmp_fds)) + continue; + + if (i == pipeOfDeath[0]) + { + char buf[101]; + read(pipeOfDeath[0], buf, 100); + pid_t result; + do + { + int status; + result = waitpid((pid_t)-1, &status, WNOHANG); + if (result > 0) + { + for(int j=handler.size(); j--;) + { + if (handler[j] && (handler[j]->m_pid == result)) + { + handler[j]->m_exitCode = WEXITSTATUS(status); + handler[j]->m_hasExitCode = true; + handler[j]->sendExitCode(); + handler[j]->m_pid = 0; + break; + } + } + } + } + while(result > 0); + } + + if (i == x11Fd) + { + // Discard X events + XEvent event_return; + if (x11Display) + while(XPending(x11Display)) + XNextEvent(x11Display, &event_return); + continue; + } + + if (i == sockfd) + { + // Accept new connection + int fd; + addrlen = 64; + fd = accept(sockfd, (struct sockaddr *) &clientname, &addrlen); + if (fd < 0) + { + kdError(1205) << "accept():" << ERR << "\n"; + continue; + } + if (fd+1 > (int) handler.size()) + handler.resize(fd+1); + handler.insert(fd, new ConnectionHandler(fd)); + maxfd = QMAX(maxfd, fd); + FD_SET(fd, &active_fds); + continue; + } + + // handle alreay established connection + if (handler[i] && handler[i]->handle() < 0) + { + handler.remove(i); + FD_CLR(i, &active_fds); + } + } + } + kdWarning(1205) << "???\n"; +} + -- cgit v1.2.3