2014-02-14 14:42:19 -08:00
|
|
|
#! /usr/bin/env python
|
2013-09-28 20:43:06 +05:30
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
|
|
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or
|
|
|
|
# modify it under the terms of version 2 of the GNU General Public
|
|
|
|
# License as published by the Free Software Foundation.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# ----------------------------------------------------------------------
|
2013-08-26 00:23:59 +05:30
|
|
|
import argparse
|
2013-08-21 11:26:09 +05:30
|
|
|
import os
|
|
|
|
import re
|
2013-09-26 18:41:41 +05:30
|
|
|
import sys
|
2013-08-21 11:26:09 +05:30
|
|
|
|
2014-02-27 14:53:25 -08:00
|
|
|
import apparmor.aa as aa
|
|
|
|
import apparmor.ui as ui
|
|
|
|
import apparmor.common
|
2013-08-21 11:26:09 +05:30
|
|
|
|
2014-02-10 22:15:05 -08:00
|
|
|
# setup module translations
|
2014-02-11 16:23:21 -08:00
|
|
|
from apparmor.translations import init_translation
|
|
|
|
_ = init_translation()
|
2014-02-10 22:15:05 -08:00
|
|
|
|
2013-12-20 03:12:58 +05:30
|
|
|
parser = argparse.ArgumentParser(description=_("Lists unconfined processes having tcp or udp ports"))
|
|
|
|
parser.add_argument("--paranoid", action="store_true", help=_("scan all processes from /proc"))
|
2013-08-21 11:26:09 +05:30
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
paranoid = args.paranoid
|
|
|
|
|
2014-02-27 14:53:25 -08:00
|
|
|
aa_mountpoint = aa.check_for_apparmor()
|
2013-08-21 11:26:09 +05:30
|
|
|
if not aa_mountpoint:
|
2014-02-27 14:53:25 -08:00
|
|
|
raise aa.AppArmorException(_("It seems AppArmor was not started. Please enable AppArmor and try again."))
|
2013-08-21 11:26:09 +05:30
|
|
|
|
|
|
|
pids = []
|
|
|
|
if paranoid:
|
2014-02-27 14:53:25 -08:00
|
|
|
pids = list(filter(lambda x: re.search(r"^\d+$", x), aa.get_subdirectories("/proc")))
|
2013-08-21 11:26:09 +05:30
|
|
|
else:
|
2013-12-20 03:12:58 +05:30
|
|
|
regex_tcp_udp = re.compile(r"^(tcp|udp)\s+\d+\s+\d+\s+\S+\:(\d+)\s+\S+\:(\*|\d+)\s+(LISTEN|\s+)\s+(\d+)\/(\S+)")
|
2013-09-20 19:20:41 +05:30
|
|
|
import subprocess
|
2013-12-20 03:12:58 +05:30
|
|
|
if sys.version_info < (3, 0):
|
|
|
|
output = subprocess.check_output("LANG=C netstat -nlp", shell=True).split("\n")
|
2013-09-26 18:41:41 +05:30
|
|
|
else:
|
|
|
|
#Python3 needs to translate a stream of bytes to string with specified encoding
|
2013-12-20 03:12:58 +05:30
|
|
|
output = str(subprocess.check_output("LANG=C netstat -nlp", shell=True), encoding='utf8').split("\n")
|
2013-09-22 22:51:30 +05:30
|
|
|
|
2013-08-21 11:26:09 +05:30
|
|
|
for line in output:
|
|
|
|
match = regex_tcp_udp.search(line)
|
|
|
|
if match:
|
|
|
|
pids.append(match.groups()[4])
|
|
|
|
# We can safely remove duplicate pid's?
|
2013-12-20 03:12:58 +05:30
|
|
|
pids = list(map(int, set(pids)))
|
2013-08-21 11:26:09 +05:30
|
|
|
|
|
|
|
for pid in sorted(pids):
|
|
|
|
try:
|
2013-12-20 03:12:58 +05:30
|
|
|
prog = os.readlink("/proc/%s/exe"%pid)
|
2013-12-29 15:12:30 +05:30
|
|
|
except OSError:
|
2013-08-21 11:26:09 +05:30
|
|
|
continue
|
|
|
|
attr = None
|
2013-12-20 03:12:58 +05:30
|
|
|
if os.path.exists("/proc/%s/attr/current"%pid):
|
2014-02-27 14:53:25 -08:00
|
|
|
with aa.open_file_read("/proc/%s/attr/current"%pid) as current:
|
2013-08-21 11:26:09 +05:30
|
|
|
for line in current:
|
2013-12-20 03:12:58 +05:30
|
|
|
if line.startswith("/") or line.startswith("null"):
|
2013-08-21 11:26:09 +05:30
|
|
|
attr = line.strip()
|
2013-09-22 22:51:30 +05:30
|
|
|
|
2014-02-27 14:53:25 -08:00
|
|
|
cmdline = apparmor.common.cmd(["cat", "/proc/%s/cmdline"%pid])[1]
|
2013-12-20 03:12:58 +05:30
|
|
|
pname = cmdline.split("\0")[0]
|
2013-08-21 11:26:09 +05:30
|
|
|
if '/' in pname and pname != prog:
|
2013-12-20 03:12:58 +05:30
|
|
|
pname = "(%s)"% pname
|
2013-08-21 11:26:09 +05:30
|
|
|
else:
|
2013-12-20 03:12:58 +05:30
|
|
|
pname = ""
|
|
|
|
regex_interpreter = re.compile(r"^(/usr)?/bin/(python|perl|bash|dash|sh)$")
|
2013-08-21 11:26:09 +05:30
|
|
|
if not attr:
|
2013-08-30 03:54:31 +05:30
|
|
|
if regex_interpreter.search(prog):
|
2013-12-20 03:12:58 +05:30
|
|
|
cmdline = re.sub(r"\x00", " ", cmdline)
|
|
|
|
cmdline = re.sub(r"\s+$", "", cmdline).strip()
|
2013-08-30 03:54:31 +05:30
|
|
|
|
2014-02-27 14:53:25 -08:00
|
|
|
ui.UI_Info(_("%s %s (%s) not confined")%(pid, prog, cmdline))
|
2013-08-21 11:26:09 +05:30
|
|
|
else:
|
|
|
|
if pname and pname[-1] == ')':
|
|
|
|
pname += ' '
|
2014-02-27 14:53:25 -08:00
|
|
|
ui.UI_Info(_("%s %s %snot confined")%(pid, prog, pname))
|
2013-08-21 11:26:09 +05:30
|
|
|
else:
|
2013-08-30 03:54:31 +05:30
|
|
|
if regex_interpreter.search(prog):
|
2013-12-20 03:12:58 +05:30
|
|
|
cmdline = re.sub(r"\0", " ", cmdline)
|
|
|
|
cmdline = re.sub(r"\s+$", "", cmdline).strip()
|
2014-02-27 14:53:25 -08:00
|
|
|
ui.UI_Info(_("%s %s (%s) confined by '%s'")%(pid, prog, cmdline, attr))
|
2013-08-21 11:26:09 +05:30
|
|
|
else:
|
|
|
|
if pname and pname[-1] == ')':
|
|
|
|
pname += ' '
|
2014-02-27 14:53:25 -08:00
|
|
|
ui.UI_Info(_("%s %s %sconfined by '%s'")%(pid, prog, pname, attr))
|