summaryrefslogtreecommitdiffstats
path: root/src/lib/Client/Tools/POSIX.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/Client/Tools/POSIX.py')
-rw-r--r--src/lib/Client/Tools/POSIX.py243
1 files changed, 243 insertions, 0 deletions
diff --git a/src/lib/Client/Tools/POSIX.py b/src/lib/Client/Tools/POSIX.py
new file mode 100644
index 000000000..c5d82a403
--- /dev/null
+++ b/src/lib/Client/Tools/POSIX.py
@@ -0,0 +1,243 @@
+'''All POSIX Type client support for Bcfg2'''
+__revision__ = '$Revision$'
+
+from stat import S_ISVTX, S_ISGID, S_ISUID, S_IXUSR, S_IWUSR, S_IRUSR, S_IXGRP
+from stat import S_IWGRP, S_IRGRP, S_IXOTH, S_IWOTH, S_IROTH, ST_MODE, S_ISDIR
+from stat import S_IFREG, ST_UID, ST_GID, S_ISREG, S_IFDIR, S_ISLNK
+
+import binascii, difflib, grp, os, pwd, xml.sax.saxutils
+import Bcfg2.Client.Tools
+
+def calcPerms(initial, perms):
+ '''This compares ondisk permissions with specified ones'''
+ pdisp = [{1:S_ISVTX, 2:S_ISGID, 4:S_ISUID}, {1:S_IXUSR, 2:S_IWUSR, 4:S_IRUSR},
+ {1:S_IXGRP, 2:S_IWGRP, 4:S_IRGRP}, {1:S_IXOTH, 2:S_IWOTH, 4:S_IROTH}]
+ tempperms = initial
+ if len(perms) == 3:
+ perms = '0%s' % (perms)
+ pdigits = [int(perms[digit]) for digit in range(4)]
+ for index in range(4):
+ for (num, perm) in pdisp[index].iteritems():
+ if pdigits[index] & num:
+ tempperms |= perm
+ return tempperms
+
+class POSIX(Bcfg2.Client.Tools.Tool):
+ '''POSIX File support code'''
+ __name__ = 'POSIX'
+ __handles__ = [('ConfigFile', None), ('Directory', None), ('Permissions', None), \
+ ('SymLink', None)]
+ __req__ = {'ConfigFile': ['name', 'owner', 'group', 'perms'],
+ 'Directory': ['name', 'owner', 'group', 'perms'],
+ 'Permissions': ['name', 'owner', 'group', 'perms'],
+ 'SymLink': ['name', 'to']}
+
+ def VerifySymLink(self, entry, _):
+ '''Verify SymLink Entry'''
+ try:
+ sloc = os.readlink(entry.get('name'))
+ if sloc == entry.get('to'):
+ return True
+ self.logger.debug("Symlink %s points to %s, should be %s" % \
+ (entry.get('name'), sloc, entry.get('to')))
+ entry.set('current_to', sloc)
+ return False
+ except OSError:
+ entry.set('current_exists', 'false')
+ return False
+
+ def InstallSymLink(self, entry):
+ '''Install SymLink Entry'''
+ self.logger.info("Installing Symlink %s" % (entry.get('name')))
+ try:
+ fmode = os.lstat(entry.get('name'))[ST_MODE]
+ if S_ISREG(fmode) or S_ISLNK(fmode):
+ self.logger.debug("Non-directory entry already exists at %s" % \
+ (entry.get('name')))
+ os.unlink(entry.get('name'))
+ elif S_ISDIR(fmode):
+ self.logger.debug("Directory entry already exists at %s" % (entry.get('name')))
+ self.cmd.run("mv %s/ %s.bak" % (entry.get('name'), entry.get('name')))
+ else:
+ os.unlink(entry.get('name'))
+ except OSError:
+ self.logger.info("Symlink %s cleanup failed" % (entry.get('name')))
+ try:
+ os.symlink(entry.get('to'), entry.get('name'))
+ return True
+ except OSError:
+ return False
+
+ def VerifyDirectory(self, entry, _):
+ '''Verify Directory Entry'''
+ while len(entry.get('perms', '')) < 4:
+ entry.set('perms', '0' + entry.get('perms', ''))
+ try:
+ ondisk = os.stat(entry.get('name'))
+ except OSError:
+ entry.set('current_exists', 'false')
+ self.logger.debug("%s %s does not exist" %
+ (entry.tag, entry.get('name')))
+ return False
+ try:
+ owner = pwd.getpwuid(ondisk[ST_UID])[0]
+ group = grp.getgrgid(ondisk[ST_GID])[0]
+ except (OSError, KeyError):
+ self.logger.error('User resolution failing')
+ owner = 'root'
+ group = 'root'
+ perms = oct(os.stat(entry.get('name'))[ST_MODE])[-4:]
+ if ((owner == entry.get('owner')) and
+ (group == entry.get('group')) and
+ (perms == entry.get('perms'))):
+ return True
+ else:
+ if owner != entry.get('owner'):
+ entry.set('current_owner', owner)
+ self.logger.debug("%s %s ownership wrong" % (entry.tag, entry.get('name')))
+ if group != entry.get('group'):
+ entry.set('current_group', group)
+ self.logger.debug("%s %s group wrong" % (entry.tag, entry.get('name')))
+ if perms != entry.get('perms'):
+ entry.set('current_perms', perms)
+ self.logger.debug("%s %s permissions wrong: are %s should be %s" %
+ (entry.tag, entry.get('name'), perms, entry.get('perms')))
+ return False
+
+ def InstallDirectory(self, entry):
+ '''Install Directory Entry'''
+ self.logger.info("Installing Directory %s" % (entry.get('name')))
+ try:
+ fmode = os.lstat(entry.get('name'))
+ if not S_ISDIR(fmode[ST_MODE]):
+ self.logger.debug("Found a non-directory entry at %s" % (entry.get('name')))
+ try:
+ os.unlink(entry.get('name'))
+ except OSError:
+ self.logger.info("Failed to unlink %s" % (entry.get('name')))
+ return False
+ else:
+ self.logger.debug("Found a pre-existing directory at %s" % (entry.get('name')))
+ exists = True
+ except OSError:
+ # stat failed
+ exists = False
+
+ if not exists:
+ parent = "/".join(entry.get('name').split('/')[:-1])
+ if parent:
+ try:
+ os.lstat(parent)
+ except:
+ self.logger.debug('Creating parent path for directory %s' % (entry.get('name')))
+ for idx in xrange(len(parent.split('/')[:-1])):
+ current = '/'+'/'.join(parent.split('/')[1:2+idx])
+ try:
+ sloc = os.lstat(current)
+ try:
+ if not S_ISDIR(sloc[ST_MODE]):
+ os.unlink(current)
+ os.mkdir(current)
+ except OSError:
+ return False
+ except OSError:
+ try:
+ os.mkdir(current)
+ except OSError:
+ return False
+
+ try:
+ os.mkdir(entry.get('name'))
+ except OSError:
+ self.logger.error('Failed to create directory %s' % (entry.get('name')))
+ return False
+ try:
+ os.chown(entry.get('name'),
+ pwd.getpwnam(entry.get('owner'))[2], grp.getgrnam(entry.get('group'))[2])
+ os.chmod(entry.get('name'), calcPerms(S_IFDIR, entry.get('perms')))
+ return True
+ except (OSError, KeyError):
+ self.logger.error('Permission fixup failed for %s' % (entry.get('name')))
+ return False
+
+ def VerifyConfigFile(self, entry, _):
+ '''Install ConfigFile Entry'''
+ # configfile verify is permissions check + content check
+ permissionStatus = self.VerifyDirectory(entry, _)
+ if entry.get('encoding', 'ascii') == 'base64':
+ tempdata = binascii.a2b_base64(entry.text)
+ elif entry.get('empty', 'false') == 'true':
+ tempdata = ''
+ else:
+ if entry.text == None:
+ self.logger.error("Cannot verify incomplete ConfigFile %s" % (entry.get('name')))
+ return False
+ tempdata = entry.text
+
+ try:
+ content = open(entry.get('name')).read()
+ except IOError:
+ # file does not exist
+ return False
+ contentStatus = content == tempdata
+ if not contentStatus:
+ diff = '\n'.join([x for x in difflib.unified_diff(content.split('\n'), tempdata.split('\n'))])
+ try:
+ entry.set("current_diff", xml.sax.saxutils.quoteattr(diff))
+ except:
+ pass
+ return contentStatus and permissionStatus
+
+ def InstallConfigFile(self, entry):
+ '''Install ConfigFile Entry'''
+ self.logger.info("Installing ConfigFile %s" % (entry.get('name')))
+
+ parent = "/".join(entry.get('name').split('/')[:-1])
+ if parent:
+ try:
+ os.lstat(parent)
+ except:
+ self.logger.debug('Creating parent path for config file %s' % (entry.get('name')))
+ for idx in xrange(len(parent.split('/')[:-1])):
+ current = '/'+'/'.join(parent.split('/')[1:2+idx])
+ try:
+ sloc = os.lstat(current)
+ try:
+ if not S_ISDIR(sloc[ST_MODE]):
+ os.unlink(current)
+ os.mkdir(current)
+ except OSError:
+ return False
+ except OSError:
+ try:
+ os.mkdir(current)
+ except OSError:
+ return False
+
+ # If we get here, then the parent directory should exist
+ try:
+ newfile = open("%s.new"%(entry.get('name')), 'w')
+ if entry.get('encoding', 'ascii') == 'base64':
+ filedata = binascii.a2b_base64(entry.text)
+ elif entry.get('empty', 'false') == 'true':
+ filedata = ''
+ else:
+ filedata = entry.text
+ newfile.write(filedata)
+ newfile.close()
+ try:
+ os.chown(newfile.name, pwd.getpwnam(entry.get('owner'))[2],
+ grp.getgrnam(entry.get('group'))[2])
+ except KeyError:
+ os.chown(newfile.name, 0, 0)
+ os.chmod(newfile.name, calcPerms(S_IFREG, entry.get('perms')))
+ if entry.get("paranoid", False) and self.setup.get("paranoid", False):
+ self.cmd.run("cp %s /var/cache/bcfg2/%s" % (entry.get('name')))
+ os.rename(newfile.name, entry.get('name'))
+ return True
+ except (OSError, IOError), err:
+ if err.errno == 13:
+ self.logger.info("Failed to open %s for writing" % (entry.get('name')))
+ else:
+ print err
+ return False