00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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
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
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
00126
00127
00128
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
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
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())
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
00429
00430
00431
00432 int ret = kapp->kdeinitExecWait(d->daemon);
00433 connect();
00434 return ret;
00435 }