Commit f93f2016 authored by Michael Hanselmann's avatar Michael Hanselmann
Browse files

masterd: Log PID, UID and GID of connected client



This can be very useful if client programs run as non-root.
Signed-off-by: default avatarMichael Hanselmann <hansmi@google.com>
Reviewed-by: default avatarGuido Trotter <ultrotter@google.com>
parent a62d1901
......@@ -108,8 +108,15 @@ class IOServer(SocketServer.UnixStreamServer):
"""Add task to workerpool to process request.
"""
(pid, uid, gid) = utils.GetSocketCredentials(request)
logging.info("Accepted connection from pid=%s, uid=%s, gid=%s",
pid, uid, gid)
self.request_workers.AddTask(self, request, client_address)
def handle_error(self, request, client_address):
logging.exception("Error while handling request")
@utils.SignalHandled([signal.SIGINT, signal.SIGTERM])
def serve_forever(self, signal_handlers=None): # pylint: disable-msg=W0221
"""Handle one request at a time until told to quit."""
......
......@@ -46,6 +46,8 @@ import signal
import datetime
import calendar
import collections
import struct
import IN
from cStringIO import StringIO
......@@ -69,6 +71,18 @@ no_fork = False
_RANDOM_UUID_FILE = "/proc/sys/kernel/random/uuid"
# Structure definition for getsockopt(SOL_SOCKET, SO_PEERCRED, ...):
# struct ucred { pid_t pid; uid_t uid; gid_t gid; };
#
# The GNU C Library defines gid_t and uid_t to be "unsigned int" and
# pid_t to "int".
#
# IEEE Std 1003.1-2008:
# "nlink_t, uid_t, gid_t, and id_t shall be integer types"
# "blksize_t, pid_t, and ssize_t shall be signed integer types"
_STRUCT_UCRED = "iII"
_STRUCT_UCRED_SIZE = struct.calcsize(_STRUCT_UCRED)
class RunResult(object):
"""Holds the result of running external programs.
......@@ -328,6 +342,19 @@ def RunParts(dir_name, env=None, reset_env=False):
return rr
def GetSocketCredentials(sock):
"""Returns the credentials of the foreign process connected to a socket.
@param sock: Unix socket
@rtype: tuple; (number, number, number)
@return: The PID, UID and GID of the connected foreign process.
"""
peercred = sock.getsockopt(socket.SOL_SOCKET, IN.SO_PEERCRED,
_STRUCT_UCRED_SIZE)
return struct.unpack(_STRUCT_UCRED, peercred)
def RemoveFile(filename):
"""Remove a file ignoring some errors.
......
......@@ -44,6 +44,7 @@ import testutils
from ganeti import constants
from ganeti import utils
from ganeti import errors
from ganeti import serializer
from ganeti.utils import IsProcessAlive, RunCmd, \
RemoveFile, MatchNameComponent, FormatUnit, \
ParseUnit, AddAuthorizedKey, RemoveAuthorizedKey, \
......@@ -910,6 +911,73 @@ class TestOwnIpAddress(unittest.TestCase):
self.failIf(OwnIpAddress(DST_IP), "Should not own IP address %s" % DST_IP)
def _GetSocketCredentials(path):
"""Connect to a Unix socket and return remote credentials.
"""
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
sock.settimeout(10)
sock.connect(path)
return utils.GetSocketCredentials(sock)
finally:
sock.close()
class TestGetSocketCredentials(unittest.TestCase):
def setUp(self):
self.tmpdir = tempfile.mkdtemp()
self.sockpath = utils.PathJoin(self.tmpdir, "sock")
self.listener = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
self.listener.settimeout(10)
self.listener.bind(self.sockpath)
self.listener.listen(1)
def tearDown(self):
self.listener.shutdown(socket.SHUT_RDWR)
self.listener.close()
shutil.rmtree(self.tmpdir)
def test(self):
(c2pr, c2pw) = os.pipe()
# Start child process
child = os.fork()
if child == 0:
try:
data = serializer.DumpJson(_GetSocketCredentials(self.sockpath))
os.write(c2pw, data)
os.close(c2pw)
os._exit(0)
finally:
os._exit(1)
os.close(c2pw)
# Wait for one connection
(conn, _) = self.listener.accept()
conn.recv(1)
conn.close()
# Wait for result
result = os.read(c2pr, 4096)
os.close(c2pr)
# Check child's exit code
(_, status) = os.waitpid(child, 0)
self.assertFalse(os.WIFSIGNALED(status))
self.assertEqual(os.WEXITSTATUS(status), 0)
# Check result
(pid, uid, gid) = serializer.LoadJson(result)
self.assertEqual(pid, os.getpid())
self.assertEqual(uid, os.getuid())
self.assertEqual(gid, os.getgid())
class TestListVisibleFiles(unittest.TestCase):
"""Test case for ListVisibleFiles"""
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment