diff options
author | Rob Crittenden <rcritten@redhat.com> | 2009-01-29 16:26:07 -0500 |
---|---|---|
committer | Rob Crittenden <rcritten@redhat.com> | 2009-02-03 15:27:14 -0500 |
commit | e30cd6ba42c256d2016db45146d616f329455e86 (patch) | |
tree | d4c5291095c80c92bc4803fe7f20fc2838124ffa /ipa-server/ipaserver | |
parent | c4ed025001895bfc65c613cabbbfcb27c19cc29f (diff) | |
download | freeipa-e30cd6ba42c256d2016db45146d616f329455e86.tar.gz freeipa-e30cd6ba42c256d2016db45146d616f329455e86.tar.xz freeipa-e30cd6ba42c256d2016db45146d616f329455e86.zip |
Mass tree reorganization for IPAv2. To view previous history of files use:
% git log --follow -- <file>
renamed: ipa-server/autogen.sh -> autogen.sh
renamed: ipa-server/ipa-kpasswd/Makefile.am -> daemons/ipa-kpasswd/Makefile.am
renamed: ipa-server/ipa-kpasswd/README -> daemons/ipa-kpasswd/README
renamed: ipa-server/ipa-kpasswd/ipa_kpasswd.c -> daemons/ipa-kpasswd/ipa_kpasswd.c
renamed: ipa-server/ipa-kpasswd/ipa_kpasswd.init -> daemons/ipa-kpasswd/ipa_kpasswd.init
renamed: ipa-server/ipa-slapi-plugins/Makefile.am -> daemons/ipa-slapi-plugins/Makefile.am
renamed: ipa-server/ipa-slapi-plugins/README -> daemons/ipa-slapi-plugins/README
renamed: ipa-server/ipa-slapi-plugins/dna/Makefile.am -> daemons/ipa-slapi-plugins/dna/Makefile.am
renamed: ipa-server/ipa-slapi-plugins/dna/dna-conf.ldif -> daemons/ipa-slapi-plugins/dna/dna-conf.ldif
renamed: ipa-server/ipa-slapi-plugins/dna/dna.c -> daemons/ipa-slapi-plugins/dna/dna.c
renamed: ipa-server/ipa-slapi-plugins/ipa-memberof/Makefile.am -> daemons/ipa-slapi-plugins/ipa-memberof/Makefile.am
renamed: ipa-server/ipa-slapi-plugins/ipa-memberof/ipa-memberof.c -> daemons/ipa-slapi-plugins/ipa-memberof/ipa-memberof.c
renamed: ipa-server/ipa-slapi-plugins/ipa-memberof/ipa-memberof.h -> daemons/ipa-slapi-plugins/ipa-memberof/ipa-memberof.h
renamed: ipa-server/ipa-slapi-plugins/ipa-memberof/ipa-memberof_config.c -> daemons/ipa-slapi-plugins/ipa-memberof/ipa-memberof_config.c
renamed: ipa-server/ipa-slapi-plugins/ipa-memberof/memberof-conf.ldif -> daemons/ipa-slapi-plugins/ipa-memberof/memberof-conf.ldif
renamed: ipa-server/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am -> daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am
renamed: ipa-server/ipa-slapi-plugins/ipa-pwd-extop/README -> daemons/ipa-slapi-plugins/ipa-pwd-extop/README
renamed: ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c -> daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
renamed: ipa-server/ipa-slapi-plugins/ipa-pwd-extop/pwd-extop-conf.ldif -> daemons/ipa-slapi-plugins/ipa-pwd-extop/pwd-extop-conf.ldif
renamed: ipa-server/ipa-slapi-plugins/ipa-winsync/Makefile.am -> daemons/ipa-slapi-plugins/ipa-winsync/Makefile.am
renamed: ipa-server/ipa-slapi-plugins/ipa-winsync/README -> daemons/ipa-slapi-plugins/ipa-winsync/README
renamed: ipa-server/ipa-slapi-plugins/ipa-winsync/ipa-winsync-conf.ldif -> daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync-conf.ldif
renamed: ipa-server/ipa-slapi-plugins/ipa-winsync/ipa-winsync-config.c -> daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync-config.c
renamed: ipa-server/ipa-slapi-plugins/ipa-winsync/ipa-winsync.c -> daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync.c
renamed: ipa-server/ipa-slapi-plugins/ipa-winsync/ipa-winsync.h -> daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync.h
renamed: ipa-server/xmlrpc-server/ipa-rewrite.conf -> install/conf/ipa-rewrite.conf
renamed: ipa-server/xmlrpc-server/ipa.conf -> install/conf/ipa.conf
renamed: ipa-server/xmlrpc-server/ssbrowser.html -> install/html/ssbrowser.html
renamed: ipa-server/xmlrpc-server/unauthorized.html -> install/html/unauthorized.html
renamed: ipa-server/ipa-install/share/60ipaconfig.ldif -> install/share/60ipaconfig.ldif
renamed: ipa-server/ipa-install/share/60kerberos.ldif -> install/share/60kerberos.ldif
renamed: ipa-server/ipa-install/share/60radius.ldif -> install/share/60radius.ldif
renamed: ipa-server/ipa-install/share/60samba.ldif -> install/share/60samba.ldif
renamed: ipa-server/ipa-install/share/Makefile.am -> install/share/Makefile.am
renamed: ipa-server/ipa-install/share/bind.named.conf.template -> install/share/bind.named.conf.template
renamed: ipa-server/ipa-install/share/bind.zone.db.template -> install/share/bind.zone.db.template
renamed: ipa-server/ipa-install/share/bootstrap-template.ldif -> install/share/bootstrap-template.ldif
renamed: ipa-server/ipa-install/share/certmap.conf.template -> install/share/certmap.conf.template
renamed: ipa-server/ipa-install/share/default-aci.ldif -> install/share/default-aci.ldif
renamed: ipa-server/ipa-install/share/default-keytypes.ldif -> install/share/default-keytypes.ldif
renamed: ipa-server/ipa-install/share/dna-posix.ldif -> install/share/dna-posix.ldif
renamed: ipa-server/ipa-install/share/encrypted_attribute.ldif -> install/share/encrypted_attribute.ldif
renamed: ipa-server/ipa-install/share/fedora-ds.init.patch -> install/share/fedora-ds.init.patch
renamed: ipa-server/ipa-install/share/indices.ldif -> install/share/indices.ldif
renamed: ipa-server/ipa-install/share/kdc.conf.template -> install/share/kdc.conf.template
renamed: ipa-server/ipa-install/share/kerberos.ldif -> install/share/kerberos.ldif
renamed: ipa-server/ipa-install/share/krb.con.template -> install/share/krb.con.template
renamed: ipa-server/ipa-install/share/krb5.conf.template -> install/share/krb5.conf.template
renamed: ipa-server/ipa-install/share/krb5.ini.template -> install/share/krb5.ini.template
renamed: ipa-server/ipa-install/share/krbrealm.con.template -> install/share/krbrealm.con.template
renamed: ipa-server/ipa-install/share/master-entry.ldif -> install/share/master-entry.ldif
renamed: ipa-server/ipa-install/share/memberof-task.ldif -> install/share/memberof-task.ldif
renamed: ipa-server/ipa-install/share/ntp.conf.server.template -> install/share/ntp.conf.server.template
renamed: ipa-server/ipa-install/share/ntpd.sysconfig.template -> install/share/ntpd.sysconfig.template
renamed: ipa-server/ipa-install/share/preferences.html.template -> install/share/preferences.html.template
renamed: ipa-server/ipa-install/share/referint-conf.ldif -> install/share/referint-conf.ldif
renamed: ipa-server/ipa-install/share/schema_compat.uldif -> install/share/schema_compat.uldif
renamed: ipa-server/ipa-install/share/unique-attributes.ldif -> install/share/unique-attributes.ldif
renamed: ipa-server/ipa-install/Makefile.am -> install/tools/Makefile.am
renamed: ipa-server/ipa-install/README -> install/tools/README
renamed: ipa-server/ipa-compat-manage -> install/tools/ipa-compat-manage
renamed: ipa-server/ipa-fix-CVE-2008-3274 -> install/tools/ipa-fix-CVE-2008-3274
renamed: ipa-server/ipa-ldap-updater -> install/tools/ipa-ldap-updater
renamed: ipa-server/ipa-install/ipa-replica-install -> install/tools/ipa-replica-install
renamed: ipa-server/ipa-install/ipa-replica-manage -> install/tools/ipa-replica-manage
renamed: ipa-server/ipa-install/ipa-replica-prepare -> install/tools/ipa-replica-prepare
renamed: ipa-server/ipa-install/ipa-server-certinstall -> install/tools/ipa-server-certinstall
renamed: ipa-server/ipa-install/ipa-server-install -> install/tools/ipa-server-install
renamed: ipa-server/ipa-upgradeconfig -> install/tools/ipa-upgradeconfig
renamed: ipa-server/ipa-install/ipactl -> install/tools/ipactl
renamed: ipa-server/man/Makefile.am -> install/tools/man/Makefile.am
renamed: ipa-server/man/ipa-compat-manage.1 -> install/tools/man/ipa-compat-manage.1
renamed: ipa-server/man/ipa-ldap-updater.1 -> install/tools/man/ipa-ldap-updater.1
renamed: ipa-server/man/ipa-replica-install.1 -> install/tools/man/ipa-replica-install.1
renamed: ipa-server/man/ipa-replica-manage.1 -> install/tools/man/ipa-replica-manage.1
renamed: ipa-server/man/ipa-replica-prepare.1 -> install/tools/man/ipa-replica-prepare.1
renamed: ipa-server/man/ipa-server-certinstall.1 -> install/tools/man/ipa-server-certinstall.1
renamed: ipa-server/man/ipa-server-install.1 -> install/tools/man/ipa-server-install.1
renamed: ipa-server/man/ipa_kpasswd.8 -> install/tools/man/ipa_kpasswd.8
renamed: ipa-server/man/ipa_webgui.8 -> install/tools/man/ipa_webgui.8
renamed: ipa-server/man/ipactl.8 -> install/tools/man/ipactl.8
renamed: ipa-server/ipa-install/updates/Makefile.am -> install/updates/Makefile.am
renamed: ipa-server/ipa-install/updates/RFC2307bis.update -> install/updates/RFC2307bis.update
renamed: ipa-server/ipa-install/updates/RFC4876.update -> install/updates/RFC4876.update
renamed: ipa-server/ipa-install/updates/indices.update -> install/updates/indices.update
renamed: ipa-server/ipa-install/updates/nss_ldap.update -> install/updates/nss_ldap.update
renamed: ipa-server/ipa-install/updates/replication.update -> install/updates/replication.update
renamed: ipa-server/ipa-install/updates/winsync_index.update -> install/updates/winsync_index.update
renamed: ipa-server/ipaserver/Makefile.am -> ipaserver/install/Makefile.am
renamed: ipa-server/ipaserver/__init__.py -> ipaserver/install/__init__.py
renamed: ipa-server/ipaserver/bindinstance.py -> ipaserver/install/bindinstance.py
renamed: ipa-server/ipaserver/certs.py -> ipaserver/install/certs.py
renamed: ipa-server/ipaserver/dsinstance.py -> ipaserver/install/dsinstance.py
renamed: ipa-server/ipaserver/httpinstance.py -> ipaserver/install/httpinstance.py
renamed: ipa-server/ipaserver/installutils.py -> ipaserver/install/installutils.py
renamed: ipa-server/ipaserver/ipaldap.py -> ipaserver/install/ipaldap.py
renamed: ipa-server/ipaserver/krbinstance.py -> ipaserver/install/krbinstance.py
renamed: ipa-server/ipaserver/ldapupdate.py -> ipaserver/install/ldapupdate.py
renamed: ipa-server/ipaserver/ntpinstance.py -> ipaserver/install/ntpinstance.py
renamed: ipa-server/ipaserver/replication.py -> ipaserver/install/replication.py
renamed: ipa-server/ipaserver/service.py -> ipaserver/install/service.py
renamed: ipa-server/selinux/Makefile -> selinux/Makefile
renamed: ipa-server/selinux/ipa-server-selinux.spec.in -> selinux/ipa-server-selinux.spec.in
renamed: ipa-server/selinux/ipa_kpasswd/ipa_kpasswd.fc -> selinux/ipa_kpasswd/ipa_kpasswd.fc
renamed: ipa-server/selinux/ipa_kpasswd/ipa_kpasswd.te -> selinux/ipa_kpasswd/ipa_kpasswd.te
renamed: ipa-server/selinux/ipa_webgui/ipa_webgui.fc -> selinux/ipa_webgui/ipa_webgui.fc
renamed: ipa-server/selinux/ipa_webgui/ipa_webgui.te -> selinux/ipa_webgui/ipa_webgui.te
renamed: ipa-server/version.m4.in -> version.m4.in
Diffstat (limited to 'ipa-server/ipaserver')
-rw-r--r-- | ipa-server/ipaserver/Makefile.am | 24 | ||||
-rw-r--r-- | ipa-server/ipaserver/__init__.py | 21 | ||||
-rw-r--r-- | ipa-server/ipaserver/bindinstance.py | 156 | ||||
-rw-r--r-- | ipa-server/ipaserver/certs.py | 424 | ||||
-rw-r--r-- | ipa-server/ipaserver/dsinstance.py | 479 | ||||
-rw-r--r-- | ipa-server/ipaserver/httpinstance.py | 231 | ||||
-rw-r--r-- | ipa-server/ipaserver/installutils.py | 248 | ||||
-rw-r--r-- | ipa-server/ipaserver/ipaldap.py | 701 | ||||
-rw-r--r-- | ipa-server/ipaserver/krbinstance.py | 428 | ||||
-rwxr-xr-x | ipa-server/ipaserver/ldapupdate.py | 593 | ||||
-rw-r--r-- | ipa-server/ipaserver/ntpinstance.py | 107 | ||||
-rw-r--r-- | ipa-server/ipaserver/replication.py | 532 | ||||
-rw-r--r-- | ipa-server/ipaserver/service.py | 169 |
13 files changed, 0 insertions, 4113 deletions
diff --git a/ipa-server/ipaserver/Makefile.am b/ipa-server/ipaserver/Makefile.am deleted file mode 100644 index 999dcf248..000000000 --- a/ipa-server/ipaserver/Makefile.am +++ /dev/null @@ -1,24 +0,0 @@ -NULL = - -appdir = $(pythondir)/ipaserver -app_PYTHON = \ - __init__.py \ - bindinstance.py \ - dsinstance.py \ - ipaldap.py \ - krbinstance.py \ - httpinstance.py \ - ntpinstance.py \ - service.py \ - installutils.py \ - replication.py \ - certs.py \ - ldapupdate.py \ - $(NULL) - -EXTRA_DIST = \ - $(NULL) - -MAINTAINERCLEANFILES = \ - *~ \ - Makefile.in diff --git a/ipa-server/ipaserver/__init__.py b/ipa-server/ipaserver/__init__.py deleted file mode 100644 index ef86f9ec5..000000000 --- a/ipa-server/ipaserver/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# Authors: Karl MacMillan <kmacmillan@mentalrootkit.com> -# see inline -# -# Copyright (C) 2007 Red Hat -# see file 'COPYING' for use and warranty information -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; version 2 or later -# -# 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. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -__all__ = ["dsinstance", "krbinstance"] diff --git a/ipa-server/ipaserver/bindinstance.py b/ipa-server/ipaserver/bindinstance.py deleted file mode 100644 index 5badf8603..000000000 --- a/ipa-server/ipaserver/bindinstance.py +++ /dev/null @@ -1,156 +0,0 @@ -# Authors: Simo Sorce <ssorce@redhat.com> -# -# Copyright (C) 2007 Red Hat -# see file 'COPYING' for use and warranty information -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; version 2 only -# -# 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. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -import string -import tempfile -import shutil -import os -import socket -import logging - -import service -from ipa import sysrestore -from ipa import ipautil - -def check_inst(): - # So far this file is always present in both RHEL5 and Fedora if all the necessary - # bind packages are installed (RHEL5 requires also the pkg: caching-nameserver) - if not os.path.exists('/etc/named.rfc1912.zones'): - return False - - return True - -class BindInstance(service.Service): - def __init__(self, fstore=None): - service.Service.__init__(self, "named") - self.fqdn = None - self.domain = None - self.host = None - self.ip_address = None - self.realm = None - self.sub_dict = None - - if fstore: - self.fstore = fstore - else: - self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') - - def setup(self, fqdn, ip_address, realm_name, domain_name): - self.fqdn = fqdn - self.ip_address = ip_address - self.realm = realm_name - self.domain = domain_name - self.host = fqdn.split(".")[0] - - self.__setup_sub_dict() - - def create_sample_bind_zone(self): - bind_txt = ipautil.template_file(ipautil.SHARE_DIR + "bind.zone.db.template", self.sub_dict) - [bind_fd, bind_name] = tempfile.mkstemp(".db","sample.zone.") - os.write(bind_fd, bind_txt) - os.close(bind_fd) - print "Sample zone file for bind has been created in "+bind_name - - def create_instance(self): - - try: - self.stop() - except: - pass - - self.step("Setting up our zone", self.__setup_zone) - self.step("Setting up named.conf", self.__setup_named_conf) - - self.step("restarting named", self.__start) - self.step("configuring named to start on boot", self.__enable) - - self.step("Changing resolv.conf to point to ourselves", self.__setup_resolv_conf) - self.start_creation("Configuring bind:") - - def __start(self): - try: - self.backup_state("running", self.is_running()) - self.restart() - except: - print "named service failed to start" - - def __enable(self): - self.backup_state("enabled", self.is_running()) - self.chkconfig_on() - - def __setup_sub_dict(self): - self.sub_dict = dict(FQDN=self.fqdn, - IP=self.ip_address, - DOMAIN=self.domain, - HOST=self.host, - REALM=self.realm) - - def __setup_zone(self): - self.backup_state("domain", self.domain) - zone_txt = ipautil.template_file(ipautil.SHARE_DIR + "bind.zone.db.template", self.sub_dict) - self.fstore.backup_file('/var/named/'+self.domain+'.zone.db') - zone_fd = open('/var/named/'+self.domain+'.zone.db', 'w') - zone_fd.write(zone_txt) - zone_fd.close() - - def __setup_named_conf(self): - self.fstore.backup_file('/etc/named.conf') - named_txt = ipautil.template_file(ipautil.SHARE_DIR + "bind.named.conf.template", self.sub_dict) - named_fd = open('/etc/named.conf', 'w') - named_fd.seek(0) - named_fd.truncate(0) - named_fd.write(named_txt) - named_fd.close() - - def __setup_resolv_conf(self): - self.fstore.backup_file('/etc/resolv.conf') - resolv_txt = "search "+self.domain+"\nnameserver "+self.ip_address+"\n" - resolv_fd = open('/etc/resolv.conf', 'w') - resolv_fd.seek(0) - resolv_fd.truncate(0) - resolv_fd.write(resolv_txt) - resolv_fd.close() - - def uninstall(self): - running = self.restore_state("running") - enabled = self.restore_state("enabled") - domain = self.restore_state("domain") - - if not running is None: - self.stop() - - if not domain is None: - try: - self.fstore.restore_file(os.path.join ("/var/named/", domain + ".zone.db")) - except ValueError, error: - logging.debug(error) - pass - - for f in ["/etc/named.conf", "/etc/resolv.conf"]: - try: - self.fstore.restore_file(f) - except ValueError, error: - logging.debug(error) - pass - - if not enabled is None and not enabled: - self.chkconfig_off() - - if not running is None and running: - self.start() diff --git a/ipa-server/ipaserver/certs.py b/ipa-server/ipaserver/certs.py deleted file mode 100644 index 8cb1d0883..000000000 --- a/ipa-server/ipaserver/certs.py +++ /dev/null @@ -1,424 +0,0 @@ -# Authors: Karl MacMillan <kmacmillan@mentalrootkit.com> -# -# Copyright (C) 2007 Red Hat -# see file 'COPYING' for use and warranty information -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; version 2 only -# -# 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. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -import os, stat, subprocess, re -import sha -import errno -import tempfile -import shutil - -from ipa import sysrestore -from ipa import ipautil - -CA_SERIALNO="/var/lib/ipa/ca_serialno" - -class CertDB(object): - def __init__(self, dir, fstore=None): - self.secdir = dir - - self.noise_fname = self.secdir + "/noise.txt" - self.passwd_fname = self.secdir + "/pwdfile.txt" - self.certdb_fname = self.secdir + "/cert8.db" - self.keydb_fname = self.secdir + "/key3.db" - self.secmod_fname = self.secdir + "/secmod.db" - self.cacert_fname = self.secdir + "/cacert.asc" - self.pk12_fname = self.secdir + "/cacert.p12" - self.pin_fname = self.secdir + "/pin.txt" - self.reqdir = tempfile.mkdtemp('', 'ipa-', '/var/lib/ipa') - self.certreq_fname = self.reqdir + "/tmpcertreq" - self.certder_fname = self.reqdir + "/tmpcert.der" - - # Making this a starting value that will generate - # unique values for the current DB is the - # responsibility of the caller for now. In the - # future we might automatically determine this - # for a given db. - self.cur_serial = -1 - - self.cacert_name = "CA certificate" - self.valid_months = "120" - self.keysize = "1024" - - # We are going to set the owner of all of the cert - # files to the owner of the containing directory - # instead of that of the process. This works when - # this is called by root for a daemon that runs as - # a normal user - mode = os.stat(self.secdir) - self.uid = mode[stat.ST_UID] - self.gid = mode[stat.ST_GID] - - if fstore: - self.fstore = fstore - else: - self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') - - def __del__(self): - shutil.rmtree(self.reqdir, ignore_errors=True) - - def set_serial_from_pkcs12(self): - """A CA cert was loaded from a PKCS#12 file. Set up our serial file""" - - self.cur_serial = self.find_cacert_serial() - try: - f=open(CA_SERIALNO,"w") - f.write(str(self.cur_serial)) - f.close() - except IOError, e: - raise RuntimeError("Unable to increment serial number: %s" % str(e)) - - def next_serial(self): - try: - f=open(CA_SERIALNO,"r") - r = f.readline() - try: - self.cur_serial = int(r) + 1 - except ValueError: - raise RuntimeError("The value in %s is not an integer" % CA_SERIALNO) - f.close() - except IOError, e: - if e.errno == errno.ENOENT: - self.cur_serial = 1000 - f=open(CA_SERIALNO,"w") - f.write(str(self.cur_serial)) - f.close() - else: - raise RuntimeError("Unable to determine serial number: %s" % str(e)) - - try: - f=open(CA_SERIALNO,"w") - f.write(str(self.cur_serial)) - f.close() - except IOError, e: - raise RuntimeError("Unable to increment serial number: %s" % str(e)) - - return str(self.cur_serial) - - def set_perms(self, fname, write=False): - os.chown(fname, self.uid, self.gid) - perms = stat.S_IRUSR - if write: - perms |= stat.S_IWUSR - os.chmod(fname, perms) - - def gen_password(self): - return sha.sha(ipautil.ipa_generate_password()).hexdigest() - - def run_certutil(self, args, stdin=None): - new_args = ["/usr/bin/certutil", "-d", self.secdir] - new_args = new_args + args - return ipautil.run(new_args, stdin) - - def run_signtool(self, args, stdin=None): - new_args = ["/usr/bin/signtool", "-d", self.secdir] - new_args = new_args + args - ipautil.run(new_args, stdin) - - def create_noise_file(self): - ipautil.backup_file(self.noise_fname) - f = open(self.noise_fname, "w") - f.write(self.gen_password()) - self.set_perms(self.noise_fname) - - def create_passwd_file(self, passwd=None): - ipautil.backup_file(self.passwd_fname) - f = open(self.passwd_fname, "w") - if passwd is not None: - f.write("%s\n" % passwd) - else: - f.write(self.gen_password()) - f.close() - self.set_perms(self.passwd_fname) - - def create_certdbs(self): - ipautil.backup_file(self.certdb_fname) - ipautil.backup_file(self.keydb_fname) - ipautil.backup_file(self.secmod_fname) - self.run_certutil(["-N", - "-f", self.passwd_fname]) - self.set_perms(self.passwd_fname, write=True) - - def create_ca_cert(self): - # Generate the encryption key - self.run_certutil(["-G", "-z", self.noise_fname, "-f", self.passwd_fname]) - # Generate the self-signed cert - self.run_certutil(["-S", "-n", self.cacert_name, - "-s", "cn=IPA Test Certificate Authority", - "-x", - "-t", "CT,,C", - "-m", self.next_serial(), - "-v", self.valid_months, - "-z", self.noise_fname, - "-f", self.passwd_fname]) - - def export_ca_cert(self, nickname, create_pkcs12=False): - """create_pkcs12 tells us whether we should create a PKCS#12 file - of the CA or not. If we are running on a replica then we won't - have the private key to make a PKCS#12 file so we don't need to - do that step.""" - # export the CA cert for use with other apps - ipautil.backup_file(self.cacert_fname) - self.run_certutil(["-L", "-n", nickname, - "-a", - "-o", self.cacert_fname]) - self.set_perms(self.cacert_fname) - if create_pkcs12: - ipautil.backup_file(self.pk12_fname) - ipautil.run(["/usr/bin/pk12util", "-d", self.secdir, - "-o", self.pk12_fname, - "-n", self.cacert_name, - "-w", self.passwd_fname, - "-k", self.passwd_fname]) - self.set_perms(self.pk12_fname) - - def load_cacert(self, cacert_fname): - self.run_certutil(["-A", "-n", self.cacert_name, - "-t", "CT,,C", - "-a", - "-i", cacert_fname]) - - def find_cacert_serial(self): - (out,err) = self.run_certutil(["-L", "-n", self.cacert_name]) - data = out.split('\n') - for line in data: - x = re.match(r'\s+Serial Number: (\d+) .*', line) - if x is not None: - return x.group(1) - - raise RuntimeError("Unable to find serial number") - - def create_server_cert(self, nickname, name, other_certdb=None): - cdb = other_certdb - if not cdb: - cdb = self - self.request_cert(name) - cdb.issue_server_cert(self.certreq_fname, self.certder_fname) - self.add_cert(self.certder_fname, nickname) - os.unlink(self.certreq_fname) - os.unlink(self.certder_fname) - - def create_signing_cert(self, nickname, name, other_certdb=None): - cdb = other_certdb - if not cdb: - cdb = self - self.request_cert(name) - cdb.issue_signing_cert(self.certreq_fname, self.certder_fname) - self.add_cert(self.certder_fname, nickname) - os.unlink(self.certreq_fname) - os.unlink(self.certder_fname) - - def request_cert(self, name): - self.run_certutil(["-R", "-s", name, - "-o", self.certreq_fname, - "-g", self.keysize, - "-z", self.noise_fname, - "-f", self.passwd_fname]) - - def issue_server_cert(self, certreq_fname, cert_fname): - p = subprocess.Popen(["/usr/bin/certutil", - "-d", self.secdir, - "-C", "-c", self.cacert_name, - "-i", certreq_fname, - "-o", cert_fname, - "-m", self.next_serial(), - "-v", self.valid_months, - "-f", self.passwd_fname, - "-1", "-5"], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE) - - # Bah - this sucks, but I guess it isn't possible to fully - # control this with command line arguments. - # - # What this is requesting is: - # -1 (Create key usage extension) - # 2 - Key encipherment - # 9 - done - # n - not critical - # - # -5 (Create netscape cert type extension) - # 1 - SSL Server - # 9 - done - # n - not critical - p.stdin.write("2\n9\nn\n1\n9\nn\n") - p.wait() - - def issue_signing_cert(self, certreq_fname, cert_fname): - p = subprocess.Popen(["/usr/bin/certutil", - "-d", self.secdir, - "-C", "-c", self.cacert_name, - "-i", certreq_fname, - "-o", cert_fname, - "-m", self.next_serial(), - "-v", self.valid_months, - "-f", self.passwd_fname, - "-1", "-5"], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE) - - # Bah - this sucks, but I guess it isn't possible to fully - # control this with command line arguments. - # - # What this is requesting is: - # -1 (Create key usage extension) - # 0 - Digital Signature - # 5 - Cert signing key - # 9 - done - # n - not critical - # - # -5 (Create netscape cert type extension) - # 3 - Object Signing - # 9 - done - # n - not critical - p.stdin.write("0\n5\n9\nn\n3\n9\nn\n") - p.wait() - - def add_cert(self, cert_fname, nickname): - self.run_certutil(["-A", "-n", nickname, - "-t", "u,u,u", - "-i", cert_fname, - "-f", cert_fname]) - - def create_pin_file(self): - ipautil.backup_file(self.pin_fname) - f = open(self.pin_fname, "w") - f.write("Internal (Software) Token:") - pwd = open(self.passwd_fname) - f.write(pwd.read()) - f.close() - self.set_perms(self.pin_fname) - - def find_root_cert(self, nickname): - p = subprocess.Popen(["/usr/bin/certutil", "-d", self.secdir, - "-O", "-n", nickname], stdout=subprocess.PIPE) - - chain = p.stdout.read() - chain = chain.split("\n") - - root_nickname = re.match('\ *"(.*)".*', chain[0]).groups()[0] - - return root_nickname - - def trust_root_cert(self, nickname): - root_nickname = self.find_root_cert(nickname) - - self.run_certutil(["-M", "-n", root_nickname, - "-t", "CT,CT,"]) - - def find_server_certs(self): - p = subprocess.Popen(["/usr/bin/certutil", "-d", self.secdir, - "-L"], stdout=subprocess.PIPE) - - certs = p.stdout.read() - - certs = certs.split("\n") - - server_certs = [] - - for cert in certs: - fields = cert.split() - if not len(fields): - continue - flags = fields[-1] - if 'u' in flags: - name = " ".join(fields[0:-1]) - # NSS 3.12 added a header to the certutil output - if name == "Certificate Nickname Trust": - continue - server_certs.append((name, flags)) - - return server_certs - - def import_pkcs12(self, pkcs12_fname, passwd_fname=None): - args = ["/usr/bin/pk12util", "-d", self.secdir, - "-i", pkcs12_fname, - "-k", self.passwd_fname] - if passwd_fname: - args = args + ["-w", passwd_fname] - try: - ipautil.run(args) - except ipautil.CalledProcessError, e: - if e.returncode == 17: - raise RuntimeError("incorrect password") - else: - raise RuntimeError("unknown error import pkcs#12 file") - - def export_pkcs12(self, pkcs12_fname, pkcs12_pwd_fname, nickname="CA certificate"): - ipautil.run(["/usr/bin/pk12util", "-d", self.secdir, - "-o", pkcs12_fname, - "-n", nickname, - "-k", self.passwd_fname, - "-w", pkcs12_pwd_fname]) - - def create_self_signed(self, passwd=None): - self.create_noise_file() - self.create_passwd_file(passwd) - self.create_certdbs() - self.create_ca_cert() - self.export_ca_cert(self.cacert_name, True) - self.create_pin_file() - - def create_from_cacert(self, cacert_fname, passwd=""): - self.create_noise_file() - self.create_passwd_file(passwd) - self.create_certdbs() - self.load_cacert(cacert_fname) - - def create_from_pkcs12(self, pkcs12_fname, pkcs12_pwd_fname, passwd=None): - """Create a new NSS database using the certificates in a PKCS#12 file. - - pkcs12_fname: the filename of the PKCS#12 file - pkcs12_pwd_fname: the file containing the pin for the PKCS#12 file - nickname: the nickname/friendly-name of the cert we are loading - passwd: The password to use for the new NSS database we are creating - """ - self.create_noise_file() - self.create_passwd_file(passwd) - self.create_certdbs() - self.import_pkcs12(pkcs12_fname, pkcs12_pwd_fname) - server_certs = self.find_server_certs() - if len(server_certs) == 0: - raise RuntimeError("Could not find a suitable server cert in import in %s" % pkcs12_fname) - - # We only handle one server cert - nickname = server_certs[0][0] - - self.cacert_name = self.find_root_cert(nickname) - self.trust_root_cert(nickname) - self.create_pin_file() - self.export_ca_cert(self.cacert_name, False) - - # This file implies that we have our own self-signed CA. Ensure - # that it no longer exists (from previous installs, for example). - try: - os.remove(CA_SERIALNO) - except: - pass - - def backup_files(self): - self.fstore.backup_file(self.noise_fname) - self.fstore.backup_file(self.passwd_fname) - self.fstore.backup_file(self.certdb_fname) - self.fstore.backup_file(self.keydb_fname) - self.fstore.backup_file(self.secmod_fname) - self.fstore.backup_file(self.cacert_fname) - self.fstore.backup_file(self.pk12_fname) - self.fstore.backup_file(self.pin_fname) - self.fstore.backup_file(self.certreq_fname) - self.fstore.backup_file(self.certder_fname) diff --git a/ipa-server/ipaserver/dsinstance.py b/ipa-server/ipaserver/dsinstance.py deleted file mode 100644 index e9826bf68..000000000 --- a/ipa-server/ipaserver/dsinstance.py +++ /dev/null @@ -1,479 +0,0 @@ -# Authors: Karl MacMillan <kmacmillan@mentalrootkit.com> -# Simo Sorce <ssorce@redhat.com> -# -# Copyright (C) 2007 Red Hat -# see file 'COPYING' for use and warranty information -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; version 2 only -# -# 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. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -import shutil -import logging -import pwd -import glob -import sys -import os -import re -import time -import tempfile -import stat - -from ipa import ipautil - -import service -import installutils -import certs -import ipaldap, ldap -from ipaserver import ldapupdate - -SERVER_ROOT_64 = "/usr/lib64/dirsrv" -SERVER_ROOT_32 = "/usr/lib/dirsrv" - -def realm_to_suffix(realm_name): - s = realm_name.split(".") - terms = ["dc=" + x.lower() for x in s] - return ",".join(terms) - -def find_server_root(): - if ipautil.dir_exists(SERVER_ROOT_64): - return SERVER_ROOT_64 - else: - return SERVER_ROOT_32 - -def realm_to_serverid(realm_name): - return "-".join(realm_name.split(".")) - -def config_dirname(serverid): - return "/etc/dirsrv/slapd-" + serverid + "/" - -def schema_dirname(serverid): - return config_dirname(serverid) + "/schema/" - -def erase_ds_instance_data(serverid): - try: - shutil.rmtree("/etc/dirsrv/slapd-%s" % serverid) - except: - pass - try: - shutil.rmtree("/usr/lib/dirsrv/slapd-%s" % serverid) - except: - pass - try: - shutil.rmtree("/usr/lib64/dirsrv/slapd-%s" % serverid) - except: - pass - try: - shutil.rmtree("/var/lib/dirsrv/slapd-%s" % serverid) - except: - pass - try: - shutil.rmtree("/var/lock/dirsrv/slapd-%s" % serverid) - except: - pass -# try: -# shutil.rmtree("/var/log/dirsrv/slapd-%s" % serverid) -# except: -# pass - -def check_existing_installation(): - dirs = glob.glob("/etc/dirsrv/slapd-*") - if not dirs: - return [] - - serverids = [] - for d in dirs: - serverids.append(os.path.basename(d).split("slapd-", 1)[1]) - - return serverids - -def check_ports(): - ds_unsecure = installutils.port_available(389) - ds_secure = installutils.port_available(636) - return (ds_unsecure, ds_secure) - -def is_ds_running(): - """The DS init script always returns 0 when requesting status so it cannot - be used to determine if the server is running. We have to look at the - output. - """ - ret = True - try: - (sout, serr) = ipautil.run(["/sbin/service", "dirsrv", "status"]) - if sout.find("is stopped") >= 0: - ret = False - except ipautil.CalledProcessError: - ret = False - return ret - - -INF_TEMPLATE = """ -[General] -FullMachineName= $FQHN -SuiteSpotUserID= $USER -ServerRoot= $SERVER_ROOT -[slapd] -ServerPort= 389 -ServerIdentifier= $SERVERID -Suffix= $SUFFIX -RootDN= cn=Directory Manager -RootDNPwd= $PASSWORD -InstallLdifFile= /var/lib/dirsrv/boot.ldif -""" - -BASE_TEMPLATE = """ -dn: $SUFFIX -objectClass: top -objectClass: domain -objectClass: pilotObject -dc: $BASEDC -info: IPA V1.0 -""" - -class DsInstance(service.Service): - def __init__(self, realm_name=None, domain_name=None, dm_password=None): - service.Service.__init__(self, "dirsrv") - self.realm_name = realm_name - self.dm_password = dm_password - self.sub_dict = None - self.domain = domain_name - self.serverid = None - self.host_name = None - self.pkcs12_info = None - self.ds_user = None - if realm_name: - self.suffix = realm_to_suffix(self.realm_name) - self.__setup_sub_dict() - else: - self.suffix = None - - def create_instance(self, ds_user, realm_name, host_name, domain_name, dm_password, pkcs12_info=None): - self.ds_user = ds_user - self.realm_name = realm_name.upper() - self.serverid = realm_to_serverid(self.realm_name) - self.suffix = realm_to_suffix(self.realm_name) - self.host_name = host_name - self.dm_password = dm_password - self.domain = domain_name - self.pkcs12_info = pkcs12_info - self.__setup_sub_dict() - - self.step("creating directory server user", self.__create_ds_user) - self.step("creating directory server instance", self.__create_instance) - self.step("adding default schema", self.__add_default_schemas) - self.step("enabling memberof plugin", self.__add_memberof_module) - self.step("enabling referential integrity plugin", self.__add_referint_module) - self.step("enabling distributed numeric assignment plugin", self.__add_dna_module) - self.step("enabling winsync plugin", self.__add_winsync_module) - self.step("configuring uniqueness plugin", self.__set_unique_attrs) - self.step("creating indices", self.__create_indices) - self.step("configuring ssl for ds instance", self.__enable_ssl) - self.step("configuring certmap.conf", self.__certmap_conf) - self.step("restarting directory server", self.__restart_instance) - self.step("adding default layout", self.__add_default_layout) - self.step("configuring Posix uid/gid generation as first master", - self.__config_uidgid_gen_first_master) - self.step("adding master entry as first master", - self.__add_master_entry_first_master) - self.step("initializing group membership", - self.init_memberof) - - self.step("configuring directory to start on boot", self.__enable) - - self.start_creation("Configuring directory server:") - - def __enable(self): - self.backup_state("enabled", self.is_enabled()) - self.chkconfig_on() - - def __setup_sub_dict(self): - server_root = find_server_root() - self.sub_dict = dict(FQHN=self.host_name, SERVERID=self.serverid, - PASSWORD=self.dm_password, SUFFIX=self.suffix.lower(), - REALM=self.realm_name, USER=self.ds_user, - SERVER_ROOT=server_root, DOMAIN=self.domain, - TIME=int(time.time())) - - def __create_ds_user(self): - user_exists = True - try: - pwd.getpwnam(self.ds_user) - logging.debug("ds user %s exists" % self.ds_user) - except KeyError: - user_exists = False - logging.debug("adding ds user %s" % self.ds_user) - args = ["/usr/sbin/useradd", "-c", "DS System User", "-d", "/var/lib/dirsrv", "-M", "-r", "-s", "/sbin/nologin", self.ds_user] - try: - ipautil.run(args) - logging.debug("done adding user") - except ipautil.CalledProcessError, e: - logging.critical("failed to add user %s" % e) - - self.backup_state("user", self.ds_user) - self.backup_state("user_exists", user_exists) - - def __create_instance(self): - self.backup_state("running", is_ds_running()) - self.backup_state("serverid", self.serverid) - - self.sub_dict['BASEDC'] = self.realm_name.split('.')[0].lower() - base_txt = ipautil.template_str(BASE_TEMPLATE, self.sub_dict) - logging.debug(base_txt) - base_fd = file("/var/lib/dirsrv/boot.ldif", "w") - base_fd.write(base_txt) - base_fd.flush() - base_fd.close() - - inf_txt = ipautil.template_str(INF_TEMPLATE, self.sub_dict) - logging.debug("writing inf template") - inf_fd = ipautil.write_tmp_file(inf_txt) - inf_txt = re.sub(r"RootDNPwd=.*\n", "", inf_txt) - logging.debug(inf_txt) - if ipautil.file_exists("/usr/sbin/setup-ds.pl"): - args = ["/usr/sbin/setup-ds.pl", "--silent", "--logfile", "-", "-f", inf_fd.name] - logging.debug("calling setup-ds.pl") - else: - args = ["/usr/bin/ds_newinst.pl", inf_fd.name] - logging.debug("calling ds_newinst.pl") - try: - ipautil.run(args) - logging.debug("completed creating ds instance") - except ipautil.CalledProcessError, e: - logging.critical("failed to restart ds instance %s" % e) - logging.debug("restarting ds instance") - try: - self.restart() - logging.debug("done restarting ds instance") - except ipautil.CalledProcessError, e: - print "failed to restart ds instance", e - logging.debug("failed to restart ds instance %s" % e) - inf_fd.close() - os.remove("/var/lib/dirsrv/boot.ldif") - - def __add_default_schemas(self): - shutil.copyfile(ipautil.SHARE_DIR + "60kerberos.ldif", - schema_dirname(self.serverid) + "60kerberos.ldif") - shutil.copyfile(ipautil.SHARE_DIR + "60samba.ldif", - schema_dirname(self.serverid) + "60samba.ldif") - shutil.copyfile(ipautil.SHARE_DIR + "60radius.ldif", - schema_dirname(self.serverid) + "60radius.ldif") - shutil.copyfile(ipautil.SHARE_DIR + "60ipaconfig.ldif", - schema_dirname(self.serverid) + "60ipaconfig.ldif") - - def __restart_instance(self): - try: - self.restart() - if not is_ds_running(): - logging.critical("Failed to restart the directory server. See the installation log for details.") - sys.exit(1) - except SystemExit, e: - raise e - except Exception, e: - # TODO: roll back here? - logging.critical("Failed to restart the directory server. See the installation log for details.") - - def __ldap_mod(self, ldif, sub_dict = None): - fd = None - path = ipautil.SHARE_DIR + ldif - - if not sub_dict is None: - txt = ipautil.template_file(path, sub_dict) - fd = ipautil.write_tmp_file(txt) - path = fd.name - - [pw_fd, pw_name] = tempfile.mkstemp() - os.write(pw_fd, self.dm_password) - os.close(pw_fd) - - args = ["/usr/bin/ldapmodify", "-h", "127.0.0.1", "-xv", - "-D", "cn=Directory Manager", "-y", pw_name, "-f", path] - - try: - try: - ipautil.run(args) - except ipautil.CalledProcessError, e: - logging.critical("Failed to load %s: %s" % (ldif, str(e))) - finally: - os.remove(pw_name) - - if not fd is None: - fd.close() - - def __add_memberof_module(self): - self.__ldap_mod("memberof-conf.ldif") - - def init_memberof(self): - self.__ldap_mod("memberof-task.ldif", self.sub_dict) - - def apply_updates(self): - ld = ldapupdate.LDAPUpdate(dm_password=self.dm_password) - files = ld.get_all_files(ldapupdate.UPDATES_DIR) - ld.update(files) - - def __add_referint_module(self): - self.__ldap_mod("referint-conf.ldif") - - def __add_dna_module(self): - self.__ldap_mod("dna-conf.ldif") - - def __set_unique_attrs(self): - self.__ldap_mod("unique-attributes.ldif", self.sub_dict) - - def __config_uidgid_gen_first_master(self): - self.__ldap_mod("dna-posix.ldif", self.sub_dict) - - def __add_master_entry_first_master(self): - self.__ldap_mod("master-entry.ldif", self.sub_dict) - - def __add_winsync_module(self): - self.__ldap_mod("ipa-winsync-conf.ldif") - - def __enable_ssl(self): - dirname = config_dirname(self.serverid) - ca = certs.CertDB(dirname) - if self.pkcs12_info: - ca.create_from_pkcs12(self.pkcs12_info[0], self.pkcs12_info[1]) - server_certs = ca.find_server_certs() - if len(server_certs) == 0: - raise RuntimeError("Could not find a suitable server cert in import in %s" % pkcs12_info[0]) - - # We only handle one server cert - nickname = server_certs[0][0] - else: - ca.create_self_signed() - ca.create_server_cert("Server-Cert", "cn=%s,ou=Fedora Directory Server" % self.host_name) - nickname = "Server-Cert" - - conn = ipaldap.IPAdmin("127.0.0.1") - conn.simple_bind_s("cn=directory manager", self.dm_password) - - mod = [(ldap.MOD_REPLACE, "nsSSLClientAuth", "allowed"), - (ldap.MOD_REPLACE, "nsSSL3Ciphers", - "-rsa_null_md5,+rsa_rc4_128_md5,+rsa_rc4_40_md5,+rsa_rc2_40_md5,\ -+rsa_des_sha,+rsa_fips_des_sha,+rsa_3des_sha,+rsa_fips_3des_sha,+fortezza,\ -+fortezza_rc4_128_sha,+fortezza_null,+tls_rsa_export1024_with_rc4_56_sha,\ -+tls_rsa_export1024_with_des_cbc_sha")] - conn.modify_s("cn=encryption,cn=config", mod) - - mod = [(ldap.MOD_ADD, "nsslapd-security", "on"), - (ldap.MOD_REPLACE, "nsslapd-ssl-check-hostname", "off")] - conn.modify_s("cn=config", mod) - - entry = ipaldap.Entry("cn=RSA,cn=encryption,cn=config") - - entry.setValues("objectclass", "top", "nsEncryptionModule") - entry.setValues("cn", "RSA") - entry.setValues("nsSSLPersonalitySSL", nickname) - entry.setValues("nsSSLToken", "internal (software)") - entry.setValues("nsSSLActivation", "on") - - conn.addEntry(entry) - - conn.unbind() - - def __add_default_layout(self): - self.__ldap_mod("bootstrap-template.ldif", self.sub_dict) - - def __create_indices(self): - self.__ldap_mod("indices.ldif") - - def __certmap_conf(self): - shutil.copyfile(ipautil.SHARE_DIR + "certmap.conf.template", - config_dirname(self.serverid) + "certmap.conf") - - def change_admin_password(self, password): - logging.debug("Changing admin password") - dirname = config_dirname(self.serverid) - if ipautil.dir_exists("/usr/lib64/mozldap"): - app = "/usr/lib64/mozldap/ldappasswd" - else: - app = "/usr/lib/mozldap/ldappasswd" - args = [app, - "-D", "cn=Directory Manager", "-w", self.dm_password, - "-P", dirname+"/cert8.db", "-ZZZ", "-s", password, - "uid=admin,cn=users,cn=accounts,"+self.suffix] - try: - ipautil.run(args) - logging.debug("ldappasswd done") - except ipautil.CalledProcessError, e: - print "Unable to set admin password", e - logging.debug("Unable to set admin password %s" % e) - - def uninstall(self): - running = self.restore_state("running") - enabled = self.restore_state("enabled") - - if not running is None: - self.stop() - - if not enabled is None and not enabled: - self.chkconfig_off() - - serverid = self.restore_state("serverid") - if not serverid is None: - erase_ds_instance_data(serverid) - - ds_user = self.restore_state("user") - user_exists = self.restore_state("user_exists") - - if not ds_user is None and not user_exists is None and not user_exists: - try: - ipautil.run(["/usr/sbin/userdel", ds_user]) - except ipautil.CalledProcessError, e: - logging.critical("failed to delete user %s" % e) - - if self.restore_state("running"): - self.start() - - # we could probably move this function into the service.Service - # class - it's very generic - all we need is a way to get an - # instance of a particular Service - def add_ca_cert(self, cacert_fname, cacert_name=''): - """Add a CA certificate to the directory server cert db. We - first have to shut down the directory server in case it has - opened the cert db read-only. Then we use the CertDB class - to add the CA cert. We have to provide a nickname, and we - do not use 'CA certificate' since that's the default, so - we use 'Imported CA' if none specified. Then we restart - the server.""" - # first make sure we have a valid cacert_fname - try: - if not os.access(cacert_fname, os.R_OK): - logging.critical("The given CA cert file named [%s] could not be read" % - cacert_fname) - return False - except OSError, e: - logging.critical("The given CA cert file named [%s] could not be read: %s" % - (cacert_fname, str(e))) - return False - # ok - ca cert file can be read - # shutdown the server - self.stop() - - dirname = config_dirname(realm_to_serverid(self.realm_name)) - certdb = certs.CertDB(dirname) - if not cacert_name or len(cacert_name) == 0: - cacert_name = "Imported CA" - # we can't pass in the nickname, so we set the instance variable - certdb.cacert_name = cacert_name - status = True - try: - certdb.load_cacert(cacert_fname) - except ipalib.CalledProcessError, e: - logging.critical("Error importing CA cert file named [%s]: %s" % - (cacert_fname, str(e))) - status = False - # restart the directory server - self.start() - - return status diff --git a/ipa-server/ipaserver/httpinstance.py b/ipa-server/ipaserver/httpinstance.py deleted file mode 100644 index f5a903b30..000000000 --- a/ipa-server/ipaserver/httpinstance.py +++ /dev/null @@ -1,231 +0,0 @@ -# Authors: Rob Crittenden <rcritten@redhat.com> -# -# Copyright (C) 2007 Red Hat -# see file 'COPYING' for use and warranty information -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; version 2 only -# -# 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. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -import os -import os.path -import subprocess -import string -import tempfile -import logging -import pwd -import fileinput -import sys -import shutil - -import service -import certs -import dsinstance -import installutils -from ipa import sysrestore -from ipa import ipautil - -HTTPD_DIR = "/etc/httpd" -SSL_CONF = HTTPD_DIR + "/conf.d/ssl.conf" -NSS_CONF = HTTPD_DIR + "/conf.d/nss.conf" -NSS_DIR = HTTPD_DIR + "/alias" - -selinux_warning = """WARNING: could not set selinux boolean httpd_can_network_connect to true. -The web interface may not function correctly until this boolean is -successfully change with the command: - /usr/sbin/setsebool -P httpd_can_network_connect true -Try updating the policycoreutils and selinux-policy packages. -""" - -class WebGuiInstance(service.SimpleServiceInstance): - def __init__(self): - service.SimpleServiceInstance.__init__(self, "ipa_webgui") - -class HTTPInstance(service.Service): - def __init__(self, fstore = None): - service.Service.__init__(self, "httpd") - if fstore: - self.fstore = fstore - else: - self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') - - def create_instance(self, realm, fqdn, domain_name, autoconfig=True, pkcs12_info=None): - self.fqdn = fqdn - self.realm = realm - self.domain = domain_name - self.pkcs12_info = pkcs12_info - self.sub_dict = { "REALM" : realm, "FQDN": fqdn, "DOMAIN" : self.domain } - - self.step("disabling mod_ssl in httpd", self.__disable_mod_ssl) - self.step("Setting mod_nss port to 443", self.__set_mod_nss_port) - self.step("Adding URL rewriting rules", self.__add_include) - self.step("configuring httpd", self.__configure_http) - self.step("creating a keytab for httpd", self.__create_http_keytab) - self.step("Setting up ssl", self.__setup_ssl) - if autoconfig: - self.step("Setting up browser autoconfig", self.__setup_autoconfig) - self.step("configuring SELinux for httpd", self.__selinux_config) - self.step("restarting httpd", self.__start) - self.step("configuring httpd to start on boot", self.__enable) - - self.start_creation("Configuring the web interface") - - def __start(self): - self.backup_state("running", self.is_running()) - self.restart() - - def __enable(self): - self.backup_state("enabled", self.is_running()) - self.chkconfig_on() - - def __selinux_config(self): - selinux=0 - try: - if (os.path.exists('/usr/sbin/selinuxenabled')): - ipautil.run(["/usr/sbin/selinuxenabled"]) - selinux=1 - except ipautil.CalledProcessError: - # selinuxenabled returns 1 if not enabled - pass - - if selinux: - try: - # returns e.g. "httpd_can_network_connect --> off" - (stdout, stderr) = ipautils.run(["/usr/sbin/getsebool", - "httpd_can_network_connect"]) - self.backup_state("httpd_can_network_connect", stdout.split()[2]) - except: - pass - - # Allow apache to connect to the turbogears web gui - # This can still fail even if selinux is enabled - try: - ipautil.run(["/usr/sbin/setsebool", "-P", "httpd_can_network_connect", "true"]) - except: - self.print_msg(selinux_warning) - - def __create_http_keytab(self): - http_principal = "HTTP/" + self.fqdn + "@" + self.realm - installutils.kadmin_addprinc(http_principal) - installutils.create_keytab("/etc/httpd/conf/ipa.keytab", http_principal) - - pent = pwd.getpwnam("apache") - os.chown("/etc/httpd/conf/ipa.keytab", pent.pw_uid, pent.pw_gid) - - def __configure_http(self): - http_txt = ipautil.template_file(ipautil.SHARE_DIR + "ipa.conf", self.sub_dict) - self.fstore.backup_file("/etc/httpd/conf.d/ipa.conf") - http_fd = open("/etc/httpd/conf.d/ipa.conf", "w") - http_fd.write(http_txt) - http_fd.close() - - http_txt = ipautil.template_file(ipautil.SHARE_DIR + "ipa-rewrite.conf", self.sub_dict) - self.fstore.backup_file("/etc/httpd/conf.d/ipa-rewrite.conf") - http_fd = open("/etc/httpd/conf.d/ipa-rewrite.conf", "w") - http_fd.write(http_txt) - http_fd.close() - - def __disable_mod_ssl(self): - if os.path.exists(SSL_CONF): - self.fstore.backup_file(SSL_CONF) - os.unlink(SSL_CONF) - - def __set_mod_nss_port(self): - self.fstore.backup_file(NSS_CONF) - if installutils.update_file(NSS_CONF, '8443', '443') != 0: - print "Updating port in %s failed." % NSS_CONF - - def __set_mod_nss_nickname(self, nickname): - installutils.set_directive(NSS_CONF, 'NSSNickname', nickname) - - def __add_include(self): - """This should run after __set_mod_nss_port so is already backed up""" - if installutils.update_file(NSS_CONF, '</VirtualHost>', 'Include conf.d/ipa-rewrite.conf\n</VirtualHost>') != 0: - print "Adding Include conf.d/ipa-rewrite to %s failed." % NSS_CONF - - def __setup_ssl(self): - ds_ca = certs.CertDB(dsinstance.config_dirname(dsinstance.realm_to_serverid(self.realm))) - ca = certs.CertDB(NSS_DIR) - if self.pkcs12_info: - ca.create_from_pkcs12(self.pkcs12_info[0], self.pkcs12_info[1], passwd="") - server_certs = ca.find_server_certs() - if len(server_certs) == 0: - raise RuntimeError("Could not find a suitable server cert in import in %s" % pkcs12_info[0]) - - # We only handle one server cert - nickname = server_certs[0][0] - - self.__set_mod_nss_nickname(nickname) - else: - ca.create_from_cacert(ds_ca.cacert_fname) - ca.create_server_cert("Server-Cert", "cn=%s,ou=Apache Web Server" % self.fqdn, ds_ca) - ca.create_signing_cert("Signing-Cert", "cn=%s,ou=Signing Certificate,o=Identity Policy Audit" % self.fqdn, ds_ca) - - # Fix the database permissions - os.chmod(NSS_DIR + "/cert8.db", 0640) - os.chmod(NSS_DIR + "/key3.db", 0640) - os.chmod(NSS_DIR + "/secmod.db", 0640) - - pent = pwd.getpwnam("apache") - os.chown(NSS_DIR + "/cert8.db", 0, pent.pw_gid ) - os.chown(NSS_DIR + "/key3.db", 0, pent.pw_gid ) - os.chown(NSS_DIR + "/secmod.db", 0, pent.pw_gid ) - - def __setup_autoconfig(self): - prefs_txt = ipautil.template_file(ipautil.SHARE_DIR + "preferences.html.template", self.sub_dict) - prefs_fd = open("/usr/share/ipa/html/preferences.html", "w") - prefs_fd.write(prefs_txt) - prefs_fd.close() - - # The signing cert is generated in __setup_ssl - ds_ca = certs.CertDB(dsinstance.config_dirname(dsinstance.realm_to_serverid(self.realm))) - ca = certs.CertDB(NSS_DIR) - - # Publish the CA certificate - shutil.copy(ds_ca.cacert_fname, "/usr/share/ipa/html/ca.crt") - os.chmod("/usr/share/ipa/html/ca.crt", 0444) - - tmpdir = tempfile.mkdtemp(prefix = "tmp-") - shutil.copy("/usr/share/ipa/html/preferences.html", tmpdir) - ca.run_signtool(["-k", "Signing-Cert", - "-Z", "/usr/share/ipa/html/configure.jar", - "-e", ".html", - tmpdir]) - shutil.rmtree(tmpdir) - - def uninstall(self): - running = self.restore_state("running") - enabled = self.restore_state("enabled") - - if not running is None: - self.stop() - - if not enabled is None and not enabled: - self.chkconfig_off() - - for f in ["/etc/httpd/conf.d/ipa.conf", SSL_CONF, NSS_CONF]: - try: - self.fstore.restore_file(f) - except ValueError, error: - logging.debug(error) - pass - - sebool_state = self.restore_state("httpd_can_network_connect") - if not sebool_state is None: - try: - ipautil.run(["/usr/sbin/setsebool", "-P", "httpd_can_network_connect", sebool_state]) - except: - self.print_msg(selinux_warning) - - if not running is None and running: - self.start() diff --git a/ipa-server/ipaserver/installutils.py b/ipa-server/ipaserver/installutils.py deleted file mode 100644 index 563b168e8..000000000 --- a/ipa-server/ipaserver/installutils.py +++ /dev/null @@ -1,248 +0,0 @@ -# Authors: Simo Sorce <ssorce@redhat.com> -# -# Copyright (C) 2007 Red Hat -# see file 'COPYING' for use and warranty information -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; version 2 only -# -# 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. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -import logging -import socket -import errno -import getpass -import os -import re -import fileinput -import sys -import time -import struct -import fcntl - -from ipa import ipautil -from ipa import dnsclient - -def get_fqdn(): - fqdn = "" - try: - fqdn = socket.getfqdn() - except: - try: - fqdn = socket.gethostname() - except: - fqdn = "" - return fqdn - -def verify_fqdn(host_name,no_host_dns=False): - - if len(host_name.split(".")) < 2 or host_name == "localhost.localdomain": - raise RuntimeError("Invalid hostname: " + host_name) - - try: - hostaddr = socket.getaddrinfo(host_name, None) - except: - raise RuntimeError("Unable to resolve host name, check /etc/hosts or DNS name resolution") - - if len(hostaddr) == 0: - raise RuntimeError("Unable to resolve host name, check /etc/hosts or DNS name resolution") - - for a in hostaddr: - if a[4][0] == '127.0.0.1' or a[4][0] == '::1': - raise RuntimeError("The IPA Server hostname cannot resolve to localhost (%s). A routable IP address must be used. Check /etc/hosts to see if %s is an alias for %s" % (a[4][0], host_name, a[4][0])) - try: - revname = socket.gethostbyaddr(a[4][0])[0] - except: - raise RuntimeError("Unable to resolve the reverse ip address, check /etc/hosts or DNS name resolution") - if revname != host_name: - raise RuntimeError("The host name %s does not match the reverse lookup %s" % (host_name, revname)) - - if no_host_dns: - print "Warning: skipping DNS resolution of host", host_name - return - - # Verify this is NOT a CNAME - rs = dnsclient.query(host_name+".", dnsclient.DNS_C_IN, dnsclient.DNS_T_CNAME) - if len(rs) != 0: - for rsn in rs: - if rsn.dns_type == dnsclient.DNS_T_CNAME: - raise RuntimeError("The IPA Server Hostname cannot be a CNAME, only A names are allowed.") - - # Verify that it is a DNS A record - rs = dnsclient.query(host_name+".", dnsclient.DNS_C_IN, dnsclient.DNS_T_A) - if len(rs) == 0: - print "Warning: Hostname (%s) not found in DNS" % host_name - return - - rec = None - for rsn in rs: - if rsn.dns_type == dnsclient.DNS_T_A: - rec = rsn - break - - if rec == None: - print "Warning: Hostname (%s) not found in DNS" % host_name - return - - # Compare the forward and reverse - forward = rec.dns_name - - addr = socket.inet_ntoa(struct.pack('<L',rec.rdata.address)) - ipaddr = socket.inet_ntoa(struct.pack('!L',rec.rdata.address)) - - addr = addr + ".in-addr.arpa." - rs = dnsclient.query(addr, dnsclient.DNS_C_IN, dnsclient.DNS_T_PTR) - if len(rs) == 0: - raise RuntimeError("Cannot find Reverse Address for %s (%s)" % (host_name, addr)) - - rev = None - for rsn in rs: - if rsn.dns_type == dnsclient.DNS_T_PTR: - rev = rsn - break - - if rev == None: - raise RuntimeError("Cannot find Reverse Address for %s (%s)" % (host_name, addr)) - - reverse = rev.rdata.ptrdname - - if forward != reverse: - raise RuntimeError("The DNS forward record %s does not match the reverse address %s" % (forward, reverse)) - -def port_available(port): - """Try to bind to a port on the wildcard host - Return 1 if the port is available - Return 0 if the port is in use - """ - rv = 1 - - try: - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - fcntl.fcntl(s, fcntl.F_SETFD, fcntl.FD_CLOEXEC) - s.bind(('', port)) - s.close() - except socket.error, e: - if e[0] == errno.EADDRINUSE: - rv = 0 - - if rv: - try: - s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) - fcntl.fcntl(s, fcntl.F_SETFD, fcntl.FD_CLOEXEC) - s.bind(('', port)) - s.close() - except socket.error, e: - if e[0] == errno.EADDRINUSE: - rv = 0 - - return rv - -def standard_logging_setup(log_filename, debug=False): - old_umask = os.umask(077) - # Always log everything (i.e., DEBUG) to the log - # file. - logging.basicConfig(level=logging.DEBUG, - format='%(asctime)s %(levelname)s %(message)s', - filename=log_filename, - filemode='w') - os.umask(old_umask) - - console = logging.StreamHandler() - # If the debug option is set, also log debug messages to the console - if debug: - console.setLevel(logging.DEBUG) - else: - # Otherwise, log critical and error messages - console.setLevel(logging.ERROR) - formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') - console.setFormatter(formatter) - logging.getLogger('').addHandler(console) - -def get_password(prompt): - if os.isatty(sys.stdin.fileno()): - return getpass.getpass(prompt) - else: - return sys.stdin.readline().rstrip() - -def read_password(user, confirm=True, validate=True): - correct = False - pwd = "" - while not correct: - pwd = get_password(user + " password: ") - if not pwd: - continue - if validate and len(pwd) < 8: - print "Password must be at least 8 characters long" - continue - if not confirm: - correct = True - continue - pwd_confirm = get_password("Password (confirm): ") - if pwd != pwd_confirm: - print "Password mismatch!" - print "" - else: - correct = True - print "" - return pwd - -def update_file(filename, orig, subst): - if os.path.exists(filename): - pattern = "%s" % re.escape(orig) - p = re.compile(pattern) - for line in fileinput.input(filename, inplace=1): - if not p.search(line): - sys.stdout.write(line) - else: - sys.stdout.write(p.sub(subst, line)) - fileinput.close() - return 0 - else: - print "File %s doesn't exist." % filename - return 1 - -def set_directive(filename, directive, value): - """Set a name/value pair directive in a configuration file. - - This has only been tested with nss.conf - """ - fd = open(filename) - file = [] - for line in fd: - if directive in line: - file.append('%s "%s"\n' % (directive, value)) - else: - file.append(line) - fd.close() - - fd = open(filename, "w") - fd.write("".join(file)) - fd.close() - -def kadmin(command): - ipautil.run(["/usr/kerberos/sbin/kadmin.local", "-q", command]) - -def kadmin_addprinc(principal): - kadmin("addprinc -randkey " + principal) - -def kadmin_modprinc(principal, options): - kadmin("modprinc " + options + " " + principal) - -def create_keytab(path, principal): - try: - if ipautil.file_exists(path): - os.remove(path) - except os.error: - logging.critical("Failed to remove %s." % path) - - kadmin("ktadd -k " + path + " " + principal) - diff --git a/ipa-server/ipaserver/ipaldap.py b/ipa-server/ipaserver/ipaldap.py deleted file mode 100644 index c2dbe4e2d..000000000 --- a/ipa-server/ipaserver/ipaldap.py +++ /dev/null @@ -1,701 +0,0 @@ -# Authors: Rich Megginson <richm@redhat.com> -# Rob Crittenden <rcritten@redhat.com -# -# Copyright (C) 2007 Red Hat -# see file 'COPYING' for use and warranty information -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; version 2 only -# -# 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. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -import sys -import os -import os.path -import popen2 -import base64 -import urllib -import urllib2 -import socket -import ldif -import re -import string -import ldap -import cStringIO -import time -import operator -import struct -import ldap.sasl -from ldap.controls import LDAPControl,DecodeControlTuples,EncodeControlTuples -from ldap.ldapobject import SimpleLDAPObject -from ipa import ipaerror, ipautil - -# Global variable to define SASL auth -sasl_auth = ldap.sasl.sasl({},'GSSAPI') - -class Entry: - """This class represents an LDAP Entry object. An LDAP entry consists of a DN - and a list of attributes. Each attribute consists of a name and a list of - values. In python-ldap, entries are returned as a list of 2-tuples. - Instance variables: - dn - string - the string DN of the entry - data - CIDict - case insensitive dict of the attributes and values""" - - def __init__(self,entrydata): - """data is the raw data returned from the python-ldap result method, which is - a search result entry or a reference or None. - If creating a new empty entry, data is the string DN.""" - if entrydata: - if isinstance(entrydata,tuple): - self.dn = entrydata[0] - self.data = ipautil.CIDict(entrydata[1]) - elif isinstance(entrydata,str) or isinstance(entrydata,unicode): - self.dn = entrydata - self.data = ipautil.CIDict() - else: - self.dn = '' - self.data = ipautil.CIDict() - - def __nonzero__(self): - """This allows us to do tests like if entry: returns false if there is no data, - true otherwise""" - return self.data != None and len(self.data) > 0 - - def hasAttr(self,name): - """Return True if this entry has an attribute named name, False otherwise""" - return self.data and self.data.has_key(name) - - def __getattr__(self,name): - """If name is the name of an LDAP attribute, return the first value for that - attribute - equivalent to getValue - this allows the use of - entry.cn - instead of - entry.getValue('cn') - This also allows us to return None if an attribute is not found rather than - throwing an exception""" - return self.getValue(name) - - def getValues(self,name): - """Get the list (array) of values for the attribute named name""" - return self.data.get(name) - - def getValue(self,name): - """Get the first value for the attribute named name""" - return self.data.get(name,[None])[0] - - def setValue(self,name,*value): - """Value passed in may be a single value, several values, or a single sequence. - For example: - ent.setValue('name', 'value') - ent.setValue('name', 'value1', 'value2', ..., 'valueN') - ent.setValue('name', ['value1', 'value2', ..., 'valueN']) - ent.setValue('name', ('value1', 'value2', ..., 'valueN')) - Since *value is a tuple, we may have to extract a list or tuple from that - tuple as in the last two examples above""" - if isinstance(value[0],list) or isinstance(value[0],tuple): - self.data[name] = value[0] - else: - self.data[name] = value - - setValues = setValue - - def toTupleList(self): - """Convert the attrs and values to a list of 2-tuples. The first element - of the tuple is the attribute name. The second element is either a - single value or a list of values.""" - return self.data.items() - - def __str__(self): - """Convert the Entry to its LDIF representation""" - return self.__repr__() - - # the ldif class base64 encodes some attrs which I would rather see in raw form - to - # encode specific attrs as base64, add them to the list below - ldif.safe_string_re = re.compile('^$') - base64_attrs = ['nsstate', 'krbprincipalkey', 'krbExtraData'] - - def __repr__(self): - """Convert the Entry to its LDIF representation""" - sio = cStringIO.StringIO() - # what's all this then? the unparse method will currently only accept - # a list or a dict, not a class derived from them. self.data is a - # cidict, so unparse barfs on it. I've filed a bug against python-ldap, - # but in the meantime, we have to convert to a plain old dict for printing - # I also don't want to see wrapping, so set the line width really high (1000) - newdata = {} - newdata.update(self.data) - ldif.LDIFWriter(sio,Entry.base64_attrs,1000).unparse(self.dn,newdata) - return sio.getvalue() - -def wrapper(f,name): - """This is the method that wraps all of the methods of the superclass. This seems - to need to be an unbound method, that's why it's outside of IPAdmin. Perhaps there - is some way to do this with the new classmethod or staticmethod of 2.4. - Basically, we replace every call to a method in SimpleLDAPObject (the superclass - of IPAdmin) with a call to inner. The f argument to wrapper is the bound method - of IPAdmin (which is inherited from the superclass). Bound means that it will implicitly - be called with the self argument, it is not in the args list. name is the name of - the method to call. If name is a method that returns entry objects (e.g. result), - we wrap the data returned by an Entry class. If name is a method that takes an entry - argument, we extract the raw data from the entry object to pass in.""" - def inner(*args, **kargs): - if name == 'result': - type, data = f(*args, **kargs) - # data is either a 2-tuple or a list of 2-tuples - # print data - if data: - if isinstance(data,tuple): - return type, Entry(data) - elif isinstance(data,list): - return type, [Entry(x) for x in data] - else: - raise TypeError, "unknown data type %s returned by result" % type(data) - else: - return type, data - elif name.startswith('add'): - # the first arg is self - # the second and third arg are the dn and the data to send - # We need to convert the Entry into the format used by - # python-ldap - ent = args[0] - if isinstance(ent,Entry): - return f(ent.dn, ent.toTupleList(), *args[2:]) - else: - return f(*args, **kargs) - else: - return f(*args, **kargs) - return inner - -class LDIFConn(ldif.LDIFParser): - def __init__( - self, - input_file, - ignored_attr_types=None,max_entries=0,process_url_schemes=None - ): - """ - See LDIFParser.__init__() - - Additional Parameters: - all_records - List instance for storing parsed records - """ - self.dndict = {} # maps dn to Entry - self.dnlist = [] # contains entries in order read - myfile = input_file - if isinstance(input_file,str) or isinstance(input_file,unicode): - myfile = open(input_file, "r") - ldif.LDIFParser.__init__(self,myfile,ignored_attr_types,max_entries,process_url_schemes) - self.parse() - if isinstance(input_file,str) or isinstance(input_file,unicode): - myfile.close() - - def handle(self,dn,entry): - """ - Append single record to dictionary of all records. - """ - if not dn: - dn = '' - newentry = Entry((dn, entry)) - self.dndict[IPAdmin.normalizeDN(dn)] = newentry - self.dnlist.append(newentry) - - def get(self,dn): - ndn = IPAdmin.normalizeDN(dn) - return self.dndict.get(ndn, Entry(None)) - -class IPAdmin(SimpleLDAPObject): - CFGSUFFIX = "o=NetscapeRoot" - DEFAULT_USER_ID = "nobody" - - def getDseAttr(self,attrname): - conffile = self.confdir + '/dse.ldif' - dseldif = LDIFConn(conffile) - cnconfig = dseldif.get("cn=config") - if cnconfig: - return cnconfig.getValue(attrname) - return None - - def __initPart2(self): - if self.binddn and len(self.binddn) and not hasattr(self,'sroot'): - try: - ent = self.getEntry('cn=config', ldap.SCOPE_BASE, '(objectclass=*)', - [ 'nsslapd-instancedir', 'nsslapd-errorlog', - 'nsslapd-certdir', 'nsslapd-schemadir' ]) - self.errlog = ent.getValue('nsslapd-errorlog') - self.confdir = ent.getValue('nsslapd-certdir') - if not self.confdir: - self.confdir = ent.getValue('nsslapd-schemadir') - if self.confdir: - self.confdir = os.path.dirname(self.confdir) - instdir = ent.getValue('nsslapd-instancedir') - ent = self.getEntry('cn=config,cn=ldbm database,cn=plugins,cn=config', - ldap.SCOPE_BASE, '(objectclass=*)', - [ 'nsslapd-directory' ]) - self.dbdir = os.path.dirname(ent.getValue('nsslapd-directory')) - except (ldap.INSUFFICIENT_ACCESS, ldap.CONNECT_ERROR): - pass # usually means - except ldap.OPERATIONS_ERROR, e: - pass # usually means this is Active Directory - except ldap.LDAPError, e: - print "caught exception ", e - raise - - def __localinit__(self): - """If a CA certificate is provided then it is assumed that we are - doing SSL client authentication with proxy auth. - - If a CA certificate is not present then it is assumed that we are - using a forwarded kerberos ticket for SASL auth. SASL provides - its own encryption. - """ - if self.cacert is not None: - SimpleLDAPObject.__init__(self,'ldaps://%s:%d' % (self.host,self.port)) - else: - SimpleLDAPObject.__init__(self,'ldap://%s:%d' % (self.host,self.port)) - - def __init__(self,host,port=389,cacert=None,bindcert=None,bindkey=None,proxydn=None,debug=None): - """We just set our instance variables and wrap the methods - the real - work is done in __localinit__ and __initPart2 - these are separated - out this way so that we can call them from places other than - instance creation e.g. when we just need to reconnect, not create a - new instance""" - if debug and debug.lower() == "on": - ldap.set_option(ldap.OPT_DEBUG_LEVEL,255) - if cacert is not None: - ldap.set_option(ldap.OPT_X_TLS_CACERTFILE,cacert) - if bindcert is not None: - ldap.set_option(ldap.OPT_X_TLS_CERTFILE,bindcert) - if bindkey is not None: - ldap.set_option(ldap.OPT_X_TLS_KEYFILE,bindkey) - - self.__wrapmethods() - self.port = port - self.host = host - self.cacert = cacert - self.bindcert = bindcert - self.bindkey = bindkey - self.proxydn = proxydn - self.suffixes = {} - self.__localinit__() - - def __str__(self): - return self.host + ":" + str(self.port) - - def __get_server_controls__(self): - """Create the proxy user server control. The control has the form - 0x04 = Octet String - 4|0x80 sets the length of the string length field at 4 bytes - the struct() gets us the length in bytes of string self.proxydn - self.proxydn is the proxy dn to send""" - - import sys - - if self.proxydn is not None: - proxydn = chr(0x04) + chr(4|0x80) + struct.pack('l', socket.htonl(len(self.proxydn))) + self.proxydn; - - # Create the proxy control - sctrl=[] - sctrl.append(LDAPControl('2.16.840.1.113730.3.4.18',True,proxydn)) - else: - sctrl=None - - return sctrl - - def toLDAPURL(self): - return "ldap://%s:%d/" % (self.host,self.port) - - def set_proxydn(self, proxydn): - self.proxydn = proxydn - - def set_krbccache(self, krbccache, principal): - if krbccache is not None: - os.environ["KRB5CCNAME"] = krbccache - self.sasl_interactive_bind_s("", sasl_auth) - self.principal = principal - self.proxydn = None - - def do_simple_bind(self, binddn="cn=directory manager", bindpw=""): - self.binddn = binddn - self.bindpwd = bindpw - self.simple_bind_s(binddn, bindpw) - self.__initPart2() - - def getEntry(self,*args): - """This wraps the search function. It is common to just get one entry""" - - sctrl = self.__get_server_controls__() - - if sctrl is not None: - self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl) - - try: - res = self.search(*args) - type, obj = self.result(res) - except ldap.NO_SUCH_OBJECT: - raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND, - notfound(args)) - except ldap.LDAPError, e: - raise ipaerror.gen_exception(ipaerror.LDAP_DATABASE_ERROR, None, e) - - if not obj: - raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND, - notfound(args)) - elif isinstance(obj,Entry): - return obj - else: # assume list/tuple - return obj[0] - - def getList(self,*args): - """This wraps the search function to find all users.""" - - sctrl = self.__get_server_controls__() - if sctrl is not None: - self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl) - - try: - res = self.search(*args) - type, obj = self.result(res) - except (ldap.ADMINLIMIT_EXCEEDED, ldap.SIZELIMIT_EXCEEDED), e: - raise ipaerror.gen_exception(ipaerror.LDAP_DATABASE_ERROR, - "Too many results returned by search", e) - except ldap.LDAPError, e: - raise ipaerror.gen_exception(ipaerror.LDAP_DATABASE_ERROR, None, e) - - if not obj: - raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND, - notfound(args)) - - all_users = [] - for s in obj: - all_users.append(s) - - return all_users - - def getListAsync(self,*args): - """This version performs an asynchronous search, to allow - results even if we hit a limit. - - It returns a list: counter followed by the results. - If the results are truncated, counter will be set to -1. - """ - - sctrl = self.__get_server_controls__() - if sctrl is not None: - self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl) - - entries = [] - partial = 0 - - try: - msgid = self.search_ext(*args) - type, result_list = self.result(msgid, 0) - while result_list: - for result in result_list: - entries.append(result) - type, result_list = self.result(msgid, 0) - except (ldap.ADMINLIMIT_EXCEEDED, ldap.SIZELIMIT_EXCEEDED, - ldap.TIMELIMIT_EXCEEDED), e: - partial = 1 - except ldap.LDAPError, e: - raise ipaerror.gen_exception(ipaerror.LDAP_DATABASE_ERROR, None, e) - - if not entries: - raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND, - notfound(args)) - - if partial == 1: - counter = -1 - else: - counter = len(entries) - - return [counter] + entries - - def addEntry(self,*args): - """This wraps the add function. It assumes that the entry is already - populated with all of the desired objectclasses and attributes""" - - sctrl = self.__get_server_controls__() - - try: - if sctrl is not None: - self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl) - self.add_s(*args) - except ldap.ALREADY_EXISTS: - raise ipaerror.gen_exception(ipaerror.LDAP_DUPLICATE) - except ldap.LDAPError, e: - raise ipaerror.gen_exception(ipaerror.LDAP_DATABASE_ERROR, None, e) - return "Success" - - def updateRDN(self, dn, newrdn): - """Wrap the modrdn function.""" - - sctrl = self.__get_server_controls__() - - if dn == newrdn: - # no need to report an error - return "Success" - - try: - if sctrl is not None: - self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl) - self.modrdn_s(dn, newrdn, delold=1) - except ldap.LDAPError, e: - raise ipaerror.gen_exception(ipaerror.LDAP_DATABASE_ERROR, None, e) - return "Success" - - def updateEntry(self,dn,olduser,newuser): - """This wraps the mod function. It assumes that the entry is already - populated with all of the desired objectclasses and attributes""" - - sctrl = self.__get_server_controls__() - - modlist = self.generateModList(olduser, newuser) - - if len(modlist) == 0: - raise ipaerror.gen_exception(ipaerror.LDAP_EMPTY_MODLIST) - - try: - if sctrl is not None: - self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl) - self.modify_s(dn, modlist) - # this is raised when a 'delete' attribute isn't found. - # it indicates the previous attribute was removed by another - # update, making the olduser stale. - except ldap.NO_SUCH_ATTRIBUTE: - raise ipaerror.gen_exception(ipaerror.LDAP_MIDAIR_COLLISION) - except ldap.LDAPError, e: - raise ipaerror.gen_exception(ipaerror.LDAP_DATABASE_ERROR, None, e) - return "Success" - - def generateModList(self, old_entry, new_entry): - """A mod list generator that computes more precise modification lists - than the python-ldap version. This version purposely generates no - REPLACE operations, to deal with multi-user updates more properly.""" - modlist = [] - - old_entry = ipautil.CIDict(old_entry) - new_entry = ipautil.CIDict(new_entry) - - keys = set(map(string.lower, old_entry.keys())) - keys.update(map(string.lower, new_entry.keys())) - - for key in keys: - new_values = new_entry.get(key, []) - if not(isinstance(new_values,list) or isinstance(new_values,tuple)): - new_values = [new_values] - new_values = filter(lambda value:value!=None, new_values) - new_values = set(new_values) - - old_values = old_entry.get(key, []) - if not(isinstance(old_values,list) or isinstance(old_values,tuple)): - old_values = [old_values] - old_values = filter(lambda value:value!=None, old_values) - old_values = set(old_values) - - adds = list(new_values.difference(old_values)) - removes = list(old_values.difference(new_values)) - - if len(removes) > 0: - modlist.append((ldap.MOD_DELETE, key, removes)) - if len(adds) > 0: - modlist.append((ldap.MOD_ADD, key, adds)) - - return modlist - - def inactivateEntry(self,dn,has_key): - """Rather than deleting entries we mark them as inactive. - has_key defines whether the entry already has nsAccountlock - set so we can determine which type of mod operation to run.""" - - sctrl = self.__get_server_controls__() - modlist=[] - - if has_key == True: - operation = ldap.MOD_REPLACE - else: - operation = ldap.MOD_ADD - - modlist.append((operation, "nsAccountlock", "true")) - - try: - if sctrl is not None: - self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl) - self.modify_s(dn, modlist) - except ldap.LDAPError, e: - raise ipaerror.gen_exception(ipaerror.LDAP_DATABASE_ERROR, None, e) - return "Success" - - def deleteEntry(self,*args): - """This wraps the delete function. Use with caution.""" - - sctrl = self.__get_server_controls__() - - try: - if sctrl is not None: - self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl) - self.delete_s(*args) - except ldap.LDAPError, e: - raise ipaerror.gen_exception(ipaerror.LDAP_DATABASE_ERROR, None, e) - return "Success" - - def modifyPassword(self,dn,oldpass,newpass): - """Set the user password using RFC 3062, LDAP Password Modify Extended - Operation. This ends up calling the IPA password slapi plugin - handler so the Kerberos password gets set properly. - - oldpass is not mandatory - """ - - sctrl = self.__get_server_controls__() - - try: - if sctrl is not None: - self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl) - self.passwd_s(dn, oldpass, newpass) - except ldap.LDAPError, e: - raise ipaerror.gen_exception(ipaerror.LDAP_DATABASE_ERROR, None, e) - return "Success" - - def __wrapmethods(self): - """This wraps all methods of SimpleLDAPObject, so that we can intercept - the methods that deal with entries. Instead of using a raw list of tuples - of lists of hashes of arrays as the entry object, we want to wrap entries - in an Entry class that provides some useful methods""" - for name in dir(self.__class__.__bases__[0]): - attr = getattr(self, name) - if callable(attr): - setattr(self, name, wrapper(attr, name)) - - def exportLDIF(self, file, suffix, forrepl=False, verbose=False): - cn = "export" + str(int(time.time())) - dn = "cn=%s, cn=export, cn=tasks, cn=config" % cn - entry = Entry(dn) - entry.setValues('objectclass', 'top', 'extensibleObject') - entry.setValues('cn', cn) - entry.setValues('nsFilename', file) - entry.setValues('nsIncludeSuffix', suffix) - if forrepl: - entry.setValues('nsExportReplica', 'true') - - rc = self.startTaskAndWait(entry, verbose) - - if rc: - if verbose: - print "Error: export task %s for file %s exited with %d" % (cn,file,rc) - else: - if verbose: - print "Export task %s for file %s completed successfully" % (cn,file) - return rc - - def waitForEntry(self, dn, timeout=7200, attr='', quiet=True): - scope = ldap.SCOPE_BASE - filter = "(objectclass=*)" - attrlist = [] - if attr: - filter = "(%s=*)" % attr - attrlist.append(attr) - timeout += int(time.time()) - - if isinstance(dn,Entry): - dn = dn.dn - - # wait for entry and/or attr to show up - if not quiet: - sys.stdout.write("Waiting for %s %s:%s " % (self,dn,attr)) - sys.stdout.flush() - entry = None - while not entry and int(time.time()) < timeout: - try: - entry = self.getEntry(dn, scope, filter, attrlist) - except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND): - pass # found entry, but no attr - except ldap.NO_SUCH_OBJECT: - pass # no entry yet - except ldap.LDAPError, e: # badness - print "\nError reading entry", dn, e - break - if not entry: - if not quiet: - sys.stdout.write(".") - sys.stdout.flush() - time.sleep(1) - - if not entry and int(time.time()) > timeout: - print "\nwaitForEntry timeout for %s for %s" % (self,dn) - elif entry and not quiet: - print "\nThe waited for entry is:", entry - elif not entry: - print "\nError: could not read entry %s from %s" % (dn,self) - - return entry - - def addSchema(self, attr, val): - dn = "cn=schema" - self.modify_s(dn, [(ldap.MOD_ADD, attr, val)]) - - def addAttr(self, *args): - return self.addSchema('attributeTypes', args) - - def addObjClass(self, *args): - return self.addSchema('objectClasses', args) - - ########################### - # Static methods start here - ########################### - def normalizeDN(dn): - # not great, but will do until we use a newer version of python-ldap - # that has DN utilities - ary = ldap.explode_dn(dn.lower()) - return ",".join(ary) - normalizeDN = staticmethod(normalizeDN) - - def getfqdn(name=''): - return socket.getfqdn(name) - getfqdn = staticmethod(getfqdn) - - def getdomainname(name=''): - fqdn = IPAdmin.getfqdn(name) - index = fqdn.find('.') - if index >= 0: - return fqdn[index+1:] - else: - return fqdn - getdomainname = staticmethod(getdomainname) - - def getdefaultsuffix(name=''): - dm = IPAdmin.getdomainname(name) - if dm: - return "dc=" + dm.replace('.', ', dc=') - else: - return 'dc=localdomain' - getdefaultsuffix = staticmethod(getdefaultsuffix) - - def is_a_dn(dn): - """Returns True if the given string is a DN, False otherwise.""" - return (dn.find("=") > 0) - is_a_dn = staticmethod(is_a_dn) - - -def notfound(args): - """Return a string suitable for displaying as an error when a - search returns no results. - - This just returns whatever is after the equals sign""" - if len(args) > 2: - filter = args[2] - try: - target = re.match(r'\(.*=(.*)\)', filter).group(1) - except: - target = filter - return "%s not found" % str(target) - else: - return args[0] diff --git a/ipa-server/ipaserver/krbinstance.py b/ipa-server/ipaserver/krbinstance.py deleted file mode 100644 index 252844304..000000000 --- a/ipa-server/ipaserver/krbinstance.py +++ /dev/null @@ -1,428 +0,0 @@ -# Authors: Simo Sorce <ssorce@redhat.com> -# -# Copyright (C) 2007 Red Hat -# see file 'COPYING' for use and warranty information -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; version 2 only -# -# 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. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -import subprocess -import string -import tempfile -import shutil -import logging -import fileinput -import re -import sys -import os -import pwd -import socket -import shutil - -import service -import installutils -from ipa import sysrestore -from ipa import ipautil -from ipa import ipaerror - -import ipaldap - -import ldap -from ldap import LDAPError -from ldap import ldapobject - -from pyasn1.type import univ, namedtype -import pyasn1.codec.ber.encoder -import pyasn1.codec.ber.decoder -import struct -import base64 - -KRBMKEY_DENY_ACI = """ -(targetattr = "krbMKey")(version 3.0; acl "No external access"; deny (all) userdn != "ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";) -""" - -def update_key_val_in_file(filename, key, val): - if os.path.exists(filename): - pattern = "^[\s#]*%s\s*=\s*%s\s*" % (re.escape(key), re.escape(val)) - p = re.compile(pattern) - for line in fileinput.input(filename): - if p.search(line): - fileinput.close() - return - fileinput.close() - - pattern = "^[\s#]*%s\s*=" % re.escape(key) - p = re.compile(pattern) - for line in fileinput.input(filename, inplace=1): - if not p.search(line): - sys.stdout.write(line) - fileinput.close() - f = open(filename, "a") - f.write("%s=%s\n" % (key, val)) - f.close() - -class KpasswdInstance(service.SimpleServiceInstance): - def __init__(self): - service.SimpleServiceInstance.__init__(self, "ipa_kpasswd") - -class KrbInstance(service.Service): - def __init__(self, fstore=None): - service.Service.__init__(self, "krb5kdc") - self.ds_user = None - self.fqdn = None - self.realm = None - self.domain = None - self.host = None - self.admin_password = None - self.master_password = None - self.suffix = None - self.kdc_password = None - self.sub_dict = None - - self.kpasswd = KpasswdInstance() - - if fstore: - self.fstore = fstore - else: - self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') - - def __common_setup(self, ds_user, realm_name, host_name, domain_name, admin_password): - self.ds_user = ds_user - self.fqdn = host_name - self.realm = realm_name.upper() - self.host = host_name.split(".")[0] - self.ip = socket.gethostbyname(host_name) - self.domain = domain_name - self.suffix = ipautil.realm_to_suffix(self.realm) - self.kdc_password = ipautil.ipa_generate_password() - self.admin_password = admin_password - - self.__setup_sub_dict() - - # get a connection to the DS - try: - self.conn = ipaldap.IPAdmin(self.fqdn) - self.conn.do_simple_bind(bindpw=self.admin_password) - except Exception, e: - logging.critical("Could not connect to the Directory Server on %s" % self.fqdn) - raise e - - self.backup_state("running", self.is_running()) - try: - self.stop() - except: - # It could have been not running - pass - - def __common_post_setup(self): - self.step("starting the KDC", self.__start_instance) - self.step("configuring KDC to start on boot", self.__enable) - - def create_instance(self, ds_user, realm_name, host_name, domain_name, admin_password, master_password): - self.master_password = master_password - - self.__common_setup(ds_user, realm_name, host_name, domain_name, admin_password) - - self.step("setting KDC account password", self.__configure_kdc_account_password) - self.step("adding sasl mappings to the directory", self.__configure_sasl_mappings) - self.step("adding kerberos entries to the DS", self.__add_krb_entries) - self.step("adding default ACIs", self.__add_default_acis) - self.step("configuring KDC", self.__create_instance) - self.step("adding default keytypes", self.__add_default_keytypes) - self.step("creating a keytab for the directory", self.__create_ds_keytab) - self.step("creating a keytab for the machine", self.__create_host_keytab) - self.step("exporting the kadmin keytab", self.__export_kadmin_changepw_keytab) - self.step("adding the password extension to the directory", self.__add_pwd_extop_module) - self.step("adding the kerberos master key to the directory", self.__add_master_key) - - self.__common_post_setup() - - self.start_creation("Configuring Kerberos KDC") - - self.kpasswd.create_instance() - - def create_replica(self, ds_user, realm_name, host_name, domain_name, admin_password, ldap_passwd_filename, kpasswd_filename): - self.__copy_ldap_passwd(ldap_passwd_filename) - self.__copy_kpasswd_keytab(kpasswd_filename) - - self.__common_setup(ds_user, realm_name, host_name, domain_name, admin_password) - - self.step("adding sasl mappings to the directory", self.__configure_sasl_mappings) - self.step("writing stash file from DS", self.__write_stash_from_ds) - self.step("configuring KDC", self.__create_replica_instance) - self.step("creating a keytab for the directory", self.__create_ds_keytab) - self.step("creating a keytab for the machine", self.__create_host_keytab) - self.step("adding the password extension to the directory", self.__add_pwd_extop_module) - - self.__common_post_setup() - - self.start_creation("Configuring Kerberos KDC") - - self.kpasswd.create_instance() - - def __copy_ldap_passwd(self, filename): - self.fstore.backup_file("/var/kerberos/krb5kdc/ldappwd") - shutil.copy(filename, "/var/kerberos/krb5kdc/ldappwd") - os.chmod("/var/kerberos/krb5kdc/ldappwd", 0600) - - def __copy_kpasswd_keytab(self, filename): - self.fstore.backup_file("/var/kerberos/krb5kdc/kpasswd.keytab") - shutil.copy(filename, "/var/kerberos/krb5kdc/kpasswd.keytab") - os.chmod("/var/kerberos/krb5kdc/kpasswd.keytab", 0600) - - - def __configure_kdc_account_password(self): - hexpwd = '' - for x in self.kdc_password: - hexpwd += (hex(ord(x))[2:]) - self.fstore.backup_file("/var/kerberos/krb5kdc/ldappwd") - pwd_fd = open("/var/kerberos/krb5kdc/ldappwd", "w") - pwd_fd.write("uid=kdc,cn=sysaccounts,cn=etc,"+self.suffix+"#{HEX}"+hexpwd+"\n") - pwd_fd.close() - os.chmod("/var/kerberos/krb5kdc/ldappwd", 0600) - - def __enable(self): - self.backup_state("enabled", self.is_enabled()) - self.chkconfig_on() - - def __start_instance(self): - try: - self.start() - except: - logging.critical("krb5kdc service failed to start") - - def __setup_sub_dict(self): - self.sub_dict = dict(FQDN=self.fqdn, - IP=self.ip, - PASSWORD=self.kdc_password, - SUFFIX=self.suffix, - DOMAIN=self.domain, - HOST=self.host, - REALM=self.realm) - - def __ldap_mod(self, ldif): - txt = ipautil.template_file(ipautil.SHARE_DIR + ldif, self.sub_dict) - fd = ipautil.write_tmp_file(txt) - - [pw_fd, pw_name] = tempfile.mkstemp() - os.write(pw_fd, self.admin_password) - os.close(pw_fd) - - args = ["/usr/bin/ldapmodify", "-h", "127.0.0.1", "-xv", - "-D", "cn=Directory Manager", "-y", pw_name, "-f", fd.name] - - try: - try: - ipautil.run(args) - except ipautil.CalledProcessError, e: - logging.critical("Failed to load %s: %s" % (ldif, str(e))) - finally: - os.remove(pw_name) - - fd.close() - - def __configure_sasl_mappings(self): - # we need to remove any existing SASL mappings in the directory as otherwise they - # they may conflict. There is no way to define the order they are used in atm. - - # FIXME: for some reason IPAdmin dies here, so we switch - # it out for a regular ldapobject. - conn = self.conn - self.conn = ldapobject.SimpleLDAPObject("ldap://127.0.0.1/") - self.conn.bind("cn=directory manager", self.admin_password) - try: - msgid = self.conn.search("cn=mapping,cn=sasl,cn=config", ldap.SCOPE_ONELEVEL, "(objectclass=nsSaslMapping)") - res = self.conn.result(msgid) - for r in res[1]: - mid = self.conn.delete_s(r[0]) - #except LDAPError, e: - # logging.critical("Error during SASL mapping removal: %s" % str(e)) - except Exception, e: - logging.critical("Could not connect to the Directory Server on %s" % self.fqdn) - raise e - print type(e) - print dir(e) - raise e - - self.conn = conn - - entry = ipaldap.Entry("cn=Full Principal,cn=mapping,cn=sasl,cn=config") - entry.setValues("objectclass", "top", "nsSaslMapping") - entry.setValues("cn", "Full Principal") - entry.setValues("nsSaslMapRegexString", '\(.*\)@\(.*\)') - entry.setValues("nsSaslMapBaseDNTemplate", self.suffix) - entry.setValues("nsSaslMapFilterTemplate", '(krbPrincipalName=\\1@\\2)') - - try: - self.conn.add_s(entry) - except ldap.ALREADY_EXISTS: - logging.critical("failed to add Full Principal Sasl mapping") - raise e - - entry = ipaldap.Entry("cn=Name Only,cn=mapping,cn=sasl,cn=config") - entry.setValues("objectclass", "top", "nsSaslMapping") - entry.setValues("cn", "Name Only") - entry.setValues("nsSaslMapRegexString", '\(.*\)') - entry.setValues("nsSaslMapBaseDNTemplate", self.suffix) - entry.setValues("nsSaslMapFilterTemplate", '(krbPrincipalName=\\1@%s)' % self.realm) - - try: - self.conn.add_s(entry) - except ldap.ALREADY_EXISTS: - logging.critical("failed to add Name Only Sasl mapping") - raise e - - def __add_krb_entries(self): - self.__ldap_mod("kerberos.ldif") - - def __add_default_acis(self): - self.__ldap_mod("default-aci.ldif") - - def __add_default_keytypes(self): - self.__ldap_mod("default-keytypes.ldif") - - def __create_replica_instance(self): - self.__create_instance(replica=True) - - def __template_file(self, path): - template = os.path.join(ipautil.SHARE_DIR, os.path.basename(path) + ".template") - conf = ipautil.template_file(template, self.sub_dict) - self.fstore.backup_file(path) - fd = open(path, "w+") - fd.write(conf) - fd.close() - - def __create_instance(self, replica=False): - self.__template_file("/var/kerberos/krb5kdc/kdc.conf") - self.__template_file("/etc/krb5.conf") - self.__template_file("/usr/share/ipa/html/krb5.ini") - self.__template_file("/usr/share/ipa/html/krb.con") - self.__template_file("/usr/share/ipa/html/krbrealm.con") - - if not replica: - #populate the directory with the realm structure - args = ["/usr/kerberos/sbin/kdb5_ldap_util", "-D", "uid=kdc,cn=sysaccounts,cn=etc,"+self.suffix, "-w", self.kdc_password, "create", "-s", "-P", self.master_password, "-r", self.realm, "-subtrees", self.suffix, "-sscope", "sub"] - try: - ipautil.run(args) - except ipautil.CalledProcessError, e: - print "Failed to populate the realm structure in kerberos", e - - def __write_stash_from_ds(self): - try: - entry = self.conn.getEntry("cn=%s, cn=kerberos, %s" % (self.realm, self.suffix), ldap.SCOPE_SUBTREE) - except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND), e: - logging.critical("Could not find master key in DS") - raise e - - krbMKey = pyasn1.codec.ber.decoder.decode(entry.krbmkey) - keytype = int(krbMKey[0][1][0]) - keydata = str(krbMKey[0][1][1]) - - format = '=hi%ss' % len(keydata) - s = struct.pack(format, keytype, len(keydata), keydata) - try: - fd = open("/var/kerberos/krb5kdc/.k5."+self.realm, "w") - fd.write(s) - fd.close() - except os.error, e: - logging.critical("failed to write stash file") - raise e - - #add the password extop module - def __add_pwd_extop_module(self): - self.__ldap_mod("pwd-extop-conf.ldif") - - def __add_master_key(self): - #get the Master Key from the stash file - try: - stash = open("/var/kerberos/krb5kdc/.k5."+self.realm, "r") - keytype = struct.unpack('h', stash.read(2))[0] - keylen = struct.unpack('i', stash.read(4))[0] - keydata = stash.read(keylen) - except os.error: - logging.critical("Failed to retrieve Master Key from Stash file: %s") - #encode it in the asn.1 attribute - MasterKey = univ.Sequence() - MasterKey.setComponentByPosition(0, univ.Integer(keytype)) - MasterKey.setComponentByPosition(1, univ.OctetString(keydata)) - krbMKey = univ.Sequence() - krbMKey.setComponentByPosition(0, univ.Integer(0)) #we have no kvno - krbMKey.setComponentByPosition(1, MasterKey) - asn1key = pyasn1.codec.ber.encoder.encode(krbMKey) - - dn = "cn="+self.realm+",cn=kerberos,"+self.suffix - #protect the master key by adding an appropriate deny rule along with the key - mod = [(ldap.MOD_ADD, 'aci', ipautil.template_str(KRBMKEY_DENY_ACI, self.sub_dict)), - (ldap.MOD_ADD, 'krbMKey', str(asn1key))] - try: - self.conn.modify_s(dn, mod) - except ldap.TYPE_OR_VALUE_EXISTS, e: - logging.critical("failed to add master key to kerberos database\n") - raise e - - def __create_ds_keytab(self): - ldap_principal = "ldap/" + self.fqdn + "@" + self.realm - installutils.kadmin_addprinc(ldap_principal) - - self.fstore.backup_file("/etc/dirsrv/ds.keytab") - installutils.create_keytab("/etc/dirsrv/ds.keytab", ldap_principal) - - self.fstore.backup_file("/etc/sysconfig/dirsrv") - update_key_val_in_file("/etc/sysconfig/dirsrv", "export KRB5_KTNAME", "/etc/dirsrv/ds.keytab") - pent = pwd.getpwnam(self.ds_user) - os.chown("/etc/dirsrv/ds.keytab", pent.pw_uid, pent.pw_gid) - - def __create_host_keytab(self): - host_principal = "host/" + self.fqdn + "@" + self.realm - installutils.kadmin_addprinc(host_principal) - - self.fstore.backup_file("/etc/krb5.keytab") - installutils.create_keytab("/etc/krb5.keytab", host_principal) - - # Make sure access is strictly reserved to root only for now - os.chown("/etc/krb5.keytab", 0, 0) - os.chmod("/etc/krb5.keytab", 0600) - - def __export_kadmin_changepw_keytab(self): - installutils.kadmin_modprinc("kadmin/changepw", "+requires_preauth") - - self.fstore.backup_file("/var/kerberos/krb5kdc/kpasswd.keytab") - installutils.create_keytab("/var/kerberos/krb5kdc/kpasswd.keytab", "kadmin/changepw") - - self.fstore.backup_file("/etc/sysconfig/ipa_kpasswd") - update_key_val_in_file("/etc/sysconfig/ipa_kpasswd", "export KRB5_KTNAME", "/var/kerberos/krb5kdc/kpasswd.keytab") - - def uninstall(self): - self.kpasswd.uninstall() - - running = self.restore_state("running") - enabled = self.restore_state("enabled") - - try: - self.stop() - except: - pass - - for f in ["/var/kerberos/krb5kdc/ldappwd", "/var/kerberos/krb5kdc/kdc.conf", "/etc/krb5.conf"]: - try: - self.fstore.restore_file(f) - except ValueError, error: - logging.debug(error) - pass - - if not enabled is None and not enabled: - self.chkconfig_off() - - if not running is None and running: - self.start() diff --git a/ipa-server/ipaserver/ldapupdate.py b/ipa-server/ipaserver/ldapupdate.py deleted file mode 100755 index cdf23125a..000000000 --- a/ipa-server/ipaserver/ldapupdate.py +++ /dev/null @@ -1,593 +0,0 @@ -# Authors: Rob Crittenden <rcritten@redhat.com> -# -# Copyright (C) 2008 Red Hat -# see file 'COPYING' for use and warranty information -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; version 2 only -# -# 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. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -# Documentation can be found at http://freeipa.org/page/LdapUpdate - -# TODO -# save undo files? - -UPDATES_DIR="/usr/share/ipa/updates/" - -import sys -from ipaserver import ipaldap, installutils -from ipa import entity, ipaerror, ipautil -import ldap -import logging -import krbV -import platform -import shlex -import time -import random -import os -import fnmatch - -class BadSyntax(Exception): - def __init__(self, value): - self.value = value - def __str__(self): - return repr(self.value) - -class LDAPUpdate: - def __init__(self, dm_password, sub_dict={}, live_run=True): - """dm_password = Directory Manager password - sub_dict = substitution dictionary - live_run = Apply the changes or just test - """ - self.sub_dict = sub_dict - self.live_run = live_run - self.dm_password = dm_password - self.conn = None - self.modified = False - - krbctx = krbV.default_context() - - fqdn = installutils.get_fqdn() - if fqdn is None: - raise RuntimeError("Unable to determine hostname") - - domain = ipautil.get_domain_name() - libarch = self.__identify_arch() - suffix = ipautil.realm_to_suffix(krbctx.default_realm) - - if not self.sub_dict.get("REALM"): - self.sub_dict["REALM"] = krbctx.default_realm - if not self.sub_dict.get("FQDN"): - self.sub_dict["FQDN"] = fqdn - if not self.sub_dict.get("DOMAIN"): - self.sub_dict["DOMAIN"] = domain - if not self.sub_dict.get("SUFFIX"): - self.sub_dict["SUFFIX"] = suffix - if not self.sub_dict.get("LIBARCH"): - self.sub_dict["LIBARCH"] = libarch - if not self.sub_dict.get("TIME"): - self.sub_dict["TIME"] = int(time.time()) - - # Try out the password - try: - conn = ipaldap.IPAdmin(fqdn) - conn.do_simple_bind(bindpw=self.dm_password) - conn.unbind() - except ldap.CONNECT_ERROR, e: - raise RuntimeError("Unable to connect to LDAP server %s" % fqdn) - except ldap.SERVER_DOWN, e: - raise RuntimeError("Unable to connect to LDAP server %s" % fqdn) - except ldap.INVALID_CREDENTIALS, e : - raise RuntimeError("The password provided is incorrect for LDAP server %s" % fqdn) - - def __detail_error(self, detail): - """IPA returns two errors back. One a generic one indicating the broad - problem and a detailed message back as well which should have come - from LDAP. This function will parse that into a human-readable - string. - """ - msg = "" - desc = detail[0].get('desc') - info = detail[0].get('info') - - if desc: - msg = desc - if info: - msg = msg + " " + info - - return msg - - def __identify_arch(self): - """On multi-arch systems some libraries may be in /lib64, /usr/lib64, - etc. Determine if a suffix is needed based on the current - architecture. - """ - bits = platform.architecture()[0] - - if bits == "64bit": - return "64" - else: - return "" - - def __template_str(self, s): - try: - return ipautil.template_str(s, self.sub_dict) - except KeyError, e: - raise BadSyntax("Unknown template keyword %s" % e) - - def __remove_quotes(self, line): - """Remove leading and trailng double or single quotes""" - if line.startswith('"'): - line = line[1:] - if line.endswith('"'): - line = line[:-1] - if line.startswith("'"): - line = line[1:] - if line.endswith("'"): - line = line[:-1] - - return line - - def __parse_values(self, line): - """Parse a comma-separated string into separate values and convert them - into a list. This should handle quoted-strings with embedded commas - """ - lexer = shlex.shlex(line) - lexer.wordchars = lexer.wordchars + ".()-" - l = [] - v = "" - for token in lexer: - if token != ',': - if v: - v = v + " " + token - else: - v = token - else: - l.append(self.__remove_quotes(v)) - v = "" - - l.append(self.__remove_quotes(v)) - - return l - - def read_file(self, filename): - if filename == '-': - fd = sys.stdin - else: - fd = open(filename) - text = fd.readlines() - if fd != sys.stdin: fd.close() - return text - - def __entry_to_entity(self, ent): - """Tne Entry class is a bare LDAP entry. The Entity class has a lot more - helper functions that we need, so convert to dict and then to Entity. - """ - entry = dict(ent.data) - entry['dn'] = ent.dn - for key,value in entry.iteritems(): - if isinstance(value,list) or isinstance(value,tuple): - if len(value) == 0: - entry[key] = '' - elif len(value) == 1: - entry[key] = value[0] - return entity.Entity(entry) - - def __combine_updates(self, dn_list, all_updates, update): - """Combine a new update with the list of total updates - - Updates are stored in 2 lists: - dn_list: contains a unique list of DNs in the updates - all_updates: the actual updates that need to be applied - - We want to apply the updates from the shortest to the longest - path so if new child and parent entries are in different updates - we can be sure the parent gets written first. This also lets - us apply any schema first since it is in the very short cn=schema. - """ - dn = update.get('dn') - dns = ldap.explode_dn(dn.lower()) - l = len(dns) - if dn_list.get(l): - if dn not in dn_list[l]: - dn_list[l].append(dn) - else: - dn_list[l] = [dn] - if not all_updates.get(dn): - all_updates[dn] = update - return all_updates - - e = all_updates[dn] - e['updates'] = e['updates'] + update['updates'] - - all_updates[dn] = e - - return all_updates - - def parse_update_file(self, data, all_updates, dn_list): - """Parse the update file into a dictonary of lists and apply the update - for each DN in the file.""" - valid_keywords = ["default", "add", "remove", "only"] - update = {} - d = "" - index = "" - dn = None - lcount = 0 - for line in data: - # Strip out \n and extra white space - lcount = lcount + 1 - - # skip comments and empty lines - line = line.rstrip() - if line.startswith('#') or line == '': continue - - if line.lower().startswith('dn:'): - if dn is not None: - all_updates = self.__combine_updates(dn_list, all_updates, update) - - update = {} - dn = line[3:].strip() - update['dn'] = self.__template_str(dn) - else: - if dn is None: - raise BadSyntax, "dn is not defined in the update" - - if line.startswith(' '): - v = d[len(d) - 1] - v = v + " " + line.strip() - d[len(d) - 1] = v - update[index] = d - continue - line = line.strip() - values = line.split(':', 2) - if len(values) != 3: - raise BadSyntax, "Bad formatting on line %d: %s" % (lcount,line) - - index = values[0].strip().lower() - - if index not in valid_keywords: - raise BadSyntax, "Unknown keyword %s" % index - - attr = values[1].strip() - value = values[2].strip() - value = self.__template_str(value) - - new_value = "" - if index == "default": - new_value = attr + ":" + value - else: - new_value = index + ":" + attr + ":" + value - index = "updates" - - d = update.get(index, []) - - d.append(new_value) - - update[index] = d - - if dn is not None: - all_updates = self.__combine_updates(dn_list, all_updates, update) - - return (all_updates, dn_list) - - def create_index_task(self, attribute): - """Create a task to update an index for an attribute""" - - r = random.SystemRandom() - - # Refresh the time to make uniqueness more probable. Add on some - # randomness for good measure. - self.sub_dict['TIME'] = int(time.time()) + r.randint(0,10000) - - cn = self.__template_str("indextask_$TIME") - dn = "cn=%s, cn=index, cn=tasks, cn=config" % cn - - e = ipaldap.Entry(dn) - - e.setValues('objectClass', ['top', 'extensibleObject']) - e.setValue('cn', cn) - e.setValue('nsInstance', 'userRoot') - e.setValues('nsIndexAttribute', attribute) - - logging.info("Creating task to index attribute: %s", attribute) - logging.debug("Task id: %s", dn) - - if self.live_run: - self.conn.addEntry(e.dn, e.toTupleList()) - - return dn - - def monitor_index_task(self, dn): - """Give a task DN monitor it and wait until it has completed (or failed) - """ - - if not self.live_run: - # If not doing this live there is nothing to monitor - return - - # Pause for a moment to give the task time to be created - time.sleep(1) - - attrlist = ['nstaskstatus', 'nstaskexitcode'] - entry = None - - while True: - try: - entry = self.conn.getEntry(dn, ldap.SCOPE_BASE, "(objectclass=*)", attrlist) - except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND): - logging.error("Task not found: %s", dn) - return - except ipaerror.exception_for(ipaerror.LDAP_DATABASE_ERROR), e: - logging.error("Task lookup failure %s: %s", e, self.__detail_error(e.detail)) - return - - status = entry.getValue('nstaskstatus') - if status is None: - # task doesn't have a status yet - time.sleep(1) - continue - - if status.lower().find("finished") > -1: - logging.info("Indexing finished") - break - - logging.debug("Indexing in progress") - time.sleep(1) - - return - - def __create_default_entry(self, dn, default): - """Create the default entry from the values provided. - - The return type is entity.Entity - """ - entry = ipaldap.Entry(dn) - - if not default: - # This means that the entire entry needs to be created with add - return self.__entry_to_entity(entry) - - for line in default: - # We already do syntax-parsing so this is safe - (k, v) = line.split(':',1) - e = entry.getValues(k) - if e: - # multi-valued attribute - e = list(e) - e.append(v) - else: - e = v - entry.setValues(k, e) - - return self.__entry_to_entity(entry) - - def __get_entry(self, dn): - """Retrieve an object from LDAP. - - The return type is ipaldap.Entry - """ - searchfilter="objectclass=*" - sattrs = ["*"] - scope = ldap.SCOPE_BASE - - return self.conn.getList(dn, scope, searchfilter, sattrs) - - def __apply_updates(self, updates, entry): - """updates is a list of changes to apply - entry is the thing to apply them to - - returns the modified entry - """ - if not updates: - return entry - - only = {} - for u in updates: - # We already do syntax-parsing so this is safe - (utype, k, values) = u.split(':',2) - - values = self.__parse_values(values) - - e = entry.getValues(k) - if not isinstance(e, list): - if e is None: - e = [] - else: - e = [e] - - for v in values: - if utype == 'remove': - logging.debug("remove: '%s' from %s, current value %s", v, k, e) - try: - e.remove(v) - except ValueError: - logging.warn("remove: '%s' not in %s", v, k) - pass - entry.setValues(k, e) - logging.debug('remove: updated value %s', e) - elif utype == 'add': - logging.debug("add: '%s' to %s, current value %s", v, k, e) - # Remove it, ignoring errors so we can blindly add it later - try: - e.remove(v) - except ValueError: - pass - e.append(v) - logging.debug('add: updated value %s', e) - entry.setValues(k, e) - elif utype == 'only': - logging.debug("only: set %s to '%s', current value %s", k, v, e) - if only.get(k): - e.append(v) - else: - e = [v] - only[k] = True - entry.setValues(k, e) - logging.debug('only: updated value %s', e) - - self.print_entity(entry) - - return entry - - def print_entity(self, e, message=None): - """The entity object currently lacks a str() method""" - logging.debug("---------------------------------------------") - if message: - logging.debug("%s", message) - logging.debug("dn: " + e.dn) - attr = e.attrList() - for a in attr: - value = e.getValues(a) - if isinstance(value,str): - logging.debug(a + ": " + value) - else: - logging.debug(a + ": ") - for l in value: - logging.debug("\t" + l) - def is_schema_updated(self, s): - """Compare the schema in 's' with the current schema in the DS to - see if anything has changed. This should account for syntax - differences (like added parens that make no difference but are - detected as a change by generateModList()). - - This doesn't handle re-ordering of attributes. They are still - detected as changes, so foo $ bar != bar $ foo. - - return True if the schema has changed - return False if it has not - """ - s = ldap.schema.SubSchema(s) - s = s.ldap_entry() - - # Get a fresh copy and convert into a SubSchema - n = self.__get_entry("cn=schema")[0] - n = dict(n.data) - n = ldap.schema.SubSchema(n) - n = n.ldap_entry() - - if s == n: - return False - else: - return True - - def __update_record(self, update): - found = False - - new_entry = self.__create_default_entry(update.get('dn'), - update.get('default')) - - try: - e = self.__get_entry(new_entry.dn) - if len(e) > 1: - # we should only ever get back one entry - raise BadSyntax, "More than 1 entry returned on a dn search!? %s" % new_entry.dn - entry = self.__entry_to_entity(e[0]) - found = True - logging.info("Updating existing entry: %s", entry.dn) - except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND): - # Doesn't exist, start with the default entry - entry = new_entry - logging.info("New entry: %s", entry.dn) - except ipaerror.exception_for(ipaerror.LDAP_DATABASE_ERROR): - # Doesn't exist, start with the default entry - entry = new_entry - logging.info("New entry, using default value: %s", entry.dn) - - self.print_entity(entry) - - # Bring this entry up to date - entry = self.__apply_updates(update.get('updates'), entry) - - self.print_entity(entry, "Final value") - - if not found: - # New entries get their orig_data set to the entry itself. We want to - # empty that so that everything appears new when generating the - # modlist - # entry.orig_data = {} - try: - if self.live_run: - self.conn.addEntry(entry.dn, entry.toTupleList()) - except Exception, e: - logging.error("Add failure %s: %s", e, self.__detail_error(e.detail)) - else: - # Update LDAP - try: - updated = False - changes = self.conn.generateModList(entry.origDataDict(), entry.toDict()) - if (entry.dn == "cn=schema"): - updated = self.is_schema_updated(entry.toDict()) - else: - if len(changes) > 1: - updated = True - logging.debug("%s" % changes) - if self.live_run and updated: - self.conn.updateEntry(entry.dn, entry.origDataDict(), entry.toDict()) - logging.info("Done") - except ipaerror.exception_for(ipaerror.LDAP_EMPTY_MODLIST), e: - logging.info("Entry already up-to-date") - updated = False - except ipaerror.exception_for(ipaerror.LDAP_DATABASE_ERROR), e: - logging.error("Update failed: %s: %s", e, self.__detail_error(e.detail)) - updated = False - - if ("cn=index" in entry.dn and - "cn=userRoot" in entry.dn): - taskid = self.create_index_task(entry.cn) - self.monitor_index_task(taskid) - - if updated: - self.modified = True - return - - def get_all_files(self, root, recursive=False): - """Get all update files""" - f = [] - for path, subdirs, files in os.walk(root): - for name in files: - if fnmatch.fnmatch(name, "*.update"): - f.append(os.path.join(path, name)) - if not recursive: - break - return f - - def update(self, files): - """Execute the update. files is a list of the update files to use. - - returns True if anything was changed, otherwise False - """ - - try: - self.conn = ipaldap.IPAdmin(self.sub_dict['FQDN']) - self.conn.do_simple_bind(bindpw=self.dm_password) - all_updates = {} - dn_list = {} - for f in files: - try: - logging.info("Parsing file %s" % f) - data = self.read_file(f) - except Exception, e: - print e - sys.exit(1) - - (all_updates, dn_list) = self.parse_update_file(data, all_updates, dn_list) - - sortedkeys = dn_list.keys() - sortedkeys.sort() - for k in sortedkeys: - for dn in dn_list[k]: - self.__update_record(all_updates[dn]) - finally: - if self.conn: self.conn.unbind() - - return self.modified diff --git a/ipa-server/ipaserver/ntpinstance.py b/ipa-server/ipaserver/ntpinstance.py deleted file mode 100644 index e2ec60650..000000000 --- a/ipa-server/ipaserver/ntpinstance.py +++ /dev/null @@ -1,107 +0,0 @@ -# Authors: Karl MacMillan <kmacmillan@redhat.com> -# -# Copyright (C) 2007 Red Hat -# see file 'COPYING' for use and warranty information -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; version 2 only -# -# 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. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -import shutil -import logging - -import service -from ipa import sysrestore -from ipa import ipautil - -class NTPInstance(service.Service): - def __init__(self, fstore=None): - service.Service.__init__(self, "ntpd") - - if fstore: - self.fstore = fstore - else: - self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') - - def __write_config(self): - # The template sets the config to point towards ntp.pool.org, but - # they request that software not point towards the default pool. - # We use the OS variable to point it towards either the rhel - # or fedora pools. Other distros should be added in the future - # or we can get our own pool. - os = "" - if ipautil.file_exists("/etc/fedora-release"): - os = "fedora" - elif ipautil.file_exists("/etc/redhat-release"): - os = "rhel" - - sub_dict = { } - sub_dict["SERVERA"] = "0.%s.pool.ntp.org" % os - sub_dict["SERVERB"] = "1.%s.pool.ntp.org" % os - sub_dict["SERVERC"] = "2.%s.pool.ntp.org" % os - - ntp_conf = ipautil.template_file(ipautil.SHARE_DIR + "ntp.conf.server.template", sub_dict) - ntp_sysconf = ipautil.template_file(ipautil.SHARE_DIR + "ntpd.sysconfig.template", {}) - - self.fstore.backup_file("/etc/ntp.conf") - self.fstore.backup_file("/etc/sysconfig/ntpd") - - fd = open("/etc/ntp.conf", "w") - fd.write(ntp_conf) - fd.close() - - fd = open("/etc/sysconfig/ntpd", "w") - fd.write(ntp_sysconf) - fd.close() - - def __stop(self): - self.backup_state("running", self.is_running()) - self.stop() - - def __start(self): - self.start() - - def __enable(self): - self.backup_state("enabled", self.is_enabled()) - self.chkconfig_on() - - def create_instance(self): - - # we might consider setting the date manually using ntpd -qg in case - # the current time is very far off. - - self.step("stopping ntpd", self.__stop) - self.step("writing configuration", self.__write_config) - self.step("configuring ntpd to start on boot", self.__enable) - self.step("starting ntpd", self.__start) - - self.start_creation("Configuring ntpd") - - def uninstall(self): - running = self.restore_state("running") - enabled = self.restore_state("enabled") - - if not running is None: - self.stop() - - try: - self.fstore.restore_file("/etc/ntp.conf") - except ValueError, error: - logging.debug(error) - pass - - if not enabled is None and not enabled: - self.chkconfig_off() - - if not running is None and running: - self.start() diff --git a/ipa-server/ipaserver/replication.py b/ipa-server/ipaserver/replication.py deleted file mode 100644 index 8477bd18a..000000000 --- a/ipa-server/ipaserver/replication.py +++ /dev/null @@ -1,532 +0,0 @@ -# Authors: Karl MacMillan <kmacmillan@mentalrootkit.com> -# -# Copyright (C) 2007 Red Hat -# see file 'COPYING' for use and warranty information -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; version 2 only -# -# 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. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -import time, logging - -import ipaldap, ldap, dsinstance -from ldap import modlist -from ipa import ipaerror - -DIRMAN_CN = "cn=directory manager" -CACERT="/usr/share/ipa/html/ca.crt" -# the default container used by AD for user entries -WIN_USER_CONTAINER="cn=Users" -# the default container used by IPA for user entries -IPA_USER_CONTAINER="cn=users,cn=accounts" -PORT = 636 -TIMEOUT = 120 - -IPA_REPLICA = 1 -WINSYNC = 2 - -class ReplicationManager: - """Manage replication agreements between DS servers, and sync - agreements with Windows servers""" - def __init__(self, hostname, dirman_passwd): - self.hostname = hostname - self.dirman_passwd = dirman_passwd - - self.conn = ipaldap.IPAdmin(hostname, port=PORT, cacert=CACERT) - self.conn.do_simple_bind(bindpw=dirman_passwd) - - self.repl_man_passwd = dirman_passwd - - # these are likely constant, but you could change them - # at runtime if you really want - self.repl_man_dn = "cn=replication manager,cn=config" - self.repl_man_cn = "replication manager" - self.suffix = "" - - def _get_replica_id(self, conn, master_conn): - """ - Returns the replica ID which is unique for each backend. - - conn is the connection we are trying to get the replica ID for. - master_conn is the master we are going to replicate with. - """ - # First see if there is already one set - dn = self.replica_dn() - try: - replica = conn.search_s(dn, ldap.SCOPE_BASE, "objectclass=*")[0] - if replica.getValue('nsDS5ReplicaId'): - return int(replica.getValue('nsDS5ReplicaId')) - except ldap.NO_SUCH_OBJECT: - pass - - # Ok, either the entry doesn't exist or the attribute isn't set - # so get it from the other master - retval = -1 - dn = "cn=replication, cn=etc, %s" % self.suffix - try: - replica = master_conn.search_s(dn, ldap.SCOPE_BASE, "objectclass=*")[0] - if not replica.getValue('nsDS5ReplicaId'): - logging.debug("Unable to retrieve nsDS5ReplicaId from remote server") - raise RuntimeError("Unable to retrieve nsDS5ReplicaId from remote server") - except ldap.NO_SUCH_OBJECT: - logging.debug("Unable to retrieve nsDS5ReplicaId from remote server") - raise - - # Now update the value on the master - retval = int(replica.getValue('nsDS5ReplicaId')) - mod = [(ldap.MOD_REPLACE, 'nsDS5ReplicaId', str(retval + 1))] - - try: - master_conn.modify_s(dn, mod) - except Exception, e: - logging.debug("Problem updating nsDS5ReplicaID %s" % e) - raise - - return retval - - def find_replication_dns(self, conn): - filt = "(|(objectclass=nsDSWindowsReplicationAgreement)(objectclass=nsds5ReplicationAgreement))" - try: - ents = conn.search_s("cn=mapping tree,cn=config", ldap.SCOPE_SUBTREE, filt) - except ldap.NO_SUCH_OBJECT: - return [] - return [ent.dn for ent in ents] - - def add_replication_manager(self, conn, passwd=None): - """ - Create a pseudo user to use for replication. If no password - is provided the directory manager password will be used. - """ - - if passwd: - self.repl_man_passwd = passwd - - ent = ipaldap.Entry(self.repl_man_dn) - ent.setValues("objectclass", "top", "person") - ent.setValues("cn", self.repl_man_cn) - ent.setValues("userpassword", self.repl_man_passwd) - ent.setValues("sn", "replication manager pseudo user") - - try: - conn.add_s(ent) - except ldap.ALREADY_EXISTS: - # should we set the password here? - pass - - def delete_replication_manager(self, conn, dn="cn=replication manager,cn=config"): - try: - conn.delete_s(dn) - except ldap.NO_SUCH_OBJECT: - pass - - def get_replica_type(self, master=True): - if master: - return "3" - else: - return "2" - - def replica_dn(self): - return 'cn=replica, cn="%s", cn=mapping tree, cn=config' % self.suffix - - def local_replica_config(self, conn, replica_id): - dn = self.replica_dn() - - try: - conn.getEntry(dn, ldap.SCOPE_BASE) - # replication is already configured - return - except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND): - pass - - replica_type = self.get_replica_type() - - entry = ipaldap.Entry(dn) - entry.setValues('objectclass', "top", "nsds5replica", "extensibleobject") - entry.setValues('cn', "replica") - entry.setValues('nsds5replicaroot', self.suffix) - entry.setValues('nsds5replicaid', str(replica_id)) - entry.setValues('nsds5replicatype', replica_type) - entry.setValues('nsds5flags', "1") - entry.setValues('nsds5replicabinddn', [self.repl_man_dn]) - entry.setValues('nsds5replicalegacyconsumer', "off") - - conn.add_s(entry) - - def setup_changelog(self, conn): - dn = "cn=changelog5, cn=config" - dirpath = conn.dbdir + "/cldb" - entry = ipaldap.Entry(dn) - entry.setValues('objectclass', "top", "extensibleobject") - entry.setValues('cn', "changelog5") - entry.setValues('nsslapd-changelogdir', dirpath) - try: - conn.add_s(entry) - except ldap.ALREADY_EXISTS: - return - - def setup_chaining_backend(self, conn): - chaindn = "cn=chaining database, cn=plugins, cn=config" - benamebase = "chaindb" - urls = [self.to_ldap_url(conn)] - cn = "" - benum = 1 - done = False - while not done: - try: - cn = benamebase + str(benum) # e.g. localdb1 - dn = "cn=" + cn + ", " + chaindn - entry = ipaldap.Entry(dn) - entry.setValues('objectclass', 'top', 'extensibleObject', 'nsBackendInstance') - entry.setValues('cn', cn) - entry.setValues('nsslapd-suffix', self.suffix) - entry.setValues('nsfarmserverurl', urls) - entry.setValues('nsmultiplexorbinddn', self.repl_man_dn) - entry.setValues('nsmultiplexorcredentials', self.repl_man_passwd) - - self.conn.add_s(entry) - done = True - except ldap.ALREADY_EXISTS: - benum += 1 - except ldap.LDAPError, e: - print "Could not add backend entry " + dn, e - raise - - return cn - - def to_ldap_url(self, conn): - return "ldap://%s:%d/" % (conn.host, conn.port) - - def setup_chaining_farm(self, conn): - try: - conn.modify_s(self.suffix, [(ldap.MOD_ADD, 'aci', - [ "(targetattr = \"*\")(version 3.0; acl \"Proxied authorization for database links\"; allow (proxy) userdn = \"ldap:///%s\";)" % self.repl_man_dn ])]) - except ldap.TYPE_OR_VALUE_EXISTS: - logging.debug("proxy aci already exists in suffix %s on %s" % (self.suffix, conn.host)) - - def get_mapping_tree_entry(self): - try: - entry = self.conn.getEntry("cn=mapping tree,cn=config", ldap.SCOPE_ONELEVEL, - "(cn=\"%s\")" % (self.suffix)) - except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND), e: - logging.debug("failed to find mappting tree entry for %s" % self.suffix) - raise e - - return entry - - - def enable_chain_on_update(self, bename): - mtent = self.get_mapping_tree_entry() - dn = mtent.dn - - plgent = self.conn.getEntry("cn=Multimaster Replication Plugin,cn=plugins,cn=config", - ldap.SCOPE_BASE, "(objectclass=*)", ['nsslapd-pluginPath']) - path = plgent.getValue('nsslapd-pluginPath') - - mod = [(ldap.MOD_REPLACE, 'nsslapd-state', 'backend'), - (ldap.MOD_ADD, 'nsslapd-backend', bename), - (ldap.MOD_ADD, 'nsslapd-distribution-plugin', path), - (ldap.MOD_ADD, 'nsslapd-distribution-funct', 'repl_chain_on_update')] - - try: - self.conn.modify_s(dn, mod) - except ldap.TYPE_OR_VALUE_EXISTS: - logging.debug("chainOnUpdate already enabled for %s" % self.suffix) - - def setup_chain_on_update(self, other_conn): - chainbe = self.setup_chaining_backend(other_conn) - self.enable_chain_on_update(chainbe) - - def add_passsync_user(self, conn, password): - pass_dn = "uid=passsync,cn=sysaccounts,cn=etc,%s" % self.suffix - print "The user for the Windows PassSync service is %s" % pass_dn - try: - conn.getEntry(pass_dn, ldap.SCOPE_BASE) - print "Windows PassSync entry exists, not resetting password" - return - except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND): - pass - - # The user doesn't exist, add it - entry = ipaldap.Entry(pass_dn) - entry.setValues("objectclass", ["account", "simplesecurityobject"]) - entry.setValues("uid", "passsync") - entry.setValues("userPassword", password) - conn.add_s(entry) - - # Add it to the list of users allowed to bypass password policy - extop_dn = "cn=ipa_pwd_extop,cn=plugins,cn=config" - entry = conn.getEntry(extop_dn, ldap.SCOPE_BASE) - pass_mgrs = entry.getValues('passSyncManagersDNs') - if not pass_mgrs: - pass_mgrs = [] - if not isinstance(pass_mgrs, list): - pass_mgrs = [pass_mgrs] - pass_mgrs.append(pass_dn) - mod = [(ldap.MOD_REPLACE, 'passSyncManagersDNs', pass_mgrs)] - conn.modify_s(extop_dn, mod) - - # And finally grant it permission to write passwords - mod = [(ldap.MOD_ADD, 'aci', - ['(targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Windows PassSync service can write passwords"; allow (write) userdn="ldap:///%s";)' % pass_dn])] - try: - conn.modify_s(self.suffix, mod) - except ldap.TYPE_OR_VALUE_EXISTS: - logging.debug("passsync aci already exists in suffix %s on %s" % (self.suffix, conn.host)) - - def setup_winsync_agmt(self, entry, **kargs): - entry.setValues("objectclass", "nsDSWindowsReplicationAgreement") - entry.setValues("nsds7WindowsReplicaSubtree", - kargs.get("win_subtree", - WIN_USER_CONTAINER + "," + self.suffix)) - entry.setValues("nsds7DirectoryReplicaSubtree", - kargs.get("ds_subtree", - IPA_USER_CONTAINER + "," + self.suffix)) - # for now, just sync users and ignore groups - entry.setValues("nsds7NewWinUserSyncEnabled", kargs.get('newwinusers', 'true')) - entry.setValues("nsds7NewWinGroupSyncEnabled", kargs.get('newwingroups', 'false')) - windomain = '' - if kargs.has_key('windomain'): - windomain = kargs['windomain'] - else: - windomain = '.'.join(ldap.explode_dn(self.suffix, 1)) - entry.setValues("nsds7WindowsDomain", windomain) - - def agreement_dn(self, hostname, port=PORT): - cn = "meTo%s%d" % (hostname, port) - dn = "cn=%s, %s" % (cn, self.replica_dn()) - - return (cn, dn) - - def setup_agreement(self, a, b, **kargs): - cn, dn = self.agreement_dn(b.host) - try: - a.getEntry(dn, ldap.SCOPE_BASE) - return - except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND): - pass - - iswinsync = kargs.get("winsync", False) - repl_man_dn = kargs.get("binddn", self.repl_man_dn) - repl_man_passwd = kargs.get("bindpw", self.repl_man_passwd) - port = kargs.get("port", PORT) - - entry = ipaldap.Entry(dn) - entry.setValues('objectclass', "nsds5replicationagreement") - entry.setValues('cn', cn) - entry.setValues('nsds5replicahost', b.host) - entry.setValues('nsds5replicaport', str(port)) - entry.setValues('nsds5replicatimeout', str(TIMEOUT)) - entry.setValues('nsds5replicabinddn', repl_man_dn) - entry.setValues('nsds5replicacredentials', repl_man_passwd) - entry.setValues('nsds5replicabindmethod', 'simple') - entry.setValues('nsds5replicaroot', self.suffix) - entry.setValues('nsds5replicaupdateschedule', '0000-2359 0123456') - entry.setValues('nsds5replicatransportinfo', 'SSL') - entry.setValues('nsDS5ReplicatedAttributeList', '(objectclass=*) $ EXCLUDE memberOf') - entry.setValues('description', "me to %s%d" % (b.host, port)) - if iswinsync: - self.setup_winsync_agmt(entry, **kargs) - - a.add_s(entry) - - entry = a.waitForEntry(entry) - - def delete_agreement(self, hostname): - cn, dn = self.agreement_dn(hostname) - return self.conn.deleteEntry(dn) - - def check_repl_init(self, conn, agmtdn): - done = False - hasError = 0 - attrlist = ['cn', 'nsds5BeginReplicaRefresh', 'nsds5replicaUpdateInProgress', - 'nsds5ReplicaLastInitStatus', 'nsds5ReplicaLastInitStart', - 'nsds5ReplicaLastInitEnd'] - entry = conn.getEntry(agmtdn, ldap.SCOPE_BASE, "(objectclass=*)", attrlist) - if not entry: - print "Error reading status from agreement", agmtdn - hasError = 1 - else: - refresh = entry.nsds5BeginReplicaRefresh - inprogress = entry.nsds5replicaUpdateInProgress - status = entry.nsds5ReplicaLastInitStatus - if not refresh: # done - check status - if not status: - print "No status yet" - elif status.find("replica busy") > -1: - print "[%s] reports: Replica Busy! Status: [%s]" % (conn.host, status) - done = True - hasError = 2 - elif status.find("Total update succeeded") > -1: - print "Update succeeded" - done = True - elif inprogress.lower() == 'true': - print "Update in progress yet not in progress" - else: - print "[%s] reports: Update failed! Status: [%s]" % (conn.host, status) - hasError = 1 - done = True - else: - print "Update in progress" - - return done, hasError - - def check_repl_update(self, conn, agmtdn): - done = False - hasError = 0 - attrlist = ['cn', 'nsds5replicaUpdateInProgress', - 'nsds5ReplicaLastUpdateStatus', 'nsds5ReplicaLastUpdateStart', - 'nsds5ReplicaLastUpdateEnd'] - entry = conn.getEntry(agmtdn, ldap.SCOPE_BASE, "(objectclass=*)", attrlist) - if not entry: - print "Error reading status from agreement", agmtdn - hasError = 1 - else: - inprogress = entry.nsds5replicaUpdateInProgress - status = entry.nsds5ReplicaLastUpdateStatus - start = entry.nsds5ReplicaLastUpdateStart - end = entry.nsds5ReplicaLastUpdateEnd - # incremental update is done if inprogress is false and end >= start - done = inprogress and inprogress.lower() == 'false' and start and end and (start <= end) - logging.info("Replication Update in progress: %s: status: %s: start: %s: end: %s" % - (inprogress, status, start, end)) - if not done and status: # check for errors - # status will usually be a number followed by a string - # number != 0 means error - rc, msg = status.split(' ', 1) - if rc != '0': - hasError = 1 - done = True - - return done, hasError - - def wait_for_repl_init(self, conn, agmtdn): - done = False - haserror = 0 - while not done and not haserror: - time.sleep(1) # give it a few seconds to get going - done, haserror = self.check_repl_init(conn, agmtdn) - return haserror - - def wait_for_repl_update(self, conn, agmtdn, maxtries=600): - done = False - haserror = 0 - while not done and not haserror and maxtries > 0: - time.sleep(1) # give it a few seconds to get going - done, haserror = self.check_repl_update(conn, agmtdn) - maxtries -= 1 - if maxtries == 0: # too many tries - print "Error: timeout: could not determine agreement status: please check your directory server logs for possible errors" - haserror = 1 - return haserror - - def start_replication(self, other_conn, conn=None): - print "Starting replication, please wait until this has completed." - if conn == None: - conn = self.conn - cn, dn = self.agreement_dn(conn.host) - - mod = [(ldap.MOD_ADD, 'nsds5BeginReplicaRefresh', 'start')] - other_conn.modify_s(dn, mod) - - return self.wait_for_repl_init(other_conn, dn) - - def basic_replication_setup(self, conn, replica_id): - self.add_replication_manager(conn) - self.local_replica_config(conn, replica_id) - self.setup_changelog(conn) - - def setup_replication(self, other_hostname, realm_name, **kargs): - """ - NOTES: - - the directory manager password needs to be the same on - both directories. Or use the optional binddn and bindpw - """ - iswinsync = kargs.get("winsync", False) - oth_port = kargs.get("port", PORT) - oth_cacert = kargs.get("cacert", CACERT) - oth_binddn = kargs.get("binddn", DIRMAN_CN) - oth_bindpw = kargs.get("bindpw", self.dirman_passwd) - # note - there appears to be a bug in python-ldap - it does not - # allow connections using two different CA certs - other_conn = ipaldap.IPAdmin(other_hostname, port=oth_port, cacert=oth_cacert) - try: - other_conn.do_simple_bind(binddn=oth_binddn, bindpw=oth_bindpw) - except Exception, e: - if iswinsync: - logging.info("Could not validate connection to remote server %s:%d - continuing" % - (other_hostname, oth_port)) - logging.info("The error was: %s" % e) - else: - raise e - - self.suffix = ipaldap.IPAdmin.normalizeDN(dsinstance.realm_to_suffix(realm_name)) - - if not iswinsync: - local_id = self._get_replica_id(self.conn, other_conn) - else: - # there is no other side to get a replica ID from - local_id = self._get_replica_id(self.conn, self.conn) - self.basic_replication_setup(self.conn, local_id) - - if not iswinsync: - other_id = self._get_replica_id(other_conn, other_conn) - self.basic_replication_setup(other_conn, other_id) - self.setup_agreement(other_conn, self.conn) - self.setup_agreement(self.conn, other_conn) - return self.start_replication(other_conn) - else: - self.add_passsync_user(self.conn, kargs.get("passsync")) - self.setup_agreement(self.conn, other_conn, **kargs) - logging.info("Added new sync agreement, waiting for it to become ready . . .") - cn, dn = self.agreement_dn(other_hostname) - self.wait_for_repl_update(self.conn, dn, 30) - logging.info("Agreement is ready, starting replication . . .") - return self.start_replication(self.conn, other_conn) - - def initialize_replication(self, dn, conn): - mod = [(ldap.MOD_ADD, 'nsds5BeginReplicaRefresh', 'start')] - try: - conn.modify_s(dn, mod) - except ldap.ALREADY_EXISTS: - return - - def force_synch(self, dn, schedule, conn): - newschedule = '2358-2359 0' - - # On the remote chance of a match. We force a synch to happen right - # now by changing the schedule to something else and quickly changing - # it back. - if newschedule == schedule: - newschedule = '2358-2359 1' - logging.info("Changing agreement %s schedule to %s to force synch" % - (dn, newschedule)) - mod = [(ldap.MOD_REPLACE, 'nsDS5ReplicaUpdateSchedule', [ newschedule ])] - conn.modify_s(dn, mod) - time.sleep(1) - logging.info("Changing agreement %s to restore original schedule %s" % - (dn, schedule)) - mod = [(ldap.MOD_REPLACE, 'nsDS5ReplicaUpdateSchedule', [ schedule ])] - conn.modify_s(dn, mod) - - def get_agreement_type(self, hostname): - cn, dn = self.agreement_dn(hostname) - - entry = self.conn.getEntry(dn, ldap.SCOPE_BASE) - - objectclass = entry.getValues("objectclass") - - for o in objectclass: - if o.lower() == "nsdswindowsreplicationagreement": - return WINSYNC - - return IPA_REPLICA diff --git a/ipa-server/ipaserver/service.py b/ipa-server/ipaserver/service.py deleted file mode 100644 index b9f6c505d..000000000 --- a/ipa-server/ipaserver/service.py +++ /dev/null @@ -1,169 +0,0 @@ -# Authors: Karl MacMillan <kmacmillan@mentalrootkit.com> -# -# Copyright (C) 2007 Red Hat -# see file 'COPYING' for use and warranty information -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; version 2 only -# -# 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. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -import logging, sys -from ipa import sysrestore -from ipa import ipautil - - -def stop(service_name): - ipautil.run(["/sbin/service", service_name, "stop"]) - -def start(service_name): - ipautil.run(["/sbin/service", service_name, "start"]) - -def restart(service_name): - ipautil.run(["/sbin/service", service_name, "restart"]) - -def is_running(service_name): - ret = True - try: - ipautil.run(["/sbin/service", service_name, "status"]) - except ipautil.CalledProcessError: - ret = False - return ret - -def chkconfig_on(service_name): - ipautil.run(["/sbin/chkconfig", service_name, "on"]) - -def chkconfig_off(service_name): - ipautil.run(["/sbin/chkconfig", service_name, "off"]) - -def chkconfig_add(service_name): - ipautil.run(["/sbin/chkconfig", "--add", service_name]) - -def chkconfig_del(service_name): - ipautil.run(["/sbin/chkconfig", "--del", service_name]) - -def is_enabled(service_name): - (stdout, stderr) = ipautil.run(["/sbin/chkconfig", "--list", service_name]) - - runlevels = {} - for runlevel in range(0, 7): - runlevels[runlevel] = False - - for line in stdout.split("\n"): - parts = line.split() - if parts[0] == service_name: - for s in parts[1:]: - (runlevel, status) = s.split(":")[0:2] - try: - runlevels[int(runlevel)] = status == "on" - except ValueError: - pass - break - - return (runlevels[3] and runlevels[4] and runlevels[5]) - -def print_msg(message, output_fd=sys.stdout): - logging.debug(message) - output_fd.write(message) - output_fd.write("\n") - - -class Service: - def __init__(self, service_name, sstore=None): - self.service_name = service_name - self.steps = [] - self.output_fd = sys.stdout - - if sstore: - self.sstore = sstore - else: - self.sstore = sysrestore.StateFile('/var/lib/ipa/sysrestore') - - def set_output(self, fd): - self.output_fd = fd - - def stop(self): - stop(self.service_name) - - def start(self): - start(self.service_name) - - def restart(self): - restart(self.service_name) - - def is_running(self): - return is_running(self.service_name) - - def chkconfig_add(self): - chkconfig_add(self.service_name) - - def chkconfig_del(self): - chkconfig_del(self.service_name) - - def chkconfig_on(self): - chkconfig_on(self.service_name) - - def chkconfig_off(self): - chkconfig_off(self.service_name) - - def is_enabled(self): - return is_enabled(self.service_name) - - def backup_state(self, key, value): - self.sstore.backup_state(self.service_name, key, value) - - def restore_state(self, key): - return self.sstore.restore_state(self.service_name, key) - - def print_msg(self, message): - print_msg(message, self.output_fd) - - def step(self, message, method): - self.steps.append((message, method)) - - def start_creation(self, message): - self.print_msg(message) - - step = 0 - for (message, method) in self.steps: - self.print_msg(" [%d/%d]: %s" % (step+1, len(self.steps), message)) - method() - step += 1 - - self.print_msg("done configuring %s." % self.service_name) - - self.steps = [] - -class SimpleServiceInstance(Service): - def create_instance(self): - self.step("starting %s " % self.service_name, self.__start) - self.step("configuring %s to start on boot" % self.service_name, self.__enable) - self.start_creation("Configuring %s" % self.service_name) - - def __start(self): - self.backup_state("running", self.is_running()) - self.restart() - - def __enable(self): - self.chkconfig_add() - self.backup_state("enabled", self.is_enabled()) - self.chkconfig_on() - - def uninstall(self): - running = self.restore_state("running") - enabled = not self.restore_state("enabled") - - if not running is None and not running: - self.stop() - if not enabled is None and not enabled: - self.chkconfig_off() - self.chkconfig_del() |