1#!/usr/bin/python
2#
3#Copyright (c) 2006 Olivier Sessink
4#All rights reserved.
5#
6#Redistribution and use in source and binary forms, with or without
7#modification, are permitted provided that the following conditions
8#are met:
9#  * Redistributions of source code must retain the above copyright
10#	notice, this list of conditions and the following disclaimer.
11#  * Redistributions in binary form must reproduce the above
12#	copyright notice, this list of conditions and the following
13#	disclaimer in the documentation and/or other materials provided
14#	with the distribution.
15#  * The names of its contributors may not be used to endorse or
16#	promote products derived from this software without specific
17#	prior written permission.
18#
19#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28#LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29#ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30#POSSIBILITY OF SUCH DAMAGE.
31#
32
33from __future__ import print_function
34
35import os
36import getopt
37import sys
38import pwd
39import string
40
41users = {}
42
43def getpwuid_cached(uid):
44	if uid in users:
45		return users[uid]
46	else:
47		user = pwd.getpwuid(uid)
48		users[uid] = user
49		return user
50
51class ListResult:
52	pid = None
53	jail = None
54	exe = None
55	uid = None
56	username = None
57	cmdline = None
58
59
60	def __init__(self, pid):
61		self.pid = pid
62		sb = os.stat('/proc/'+pid)
63		self.uid = sb.st_uid
64		pwdret = getpwuid_cached(sb.st_uid)
65		self.username = pwdret[0]
66		self.jail = os.readlink('/proc/'+pid+'/root')
67		self.exe = os.readlink('/proc/'+pid+'/exe')
68		fd = open('/proc/'+pid+'/cmdline')
69		buf = fd.read(4096)
70		self.cmdline = ' '.join(buf.split('\0')[1:])
71		fd.close()
72
73	def __eq__(self, other):
74		return (self.jail == other.jail)
75
76	def __ne__(self, other):
77		return (self.jail == other.jail)
78
79	def __lt__(self, other):
80		return (self.jail < other.jail)
81
82	def __le__(self, other):
83		return (self.jail <= other.jail)
84
85	def __gt__(self, other):
86		return (self.jail > other.jail)
87
88	def __ge__(self, other):
89		return (self.jail >= other.jail)
90
91#	def __cmp__(self, other):
92#		ret = cmp(self.jail, other.jail)
93#		if(ret ==0):
94#			ret = cmp(self.uid, other.uid)
95#			if(ret ==0):
96#				ret = cmp(self.pid, other.pid)
97#		return ret
98
99	def optistr(self,usernamelen,jaillen,cmdlen):
100		formatstring = '%%-06s %%-0%ds %%-0%ds %%-0%ds' % (usernamelen,jaillen,cmdlen)
101		return formatstring % (self.pid, self.username[:usernamelen], self.jail[:jaillen], (self.exe+' '+self.cmdline)[:cmdlen])
102
103	def __str__(self):
104		return '%-06s %-05s %-011s %-019s %-019s' % (self.pid, self.username, self.jail, self.exe,self.cmdline)
105
106def printResults(results,wide):
107	if (len(results)==0):
108		print('No jailed processes found')
109		return
110	results.sort()
111	usernamelen=4 # User
112	jaillen=4 # Jail
113	cmdlen=7 #Command
114	for result in results:
115		usernamelen = max(usernamelen,len(result.username))
116		jaillen = max(jaillen,len(result.jail))
117		cmdlen = max(cmdlen,len(result.cmdline+' '+result.exe))
118
119	if (not wide):
120		cmdlen = min(cmdlen,80-5-usernamelen-jaillen-4)
121
122	titleformat =  '%%-06s %%-0%ds %%-0%ds %%-0%ds' % (usernamelen,jaillen,min(cmdlen,80-5-usernamelen-jaillen-4))
123	print(titleformat % ('Pid', 'User','Jail','Command'))
124	for result in results:
125		if (wide):
126			mycmdlen = len(result.cmdline+' '+result.exe)
127		else:
128			mycmdlen = cmdlen
129		print(result.optistr(usernamelen,jaillen,mycmdlen))
130
131
132def runList(verbose,jail):
133	# open /proc/
134	results = []
135	dirlist = os.listdir('/proc')
136	try:
137		for entry in dirlist:
138			if (entry.isdigit()):
139				# we have a process, now read the link root
140					ret = os.readlink('/proc/'+entry+'/root')
141					if (ret != '/'):
142						results.append(ListResult(entry))
143	except OSError as e:
144		if (e.errno == 13):
145			print('Permission denied')
146	return results
147
148def printusage():
149	print("jk_list, lists pocesses running in a chroot jail")
150	print("-h --help		print this message")
151	print("-j --jail=/path  list only processes in this jail")
152	print("-w --wide   print wide listing")
153
154def main():
155	try:
156		opts, args = getopt.getopt(sys.argv[1:], "hwj:", ['wide', "help", "jail"])
157	except getopt.GetoptError:
158		printusage()
159		sys.exit(1)
160	verbose = 0
161	jail = None
162	wide = 0
163	for o, a in opts:
164		if o in ("-h", "--help"):
165			printusage()
166			sys.exit()
167		if o in ("-j", "--jail"):
168			jail = a
169		if o in ("-v", "--verbose"):
170			verbose = 1
171		if o in ("-w", "--wide"):
172			wide = 1
173	results = runList(verbose,jail)
174	printResults(results,wide)
175
176if __name__ == "__main__":
177	main()
178