You are not logged in.
hi . i stumbled upon this feature request http://bugs.archlinux.org/task/11091?project=3
and then coded a python script that check that installed files of packages are the same as in the downloaded package in the cache.
beware it's a quick script. and not a security software like tripwire (non free), aide, or samhain or whatever...
it can take parameter from a pipe like
tail -n 10 /var/log/pacman.log |grep upgraded|cut -f 4 -d ' '|python verifypkg.pyor
python verifypkg.py /var/cache/pacman/pkg/xorg-utils-7.5-1-i686.pkg.tar.gzhere is an updated version of that script
#!/usr/bin/env python
# verify.py Version 0.1 2009-10-18
#
# under the WTFPL. see http://sam.zoy.org/wtfpl/
#
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# Version 2, December 2004
#
# Copyright (C) 2006 solsTiCe d'Hiver <solstice.dhiver@gmail.com>
# Everyone is permitted to copy and distribute verbatim or modified
# copies of this license document, and changing it is allowed as long
# as the name is changed.
#
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
#
# 0. You just DO WHAT THE FUCK YOU WANT TO.
'''a python script that compare the files in a package tarball and the files
installed on the system:
It reports changed files, missing files'''
import tarfile
import hashlib
from sys import argv, exit, stderr, stdin
from os import listdir
from os.path import exists, basename
from glob import glob
DB = '/var/lib/pacman'
CACHE = '/var/cache/pacman/pkg'
# TODO: use logging module ?
def error(s):
stderr.write('Error: %s\n' % s)
def warning(s):
stderr.write('Warning: %s\n' % s)
def getpkgname(pkgfile):
'''return package name from its pkgfilename'''
pkg = basename(pkgfile.rstrip('.pkg.tar.gz'))
pkg = pkg[:pkg.rfind('-')]
return pkg
def ispkginstalled(pkgfile):
'''return wether or not a package is installed'''
return exists('/'.join([DB, 'local', getpkgname(pkgfile)]))
def checkpkg(pkgfile):
'''check if the installed files of a package have changed compared to the
files in the package tarball'''
missing = 0
changed = 0
md5s = md5pkg(pkgfile)
for filename,md5 in md5s.items():
ff = '/' + filename
if exists(ff):
try:
with open(ff) as g:
if hashlib.md5(g.read()).hexdigest() != md5:
warning('%s has changed' % ff)
changed += 1
except IOError as e:
error('%s: %s ' % (e.strerror, filename))
continue
else:
warning('%s has not been found' % ff)
missing += 1
return (len(md5s), changed, missing)
def listpkg():
'''return a list of all isntalled pkg'''
return sorted(listdir('/'.join([DB, 'local'])))
def findpkg(s, dbpkg):
'''look for an installed pkg matching s and return the path of tarball in
the cache'''
candidates = [p for p in dbpkg if p.startswith(s)]
found = False
for i in candidates:
pkgname = '-'.join(i.split('-')[:-2])
if pkgname == s:
found = True
break
if found:
res = glob('/'.join([CACHE, i+'*']))
if len(res) == 1:
return res[0]
return None
def md5pkg(pkgfile):
'''return a dictionary of filename and md5 of the package'''
tf = tarfile.open(pkgfile, 'r')
md5s = {}
for ti in tf:
if ti.isfile() and ti.name not in ('.PKGINFO', '.INSTALL', '.CHANGELOG'):
f = tf.extractfile(ti)
md5s[ti.name] = hashlib.md5(f.read()).hexdigest()
f.close()
tf.close()
return md5s
if __name__ == '__main__':
dbpkg = listpkg()
try:
if len(argv) == 1:
# try to use stdin if no argument
pkglist = stdin.readlines()
pkglist = [i.strip() for i in pkglist]
else:
pkglist = argv[1:]
for pkg in pkglist:
if exists(pkg):
if not ispkginstalled(pkg):
error('%s is not installed' % getpkgname(pkg))
continue
else:
# if we do not find the archive pkg, then look for a package with
# that name in the db of pacman
p = findpkg(pkg, dbpkg)
if p != None:
# strange but it works
pkg = p
else:
error('%s not found' % pkg)
continue
# finaly check the tarball pkg
(n,c,m) = checkpkg(pkg)
print '%s: %d files, %d changed, %d missing' % (getpkgname(pkg), n, c, m)
except KeyboardInterrupt:
passLast edited by solstice (2009-11-02 15:00:51)
Offline
A new version that simplify it's use
python2 verifypkg.pyIt will look for all packages in pacman cache and check the integrety of each of its files
or you could check only a given package, for example:
$ python2 verifypkg.py coreutils-8.13-2
coreutils-8.13-2: 240 files, 0 changed, 0 missingyou need to use the complete name of the package with version and release
http://paste.pocoo.org/show/485669/
#!/usr/bin/env python2
# verify.py Version 0.2 2009-10-18
#
# under the WTFPL. see http://sam.zoy.org/wtfpl/
#
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# Version 2, December 2004
#
# Copyright (C) 2006 solsTiCe d'Hiver <solstice.dhiver@gmail.com>
# Everyone is permitted to copy and distribute verbatim or modified
# copies of this license document, and changing it is allowed as long
# as the name is changed.
#
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
#
# 0. You just DO WHAT THE FUCK YOU WANT TO.
'''a python script that compare the files in a package tarball and the files
installed on the system:
It reports changed files, missing files'''
import sys
import os
import tarfile
from glob import glob
from StringIO import StringIO
import hashlib
try:
import lzma
except ImportError:
print >>sys.stderr, 'You need the python bindings for lzma: python-pyliblzma or pylzma'
DB = '/var/lib/pacman'
CACHE = '/var/cache/pacman/pkg'
# TODO: use logging module ?
def error(s):
sys.stderr.write('Error: %s\n' % s)
def warning(s):
sys.stderr.write('Warning: %s\n' % s)
def getpkgname(pkgfile):
'''return package name from its pkgfilename'''
pkg = '.'.join(os.path.basename(pkgfile).split('.')[:-3]) # remove trailing .pkg.tar.gz
pkg = '-'.join(pkg.split('-')[:-1]) # remove arch field
return pkg
def ispkginstalled(pkgfile):
'''return wether or not a package is installed'''
return os.path.exists('/'.join([DB, 'local', getpkgname(pkgfile)]))
def checkpkg(pkgfile):
'''check if the installed files of a package have changed compared to the
files in the package tarball'''
missing = 0
changed = 0
md5s = pkgmd5s(pkgfile)
for filename,md5 in md5s.items():
ff = '/' + filename
if os.path.exists(ff):
try:
with open(ff) as g:
if hashlib.md5(g.read()).hexdigest() != md5:
warning('%s has changed' % ff)
changed += 1
except IOError as e:
error('%s: %s ' % (e.strerror, filename))
continue
else:
warning('%s has not been found' % ff)
missing += 1
return (len(md5s), changed, missing)
def listpkg():
'''return a list of all installed pkg'''
return sorted(os.listdir('/'.join([DB, 'local'])))
def findpkgtarball(s, dbpkg):
'''look for an installed pkg matching s and return the path of tarball in
the cache'''
candidates = [p for p in dbpkg if p.startswith(s)]
found = False
if s in candidates:
found = True
name = s
else:
for i in candidates:
pkgname = '-'.join(i.split('-')[:-2])
if pkgname == s:
found = True
name = i
break
if found:
res = glob('/'.join([CACHE, name+'*']))
if len(res) == 1:
return res[0]
return None
def pkgmd5s(pkgfile):
'''return a dictionary of filename and md5 of the package'''
if pkgfile.endswith('xz'):
with open(pkgfile, 'r') as f:
tf = tarfile.TarFile(fileobj=StringIO(lzma.decompress(f.read())))
else:
tf = tarfile.open(pkgfile, 'r')
md5s = {}
for ti in tf:
if ti.isfile() and ti.name not in ('.PKGINFO', '.INSTALL', '.CHANGELOG'):
f = tf.extractfile(ti)
md5s[ti.name] = hashlib.md5(f.read()).hexdigest()
f.close()
tf.close()
return md5s
if __name__ == '__main__':
try:
pkglist = sys.argv[1:]
dbpkg = listpkg()
if pkglist == []:
pkglist = dbpkg
for pkg in pkglist:
if os.path.exists(pkg):
if not ispkginstalled(pkg):
error('%s is not installed' % getpkgname(pkg))
continue
else:
# if we do not find the archive pkg, then look for a package with
# that name in the db of pacman
p = findpkgtarball(pkg, dbpkg)
if p != None:
pkg = p
else:
error('%s not found in the cache' % pkg)
continue
# finaly check the tarball pkg
(n,c,m) = checkpkg(pkg)
print '%s: %d files, %d changed, %d missing' % (getpkgname(pkg), n, c, m)
except KeyboardInterrupt:
passLast edited by solstice (2011-10-01 17:31:19)
Offline