not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kcontrol / kfontinst / kio / Socket.cpp
blob0d894545b3cd5e3861ecd6adcb3f852da058e5fe
1 /*
2 * KFontInst - KDE Font Installer
4 * Copyright 2003-2007 Craig Drummond <craig@kde.org>
6 * ----
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; see the file COPYING. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
25 // This file contains code taken from kdelibs/kdesu/client.cpp
28 #include "Socket.h"
30 #include <stdio.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/un.h>
38 #include <sys/stat.h>
39 #include <QtCore/QByteArray>
40 #include <config-workspace.h>
41 #include <KDE/KDebug>
42 #include <kde_file.h>
44 #ifndef SUN_LEN
45 #define SUN_LEN(ptr) ((socklen_t) (((struct sockaddr_un *) 0)->sun_path) \
46 + strlen ((ptr)->sun_path))
47 #endif
49 namespace KFI
52 CSocket::CSocket(int fd)
53 : itsFd(fd)
57 CSocket::~CSocket()
59 if (itsFd>=0)
60 ::close(itsFd);
63 bool CSocket::read(QVariant &var, int timeout)
65 if(itsFd<0)
66 return false;
68 int type;
70 if(readBlock((char *)&type, sizeof(type), timeout))
72 switch(type)
74 case QVariant::Int:
76 int val;
77 if(readBlock((char *)(&val), sizeof(int), timeout))
79 var=QVariant(val);
80 return true;
82 break;
84 case QVariant::ULongLong:
86 qulonglong val;
87 if(readBlock((char *)(&val), sizeof(qulonglong), timeout))
89 var=QVariant(val);
90 return true;
92 break;
94 case QVariant::Bool:
96 unsigned char val;
97 if(readBlock((char *)(&val), sizeof(unsigned char), timeout))
99 var=QVariant((bool)val);
100 return true;
102 break;
104 case QVariant::String:
106 int len;
108 if(readBlock((char *)&len, sizeof(unsigned int), timeout))
110 QByteArray data(len, '\0');
112 if(readBlock(data.data(), len, timeout))
114 var=QVariant(QString::fromUtf8(data));
115 return true;
118 break;
120 default:
124 return false;
127 bool CSocket::read(QString &str, int timeout)
129 QVariant var;
131 if(read(var, timeout) && QVariant::String==var.type())
133 str=var.toString();
134 return true;
137 return false;
140 bool CSocket::read(int &i, int timeout)
142 QVariant var;
144 if(read(var, timeout) && QVariant::Int==var.type())
146 i=var.toInt();
147 return true;
150 return false;
153 bool CSocket::read(qulonglong &i, int timeout)
155 QVariant var;
157 if(read(var, timeout) && QVariant::ULongLong==var.type())
159 i=var.toULongLong();
160 return true;
163 return false;
166 bool CSocket::read(bool &b, int timeout)
168 QVariant var;
170 if(read(var, timeout) && QVariant::Bool==var.type())
172 b=var.toBool();
173 return true;
176 return false;
179 bool CSocket::write(const QVariant &var, int timeout)
181 if(itsFd<0)
182 return false;
184 int type(var.type());
186 switch(type)
188 case QVariant::Int:
190 int val(var.toInt());
191 return writeBlock((const char *)(&type), sizeof(int), timeout) &&
192 writeBlock((const char *)(&val), sizeof(int), timeout);
194 case QVariant::ULongLong:
196 qulonglong val(var.toInt());
197 return writeBlock((const char *)(&type), sizeof(int), timeout) &&
198 writeBlock((const char *)(&val), sizeof(qulonglong), timeout);
200 case QVariant::Bool:
202 unsigned char val(var.toBool());
204 return writeBlock((const char *)(&type), sizeof(int), timeout) &&
205 writeBlock((const char *)(&val), sizeof(unsigned char), timeout);
206 break;
208 case QVariant::String:
210 QByteArray data(var.toString().toUtf8());
211 int len(data.size());
213 return writeBlock((const char *)(&type), sizeof(int), timeout) &&
214 writeBlock((const char *)(&len), sizeof(int), timeout) &&
215 writeBlock(data.constData(), len, timeout);
216 break;
218 default:
222 return false;
225 bool CSocket::connectToServer(const QByteArray &sock, unsigned int socketUid)
227 if (itsFd >= 0)
228 ::close(itsFd);
229 itsFd=-1;
230 if (access(sock, R_OK|W_OK))
231 return false;
233 itsFd =::socket(PF_UNIX, SOCK_STREAM, 0);
234 if (itsFd < 0)
236 kWarning() << k_lineinfo << "socket(): " << errno ;
237 return false;
239 struct sockaddr_un addr;
240 addr.sun_family = AF_UNIX;
241 strcpy(addr.sun_path, sock);
243 if (::connect(itsFd, (struct sockaddr *) &addr, SUN_LEN(&addr)) < 0)
245 kWarning() << k_lineinfo << "connect():" << errno ;
246 ::close(itsFd);
247 itsFd = -1;
248 return false;
251 #if !defined(SO_PEERCRED) || !defined(HAVE_STRUCT_UCRED)
252 # if defined(HAVE_GETPEEREID)
253 uid_t euid;
254 gid_t egid;
255 // Security: if socket exists, we must own it
256 if (getpeereid(itsFd, &euid, &egid) == 0)
258 if (euid != socketUid)
260 kWarning(900) << "socket not owned by me! socket uid = " << euid;
261 ::close(itsFd);
262 itsFd = -1;
263 return -1;
266 # else
267 # ifdef __GNUC__
268 # warning "Using sloppy security checks"
269 # endif
270 // We check the owner of the socket after we have connected.
271 // If the socket was somehow not ours an attacker will be able
272 // to delete it after we connect but shouldn't be able to
273 // create a socket that is owned by us.
274 KDE_struct_stat s;
275 if (KDE_lstat(sock, &s)!=0)
277 kWarning(900) << "stat failed (" << sock << ")";
278 ::close(itsFd);
279 itsFd = -1;
280 return false;
282 if (s.st_uid != socketUid)
284 kWarning(900) << "socket not owned by me! socket uid = " << s.st_uid;
285 ::close(itsFd);
286 itsFd = -1;
287 return false;
289 if (!S_ISSOCK(s.st_mode))
291 kWarning(900) << "socket is not a socket (" << sock << ")";
292 ::close(itsFd);
293 itsFd = -1;
294 return false;
296 # endif
297 #else
298 struct ucred cred;
299 socklen_t siz = sizeof(cred);
301 // Security: if socket exists, we must own it
302 if (getsockopt(itsFd, SOL_SOCKET, SO_PEERCRED, &cred, &siz) == 0)
304 if (cred.uid != socketUid)
306 kWarning(900) << "socket not owned by me! socket uid = " << cred.uid;
307 ::close(itsFd);
308 itsFd = -1;
309 return false;
312 #endif
314 return true;
317 bool CSocket::readBlock(char *data, int size, int timeout)
319 int bytesToRead=size;
323 if(waitForReadyRead(timeout))
325 int bytesRead=::read(itsFd, &data[size-bytesToRead], bytesToRead);
327 if (bytesRead>0)
328 bytesToRead-=bytesRead;
329 else
330 return false;
332 else
333 return false;
335 while(bytesToRead>0);
337 return true;
340 bool CSocket::writeBlock(const char *data, int size, int timeout)
342 int bytesToWrite=size;
346 if(waitForReadyWrite(timeout))
348 int bytesWritten=::write(itsFd, (char *)&data[size-bytesToWrite], bytesToWrite);
350 if (bytesWritten>0)
351 bytesToWrite-=bytesWritten;
352 else
353 return false;
355 else
356 return false;
358 while(bytesToWrite>0);
360 return true;
363 bool CSocket::waitForReadyRead(int timeout)
365 fd_set fdSet;
366 struct timeval tv;
368 FD_ZERO(&fdSet);
369 FD_SET(itsFd, &fdSet);
370 tv.tv_sec = timeout;
371 tv.tv_usec = 0;
373 for(;;)
374 if(select(itsFd + 1, &fdSet, NULL, NULL, -1==timeout ? NULL : &tv)<0)
376 if(errno == EINTR)
377 continue;
378 else
379 return false;
381 else
382 return FD_ISSET(itsFd, &fdSet);
384 return false;
387 bool CSocket::waitForReadyWrite(int timeout)
389 fd_set fdSet;
390 struct timeval tv;
392 FD_ZERO(&fdSet);
393 FD_SET(itsFd, &fdSet);
394 tv.tv_sec = timeout;
395 tv.tv_usec = 0;
397 for(;;)
398 if(select(itsFd + 1, NULL, &fdSet, NULL, -1==timeout ? NULL : &tv)<0)
400 if(errno == EINTR)
401 continue;
402 else
403 return false;
405 else
406 return FD_ISSET(itsFd, &fdSet);
408 return false;