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

KDEsu

  • sources
  • kde-4.12
  • kdelibs
  • 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 
39 extern int kdesuDebugArea();
40 
41 namespace KDESu {
42 
43 class KDEsuClient::KDEsuClientPrivate {
44 public:
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 
56 KDEsuClient::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 
81 KDEsuClient::~KDEsuClient()
82 {
83  if (d->sockfd >= 0)
84  close(d->sockfd);
85  delete d;
86 }
87 
88 int 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 
176 QByteArray 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 
197 int 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 
223 int 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 
233 int 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 
254 int KDEsuClient::setHost(const QByteArray &host)
255 {
256  QByteArray cmd = "HOST ";
257  cmd += escape(host);
258  cmd += '\n';
259  return command(cmd);
260 }
261 
262 int 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 
271 int 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 
280 int 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 }
289 int 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 
304 QByteArray 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 
314 QList<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 
347 bool 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 
357 int KDEsuClient::delVar(const QByteArray &key)
358 {
359  QByteArray cmd = "DELV ";
360  cmd += escape(key);
361  cmd += '\n';
362  return command(cmd);
363 }
364 
365 int KDEsuClient::delGroup(const QByteArray &group)
366 {
367  QByteArray cmd = "DELG ";
368  cmd += escape(group);
369  cmd += '\n';
370  return command(cmd);
371 }
372 
373 int 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 
381 int KDEsuClient::ping()
382 {
383  return command("PING\n");
384 }
385 
386 int KDEsuClient::exitCode()
387 {
388  QByteArray result;
389  if (command("EXIT\n", &result) != 0)
390  return -1;
391 
392  return result.toInt();
393 }
394 
395 int KDEsuClient::stopServer()
396 {
397  return command("STOP\n");
398 }
399 
400 static 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 
413 bool 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 
429 int 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::setPriority
int setPriority(int priority)
Set the desired priority (optional), see StubProcess.
Definition: client.cpp:262
perror
QDebug perror(QDebug s, KDebugTag)
KDESu::findDaemon
static QString findDaemon()
Definition: client.cpp:400
kdebug.h
kdesuDebugArea
int kdesuDebugArea()
Definition: su.cpp:43
KStandardDirs::locate
static QString locate(const char *type, const QString &filename, const KComponentData &cData=KGlobal::mainComponent())
KDESu::KDEsuClient::getVar
QByteArray getVar(const QByteArray &key)
Get a persistent variable.
Definition: client.cpp:304
KDESu::KDEsuClient::exitCode
int exitCode()
Wait for the last command to exit and return the exit code.
Definition: client.cpp:386
KDE::stat
int stat(const QString &path, KDE_struct_stat *buf)
KDESu::KDEsuClient::delCommand
int delCommand(const QByteArray &command, const QByteArray &user)
Remove a password for a user/command.
Definition: client.cpp:280
QString
KDESu::KDEsuClient::ping
int ping()
Ping kdesud.
Definition: client.cpp:381
ktoolinvocation.h
KDESu::KDEsuClient::delVars
int delVars(const QByteArray &special_key)
Delete all persistent variables with the given key.
Definition: client.cpp:373
KDESu::KDEsuClient::setHost
int setHost(const QByteArray &host)
Set the target host (optional).
Definition: client.cpp:254
KDESu::KDEsuClient::delVar
int delVar(const QByteArray &key)
Delete a persistent variable.
Definition: client.cpp:357
KDESu::KDEsuClient::stopServer
int stopServer()
Stop the daemon.
Definition: client.cpp:395
SUN_LEN
#define SUN_LEN(ptr)
Definition: client.cpp:52
KDESu::KDEsuClient::delGroup
int delGroup(const QByteArray &group)
Delete all persistent variables in a group.
Definition: client.cpp:365
KDESu::KDEsuClient::isServerSGID
bool isServerSGID()
Returns true if the server is safe (installed setgid), false otherwise.
Definition: client.cpp:413
KDESu::KDEsuClient::setScheduler
int setScheduler(int scheduler)
Set the desired scheduler (optional), see StubProcess.
Definition: client.cpp:271
KDESu::KDEsuClient::~KDEsuClient
~KDEsuClient()
Definition: client.cpp:81
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
KStandardDirs::locateLocal
static QString locateLocal(const char *type, const QString &filename, const KComponentData &cData=KGlobal::mainComponent())
access
int access(const QString &path, int mode)
kstandarddirs.h
KToolInvocation::kdeinitExecWait
static int kdeinitExecWait(const QString &name, const QStringList &args=QStringList(), QString *error=0, int *pid=0, const QByteArray &startup_id=QByteArray())
KStandardDirs::findExe
static QString findExe(const QString &appname, const QString &pathstr=QString(), SearchOptions options=NoSearchOptions)
KDESu::KDEsuClient::findGroup
bool findGroup(const QByteArray &group)
Returns true if the specified group exists is cached.
Definition: client.cpp:347
kWarning
static QDebug kWarning(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
KDESu::KDEsuClient::startServer
int startServer()
Try to start up kdesud.
Definition: client.cpp:429
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
client.h
k_lineinfo
#define k_lineinfo
KDESu::KDEsuClient::setPass
int setPass(const char *pass, int timeout)
Set root's password, lasts one session.
Definition: client.cpp:223
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
QList< QByteArray >
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:49:48 by doxygen 1.8.7 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 API Reference

Skip menu "kdelibs 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
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



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