[Kimchi-devel] [PATCH] sudo: run sudo with a pseudo controlling terminal

zhshzhou at linux.vnet.ibm.com zhshzhou at linux.vnet.ibm.com
Tue Mar 18 16:48:37 UTC 2014


From: Zhou Zheng Sheng <zhshzhou at linux.vnet.ibm.com>

In commit 456018a, we assign a TTY to kimchid in the SystemD service
file. This is because sudo requires a TTY by default for security
reason.

Usually Linux daemon detaches from controlling terminal so that it makes
use of the SIGHUP signal to reload its settings. If the daemon has a
console interface for the admin to interact (like a QEMU monitor), it
can have a TTY to run the console interface. At lease for now, Kimchi is
a traditional plain daemon that needs no TTY.

This patch creates a temporary PTY and assigns the slave to the sudo
process as the controlling terminal each time it runs sudo. In this way
we do not have to assign a TTY to kimchid. Maybe it's more portable than
specifying TTY in a SystemD service file.

Before running sudo, it creates a subprocess to make sure the child is
not the session leader. Then the child creates a new session and PYT,
and sets the slave as the controlling termial. At last the child calls
sudo. The result from the child is delivered to the parent via a shared
memory object.

Signed-off-by: Zhou Zheng Sheng <zhshzhou at linux.vnet.ibm.com>
---
 contrib/kimchid.service.fedora |  3 ---
 src/kimchi/auth.py             | 24 ++++++++++++++++++++----
 2 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/contrib/kimchid.service.fedora b/contrib/kimchid.service.fedora
index 5f274fb..7abe49b 100644
--- a/contrib/kimchid.service.fedora
+++ b/contrib/kimchid.service.fedora
@@ -8,9 +8,6 @@ Type=simple
 ExecStart=/usr/bin/kimchid
 ExecStop=/bin/kill -TERM $MAINPID
 EnvironmentFile=/etc/kimchi/kimchi.conf
-StandardInput=tty
-StandardOutput=tty
-TTYPath=/dev/tty11
 
 [Install]
 WantedBy=multi-user.target
diff --git a/src/kimchi/auth.py b/src/kimchi/auth.py
index b042d73..9f6f2f4 100644
--- a/src/kimchi/auth.py
+++ b/src/kimchi/auth.py
@@ -19,9 +19,14 @@
 
 import base64
 import cherrypy
+import fcntl
 import grp
+import multiprocessing
+import os
 import PAM
+import pty
 import re
+import termios
 import time
 
 
@@ -55,6 +60,18 @@ class User(object):
         return self.user[USER_GROUPS]
 
     def has_sudo(self):
+        result = multiprocessing.Value('i', 0, lock=False)
+        p = multiprocessing.Process(target=self._has_sudo, args=(result,))
+        p.start()
+        p.join()
+        self.user[USER_SUDO] = bool(result.value)
+        return self.user[USER_SUDO]
+
+    def _has_sudo(self, result):
+        _master, slave = pty.openpty()
+        os.setsid()
+        fcntl.ioctl(slave, termios.TIOCSCTTY, 0)
+
         out, err, exit = run_command(['sudo', '-l', '-U', self.user[USER_ID],
                                       'sudo'])
         if exit == 0:
@@ -67,15 +84,14 @@ class User(object):
                                           self.user[USER_ID]])
             for line in out.split('\n'):
                 if line and re.search("(ALL)", line):
-                    self.user[USER_SUDO] = True
+                    result.value = 1
                     debug("User %s can run any command with sudo" %
-                          self.user[USER_ID])
-                    return self.user[USER_SUDO]
+                          result.value)
+                    return
             debug("User %s can only run some commands with sudo" %
                   self.user[USER_ID])
         else:
             debug("User %s is not allowed to run sudo" % self.user[USER_ID])
-        return self.user[USER_SUDO]
 
     def get_user(self):
         return self.user
-- 
1.8.5.3




More information about the Kimchi-devel mailing list