• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KDEsu

  • kdesu
client.cpp
Go to the documentation of this file.
1/* vi: ts=8 sts=4 sw=4
2 *
3 * This file is part of the KDE project, module kdesu.
4 * Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org>
5 *
6 * This is free software; you can use this library under the GNU Library
7 * General Public License, version 2. See the file "COPYING.LIB" for the
8 * exact licensing terms.
9 *
10 * client.cpp: A client for kdesud.
11 */
12
13#include "client.h"
14
15#include <config.h>
16#include <config-kdesu.h>
17
18#include <stdio.h>
19#include <unistd.h>
20#include <stdlib.h>
21#include <pwd.h>
22#include <errno.h>
23#include <string.h>
24
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <sys/un.h>
28#include <sys/stat.h>
29
30#include <QtCore/QBool>
31#include <QtCore/QFile>
32#include <QtCore/QRegExp>
33
34#include <kdebug.h>
35#include <kstandarddirs.h>
36#include <ktoolinvocation.h>
37#include <kde_file.h>
38
39extern int kdesuDebugArea();
40
41namespace KDESu {
42
43class KDEsuClient::KDEsuClientPrivate {
44public:
45 KDEsuClientPrivate() : sockfd(-1) {}
46 QString daemon;
47 int sockfd;
48 QByteArray sock;
49};
50
51#ifndef SUN_LEN
52#define SUN_LEN(ptr) ((socklen_t) (((struct sockaddr_un *) 0)->sun_path) \
53 + strlen ((ptr)->sun_path))
54#endif
55
56KDEsuClient::KDEsuClient()
57 :d(new KDEsuClientPrivate)
58{
59#ifdef Q_WS_X11
60 QString display = QString::fromLatin1(qgetenv("DISPLAY"));
61 if (display.isEmpty())
62 {
63 kWarning(kdesuDebugArea()) << k_lineinfo << "$DISPLAY is not set.";
64 return;
65 }
66
67 // strip the screen number from the display
68 display.remove(QRegExp("\\.[0-9]+$"));
69#elif defined(Q_WS_QWS)
70 QByteArray display("QWS");
71#else
72 QByteArray display("NODISPLAY");
73#endif
74
75 d->sock = QFile::encodeName( KStandardDirs::locateLocal("socket",
76 QString("kdesud_").append(display)));
77 connect();
78}
79
80
81KDEsuClient::~KDEsuClient()
82{
83 if (d->sockfd >= 0)
84 close(d->sockfd);
85 delete d;
86}
87
88int KDEsuClient::connect()
89{
90 if (d->sockfd >= 0)
91 close(d->sockfd);
92 if (access(d->sock, R_OK|W_OK))
93 {
94 d->sockfd = -1;
95 return -1;
96 }
97
98 d->sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
99 if (d->sockfd < 0)
100 {
101 kWarning(kdesuDebugArea()) << k_lineinfo << "socket():" << perror;
102 return -1;
103 }
104 struct sockaddr_un addr;
105 addr.sun_family = AF_UNIX;
106 strcpy(addr.sun_path, d->sock);
107
108 if (::connect(d->sockfd, (struct sockaddr *) &addr, SUN_LEN(&addr)) < 0)
109 {
110 kWarning(kdesuDebugArea()) << k_lineinfo << "connect():" << perror;
111 close(d->sockfd); d->sockfd = -1;
112 return -1;
113 }
114
115#if !defined(SO_PEERCRED) || !defined(HAVE_STRUCT_UCRED)
116# if defined(HAVE_GETPEEREID)
117 uid_t euid;
118 gid_t egid;
119 // Security: if socket exists, we must own it
120 if (getpeereid(d->sockfd, &euid, &egid) == 0)
121 {
122 if (euid != getuid())
123 {
124 kWarning(kdesuDebugArea()) << "socket not owned by me! socket uid =" << euid;
125 close(d->sockfd); d->sockfd = -1;
126 return -1;
127 }
128 }
129# else
130# ifdef __GNUC__
131# warning "Using sloppy security checks"
132# endif
133 // We check the owner of the socket after we have connected.
134 // If the socket was somehow not ours an attacker will be able
135 // to delete it after we connect but shouldn't be able to
136 // create a socket that is owned by us.
137 KDE_struct_stat s;
138 if (KDE_lstat(d->sock, &s)!=0)
139 {
140 kWarning(kdesuDebugArea()) << "stat failed (" << d->sock << ")";
141 close(d->sockfd); d->sockfd = -1;
142 return -1;
143 }
144 if (s.st_uid != getuid())
145 {
146 kWarning(kdesuDebugArea()) << "socket not owned by me! socket uid =" << s.st_uid;
147 close(d->sockfd); d->sockfd = -1;
148 return -1;
149 }
150 if (!S_ISSOCK(s.st_mode))
151 {
152 kWarning(kdesuDebugArea()) << "socket is not a socket (" << d->sock << ")";
153 close(d->sockfd); d->sockfd = -1;
154 return -1;
155 }
156# endif
157#else
158 struct ucred cred;
159 socklen_t siz = sizeof(cred);
160
161 // Security: if socket exists, we must own it
162 if (getsockopt(d->sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &siz) == 0)
163 {
164 if (cred.uid != getuid())
165 {
166 kWarning(kdesuDebugArea()) << "socket not owned by me! socket uid =" << cred.uid;
167 close(d->sockfd); d->sockfd = -1;
168 return -1;
169 }
170 }
171#endif
172
173 return 0;
174}
175
176QByteArray KDEsuClient::escape(const QByteArray &str)
177{
178 QByteArray copy;
179 copy.reserve(str.size() + 4);
180 copy.append('"');
181 for (int i = 0; i < str.size(); i++) {
182 uchar c = str.at(i);
183 if (c < 32) {
184 copy.append('\\');
185 copy.append('^');
186 copy.append(c + '@');
187 } else {
188 if (c == '\\' || c == '"')
189 copy.append('\\');
190 copy.append(c);
191 }
192 }
193 copy.append('"');
194 return copy;
195}
196
197int KDEsuClient::command(const QByteArray &cmd, QByteArray *result)
198{
199 if (d->sockfd < 0)
200 return -1;
201
202 if (send(d->sockfd, cmd, cmd.length(), 0) != (int) cmd.length())
203 return -1;
204
205 char buf[1024];
206 int nbytes = recv(d->sockfd, buf, 1023, 0);
207 if (nbytes <= 0)
208 {
209 kWarning(kdesuDebugArea()) << k_lineinfo << "no reply from daemon.";
210 return -1;
211 }
212 buf[nbytes] = '\000';
213
214 QByteArray reply = buf;
215 if (reply.left(2) != "OK")
216 return -1;
217
218 if (result)
219 *result = reply.mid(3, reply.length()-4);
220 return 0;
221}
222
223int KDEsuClient::setPass(const char *pass, int timeout)
224{
225 QByteArray cmd = "PASS ";
226 cmd += escape(pass);
227 cmd += ' ';
228 cmd += QByteArray().setNum(timeout);
229 cmd += '\n';
230 return command(cmd);
231}
232
233int KDEsuClient::exec(const QByteArray &prog, const QByteArray &user, const QByteArray &options, const QList<QByteArray> &env)
234{
235 QByteArray cmd;
236 cmd = "EXEC ";
237 cmd += escape(prog);
238 cmd += ' ';
239 cmd += escape(user);
240 if (!options.isEmpty() || !env.isEmpty())
241 {
242 cmd += ' ';
243 cmd += escape(options);
244 for (int i = 0; i < env.count(); ++i)
245 {
246 cmd += ' ';
247 cmd += escape(env.at(i));
248 }
249 }
250 cmd += '\n';
251 return command(cmd);
252}
253
254int KDEsuClient::setHost(const QByteArray &host)
255{
256 QByteArray cmd = "HOST ";
257 cmd += escape(host);
258 cmd += '\n';
259 return command(cmd);
260}
261
262int KDEsuClient::setPriority(int prio)
263{
264 QByteArray cmd;
265 cmd += "PRIO ";
266 cmd += QByteArray::number(prio);
267 cmd += '\n';
268 return command(cmd);
269}
270
271int KDEsuClient::setScheduler(int sched)
272{
273 QByteArray cmd;
274 cmd += "SCHD ";
275 cmd += QByteArray::number(sched);
276 cmd += '\n';
277 return command(cmd);
278}
279
280int KDEsuClient::delCommand(const QByteArray &key, const QByteArray &user)
281{
282 QByteArray cmd = "DEL ";
283 cmd += escape(key);
284 cmd += ' ';
285 cmd += escape(user);
286 cmd += '\n';
287 return command(cmd);
288}
289int KDEsuClient::setVar(const QByteArray &key, const QByteArray &value, int timeout,
290 const QByteArray &group)
291{
292 QByteArray cmd = "SET ";
293 cmd += escape(key);
294 cmd += ' ';
295 cmd += escape(value);
296 cmd += ' ';
297 cmd += escape(group);
298 cmd += ' ';
299 cmd += QByteArray().setNum(timeout);
300 cmd += '\n';
301 return command(cmd);
302}
303
304QByteArray KDEsuClient::getVar(const QByteArray &key)
305{
306 QByteArray cmd = "GET ";
307 cmd += escape(key);
308 cmd += '\n';
309 QByteArray reply;
310 command(cmd, &reply);
311 return reply;
312}
313
314QList<QByteArray> KDEsuClient::getKeys(const QByteArray &group)
315{
316 QByteArray cmd = "GETK ";
317 cmd += escape(group);
318 cmd += '\n';
319 QByteArray reply;
320 command(cmd, &reply);
321 int index=0, pos;
322 QList<QByteArray> list;
323 if( !reply.isEmpty() )
324 {
325 // kDebug(kdesuDebugArea()) << "Found a matching entry:" << reply;
326 while (1)
327 {
328 pos = reply.indexOf( '\007', index );
329 if( pos == -1 )
330 {
331 if( index == 0 )
332 list.append( reply );
333 else
334 list.append( reply.mid(index) );
335 break;
336 }
337 else
338 {
339 list.append( reply.mid(index, pos-index) );
340 }
341 index = pos+1;
342 }
343 }
344 return list;
345}
346
347bool KDEsuClient::findGroup(const QByteArray &group)
348{
349 QByteArray cmd = "CHKG ";
350 cmd += escape(group);
351 cmd += '\n';
352 if( command(cmd) == -1 )
353 return false;
354 return true;
355}
356
357int KDEsuClient::delVar(const QByteArray &key)
358{
359 QByteArray cmd = "DELV ";
360 cmd += escape(key);
361 cmd += '\n';
362 return command(cmd);
363}
364
365int KDEsuClient::delGroup(const QByteArray &group)
366{
367 QByteArray cmd = "DELG ";
368 cmd += escape(group);
369 cmd += '\n';
370 return command(cmd);
371}
372
373int KDEsuClient::delVars(const QByteArray &special_key)
374{
375 QByteArray cmd = "DELS ";
376 cmd += escape(special_key);
377 cmd += '\n';
378 return command(cmd);
379}
380
381int KDEsuClient::ping()
382{
383 return command("PING\n");
384}
385
386int KDEsuClient::exitCode()
387{
388 QByteArray result;
389 if (command("EXIT\n", &result) != 0)
390 return -1;
391
392 return result.toInt();
393}
394
395int KDEsuClient::stopServer()
396{
397 return command("STOP\n");
398}
399
400static QString findDaemon()
401{
402 QString daemon = KStandardDirs::locate("bin", "kdesud");
403 if (daemon.isEmpty()) // if not in KDEDIRS, rely on PATH
404 daemon = KStandardDirs::findExe("kdesud");
405
406 if (daemon.isEmpty())
407 {
408 kWarning(kdesuDebugArea()) << k_lineinfo << "daemon not found.";
409 }
410 return daemon;
411}
412
413bool KDEsuClient::isServerSGID()
414{
415 if (d->daemon.isEmpty())
416 d->daemon = findDaemon();
417 if (d->daemon.isEmpty())
418 return false;
419
420 KDE_struct_stat sbuf;
421 if (KDE::stat(d->daemon, &sbuf) < 0)
422 {
423 kWarning(kdesuDebugArea()) << k_lineinfo << "stat():" << perror;
424 return false;
425 }
426 return (sbuf.st_mode & S_ISGID);
427}
428
429int KDEsuClient::startServer()
430{
431 if (d->daemon.isEmpty())
432 d->daemon = findDaemon();
433 if (d->daemon.isEmpty())
434 return -1;
435
436 if (!isServerSGID()) {
437 kWarning(kdesuDebugArea()) << k_lineinfo << "kdesud not setgid!";
438 }
439
440 // kdesud only forks to the background after it is accepting
441 // connections.
442 // We start it via kdeinit to make sure that it doesn't inherit
443 // any fd's from the parent process.
444 int ret = KToolInvocation::kdeinitExecWait(d->daemon);
445 connect();
446 return ret;
447}
448
449}
KDESu::KDEsuClient::setScheduler
int setScheduler(int scheduler)
Set the desired scheduler (optional), see StubProcess.
Definition: client.cpp:271
KDESu::KDEsuClient::delVars
int delVars(const QByteArray &special_key)
Delete all persistent variables with the given key.
Definition: client.cpp:373
KDESu::KDEsuClient::delCommand
int delCommand(const QByteArray &command, const QByteArray &user)
Remove a password for a user/command.
Definition: client.cpp:280
KDESu::KDEsuClient::ping
int ping()
Ping kdesud.
Definition: client.cpp:381
KDESu::KDEsuClient::getKeys
QList< QByteArray > getKeys(const QByteArray &group)
Gets all the keys that are membes of the given group.
Definition: client.cpp:314
KDESu::KDEsuClient::KDEsuClient
KDEsuClient()
Definition: client.cpp:56
KDESu::KDEsuClient::setHost
int setHost(const QByteArray &host)
Set the target host (optional).
Definition: client.cpp:254
KDESu::KDEsuClient::setPass
int setPass(const char *pass, int timeout)
Set root's password, lasts one session.
Definition: client.cpp:223
KDESu::KDEsuClient::delGroup
int delGroup(const QByteArray &group)
Delete all persistent variables in a group.
Definition: client.cpp:365
KDESu::KDEsuClient::getVar
QByteArray getVar(const QByteArray &key)
Get a persistent variable.
Definition: client.cpp:304
KDESu::KDEsuClient::setPriority
int setPriority(int priority)
Set the desired priority (optional), see StubProcess.
Definition: client.cpp:262
KDESu::KDEsuClient::exec
int exec(const QByteArray &command, const QByteArray &user, const QByteArray &options=0, const QList< QByteArray > &env=QList< QByteArray >())
Lets kdesud execute a command.
Definition: client.cpp:233
KDESu::KDEsuClient::~KDEsuClient
~KDEsuClient()
Definition: client.cpp:81
KDESu::KDEsuClient::setVar
int setVar(const QByteArray &key, const QByteArray &value, int timeout=0, const QByteArray &group=0)
Set a persistent variable.
Definition: client.cpp:289
KDESu::KDEsuClient::stopServer
int stopServer()
Stop the daemon.
Definition: client.cpp:395
KDESu::KDEsuClient::isServerSGID
bool isServerSGID()
Returns true if the server is safe (installed setgid), false otherwise.
Definition: client.cpp:413
KDESu::KDEsuClient::exitCode
int exitCode()
Wait for the last command to exit and return the exit code.
Definition: client.cpp:386
KDESu::KDEsuClient::findGroup
bool findGroup(const QByteArray &group)
Returns true if the specified group exists is cached.
Definition: client.cpp:347
KDESu::KDEsuClient::startServer
int startServer()
Try to start up kdesud.
Definition: client.cpp:429
KDESu::KDEsuClient::delVar
int delVar(const QByteArray &key)
Delete a persistent variable.
Definition: client.cpp:357
KStandardDirs::findExe
static QString findExe(const QString &appname, const QString &pathstr=QString(), SearchOptions options=NoSearchOptions)
KStandardDirs::locate
static QString locate(const char *type, const QString &filename, const KComponentData &cData=KGlobal::mainComponent())
KStandardDirs::locateLocal
static QString locateLocal(const char *type, const QString &filename, bool createDir, const KComponentData &cData=KGlobal::mainComponent())
KToolInvocation::kdeinitExecWait
static int kdeinitExecWait(const QString &name, const QStringList &args=QStringList(), QString *error=0, int *pid=0, const QByteArray &startup_id=QByteArray())
QList
kdesuDebugArea
int kdesuDebugArea()
Definition: su.cpp:43
SUN_LEN
#define SUN_LEN(ptr)
Definition: client.cpp:52
client.h
kWarning
#define kWarning
k_lineinfo
#define k_lineinfo
perror
QDebug perror(QDebug s, KDebugTag)
kdebug.h
timeout
int timeout
kstandarddirs.h
ktoolinvocation.h
KDESu
Definition: client.cpp:41
KDESu::findDaemon
static QString findDaemon()
Definition: client.cpp:400
KDE::stat
int stat(const QString &path, KDE_struct_stat *buf)
access
int access(const QString &path, int mode)
group
group
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDEsu

Skip menu "KDEsu"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal