3 * This file is part of the KDE project, module kdesu.
4 * Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org>
7 * kdesud.cpp: KDE su daemon. Offers "keep password" functionality to kde su.
9 * The socket $KDEHOME/socket-$(HOSTNAME)/kdesud_$(display) is used for communication with
12 * The protocol: Client initiates the connection. All commands and responses
13 * are terminated by a newline.
15 * Client Server Description
16 * ------ ------ -----------
18 * PASS <pass> <timeout> OK Set password for commands in
19 * this session. Password is
20 * valid for <timeout> seconds.
22 * USER <user> OK Set the target user [required]
24 * EXEC <command> OK Execute command <command>. If
25 * NO <command> has been executed
26 * before (< timeout) no PASS
29 * DEL <command> OK Delete password for command
32 * PING OK Ping the server (diagnostics).
36 #include <config-runtime.h>
50 #include <sys/types.h>
51 #include <sys/socket.h>
53 #include <sys/resource.h>
55 #ifdef HAVE_SYS_SELECT_H
56 #include <sys/select.h> // Needed on some systems.
64 #include <kcomponentdata.h>
67 #include <kcmdlineargs.h>
68 #include <kstandarddirs.h>
69 #include <kaboutdata.h>
70 #include <kdesu/client.h>
71 #include <kdesu/defaults.h>
82 #define SUN_LEN(ptr) ((kde_socklen_t) (((struct sockaddr_un *) 0)->sun_path) \
83 + strlen ((ptr)->sun_path))
86 #define ERR strerror(errno)
89 using namespace KDESu
;
94 const char *Version
= "1.01";
101 // FIXME: This is just here to make it compile
102 // It would be better to fix it more globally (Caleb Tennis)
103 typedef unsigned ksocklen_t
;
105 void kdesud_cleanup()
111 // Borrowed from kdebase/kaudio/kaudioserver.cpp
114 extern "C" int xio_errhandler(Display
*);
116 int xio_errhandler(Display
*)
118 kError(1205) << "Fatal IO error, exiting...\n";
121 return 1; //silence compilers
124 int initXconnection()
126 x11Display
= XOpenDisplay(NULL
);
127 if (x11Display
!= 0L)
129 XSetIOErrorHandler(xio_errhandler
);
130 XCreateSimpleWindow(x11Display
, DefaultRootWindow(x11Display
),
132 BlackPixelOfScreen(DefaultScreenOfDisplay(x11Display
)),
133 BlackPixelOfScreen(DefaultScreenOfDisplay(x11Display
)));
134 return XConnectionNumber(x11Display
);
137 kWarning(1205) << "Can't connect to the X Server.\n";
138 kWarning(1205) << "Might not terminate at end of session.\n";
145 void signal_exit(int);
146 void sigchld_handler(int);
149 void signal_exit(int sig
)
151 kDebug(1205) << "Exiting on signal " << sig
<< "\n";
156 void sigchld_handler(int)
159 write(pipeOfDeath
[1], &c
, 1);
163 * Creates an AF_UNIX socket in socket resource, mode 0600.
172 QString display
= QString::fromAscii(getenv("DISPLAY"));
173 if (display
.isEmpty())
175 kWarning(1205) << "$DISPLAY is not set\n";
179 // strip the screen number from the display
180 display
.replace(QRegExp("\\.[0-9]+$"), "");
182 sock
= QFile::encodeName(KStandardDirs::locateLocal("socket", QString("kdesud_%1").arg(display
)));
183 int stat_err
=lstat(sock
, &s
);
184 if(!stat_err
&& S_ISLNK(s
.st_mode
)) {
185 kWarning(1205) << "Someone is running a symlink attack on you\n";
187 kWarning(1205) << "Could not delete symlink\n";
192 if (!access(sock
, R_OK
|W_OK
))
195 if (client
.ping() == -1)
197 kWarning(1205) << "stale socket exists\n";
200 kWarning(1205) << "Could not delete stale socket\n";
205 kWarning(1205) << "kdesud is already running\n";
211 sockfd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
214 kError(1205) << "socket(): " << ERR
<< "\n";
218 struct sockaddr_un addr
;
219 addr
.sun_family
= AF_UNIX
;
220 strncpy(addr
.sun_path
, sock
, sizeof(addr
.sun_path
)-1);
221 addr
.sun_path
[sizeof(addr
.sun_path
)-1] = '\000';
222 addrlen
= SUN_LEN(&addr
);
223 if (bind(sockfd
, (struct sockaddr
*)&addr
, addrlen
) < 0)
225 kError(1205) << "bind(): " << ERR
<< "\n";
230 lin
.l_onoff
= lin
.l_linger
= 0;
231 if (setsockopt(sockfd
, SOL_SOCKET
, SO_LINGER
, (char *) &lin
,
234 kError(1205) << "setsockopt(SO_LINGER): " << ERR
<< "\n";
239 if (setsockopt(sockfd
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &opt
,
242 kError(1205) << "setsockopt(SO_REUSEADDR): " << ERR
<< "\n";
246 if (setsockopt(sockfd
, SOL_SOCKET
, SO_KEEPALIVE
, (char *) &opt
,
249 kError(1205) << "setsockopt(SO_KEEPALIVE): " << ERR
<< "\n";
261 int main(int argc
, char *argv
[])
263 KAboutData
aboutData("kdesud", 0, ki18n("KDE su daemon"),
264 Version
, ki18n("Daemon used by kdesu"),
265 KAboutData::License_Artistic
,
266 ki18n("Copyright (c) 1999,2000 Geert Jansen"));
267 aboutData
.addAuthor(ki18n("Geert Jansen"), ki18n("Author"),
268 "jansen@kde.org", "http://www.stack.nl/~geertj/");
269 KCmdLineArgs::init(argc
, argv
, &aboutData
);
270 KComponentData
componentData(&aboutData
);
272 // Set core dump size to 0
274 rlim
.rlim_cur
= rlim
.rlim_max
= 0;
275 if (setrlimit(RLIMIT_CORE
, &rlim
) < 0)
277 kError(1205) << "setrlimit(): " << ERR
<< "\n";
281 // Create the Unix socket.
282 int sockfd
= create_socket();
285 if (listen(sockfd
, 1) < 0)
287 kError(1205) << "listen(): " << ERR
<< "\n";
293 // Ok, we're accepting connections. Fork to the background.
297 kError(1205) << "fork():" << ERR
<< "\n";
305 // Make sure we exit when the display gets closed.
306 int x11Fd
= initXconnection();
307 maxfd
= qMax(maxfd
, x11Fd
);
310 repo
= new Repository
;
311 QVector
<ConnectionHandler
*> handler
;
314 maxfd
= qMax(maxfd
, pipeOfDeath
[0]);
318 sa
.sa_handler
= signal_exit
;
319 sigemptyset(&sa
.sa_mask
);
321 sigaction(SIGHUP
, &sa
, 0L);
322 sigaction(SIGINT
, &sa
, 0L);
323 sigaction(SIGTERM
, &sa
, 0L);
324 sigaction(SIGQUIT
, &sa
, 0L);
326 sa
.sa_handler
= sigchld_handler
;
327 sa
.sa_flags
= SA_NOCLDSTOP
;
328 sigaction(SIGCHLD
, &sa
, 0L);
329 sa
.sa_handler
= SIG_IGN
;
330 sigaction(SIGPIPE
, &sa
, 0L);
332 // Main execution loop
335 struct sockaddr_un clientname
;
337 fd_set tmp_fds
, active_fds
;
338 FD_ZERO(&active_fds
);
339 FD_SET(sockfd
, &active_fds
);
340 FD_SET(pipeOfDeath
[0], &active_fds
);
343 FD_SET(x11Fd
, &active_fds
);
348 tmp_fds
= active_fds
;
353 if (select(maxfd
+1, &tmp_fds
, 0L, 0L, 0L) < 0)
355 if (errno
== EINTR
) continue;
357 kError(1205) << "select(): " << ERR
<< "\n";
361 for (int i
=0; i
<=maxfd
; i
++)
363 if (!FD_ISSET(i
, &tmp_fds
))
366 if (i
== pipeOfDeath
[0])
369 read(pipeOfDeath
[0], buf
, 100);
374 result
= waitpid((pid_t
)-1, &status
, WNOHANG
);
377 for(int j
=handler
.size(); j
--;)
379 if (handler
[j
] && (handler
[j
]->m_pid
== result
))
381 handler
[j
]->m_exitCode
= WEXITSTATUS(status
);
382 handler
[j
]->m_hasExitCode
= true;
383 handler
[j
]->sendExitCode();
384 handler
[j
]->m_pid
= 0;
399 while(XPending(x11Display
))
400 XNextEvent(x11Display
, &event_return
);
407 // Accept new connection
410 fd
= accept(sockfd
, (struct sockaddr
*) &clientname
, &addrlen
);
413 kError(1205) << "accept():" << ERR
<< "\n";
416 while (fd
+1 > (int) handler
.size())
419 handler
[fd
] = new ConnectionHandler(fd
);
420 maxfd
= qMax(maxfd
, fd
);
421 FD_SET(fd
, &active_fds
);
425 // handle already established connection
426 if (handler
[i
] && handler
[i
]->handle() < 0)
430 FD_CLR(i
, &active_fds
);
434 kWarning(1205) << "???\n";