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

KDEsu

client.cpp

Go to the documentation of this file.
00001 /* vi: ts=8 sts=4 sw=4
00002  *
00003  * This file is part of the KDE project, module kdesu.
00004  * Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org>
00005  *
00006  * This is free software; you can use this library under the GNU Library
00007  * General Public License, version 2. See the file "COPYING.LIB" for the
00008  * exact licensing terms.
00009  *
00010  * client.cpp: A client for kdesud.
00011  */
00012 
00013 #include "client.h"
00014 
00015 #include <config.h>
00016 #include <stdio.h>
00017 #include <unistd.h>
00018 #include <stdlib.h>
00019 #include <pwd.h>
00020 #include <errno.h>
00021 #include <string.h>
00022 
00023 #include <sys/types.h>
00024 #include <sys/socket.h>
00025 #include <sys/un.h>
00026 #include <sys/stat.h>
00027 
00028 #include <QtCore/QBool>
00029 #include <QtCore/QFile>
00030 #include <QtCore/QRegExp>
00031 
00032 #include <kdebug.h>
00033 #include <kstandarddirs.h>
00034 #include <kapplication.h>
00035 #include <ktoolinvocation.h>
00036 #include <kde_file.h>
00037 
00038 
00039 namespace KDESu {
00040 
00041 class KDEsuClient::KDEsuClientPrivate {
00042 public:
00043     KDEsuClientPrivate() : sockfd(-1) {}
00044     QString daemon;
00045     int sockfd;
00046     QByteArray sock;
00047 };
00048 
00049 #ifndef SUN_LEN
00050 #define SUN_LEN(ptr) ((socklen_t) (((struct sockaddr_un *) 0)->sun_path) \
00051                  + strlen ((ptr)->sun_path))
00052 #endif
00053 
00054 KDEsuClient::KDEsuClient()
00055     :d(new KDEsuClientPrivate)
00056 {
00057 #ifdef Q_WS_X11
00058     QString display = QString::fromAscii(qgetenv("DISPLAY"));
00059     if (display.isEmpty())
00060     {
00061         kWarning(900) << k_lineinfo << "$DISPLAY is not set\n";
00062         return;
00063     }
00064 
00065     // strip the screen number from the display
00066     display.remove(QRegExp("\\.[0-9]+$"));
00067 #elif defined(Q_WS_QWS)
00068     QByteArray display("QWS");
00069 #else
00070     QByteArray display("NODISPLAY");
00071 #endif
00072 
00073     d->sock = QFile::encodeName( KStandardDirs::locateLocal("socket",
00074                                     QString("kdesud_").append(display)));
00075     connect();
00076 }
00077 
00078 
00079 KDEsuClient::~KDEsuClient()
00080 {
00081     if (d->sockfd >= 0)
00082     close(d->sockfd);
00083     delete d;
00084 }
00085 
00086 int KDEsuClient::connect()
00087 {
00088     if (d->sockfd >= 0)
00089     close(d->sockfd);
00090     if (access(d->sock, R_OK|W_OK))
00091     {
00092     d->sockfd = -1;
00093     return -1;
00094     }
00095 
00096     d->sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
00097     if (d->sockfd < 0)
00098     {
00099     kWarning(900) << k_lineinfo << "socket(): " << perror << "\n";
00100     return -1;
00101     }
00102     struct sockaddr_un addr;
00103     addr.sun_family = AF_UNIX;
00104     strcpy(addr.sun_path, d->sock);
00105 
00106     if (::connect(d->sockfd, (struct sockaddr *) &addr, SUN_LEN(&addr)) < 0)
00107     {
00108         kWarning(900) << k_lineinfo << "connect():" << perror;
00109     close(d->sockfd); d->sockfd = -1;
00110     return -1;
00111     }
00112 
00113 #if !defined(SO_PEERCRED) || !defined(HAVE_STRUCT_UCRED)
00114 # if defined(HAVE_GETPEEREID)
00115     uid_t euid;
00116     gid_t egid;
00117     // Security: if socket exists, we must own it
00118     if (getpeereid(d->sockfd, &euid, &egid) == 0)
00119     {
00120        if (euid != getuid())
00121        {
00122             kWarning(900) << "socket not owned by me! socket uid = " << euid;
00123             close(d->sockfd); d->sockfd = -1;
00124             return -1;
00125        }
00126     }
00127 # else
00128 #  ifdef __GNUC__
00129 #   warning "Using sloppy security checks"
00130 #  endif
00131     // We check the owner of the socket after we have connected.
00132     // If the socket was somehow not ours an attacker will be able
00133     // to delete it after we connect but shouldn't be able to
00134     // create a socket that is owned by us.
00135     KDE_struct_stat s;
00136     if (KDE_lstat(d->sock, &s)!=0)
00137     {
00138         kWarning(900) << "stat failed (" << d->sock << ")";
00139     close(d->sockfd); d->sockfd = -1;
00140     return -1;
00141     }
00142     if (s.st_uid != getuid())
00143     {
00144         kWarning(900) << "socket not owned by me! socket uid = " << s.st_uid;
00145     close(d->sockfd); d->sockfd = -1;
00146     return -1;
00147     }
00148     if (!S_ISSOCK(s.st_mode))
00149     {
00150         kWarning(900) << "socket is not a socket (" << d->sock << ")";
00151     close(d->sockfd); d->sockfd = -1;
00152     return -1;
00153     }
00154 # endif
00155 #else
00156     struct ucred cred;
00157     socklen_t siz = sizeof(cred);
00158 
00159     // Security: if socket exists, we must own it
00160     if (getsockopt(d->sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &siz) == 0)
00161     {
00162         if (cred.uid != getuid())
00163         {
00164             kWarning(900) << "socket not owned by me! socket uid = " << cred.uid;
00165             close(d->sockfd); d->sockfd = -1;
00166             return -1;
00167         }
00168     }
00169 #endif
00170 
00171     return 0;
00172 }
00173 
00174 QByteArray KDEsuClient::escape(const QByteArray &str)
00175 {
00176     QByteArray copy = str;
00177     copy.replace('\\', "\\\\");
00178     copy.replace('\"', "\\\"");
00179     copy.prepend("\"");
00180     copy.append("\"");
00181     return copy;
00182 }
00183 
00184 int KDEsuClient::command(const QByteArray &cmd, QByteArray *result)
00185 {
00186     if (d->sockfd < 0)
00187     return -1;
00188 
00189     if (send(d->sockfd, cmd, cmd.length(), 0) != (int) cmd.length())
00190     return -1;
00191 
00192     char buf[1024];
00193     int nbytes = recv(d->sockfd, buf, 1023, 0);
00194     if (nbytes <= 0)
00195     {
00196     kWarning(900) << k_lineinfo << "no reply from daemon\n";
00197     return -1;
00198     }
00199     buf[nbytes] = '\000';
00200 
00201     QByteArray reply = buf;
00202     if (reply.left(2) != "OK")
00203     return -1;
00204 
00205     if (result)
00206     *result = reply.mid(3, reply.length()-4);
00207     return 0;
00208 }
00209 
00210 int KDEsuClient::setPass(const char *pass, int timeout)
00211 {
00212     QByteArray cmd = "PASS ";
00213     cmd += escape(pass);
00214     cmd += ' ';
00215     cmd += QByteArray().setNum(timeout);
00216     cmd += '\n';
00217     return command(cmd);
00218 }
00219 
00220 int KDEsuClient::exec(const QByteArray &prog, const QByteArray &user, const QByteArray &options, const QList<QByteArray> &env)
00221 {
00222     QByteArray cmd;
00223     cmd = "EXEC ";
00224     cmd += escape(prog);
00225     cmd += ' ';
00226     cmd += escape(user);
00227     if (!options.isEmpty() || !env.isEmpty())
00228     {
00229        cmd += ' ';
00230        cmd += escape(options);
00231        for (int i = 0; i < env.count(); ++i)
00232        {
00233           cmd += ' ';
00234           cmd += escape(env.at(i));
00235        }
00236     }
00237     cmd += '\n';
00238     return command(cmd);
00239 }
00240 
00241 int KDEsuClient::setHost(const QByteArray &host)
00242 {
00243     QByteArray cmd = "HOST ";
00244     cmd += escape(host);
00245     cmd += '\n';
00246     return command(cmd);
00247 }
00248 
00249 int KDEsuClient::setPriority(int prio)
00250 {
00251     QByteArray cmd;
00252     cmd += "PRIO ";
00253     cmd += QByteArray::number(prio);
00254     cmd += '\n';
00255     return command(cmd);
00256 }
00257 
00258 int KDEsuClient::setScheduler(int sched)
00259 {
00260     QByteArray cmd;
00261     cmd += "SCHD ";
00262     cmd += QByteArray::number(sched);
00263     cmd += '\n';
00264     return command(cmd);
00265 }
00266 
00267 int KDEsuClient::delCommand(const QByteArray &key, const QByteArray &user)
00268 {
00269     QByteArray cmd = "DEL ";
00270     cmd += escape(key);
00271     cmd += ' ';
00272     cmd += escape(user);
00273     cmd += '\n';
00274     return command(cmd);
00275 }
00276 int KDEsuClient::setVar(const QByteArray &key, const QByteArray &value, int timeout,
00277                         const QByteArray &group)
00278 {
00279     QByteArray cmd = "SET ";
00280     cmd += escape(key);
00281     cmd += ' ';
00282     cmd += escape(value);
00283     cmd += ' ';
00284     cmd += escape(group);
00285     cmd += ' ';
00286     cmd += QByteArray().setNum(timeout);
00287     cmd += '\n';
00288     return command(cmd);
00289 }
00290 
00291 QByteArray KDEsuClient::getVar(const QByteArray &key)
00292 {
00293     QByteArray cmd = "GET ";
00294     cmd += escape(key);
00295     cmd += '\n';
00296     QByteArray reply;
00297     command(cmd, &reply);
00298     return reply;
00299 }
00300 
00301 QList<QByteArray> KDEsuClient::getKeys(const QByteArray &group)
00302 {
00303     QByteArray cmd = "GETK ";
00304     cmd += escape(group);
00305     cmd += '\n';
00306     QByteArray reply;
00307     command(cmd, &reply);
00308     int index=0, pos;
00309     QList<QByteArray> list;
00310     if( !reply.isEmpty() )
00311     {
00312         // kDebug(900) << "Found a matching entry: " << reply;
00313         while (1)
00314         {
00315             pos = reply.indexOf( '\007', index );
00316             if( pos == -1 )
00317             {
00318                 if( index == 0 )
00319                     list.append( reply );
00320                 else
00321                     list.append( reply.mid(index) );
00322                 break;
00323             }
00324             else
00325             {
00326                 list.append( reply.mid(index, pos-index) );
00327             }
00328             index = pos+1;
00329         }
00330     }
00331     return list;
00332 }
00333 
00334 bool KDEsuClient::findGroup(const QByteArray &group)
00335 {
00336     QByteArray cmd = "CHKG ";
00337     cmd += escape(group);
00338     cmd += '\n';
00339     if( command(cmd) == -1 )
00340         return false;
00341     return true;
00342 }
00343 
00344 int KDEsuClient::delVar(const QByteArray &key)
00345 {
00346     QByteArray cmd = "DELV ";
00347     cmd += escape(key);
00348     cmd += '\n';
00349     return command(cmd);
00350 }
00351 
00352 int KDEsuClient::delGroup(const QByteArray &group)
00353 {
00354     QByteArray cmd = "DELG ";
00355     cmd += escape(group);
00356     cmd += '\n';
00357     return command(cmd);
00358 }
00359 
00360 int KDEsuClient::delVars(const QByteArray &special_key)
00361 {
00362     QByteArray cmd = "DELS ";
00363     cmd += escape(special_key);
00364     cmd += '\n';
00365     return command(cmd);
00366 }
00367 
00368 int KDEsuClient::ping()
00369 {
00370     return command("PING\n");
00371 }
00372 
00373 int KDEsuClient::exitCode()
00374 {
00375     QByteArray result;
00376     if (command("EXIT\n", &result) != 0)
00377        return -1;
00378 
00379     return result.toInt();
00380 }
00381 
00382 int KDEsuClient::stopServer()
00383 {
00384     return command("STOP\n");
00385 }
00386 
00387 static QString findDaemon()
00388 {
00389     QString daemon = KStandardDirs::locate("bin", "kdesud");
00390     if (daemon.isEmpty()) // if not in KDEDIRS, rely on PATH
00391     daemon = KStandardDirs::findExe("kdesud");
00392 
00393     if (daemon.isEmpty())
00394     {
00395     kWarning(900) << k_lineinfo << "daemon not found\n";
00396     }
00397     return daemon;
00398 }
00399 
00400 bool KDEsuClient::isServerSGID()
00401 {
00402     if (d->daemon.isEmpty())
00403        d->daemon = findDaemon();
00404     if (d->daemon.isEmpty())
00405        return false;
00406 
00407     KDE_struct_stat sbuf;
00408     if (KDE::stat(d->daemon, &sbuf) < 0)
00409     {
00410     kWarning(900) << k_lineinfo << "stat(): " << perror << "\n";
00411     return false;
00412     }
00413     return (sbuf.st_mode & S_ISGID);
00414 }
00415 
00416 int KDEsuClient::startServer()
00417 {
00418     if (d->daemon.isEmpty())
00419        d->daemon = findDaemon();
00420     if (d->daemon.isEmpty())
00421        return -1;
00422 
00423     if (!isServerSGID()) {
00424     kWarning(900) << k_lineinfo << "kdesud not setgid!\n";
00425     }
00426 
00427     // kdesud only forks to the background after it is accepting
00428     // connections.
00429     // We start it via kdeinit to make sure that it doesn't inherit
00430     // any fd's from the parent process.
00431     int ret = KToolInvocation::kdeinitExecWait(d->daemon);
00432     connect();
00433     return ret;
00434 }
00435 
00436 }

KDEsu

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal