summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNecoro <>2007-10-15 08:54:54 +0000
committerNecoro <>2007-10-15 08:54:54 +0000
commitac3b08b33934c247345673bb8c746ffda17b5a60 (patch)
treecf2985f51e890831189f2dcfc11c27f1b20b64da
parentd14f493eaef54c9120d9c24951d82c45a0b51f44 (diff)
downloadportato-ac3b08b33934c247345673bb8c746ffda17b5a60.tar.gz
portato-ac3b08b33934c247345673bb8c746ffda17b5a60.tar.bz2
portato-ac3b08b33934c247345673bb8c746ffda17b5a60.zip
use anonymous pipe instead of socket -- fixes security issue
-rwxr-xr-xportato.py52
-rw-r--r--portato/constants.py9
-rw-r--r--portato/plistener.py53
3 files changed, 51 insertions, 63 deletions
diff --git a/portato.py b/portato.py
index 765e070..93fc88e 100755
--- a/portato.py
+++ b/portato.py
@@ -14,7 +14,7 @@
from __future__ import with_statement, absolute_import
-import sys, os
+import sys, os, subprocess
import gettext, locale
from optparse import OptionParser
@@ -47,6 +47,9 @@ def main ():
parser.add_option("-e", "--ebuild", action = "store", dest = "ebuild",
help = _("opens the ebuild viewer instead of launching Portato"))
+ parser.add_option("-p", "--pipe", action = "store", dest = "pipe",
+ help = _("file descriptor to use to communicate with the listener (internal use only)"))
+
parser.add_option("-x", "--validate", action = "store", dest = "validate", metavar="PLUGIN",
help = _("validates the given plugin xml instead of launching Portato"))
@@ -58,7 +61,7 @@ def main ():
# evaluate parser's results
if options.check: # run pychecker
- os.environ['PYCHECKER'] = "--limit 50"
+ os.environ['PYCHECKER'] = "--limit 100"
import pychecker.checker
if len(args): # additional arguments overwrite given frontend
@@ -75,9 +78,9 @@ def main ():
print _("'%(frontend)s' should be installed, but cannot be imported. This is definitly a bug. (%(error)s)") % {"frontend": options.frontend, "error": e[0]}
sys.exit(1)
- if options.ebuild:
+ if options.ebuild: # show ebuild
show_ebuild(options.ebuild)
- elif options.validate:
+ elif options.validate: # validate a plugin
from lxml import etree
try:
etree.XMLSchema(file = XSD_LOCATION).assertValid(etree.parse(options.validate))
@@ -90,25 +93,30 @@ def main ():
else:
print _("Validation succeeded.")
return
- elif options.nolistener or os.getuid() == 0:
- listener.set_send()
+
+ elif options.nolistener or os.getuid() == 0: # start GUI
+ if options.pipe:
+ listener.set_send(int(options.pipe))
+ else:
+ listener.set_send()
+
run()
- else: # start listener and start us again in root modus
- pid = os.fork()
- if pid == 0: # start portato in child
- additional = []
- if options.check:
- additional.append("-c")
- if options.frontend:
- additional.extend(["-f", options.frontend])
-
- cmd = SU_COMMAND.split()
- env = os.environ.copy()
- env.update(DBUS_SESSION_BUS_ADDRESS="")
- os.execvpe(cmd[0], cmd+["%s --no-listener %s" % (sys.argv[0], " ".join(additional))], env = env)
-
- else: # start listener
- listener.set_recv()
+
+ else: # start us again in root modus and launch listener
+ read, write = os.pipe()
+ additional = []
+ if options.check:
+ additional.append("--check")
+ if options.frontend:
+ additional.extend(["--frontend", options.frontend])
+
+ # set DBUS_SESSION_BUS_ADDRESS to "" to make dbus work as root ;)
+ env = os.environ.copy()
+ env.update(DBUS_SESSION_BUS_ADDRESS="")
+ cmd = SU_COMMAND.split()
+ subprocess.Popen(cmd+["%s --no-listener --pipe %d %s" % (sys.argv[0], write, " ".join(additional))], env = env, close_fds = False)
+
+ listener.set_recv(read)
if __name__ == "__main__":
main()
diff --git a/portato/constants.py b/portato/constants.py
index d871e78..3aea05d 100644
--- a/portato/constants.py
+++ b/portato/constants.py
@@ -40,8 +40,6 @@ These should be set during the installation.
@type STD_FRONTEND: string
@var SU_COMMAND: command to execute to "su"
@type SU_COMMAND: string
-@var SOCKET: path to socket for communication between listener and GUI
-@type SOCKET: string
"""
import os
from os.path import join as pjoin
@@ -56,6 +54,8 @@ SETTINGS_DIR = pjoin(HOME, "."+APP)
CONFIG_DIR = "/etc/portato/"
CONFIG_LOCATION = pjoin(CONFIG_DIR, "portato.cfg")
+VAR_DIR = "/var/portato/"
+
DATA_DIR = "portato/gui/templates/"
PLUGIN_DIR = "plugins/"
@@ -67,10 +67,9 @@ APP_ICON = pjoin(ICON_DIR, "portato-icon.png")
LOCALE_DIR = "i18n/"
-FRONTENDS = ["gtk" ,"qt"]
+FRONTENDS = ["gtk"]
STD_FRONTEND = "gtk"
SU_COMMAND = "gksu -D 'Portato'"
-SOCKET = "/tmp/portato.socket"
-USE_CATAPULT = False
+USE_CATAPULT = True
diff --git a/portato/plistener.py b/portato/plistener.py
index 452bee6..a24a262 100644
--- a/portato/plistener.py
+++ b/portato/plistener.py
@@ -21,7 +21,7 @@ try:
except ImportError:
pynotify = None
-from .constants import SOCKET, APP
+from .constants import APP
from .helper import debug, warning
class PListener (object):
@@ -29,29 +29,17 @@ class PListener (object):
This listener starts programs as the user while the GUI runs as root.
@ivar _recv: listener socket
- @type _recv: socket.socket
+ @type _recv: int
@ivar _send: sender socket
- @type _send: socket.socket"""
+ @type _send: int"""
- def set_recv (self):
- self._recv = socket.socket(socket.AF_UNIX)
+ def set_recv (self, pipe):
+ self._recv = pipe
- try:
- self._recv.bind(SOCKET)
- except socket.error, e:
- if int(e[0]) == 98: # already existing - delete
- os.unlink(SOCKET)
- self._recv.bind(SOCKET)
- else:
- raise
-
- self._recv.listen(1)
- con, addr = self._recv.accept()
-
while True:
try:
- len = con.recv(4)
- string = con.recv(int(len))
+ len = os.read(self._recv, 4)
+ string = os.read(self._recv, int(len))
data = string.split("\0")
@@ -62,10 +50,9 @@ class PListener (object):
elif data[0] == "close":
break
except KeyboardInterrupt:
- pass
+ break
- con.close()
- self._recv.close()
+ os.close(self._recv)
def do_cmd (self, cmdlist):
"""Starts a command as the user.
@@ -87,20 +74,15 @@ class PListener (object):
n.set_urgency(int(urgency))
n.show()
- def set_send (self):
- self._send = socket.socket(socket.AF_UNIX)
- try:
- self._send.connect(SOCKET)
- except socket.error, e:
- if e[0] in [111, 2]: # can't connect
- warning(_("Listener has not been started."))
- self._send = None
- else:
- raise
+ def set_send (self, pipe = None):
+ if pipe is None:
+ warning(_("Listener has not been started."))
+
+ self._send = pipe
def __send (self, string):
- self._send.sendall("%4d" % len(string))
- self._send.sendall(string)
+ os.write(self._send, "%4d" % len(string))
+ os.write(self._send, string)
def send_notify (self, base = "", descr = "", icon = "", urgency = None):
if self._send is None:
@@ -124,5 +106,4 @@ class PListener (object):
def close (self):
if self._send is not None:
self.__send("close")
- self._send.close()
- os.unlink(SOCKET)
+ os.close(self._send)