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

KDEsu

client.cpp

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

KDEsu

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

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
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