aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Bersenev <bay@hackerdom.ru>2011-08-03 23:55:50 +0000
committerAlexander Bersenev <bay@hackerdom.ru>2011-08-03 23:55:50 +0000
commitf04c87bf5470eb417d76e0e97ccf3374da0fa4f3 (patch)
tree95ba1c3e628b866d0eb51c24eefc821b13d023b3
parentsmall docs changes (diff)
downloadautodep-f04c87bf5470eb417d76e0e97ccf3374da0fa4f3.tar.gz
autodep-f04c87bf5470eb417d76e0e97ccf3374da0fa4f3.tar.bz2
autodep-f04c87bf5470eb417d76e0e97ccf3374da0fa4f3.zip
fusefs: hiding blocked files in directory listings, tests updated
-rwxr-xr-x[-rw-r--r--]src/autodep/autodep192
-rw-r--r--src/autodep/logfs/fstracer.py2
-rw-r--r--src/autodep/package_utils/portage_misc_functions.py6
-rw-r--r--src/autodep/tests/test_fusefs.py33
-rw-r--r--src/autodep/tests/test_hookfs.py30
-rw-r--r--src/hook_fusefs/hookfs.c26
6 files changed, 213 insertions, 76 deletions
diff --git a/src/autodep/autodep b/src/autodep/autodep
index 518eed8..45f4a5b 100644..100755
--- a/src/autodep/autodep
+++ b/src/autodep/autodep
@@ -17,14 +17,21 @@ def parse_args():
"""
args_parser=optparse.OptionParser("%prog [options] <command>")
- args_parser.add_option("-b", "--block",action="store", type="string",
+ args_parser.add_option("-b","--block",action="store_true",
+ dest="strict_block", default="",
+ help="strict mode: deny all access to non-dependency packages")
+ args_parser.add_option("--blockpkgs",action="store", type="string",
dest="packages", default="",
help="block an access to files from this packages")
args_parser.add_option("-f","--files", action="store_true", dest="show_files",
- default=False, help="show accessed files and not founded files")
+ default=False, help="show all accessed files and not founded files")
args_parser.add_option("-v","--verbose", action="store_true", dest="verbose",
default=False, help="show non-important packages, "
"show unknown package and unknown stage")
+ args_parser.add_option("-n","--numfiles",action="store", type="string",
+ dest="numfiles",
+ default=10,
+ help="maximum number of files from each package to show(default is 10)")
args_parser.add_option("-C","--nocolor",action="store_true", dest="nocolor",
default=False, help="don't output color")
@@ -43,49 +50,114 @@ def parse_args():
return options,args
-portage_api=portage_misc_functions.portage_api()
-system_packages = portage_api.get_system_packages_list()
-
-runtime_vars={} # This is here mainly for grouping. We are trying to
- # get as much data about an environment as possible
-runtime_vars["starttime"]=int(time.time())
-#print package_utils.portage_log_parser.get_list_of_merged_packages(1244256830)
-
-#quit(1)
+def init_environment():
+ portage_api=portage_misc_functions.portage_api()
+ system_packages = portage_api.get_system_packages_list()
+
+ return portage_api, system_packages
+
+def init_runtime_vars(options,args):
+ runtime_vars={} # This is here mainly for grouping. We are trying to
+ # get as much data about an environment as possible
+
+ runtime_vars["starttime"]=int(time.time())
+
+ # trivial check for emerge proccess
+ if args[0]=="emerge":
+ runtime_vars["is_emerge"]=True
+ emergeaction ,emergeopts, emergefiles=portage_api.parse_emerge_args(args[1:])
+ runtime_vars["raw_emerge_parameters"]=args[1:]
+ runtime_vars["emerge_parameters"]=(emergeaction ,emergeopts, emergefiles)
+ if len(emergefiles)>1:
+ print "Please, install packages one by one to get more accurate reports"
+ else:
+ runtime_vars["is_emerge"]=False
+
+ return runtime_vars
+
+def get_filter_function(options,system_packages,portage_api):
+ # handling --block
+ # exits if package name is bad
+ if not options.packages and not options.strict_block:
+ return lambda eventname,filename,stage: True
+ elif not options.strict_block and options.packages:
+ packages=options.packages.split(",")
+ files_to_block=[]
+ for package in packages:
+ files_in_package=portage_utils.getfilesbypackage(package)
+ if len(files_in_package)==0:
+ print "Bad package name: %s. Exiting" % package
+ exit(1)
+ files_to_block+=files_in_package
+ files_to_block={}.fromkeys(files_to_block)
+ # new filter function
+ def filter(eventname,filename,stage):
+ return not filename in files_to_block
+ return filter
+ elif options.strict_block and options.packages:
+ print "You can't use --block and --blockpkgs options togeter\n"
+ exit(1)
+ elif options.strict_block: # this option is very strict
+ # because blocking logic is complex
+ print "Building a list of files to block. This may take some time"
+ # we get list of all files and substract list of allowed files from it
+ allfiles=portage_utils.get_all_packages_files()
+ allowedpkgs=[]
+ allowedpkgs+=system_packages
+ if runtime_vars["is_emerge"]: # blocking logic for emerge
+ (emergeaction ,emergeopts, emergefiles)=runtime_vars["emerge_parameters"]
+ if len(emergefiles)>1:
+ print "You can't install several packages with option -b"
+ exit(1)
+ mergelist=portage_api.get_merge_list(runtime_vars["raw_emerge_parameters"])
+ if len(mergelist)!=1:
+ print "You can't install several packages with option -b"
+ print "Emerge tried to install several packages: %s" % mergelist
+ print "You can force emerge to merge a package without any other " \
+ "packages with emerge --nodeps option or you can install these " \
+ "packages first"
+
+ exit(1)
+ pkg=mergelist[0]
+ depslist=list(portage_api.get_deps(pkg))
+ allowedpkgs+=depslist
+ else:
+ pass # TODO: blocking logic for non-emerge proccesses
+ # always include current python interpreter
+ #print allowedpkgs
+ #allowedpkgs+=portage_utils.getpackagesbyfiles(sys.executable)
+ #print allowedpkgs
+
+ allowedfiles=[]
+ for pkg in allowedpkgs:
+ allowedfiles+=portage_utils.getfilesbypackage(pkg)
+ # manually add all python interpreters to this list
+ allowedfiles+=portage_utils.getfilesbypackage('python')
+ # manually add sandbox to this list
+ allowedfiles+=portage_utils.getfilesbypackage('sandbox')
+
+ allowedfiles=set(allowedfiles)
+
+ deniedfiles=allfiles-allowedfiles
+
+
+ print "The list size is about %dM" % (int(sys.getsizeof(deniedfiles))/1024/1024)
+ def filter(eventname,filename,stage):
+ if filename in deniedfiles:
+ return False
+ return True
+ return filter
+
+
+
+portage_api, system_packages=init_environment()
options,args=parse_args()
-
+runtime_vars=init_runtime_vars(options,args)
color_printer=colorize_output.color_printer(not options.nocolor)
-
-if args[0]=="emerge":
- runtime_vars["is_emerge"]=True
- emergeaction ,emergeopts, emergefiles=portage_api.parse_emerge_args(args[1:])
- runtime_vars["emerge_parameters"]=(emergeaction ,emergeopts, emergefiles)
- if len(emergefiles)>1:
- print "Please, install packages one by one to get more accurate reports"
-else:
- runtime_vars["is_emerge"]=False
-
-
-filter_function=lambda eventname,filename,stage: True
-
-# handling --block
-if options.packages:
- packages=options.packages.split(",")
- files_to_block=[]
- for package in packages:
- files_in_package=portage_utils.getfilesbypackage(package)
- if len(files_in_package)==0:
- print "Bad package name: %s. Exiting" % package
- exit(1)
- files_to_block+=files_in_package
- files_to_block={}.fromkeys(files_to_block)
- # new filter function
- def filter(eventname,filename,stage):
- return not filename in files_to_block
- filter_function=filter
+filter_function=get_filter_function(options,system_packages,portage_api)
# launching program
events=logfs.fstracer.getfsevents(args[0], args,approach=options.approach,filterproc=filter_function)
@@ -100,15 +172,14 @@ if runtime_vars["is_emerge"]:
)
if len(pkgs) > 1:
print "Several packages were installed. The report will be inaccurate"
+ elif len(pkgs)==0:
+ print "None packages have been installed sucessfully. The report will be inaccurate"
runtime_vars["pkgs_installed"]=pkgs
runtime_vars["deps_buildtime"]=[]
runtime_vars["deps_all"]=[]
for pkg in pkgs:
runtime_vars["deps_buildtime"]+=portage_api.get_deps(pkg,["DEPEND"])
runtime_vars["deps_all"]+=portage_api.get_deps(pkg,["DEPEND","RDEPEND"])
-
- #print runtime_vars["deps_buildtime"]
- #print runtime_vars["deps_all"]
except:
print "Non-critical error while parsing logfile of emerge"
runtime_vars["is_emerge"]=False # shutting down all emerge handling logic
@@ -170,13 +241,10 @@ for stage in sorted(events):
filesinfo[filename]={"found":[],"notfound":[]}
filesinfo[filename]["notfound"]=fail_events[filename]
-#print events_converted_for_output
-
# generating output
stagesorder={"clean":1,"setup":2,"unpack":3,"prepare":4,"configure":5,"compile":6,"test":7,
"install":8,"preinst":9,"postinst":10,"prerm":11,"postrm":12,"unknown":13}
-
# print information grouped by package
for package in sorted(packagesinfo):
# not showing special directory package
@@ -218,19 +286,27 @@ for package in sorted(packagesinfo):
# show information about accessed files
print "%-40s: %s"%(package,stages)
+# if options.show_files:
- if options.show_files:
- # this is here for readability
- action={
- (False,False):"accessed",
- (True,False):"readed",
- (False,True):"writed",
- (True,True):"readed and writed"
- }
-
- for filename in filenames:
- event_info=tuple(filenames[filename])
- print " %-56s %-21s" % (filename,action[event_info])
+ # this is here for readability
+ action={
+ (False,False):"accessed",
+ (True,False):"readed",
+ (False,True):"writed",
+ (True,True):"readed and writed"
+ }
+
+ filescounter=0
+
+ for filename in filenames:
+ event_info=tuple(filenames[filename])
+ print " %-56s %-21s" % (filename,action[event_info])
+ filescounter+=1
+ if options.show_files:
+ continue
+ elif filescounter>=options.numfiles:
+ print " ..."
+ break
# print not founded files with stages
if options.show_files:
diff --git a/src/autodep/logfs/fstracer.py b/src/autodep/logfs/fstracer.py
index ef185b8..58507bb 100644
--- a/src/autodep/logfs/fstracer.py
+++ b/src/autodep/logfs/fstracer.py
@@ -169,7 +169,7 @@ def getfsevents(prog_name,arguments,approach="hooklib",filterproc=defaultfilter)
message=record.split("\0")
#if message[3]=="compile": #and message[1]=="debug":
#print message
-
+ #print message
try:
if message[4]=="ASKING":
diff --git a/src/autodep/package_utils/portage_misc_functions.py b/src/autodep/package_utils/portage_misc_functions.py
index ca6d890..6afe2c3 100644
--- a/src/autodep/package_utils/portage_misc_functions.py
+++ b/src/autodep/package_utils/portage_misc_functions.py
@@ -30,7 +30,9 @@ class portage_api:
def get_best_visible_pkg(self,pkg):
"""
Gets best candidate on installing. Returns empty string if no found
-
+
+ :param pkg: package name
+
"""
try:
return self.portdb.xmatch("bestmatch-visible", pkg)
@@ -43,6 +45,8 @@ class portage_api:
This function uses very internal functions of portage so
it may be unreliable in various portage versions
+ :param emergeargs: list of raw args of emerge, for example, ['-1','bash']
+
"""
try:
diff --git a/src/autodep/tests/test_fusefs.py b/src/autodep/tests/test_fusefs.py
index 71e2a85..c395ddf 100644
--- a/src/autodep/tests/test_fusefs.py
+++ b/src/autodep/tests/test_fusefs.py
@@ -3,6 +3,8 @@ import logfs.fstracer
import os
import sys
+# just a copypasted tests for fusefs but with hooklib approach
+
class null_writer:
def __init__(self):
pass
@@ -10,7 +12,7 @@ class null_writer:
pass
-def simple_getfsevents(prog,args,approach="fusefs"):
+def simple_getfsevents(prog,args,approach="fusefs", filestoblock=set([])):
ret=[]
null_out=null_writer()
nullfile=open("/dev/null")
@@ -19,23 +21,28 @@ def simple_getfsevents(prog,args,approach="fusefs"):
errfd=os.dup(sys.stderr.fileno())
os.dup2(nullfd,sys.stdout.fileno())
os.dup2(nullfd,sys.stderr.fileno())
-
- events = logfs.fstracer.getfsevents(prog,args,approach)
+
+ def filter(eventname,filename,stage):
+ if filename in filestoblock:
+ return False
+ return True
+
+ events = logfs.fstracer.getfsevents(prog,args,approach,filter)
os.dup2(outfd,sys.stdout.fileno())
os.dup2(errfd,sys.stderr.fileno())
-
+
#print events
for stage in events:
for filename in events[stage][0]:
ret.append([filename,'success'])
for filename in events[stage][1]:
ret.append([filename,'fail'])
-
+
return ret
-
class fusefs_simple_tests(unittest.TestCase):
+ """
def test_open_unexists(self):
eventslist=simple_getfsevents('/bin/cat', ['/bin/cat','/f1','/f2'])
self.assertTrue(eventslist.count(['/f1',"fail"])==1)
@@ -84,6 +91,20 @@ class fusefs_simple_tests(unittest.TestCase):
for i in range(1,14):
self.assertTrue(eventslist.count(['/f'+str(i),"fail"])==1)
+ def test_block(self):
+ eventslist=simple_getfsevents('/bin/cat', ['/bin/cat','/etc/passwd'],filestoblock=['/etc/passwd'])
+ self.assertTrue(eventslist.count(['/etc/passwd',"fail"])==1)
+ self.assertFalse(eventslist.count(['/etc/passwd',"success"])==1)
+ """
+ def test_ls(self):
+ # this is a little tricky: check if passwd not showed in /etc/ if blocked
+ command="import os; print open('/etc/group').read() if 'passwd' in os.listdir('/etc/') else quit(1)"
+ resultarray=simple_getfsevents('python2', ['python','-c',command])
+ self.assertTrue(['/etc/group','success'] in resultarray)
+ resultarray=simple_getfsevents('python2', ['python','-c',command], filestoblock=['/etc/passwd'])
+ self.assertFalse(['/etc/group','success'] in resultarray)
+
+
#if __name__ == '__main__':
#unittest.main()
#suite = unittest.TestLoader().loadTestsFromTestCase(fusefs_simple_tests)
diff --git a/src/autodep/tests/test_hookfs.py b/src/autodep/tests/test_hookfs.py
index 0dbabed..037f4a9 100644
--- a/src/autodep/tests/test_hookfs.py
+++ b/src/autodep/tests/test_hookfs.py
@@ -12,7 +12,7 @@ class null_writer:
pass
-def simple_getfsevents(prog,args,approach="hooklib"):
+def simple_getfsevents(prog,args,approach="hooklib", filestoblock=set([])):
ret=[]
null_out=null_writer()
nullfile=open("/dev/null")
@@ -21,22 +21,26 @@ def simple_getfsevents(prog,args,approach="hooklib"):
errfd=os.dup(sys.stderr.fileno())
os.dup2(nullfd,sys.stdout.fileno())
os.dup2(nullfd,sys.stderr.fileno())
-
- events = logfs.fstracer.getfsevents(prog,args,approach)
+
+ def filter(eventname,filename,stage):
+ if filename in filestoblock:
+ return False
+ return True
+
+ events = logfs.fstracer.getfsevents(prog,args,approach,filter)
os.dup2(outfd,sys.stdout.fileno())
os.dup2(errfd,sys.stderr.fileno())
-
+
#print events
for stage in events:
for filename in events[stage][0]:
ret.append([filename,'success'])
for filename in events[stage][1]:
ret.append([filename,'fail'])
-
+
return ret
-
class fusefs_simple_tests(unittest.TestCase):
def test_open_unexists(self):
eventslist=simple_getfsevents('/bin/cat', ['/bin/cat','/f1','/f2'])
@@ -86,6 +90,20 @@ class fusefs_simple_tests(unittest.TestCase):
for i in range(1,14):
self.assertTrue(eventslist.count(['/f'+str(i),"fail"])==1)
+ def test_block(self):
+ eventslist=simple_getfsevents('/bin/cat', ['/bin/cat','/etc/passwd'],filestoblock=['/etc/passwd'])
+ self.assertTrue(eventslist.count(['/etc/passwd',"fail"])==1)
+ self.assertFalse(eventslist.count(['/etc/passwd',"success"])==1)
+
+ def test_ls(self):
+ # this is a little tricky: check if passwd not showed in /etc/ if blocked
+ command="import os; print open('/etc/group').read() if 'passwd' in os.listdir('/etc/') else quit(1)"
+ resultarray=simple_getfsevents('python2', ['python','-c',command])
+ self.assertTrue(['/etc/group','success'] in resultarray)
+ resultarray=simple_getfsevents('python2', ['python','-c',command], filestoblock=['/etc/passwd'])
+ self.assertFalse(['/etc/group','success'] in resultarray)
+
+
#if __name__ == '__main__':
#unittest.main()
#suite = unittest.TestLoader().loadTestsFromTestCase(fusefs_simple_tests)
diff --git a/src/hook_fusefs/hookfs.c b/src/hook_fusefs/hookfs.c
index 00a27a8..d6371dd 100644
--- a/src/hook_fusefs/hookfs.c
+++ b/src/hook_fusefs/hookfs.c
@@ -42,7 +42,7 @@
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#define MAXPATHLEN 256
+#define MAXPATHLEN PATH_MAX
#define MAXSOCKETPATHLEN 108
#define MAXFILEBUFFLEN 2048
@@ -454,7 +454,11 @@ static int hookfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
{
struct hookfs_dirp *d = get_dirp(fi);
- (void) path;
+ struct fuse_context * context = fuse_get_context();
+ char *stage=getstagebypid(context->pid);
+
+
+ //(void) path;
if (offset != d->offset) {
seekdir(d->dp, offset);
d->entry = NULL;
@@ -466,17 +470,31 @@ static int hookfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
if (!d->entry) {
d->entry = readdir(d->dp);
+
if (!d->entry)
break;
}
+ //log_event("debug",d->entry->d_name,"DENIED",0,stage);
memset(&st, 0, sizeof(st));
st.st_ino = d->entry->d_ino;
st.st_mode = d->entry->d_type << 12;
nextoff = telldir(d->dp);
- if (filler(buf, d->entry->d_name, &st, nextoff))
+
+ // we must ask registrar about should we show the file
+ char fullpath[MAXPATHLEN];
+ snprintf(fullpath,MAXPATHLEN,"%s/%s",path,d->entry->d_name);
+
+ char abspath[MAXPATHLEN];
+ realpath(fullpath,abspath);
+
+ if(! is_event_allowed("stat",abspath,context->pid,stage)) {
+ errno=2;
+ log_event("stat",abspath,"DENIED",errno,stage);
+ } else if (filler(buf, d->entry->d_name, &st, nextoff)) {
break;
-
+ }
+
d->entry = NULL;
d->offset = nextoff;
}