summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarl MacMillan <kmacmill@redhat.com>2007-12-18 16:25:46 -0500
committerKarl MacMillan <kmacmill@redhat.com>2007-12-18 16:25:46 -0500
commit6575aa606f18f8d998dcad5552e4f770e9addcdf (patch)
treed75cb650b3b9f27cad0786d7aa40a5cd3f188061
parenta0eacec8e587c0fbc7e24378cef58fa7835ae64a (diff)
parent4814c0d3f6c11971b841eb6eedcd7925d8840f26 (diff)
downloadfreeipa-6575aa606f18f8d998dcad5552e4f770e9addcdf.tar.gz
freeipa-6575aa606f18f8d998dcad5552e4f770e9addcdf.tar.xz
freeipa-6575aa606f18f8d998dcad5552e4f770e9addcdf.zip
Merge.
-rw-r--r--Makefile28
-rw-r--r--ipa-admintools/man/Makefile3
-rw-r--r--ipa-admintools/man/ipa-getkeytab.164
-rw-r--r--ipa-client/ipa-install/ipa-client-install17
-rwxr-xr-xipa-python/ipa-python.spec5
-rwxr-xr-xipa-python/ipa-python.spec.in5
-rw-r--r--ipa-python/ipaclient.py4
-rw-r--r--ipa-python/ipaerror.py6
-rw-r--r--ipa-python/ipautil.py1
-rw-r--r--ipa-python/radius_util.py2
-rw-r--r--ipa-python/rpcclient.py35
-rw-r--r--ipa-python/setup.py2
-rw-r--r--ipa-radius-server/Makefile20
-rw-r--r--ipa-radius-server/ipa-radius-install73
-rwxr-xr-xipa-radius-server/ipa-radius-server.spec50
-rwxr-xr-xipa-radius-server/ipa-radius-server.spec.in50
-rw-r--r--ipa-radius-server/plugins/__init__.py1
-rw-r--r--ipa-radius-server/plugins/radiusinstance.py (renamed from ipa-server/ipaserver/radiusinstance.py)63
-rw-r--r--ipa-radius-server/share/radius.radiusd.conf.template (renamed from ipa-server/ipa-install/share/radius.radiusd.conf.template)0
-rw-r--r--ipa-server/ipa-gui/ipa-webgui69
-rw-r--r--ipa-server/ipa-gui/ipagui/forms/delegate.py5
-rw-r--r--ipa-server/ipa-gui/ipagui/forms/user.py4
-rw-r--r--ipa-server/ipa-gui/ipagui/subcontrollers/delegation.py26
-rw-r--r--ipa-server/ipa-gui/ipagui/templates/delegateform.kid15
-rw-r--r--ipa-server/ipa-install/Makefile.am1
-rw-r--r--ipa-server/ipa-install/ipa-server-certinstall156
-rw-r--r--ipa-server/ipa-install/ipa-server-install6
-rw-r--r--ipa-server/ipa-install/share/Makefile.am2
-rw-r--r--ipa-server/ipa-install/share/bootstrap-template.ldif4
-rw-r--r--ipa-server/ipa-install/share/default-aci.ldif26
-rw-r--r--ipa-server/ipa-install/share/preferences.html.template33
-rw-r--r--ipa-server/ipa-install/share/referint-conf.ldif4
-rw-r--r--ipa-server/ipa-kpasswd/ipa_kpasswd.c2
-rwxr-xr-xipa-server/ipa-server.spec21
-rw-r--r--ipa-server/ipa-server.spec.in21
-rw-r--r--ipa-server/ipaserver/Makefile.am1
-rw-r--r--ipa-server/ipaserver/bindinstance.py22
-rw-r--r--ipa-server/ipaserver/certs.py105
-rw-r--r--ipa-server/ipaserver/dsinstance.py169
-rw-r--r--ipa-server/ipaserver/httpinstance.py97
-rw-r--r--ipa-server/ipaserver/installutils.py19
-rw-r--r--ipa-server/ipaserver/krbinstance.py186
-rw-r--r--ipa-server/ipaserver/ntpinstance.py25
-rw-r--r--ipa-server/ipaserver/service.py38
-rw-r--r--ipa-server/ipaserver/webguiinstance.py17
-rw-r--r--ipa-server/xmlrpc-server/funcs.py282
-rw-r--r--ipa-server/xmlrpc-server/ipa.conf5
-rw-r--r--ipa-server/xmlrpc-server/unauthorized.html14
48 files changed, 1291 insertions, 513 deletions
diff --git a/Makefile b/Makefile
index 0461144ac..25af85334 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-SUBDIRS=ipa-server ipa-admintools ipa-python ipa-client
+SUBDIRS=ipa-server ipa-admintools ipa-python ipa-client ipa-radius-server
PRJ_PREFIX=ipa
@@ -35,6 +35,13 @@ CLI_VERSION=$(CLI_MAJOR).$(CLI_MINOR).$(CLI_RELEASE)
CLI_TARBALL_PREFIX=$(PRJ_PREFIX)-client-$(CLI_VERSION)
CLI_TARBALL=$(CLI_TARBALL_PREFIX).tgz
+RADIUS_SERVER_MAJOR=0
+RADIUS_SERVER_MINOR=5
+RADIUS_SERVER_RELEASE=0
+RADIUS_SERVER_VERSION=$(RADIUS_SERVER_MAJOR).$(RADIUS_SERVER_MINOR).$(RADIUS_SERVER_RELEASE)
+RADIUS_SERVER_TARBALL_PREFIX=$(PRJ_PREFIX)-radius-server-$(RADIUS_SERVER_VERSION)
+RADIUS_SERVER_TARBALL=$(RADIUS_SERVER_TARBALL_PREFIX).tgz
+
LIBDIR ?= /usr/lib
all: bootstrap-autogen
@@ -77,6 +84,9 @@ version-update:
sed s/VERSION/$(CLI_VERSION)/ ipa-client/ipa-client.spec.in \
> ipa-client/ipa-client.spec
+ sed s/VERSION/$(RADIUS_SERVER_VERSION)/ ipa-radius-server/ipa-radius-server.spec.in \
+ > ipa-radius-server/ipa-radius-server.spec
+
archive:
-mkdir -p dist
@@ -120,6 +130,13 @@ tarballs:
cd dist; tar cfz sources/$(CLI_TARBALL) $(CLI_TARBALL_PREFIX)
rm -fr dist/$(CLI_TARBALL_PREFIX)
+ # ipa-radius-server
+ mv dist/ipa/ipa-radius-server dist/$(RADIUS_SERVER_TARBALL_PREFIX)
+ rm -f dist/sources/$(RADIUS_SERVER_TARBALL)
+ cd dist; tar cfz sources/$(RADIUS_SERVER_TARBALL) $(RADIUS_SERVER_TARBALL_PREFIX)
+ rm -fr dist/$(RADIUS_SERVER_TARBALL_PREFIX)
+
+
rpmroot:
mkdir -p $(RPMBUILD)/BUILD
mkdir -p $(RPMBUILD)/RPMS
@@ -155,7 +172,14 @@ rpm-ipa-client:
cp rpmbuild/RPMS/*/$(PRJ_PREFIX)-client-$(CLI_VERSION)-*.rpm dist/rpms/
cp rpmbuild/SRPMS/$(PRJ_PREFIX)-client-$(CLI_VERSION)-*.src.rpm dist/srpms/
-rpms: rpmroot rpmdistdir rpm-ipa-server rpm-ipa-admin rpm-ipa-python rpm-ipa-client
+rpm-ipa-radius-server:
+ cp dist/sources/$(RADIUS_SERVER_TARBALL) $(RPMBUILD)/SOURCES/.
+ rpmbuild --define "_topdir $(RPMBUILD)" -ba ipa-radius-server/ipa-radius-server.spec
+ cp rpmbuild/RPMS/noarch/$(PRJ_PREFIX)-radius-server-$(RADIUS_SERVER_VERSION)-*.rpm dist/rpms/
+ cp rpmbuild/SRPMS/$(PRJ_PREFIX)-radius-server-$(RADIUS_SERVER_VERSION)-*.src.rpm dist/srpms/
+
+
+rpms: rpmroot rpmdistdir rpm-ipa-server rpm-ipa-admin rpm-ipa-python rpm-ipa-client rpm-ipa-radius-server
repodata:
-createrepo -p dist
diff --git a/ipa-admintools/man/Makefile b/ipa-admintools/man/Makefile
index 19648f539..154124753 100644
--- a/ipa-admintools/man/Makefile
+++ b/ipa-admintools/man/Makefile
@@ -14,7 +14,8 @@ MANFILES=\
ipa-lockuser.1 \
ipa-moddelegation.1 \
ipa-passwd.1 \
- ipa-usermod.1
+ ipa-usermod.1 \
+ ipa-getkeytab.1
all: ;
diff --git a/ipa-admintools/man/ipa-getkeytab.1 b/ipa-admintools/man/ipa-getkeytab.1
new file mode 100644
index 000000000..da511171a
--- /dev/null
+++ b/ipa-admintools/man/ipa-getkeytab.1
@@ -0,0 +1,64 @@
+.\" A man page for ipa-getkeytab
+.\" Copyright (C) 2007 Red Hat, Inc.
+.\"
+.\" This is free software; you can redistribute it and/or modify it under
+.\" the terms of the GNU Library General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" 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 Library General Public
+.\" License along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\" Author: Karl MacMillan <kmacmill@redhat.com>
+.\"
+.TH "ipa-getkeytab" "1" "Oct 10 2007" "freeipa" ""
+.SH "NAME"
+ipa\-getkeytab \- Get a keytab for a kerberos principal
+.SH "SYNOPSIS"
+ipa\-getkeytab [\fI-a\fR] \fIprincipal-name\fR \fIfile-name\fR
+
+.SH "DESCRIPTION"
+Retrieves a kerberos \fIkeytab\fR and optionally adds a
+service \fIprincipal\fR.
+
+Kerberos keytabs are used for services (like sshd) to
+perform kerberos authentication. A keytab is a file
+with one or more secrets (or keys) for a kerberos
+principal.
+
+A kerberos service principal is a kerberos identity
+that can be used for authentication. Service principals
+contain the name of the service, the hostname of the
+server, and the realm name. For example, the following
+is an example principal for an ldap server:
+
+ ldap/foo.example.com@EXAMPLE.COM
+
+When using ipa-getkeytab the realm name is already
+provided, so the principal name is just the service
+name and hostname (ldap/foo.example.com from the
+example above).
+
+\fBWARNING:\fR retrieving the keytab resets the secret
+rendering all other keytabs for that principal invalid.
+
+.SH "OPTIONS"
+.TP
+\fB\-a\fR
+Add the service principal in addition to getting the keytab
+
+.SH "EXAMPLES"
+
+Add and retrieve a keytab for the ldap service principal on
+the host foo.example.com and save it in the file ldap.keytab.
+
+ # ipa-getkeytab -a ldap/foo.example.com ldap.keytab
+
+.SH "EXIT STATUS"
+The exit status is 0 on success, nonzero on error.
diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install
index bc8e7c9c3..9cc6f6f6b 100644
--- a/ipa-client/ipa-install/ipa-client-install
+++ b/ipa-client/ipa-install/ipa-client-install
@@ -51,6 +51,13 @@ def parse_options():
return options
+def ask_for_confirmation(message):
+ yesno = raw_input(message + " [y/N]: ")
+ if not yesno or yesno.lower()[0] != "y":
+ return False
+ print "\n"
+ return True
+
def logging_setup(options):
# Always log everything (i.e., DEBUG) to the log
# file.
@@ -114,16 +121,18 @@ def main():
print "\nThe failure to use DNS to find your IPA server indicates that your resolv.conf file is not properly configured\n."
print "Autodiscovery of servers for failover cannot work with this configuration.\n"
print "If you proceed with the installation, services will be configured to always access the discovered server for all operation and will not fail over to other servers in case of failure\n"
- yesno = raw_input("Do you want to proceed and configure the system with fixed values with no DNS discovery? [y/N] ")
- if yesno.lower() != "y":
+ if not ask_for_confirmation("Do you want to proceed and configure the system with fixed values with no DNS discovery?"):
return ret
- print "\n"
print "Realm: "+ds.getRealmName()
print "DNS Domain: "+ds.getDomainName()
print "IPA Server: "+ds.getServerName()
print "BaseDN: "+ds.getBaseDN()
+ print "\n"
+ if not ask_for_confirmation("Continue to configure the system with these values?"):
+ return 1
+
# Configure ipa.conf
ipaconf = ipaclient.ipachangeconf.IPAChangeConf("IPA Installer")
ipaconf.setOptionAssignment(" = ")
@@ -225,4 +234,4 @@ def main():
return 0
-main()
+sys.exit(main())
diff --git a/ipa-python/ipa-python.spec b/ipa-python/ipa-python.spec
index 2837a2832..1c838821b 100755
--- a/ipa-python/ipa-python.spec
+++ b/ipa-python/ipa-python.spec
@@ -14,8 +14,6 @@ Requires: PyKerberos
%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
-%define pkgpythondir %{python_sitelib}/ipa
-
%description
Ipa is a server for identity, policy, and audit.
@@ -33,8 +31,7 @@ rm -rf %{buildroot}
%files
%defattr(-,root,root,-)
-%dir %{pkgpythondir}
-%{pkgpythondir}/*
+%{python_sitelib}/*
%config(noreplace) %{_sysconfdir}/ipa/ipa.conf
%changelog
diff --git a/ipa-python/ipa-python.spec.in b/ipa-python/ipa-python.spec.in
index bd8ac0da6..9eb2e11c2 100755
--- a/ipa-python/ipa-python.spec.in
+++ b/ipa-python/ipa-python.spec.in
@@ -14,8 +14,6 @@ Requires: PyKerberos
%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
-%define pkgpythondir %{python_sitelib}/ipa
-
%description
Ipa is a server for identity, policy, and audit.
@@ -33,8 +31,7 @@ rm -rf %{buildroot}
%files
%defattr(-,root,root,-)
-%dir %{pkgpythondir}
-%{pkgpythondir}/*
+%{python_sitelib}/*
%config(noreplace) %{_sysconfdir}/ipa/ipa.conf
%changelog
diff --git a/ipa-python/ipaclient.py b/ipa-python/ipaclient.py
index d815afa7b..bd1fb235a 100644
--- a/ipa-python/ipaclient.py
+++ b/ipa-python/ipaclient.py
@@ -19,14 +19,10 @@
#!/usr/bin/python
-import sys
-
import ipa.rpcclient as rpcclient
import entity
import user
import group
-import ipa
-import config
import radius_util
class IPAClient:
diff --git a/ipa-python/ipaerror.py b/ipa-python/ipaerror.py
index e34963365..59e262018 100644
--- a/ipa-python/ipaerror.py
+++ b/ipa-python/ipaerror.py
@@ -129,14 +129,14 @@ LDAP_NO_CONFIG = gen_error_code(
"IPA configuration not found")
#
-# Input errors (sample - replace me)
+# Function input errors
#
INPUT_CATEGORY = 0x0002
-INPUT_INVALID_ERROR = gen_error_code(
+INPUT_INVALID_PARAMETER = gen_error_code(
INPUT_CATEGORY,
0x0001,
- "Illegal input")
+ "Invalid parameter(s)")
#
# Connection errors
diff --git a/ipa-python/ipautil.py b/ipa-python/ipautil.py
index 3c2b37f73..c617854e5 100644
--- a/ipa-python/ipautil.py
+++ b/ipa-python/ipautil.py
@@ -18,6 +18,7 @@
#
SHARE_DIR = "/usr/share/ipa/"
+PLUGINS_SHARE_DIR = "/usr/share/ipa/plugins"
import string
import tempfile
diff --git a/ipa-python/radius_util.py b/ipa-python/radius_util.py
index e1401fb7b..fb3e581e6 100644
--- a/ipa-python/radius_util.py
+++ b/ipa-python/radius_util.py
@@ -79,7 +79,7 @@ RADIUS_USER = 'radiusd'
RADIUS_IPA_KEYTAB_FILEPATH = os.path.join(RADIUS_PKG_CONFIG_DIR, 'ipa.keytab')
RADIUS_LDAP_ATTR_MAP_FILEPATH = os.path.join(RADIUS_PKG_CONFIG_DIR, 'ldap.attrmap')
RADIUSD_CONF_FILEPATH = os.path.join(RADIUS_PKG_CONFIG_DIR, 'radiusd.conf')
-RADIUSD_CONF_TEMPLATE_FILEPATH = os.path.join(ipautil.SHARE_DIR, 'radius.radiusd.conf.template')
+RADIUSD_CONF_TEMPLATE_FILEPATH = os.path.join(ipautil.PLUGINS_SHARE_DIR, 'radius.radiusd.conf.template')
RADIUSD = '/usr/sbin/radiusd'
diff --git a/ipa-python/rpcclient.py b/ipa-python/rpcclient.py
index 5656b99d9..c993ac991 100644
--- a/ipa-python/rpcclient.py
+++ b/ipa-python/rpcclient.py
@@ -24,11 +24,8 @@ import socket
import config
from krbtransport import KerbTransport
from kerberos import GSSError
-import os
-import base64
-import user
-import ipa
from ipa import ipaerror, ipautil
+from ipa import config
# Some errors to catch
# http://cvs.fedora.redhat.com/viewcvs/ldapserver/ldap/servers/plugins/pam_passthru/README?root=dirsec&rev=1.6&view=auto
@@ -36,7 +33,7 @@ from ipa import ipaerror, ipautil
class RPCClient:
def __init__(self):
- ipa.config.init_config()
+ config.init_config()
def server_url(self):
"""Build the XML-RPC server URL from our configuration"""
@@ -47,25 +44,6 @@ class RPCClient:
authentication"""
return xmlrpclib.ServerProxy(self.server_url(), KerbTransport())
- def convert_entry(self,ent):
- # Convert into a dict. We need to handle multi-valued attributes as well
- # so we'll convert those into lists.
- obj={}
- for (k) in ent:
- k = k.lower()
- if obj.get(k) is not None:
- if isinstance(obj[k],list):
- obj[k].append(ent[k].strip())
- else:
- first = obj[k]
- obj[k] = ()
- obj[k].append(first)
- obj[k].append(ent[k].strip())
- else:
- obj[k] = ent[k]
-
- return obj
-
# Higher-level API
def get_aci_entry(self, sattrs=None):
@@ -168,7 +146,8 @@ class RPCClient:
def get_user_by_email(self,email,sattrs=None):
"""Get a specific user's entry. Return as a dict of values.
- Multi-valued fields are represented as lists.
+ Multi-valued fields are represented as lists. The result is a
+ dict.
"""
server = self.setup_server()
if sattrs is None:
@@ -245,7 +224,7 @@ class RPCClient:
return ipautil.unwrap_binary_data(result)
def get_all_users (self):
- """Return a list containing a User object for each existing user."""
+ """Return a list containing a dict for each existing user."""
server = self.setup_server()
try:
@@ -258,7 +237,7 @@ class RPCClient:
return ipautil.unwrap_binary_data(result)
def find_users (self, criteria, sattrs=None, searchlimit=0, timelimit=-1):
- """Return a list: counter followed by a User object for each user that
+ """Return a list: counter followed by a dict for each user that
matches the criteria. If the results are truncated, counter will
be set to -1"""
@@ -381,6 +360,8 @@ class RPCClient:
except socket.error, (value, msg):
raise xmlrpclib.Fault(value, msg)
+ return ipautil.unwrap_binary_data(result)
+
def find_groups (self, criteria, sattrs=None, searchlimit=0, timelimit=-1):
"""Return a list containing a Group object for each group that matches
the criteria."""
diff --git a/ipa-python/setup.py b/ipa-python/setup.py
index 3a5a6f4eb..deb84f293 100644
--- a/ipa-python/setup.py
+++ b/ipa-python/setup.py
@@ -34,7 +34,7 @@ def setup_package():
try:
setup(
- name = "freeipa-python",
+ name = "ipa",
version = "0.5.0",
license = "GPL",
author = "Karl MacMillan, et.al.",
diff --git a/ipa-radius-server/Makefile b/ipa-radius-server/Makefile
new file mode 100644
index 000000000..7de51b469
--- /dev/null
+++ b/ipa-radius-server/Makefile
@@ -0,0 +1,20 @@
+PLUGINS_SHARE = $(DESTDIR)/usr/share/ipa/plugins
+PLUGINS_PYTHON = $(DESTDIR)/usr/share/ipa/ipaserver/plugins
+SBINDIR = $(DESTDIR)/usr/sbin
+
+all:
+
+install:
+ -mkdir -p $(PLUGINS_SHARE)
+ -mkdir -p $(PLUGINS_PYTHON)
+ -mkdir -p $(PLUGINS_SBINDIR)
+ install -m 644 plugins/*.py $(PLUGINS_PYTHON)
+ install -m 644 share/*.template $(PLUGINS_SHARE)
+ install -m 755 ipa-radius-install $(SBINDIR)
+
+clean:
+ rm -fr *.pyc *~
+
+distclean: clean
+
+test: \ No newline at end of file
diff --git a/ipa-radius-server/ipa-radius-install b/ipa-radius-server/ipa-radius-install
new file mode 100644
index 000000000..3e759d8d2
--- /dev/null
+++ b/ipa-radius-server/ipa-radius-install
@@ -0,0 +1,73 @@
+#! /usr/bin/python -E
+# 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 sys
+sys.path.append("/usr/share/ipa")
+
+import traceback, logging, krbV
+
+from ipaserver import installutils
+from ipaserver.plugins import radiusinstance
+
+from ipa import ipautil
+
+def get_host_name():
+ hostname = installutils.get_fqdn()
+ try:
+ installutils.verify_fqdn(hostname)
+ except RuntimeError, e:
+ logging.error(str(e))
+ sys.exit(1)
+
+ return hostname
+
+def get_realm_name():
+ c = krbV.default_context()
+ return c.default_realm
+
+def main():
+ if not ipautil.file_exists("/etc/ipa/ipa.conf"):
+ print "This system does not appear to have IPA configured."
+ print "Has ipa-server-install been run?"
+ yesno = raw_input("Continue with radius install [y/N]? ")
+ if yesno.lower() != "y":
+ sys.exit(1)
+
+ installutils.standard_logging_setup("iparadius-install.log", False)
+
+ host_name = get_host_name()
+
+ realm_name = get_realm_name()
+
+ # Create a radius instance
+ radius = radiusinstance.RadiusInstance()
+ # FIXME: ldap_server should be derived, not hardcoded to localhost, also should it be a URL?
+ radius.create_instance(realm_name, host_name, 'localhost')
+
+
+try:
+ main()
+except Exception, e:
+ message = "Unexpected error - see iparadius-install.log for details:\n %s" % str(e)
+ print message
+ message = str(e)
+ for str in traceback.format_tb(sys.exc_info()[2]):
+ message = message + "\n" + str
+ logging.debug(message)
diff --git a/ipa-radius-server/ipa-radius-server.spec b/ipa-radius-server/ipa-radius-server.spec
new file mode 100755
index 000000000..2b8b61624
--- /dev/null
+++ b/ipa-radius-server/ipa-radius-server.spec
@@ -0,0 +1,50 @@
+Name: ipa-radius-server
+Version: 0.5.0
+Release: 1%{?dist}
+Summary: IPA authentication server - radius plugin
+
+Group: System Environment/Base
+License: GPL
+URL: http://www.freeipa.org
+Source0: %{name}-%{version}.tgz
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+BuildArch: noarch
+
+Requires: python
+Requires: ipa-server
+Requires: freeradius
+
+%description
+Radius plugin for an IPA server
+
+%prep
+%setup -q
+
+%install
+rm -rf %{buildroot}
+mkdir -p %{buildroot}%{_sbindir}
+
+make install DESTDIR=%{buildroot}
+
+
+%clean
+rm -rf %{buildroot}
+
+
+%files
+%defattr(-,root,root,-)
+%{_sbindir}/ipa*
+
+%dir %{_usr}/share/ipa/plugins
+%{_usr}/share/ipa/plugins/*
+
+%dir %{_usr}/share/ipa/ipaserver/plugins
+%{_usr}/share/ipa/ipaserver/plugins/*
+
+%changelog
+* Wed Dec 12 2007 Karl MacMillan <kmacmill@redhat.com> - 0.5.0-1
+- Initial version
+
+
+
+
diff --git a/ipa-radius-server/ipa-radius-server.spec.in b/ipa-radius-server/ipa-radius-server.spec.in
new file mode 100755
index 000000000..5937d3b19
--- /dev/null
+++ b/ipa-radius-server/ipa-radius-server.spec.in
@@ -0,0 +1,50 @@
+Name: ipa-radius-server
+Version: VERSION
+Release: 1%{?dist}
+Summary: IPA authentication server - radius plugin
+
+Group: System Environment/Base
+License: GPL
+URL: http://www.freeipa.org
+Source0: %{name}-%{version}.tgz
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+BuildArch: noarch
+
+Requires: python
+Requires: ipa-server
+Requires: freeradius
+
+%description
+Radius plugin for an IPA server
+
+%prep
+%setup -q
+
+%install
+rm -rf %{buildroot}
+mkdir -p %{buildroot}%{_sbindir}
+
+make install DESTDIR=%{buildroot}
+
+
+%clean
+rm -rf %{buildroot}
+
+
+%files
+%defattr(-,root,root,-)
+%{_sbindir}/ipa*
+
+%dir %{_usr}/share/ipa/plugins
+%{_usr}/share/ipa/plugins/*
+
+%dir %{_usr}/share/ipa/ipaserver/plugins
+%{_usr}/share/ipa/ipaserver/plugins/*
+
+%changelog
+* Wed Dec 12 2007 Karl MacMillan <kmacmill@redhat.com> - 0.5.0-1
+- Initial version
+
+
+
+
diff --git a/ipa-radius-server/plugins/__init__.py b/ipa-radius-server/plugins/__init__.py
new file mode 100644
index 000000000..636bc1a8a
--- /dev/null
+++ b/ipa-radius-server/plugins/__init__.py
@@ -0,0 +1 @@
+# intentionally empty
diff --git a/ipa-server/ipaserver/radiusinstance.py b/ipa-radius-server/plugins/radiusinstance.py
index 3b89018f0..731cd65a1 100644
--- a/ipa-server/ipaserver/radiusinstance.py
+++ b/ipa-radius-server/plugins/radiusinstance.py
@@ -19,6 +19,8 @@
#
import sys
+sys.path.append("/usr/share/ipa")
+
import subprocess
import string
import tempfile
@@ -27,10 +29,10 @@ import logging
import pwd
import time
import sys
-from ipa.ipautil import *
+from ipa import ipautil
from ipa import radius_util
-import service
+from ipaserver import service
import os
import re
@@ -42,10 +44,6 @@ from ipaserver.funcs import DefaultUserContainer, DefaultGroupContainer
#-------------------------------------------------------------------------------
-def ldap_mod(fd, dn, pwd):
- args = ["/usr/bin/ldapmodify", "-h", "127.0.0.1", "-xv", "-D", dn, "-w", pwd, "-f", fd.name]
- run(args)
-
def get_radius_version():
version = None
try:
@@ -74,14 +72,13 @@ class RadiusInstance(service.Service):
def create_instance(self, realm_name, host_name, ldap_server):
self.realm = realm_name.upper()
- self.suffix = realm_to_suffix(self.realm)
+ self.suffix = ipautil.realm_to_suffix(self.realm)
self.fqdn = host_name
self.ldap_server = ldap_server
self.principal = "%s/%s@%s" % (radius_util.RADIUS_SERVICE_NAME, self.fqdn, self.realm)
self.basedn = self.suffix
self.user_basedn = "%s,%s" % (DefaultUserContainer, self.basedn) # FIXME, should be utility to get this
self.radius_version = get_radius_version()
- self.start_creation(4, "Configuring radiusd")
try:
self.stop()
@@ -89,22 +86,23 @@ class RadiusInstance(service.Service):
# It could have been not running
pass
- self.__create_radius_keytab()
- self.__radiusd_conf()
+ self.step("create radiusd keytab", self.__create_radius_keytab)
+ self.step("configuring radiusd.conf for radius instance", self.__radiusd_conf)
+ self.step("starting radiusd", self.__start_instance)
+ self.step("configuring radiusd to start on boot", self.chkconfig_on)
+
+ # FIXME:
+ # self.step("setting ldap encrypted attributes", self.__set_ldap_encrypted_attributes)
+
+ self.start_creation("Configuring radiusd")
+ def __start_instance(self):
try:
- self.step("starting radiusd")
self.start()
except:
logging.error("radiusd service failed to start")
- self.step("configuring radiusd to start on boot")
- self.chkconfig_on()
-
-
def __radiusd_conf(self):
- self.step('configuring radiusd.conf for radius instance')
-
version = 'IPA_RADIUS_VERSION=%s FREE_RADIUS_VERSION=%s' % (IPA_RADIUS_VERSION, self.radius_version)
sub_dict = {'CONFIG_FILE_VERSION_INFO' : version,
'LDAP_SERVER' : self.ldap_server,
@@ -117,7 +115,7 @@ class RadiusInstance(service.Service):
'SUFFIX' : self.suffix,
}
try:
- radiusd_conf = template_file(radius_util.RADIUSD_CONF_TEMPLATE_FILEPATH, sub_dict)
+ radiusd_conf = ipautil.template_file(radius_util.RADIUSD_CONF_TEMPLATE_FILEPATH, sub_dict)
radiusd_fd = open(radius_util.RADIUSD_CONF_FILEPATH, 'w+')
radiusd_fd.write(radiusd_conf)
radiusd_fd.close()
@@ -125,9 +123,8 @@ class RadiusInstance(service.Service):
logging.error("could not create %s: %s", radius_util.RADIUSD_CONF_FILEPATH, e)
def __create_radius_keytab(self):
- self.step("creating a keytab for httpd")
try:
- if file_exists(radius_util.RADIUS_IPA_KEYTAB_FILEPATH):
+ if ipautil.file_exists(radius_util.RADIUS_IPA_KEYTAB_FILEPATH):
os.remove(radius_util.RADIUS_IPA_KEYTAB_FILEPATH)
except os.error:
logging.error("Failed to remove %s", radius_util.RADIUS_IPA_KEYTAB_FILEPATH)
@@ -143,7 +140,7 @@ class RadiusInstance(service.Service):
# give kadmin time to actually write the file before we go on
retry = 0
- while not file_exists(radius_util.RADIUS_IPA_KEYTAB_FILEPATH):
+ while not ipautil.file_exists(radius_util.RADIUS_IPA_KEYTAB_FILEPATH):
time.sleep(1)
retry += 1
if retry > 15:
@@ -155,17 +152,23 @@ class RadiusInstance(service.Service):
except Exception, e:
logging.error("could not chown on %s to %s: %s", radius_util.RADIUS_IPA_KEYTAB_FILEPATH, radius_util.RADIUS_USER, e)
+ def __ldap_mod(self, ldif):
+ txt = iputil.template_file(ipautil.SHARE_DIR + ldif, self.sub_dict)
+ fd = ipautil.write_tmp_file(txt)
+
+ args = ["/usr/bin/ldapmodify", "-h", "127.0.0.1", "-xv",
+ "-D", "cn=Directory Manager", "-w", self.dm_password, "-f", fd.name]
+
+ try:
+ ipautil.run(args)
+ except ipautil.CalledProcessError, e:
+ logging.critical("Failed to load %s: %s" % (ldif, str(e)))
+
+ fd.close()
+
#FIXME, should use IPAdmin method
def __set_ldap_encrypted_attributes(self):
- ldif_file = 'encrypted_attribute.ldif'
- self.step("setting ldap encrypted attributes")
- ldif_txt = template_file(SHARE_DIR + ldif_file, {'ENCRYPTED_ATTRIBUTE':'radiusClientSecret'})
- ldif_fd = write_tmp_file(ldif_txt)
- try:
- ldap_mod(ldif_fd, "cn=Directory Manager", self.dm_password)
- except subprocess.CalledProcessError, e:
- logging.critical("Failed to load %s: %s" % (ldif_file, str(e)))
- ldif_fd.close()
+ self.__ldap_mod("encrypted_attribute.ldif", {"ENCRYPTED_ATTRIBUTE" : "radiusClientSecret"})
#-------------------------------------------------------------------------------
diff --git a/ipa-server/ipa-install/share/radius.radiusd.conf.template b/ipa-radius-server/share/radius.radiusd.conf.template
index 3bc4927dd..3bc4927dd 100644
--- a/ipa-server/ipa-install/share/radius.radiusd.conf.template
+++ b/ipa-radius-server/share/radius.radiusd.conf.template
diff --git a/ipa-server/ipa-gui/ipa-webgui b/ipa-server/ipa-gui/ipa-webgui
index c8e3d0589..a18c2db81 100644
--- a/ipa-server/ipa-gui/ipa-webgui
+++ b/ipa-server/ipa-gui/ipa-webgui
@@ -63,41 +63,48 @@ def daemonize():
# stderr
os.open("/dev/null", os.O_RDWR)
-# To make development easier, we detect if we are in the development
-# environment to load a different configuration and avoid becoming
-# a daemon
-devel = False
-if os.path.exists(os.path.join(os.path.dirname(__file__), "Makefile.am")):
- devel = True
-
-if not devel:
- try:
- daemonize()
- except Exception, e:
- sys.stderr.write("error becoming daemon: " + str(e))
- sys.exit(1)
+def main():
+ # To make development easier, we detect if we are in the development
+ # environment to load a different configuration and avoid becoming
+ # a daemon
+ devel = False
+ if os.path.exists(os.path.join(os.path.dirname(__file__), "Makefile.am")):
+ devel = True
+
+ if not devel:
+ try:
+ daemonize()
+ except Exception, e:
+ sys.stderr.write("error becoming daemon: " + str(e))
+ sys.exit(1)
+
+ sys.path.append("/usr/share/ipa/")
-sys.path.append("/usr/share/ipa/")
+ # this must be after sys.path is changed to work correctly
+ import pkg_resources
+ pkg_resources.require("TurboGears")
+ pkg_resources.require("ipa_gui")
-# this must be after sys.path is changed to work correctly
-import pkg_resources
-pkg_resources.require("TurboGears")
-pkg_resources.require("ipa_gui")
+ from turbogears import update_config, start_server
+ import cherrypy
+ cherrypy.lowercase_api = True
-from turbogears import update_config, start_server
-import cherrypy
-cherrypy.lowercase_api = True
+ # Load the config - look for a local file first for development
+ # and then the system config file
+ if devel:
+ update_config(configfile="dev.cfg",
+ modulename="ipagui.config")
+ else:
+ update_config(configfile="/usr/share/ipa/ipa-webgui.cfg",
+ modulename="ipagui.config.app")
-# Load the config - look for a local file first for development
-# and then the system config file
-if devel:
- update_config(configfile="dev.cfg",
- modulename="ipagui.config")
-else:
- update_config(configfile="/usr/share/ipa/ipa-webgui.cfg",
- modulename="ipagui.config.app")
+ from ipagui.controllers import Root
-from ipagui.controllers import Root
+ start_server(Root())
-start_server(Root())
+try:
+ main()
+except Exception, e:
+ print "failed to start web gui: %s" % str(e)
+ sys.exit(1)
diff --git a/ipa-server/ipa-gui/ipagui/forms/delegate.py b/ipa-server/ipa-gui/ipagui/forms/delegate.py
index d9d5d727c..7eadfe23e 100644
--- a/ipa-server/ipa-gui/ipagui/forms/delegate.py
+++ b/ipa-server/ipa-gui/ipagui/forms/delegate.py
@@ -65,8 +65,9 @@ class DelegateValidator(validators.Schema):
messages = { 'empty': _("Please choose a group"), })
dest_group_dn = validators.String(not_empty=True,
messages = { 'empty': _("Please choose a group"), })
- attrs = validators.NotEmpty(
- messages = { 'empty': _("Please select at least one value"), })
+ # There is no attrs validator here because then it shows as one
+ # huge block of color in the form. The validation is done in
+ # the subcontroller.
class DelegateForm(widgets.Form):
params = ['delegate_fields', 'attr_list']
diff --git a/ipa-server/ipa-gui/ipagui/forms/user.py b/ipa-server/ipa-gui/ipagui/forms/user.py
index 74369a6ae..43a7a5477 100644
--- a/ipa-server/ipa-gui/ipagui/forms/user.py
+++ b/ipa-server/ipa-gui/ipagui/forms/user.py
@@ -5,8 +5,8 @@ from tg_expanding_form_widget.tg_expanding_form_widget import ExpandingForm
class UserFields(object):
givenname = widgets.TextField(name="givenname", label="First Name")
sn = widgets.TextField(name="sn", label="Last Name")
- cn = widgets.TextField(name="cn", label="Common Names")
- cns = ExpandingForm(name="cns", label="Common Names", fields=[cn])
+ cn = widgets.TextField(name="cn", label="Full Name")
+ cns = ExpandingForm(name="cns", label="Full Name", fields=[cn])
title = widgets.TextField(name="title", label="Title")
displayname = widgets.TextField(name="displayname", label="Display Name")
initials = widgets.TextField(name="initials", label="Initials")
diff --git a/ipa-server/ipa-gui/ipagui/subcontrollers/delegation.py b/ipa-server/ipa-gui/ipagui/subcontrollers/delegation.py
index cee239e72..2319b944a 100644
--- a/ipa-server/ipa-gui/ipagui/subcontrollers/delegation.py
+++ b/ipa-server/ipa-gui/ipagui/subcontrollers/delegation.py
@@ -56,6 +56,25 @@ class DelegationController(IPAController):
turbogears.flash("Add delegation cancelled")
raise turbogears.redirect('/delegate/list')
+ # Try to handle the case where the user entered just some data
+ # into the source/dest group name but didn't do a Find. We'll do
+ # our best to see if a group by that name exists and if so, use it.
+ dest_group_dn = kw.get('dest_group_dn')
+ dest_group_cn = kw.get('dest_group_cn')
+ if not dest_group_dn and dest_group_cn:
+ try:
+ group = client.get_entry_by_cn(dest_group_cn, ['dn'])
+ kw['dest_group_dn'] = group.dn
+ except:
+ kw['dest_group_cn'] = "Please choose:"
+ source_group_dn = kw.get('source_group_dn')
+ source_group_cn = kw.get('source_group_cn')
+ if not source_group_dn and source_group_cn:
+ try:
+ group = client.get_entry_by_cn(source_group_cn, ['dn'])
+ kw['source_group_dn'] = group.dn
+ except:
+ kw['source_group_cn'] = "Please choose:"
tg_errors, kw = self.delegatevalidate(**kw)
if tg_errors:
turbogears.flash("There were validation errors.<br/>" +
@@ -292,4 +311,11 @@ class DelegationController(IPAController):
@validate(form=delegate_form)
@identity.require(identity.not_anonymous())
def delegatevalidate(self, tg_errors=None, **kw):
+ # We are faking this because otherwise it shows up as one huge
+ # block of color in the UI when it has a not empty validator.
+ if not kw.get('attrs'):
+ if not tg_errors:
+ tg_errors = {}
+ tg_errors['attrs'] = _("Please select at least one value")
+ cherrypy.request.validation_errors = tg_errors
return tg_errors, kw
diff --git a/ipa-server/ipa-gui/ipagui/templates/delegateform.kid b/ipa-server/ipa-gui/ipagui/templates/delegateform.kid
index 4eb846d53..3f885fa03 100644
--- a/ipa-server/ipa-gui/ipagui/templates/delegateform.kid
+++ b/ipa-server/ipa-gui/ipagui/templates/delegateform.kid
@@ -4,6 +4,13 @@
<?python searchurl = tg.url('/delegate/group_search') ?>
<script type="text/javascript">
+ function lostFocus(which_group) {
+ /* The user has left the field, save what they put in there in case
+ * they don't do a Find. */
+ group_cn_field = $('form_' + which_group + '_group_cn');
+ group_criteria_field = $(which_group + '_criteria')
+ group_cn_field.value = group_criteria_field.value
+ }
function enterDoSearch(e, which_group) {
var keyPressed;
@@ -104,8 +111,8 @@
py:content="tg.errors.get('source_group_dn')" />
</div>
<div id="source_searcharea" style="display:none">
- <input id="source_criteria" type="text"
- onkeypress="return enterDoSearch(event, 'source');" />
+ <input class="requiredfield" id="source_criteria" type="text"
+ onkeypress="return enterDoSearch(event, 'source');" onblur="return lostFocus('source');"/>
<input class="searchbutton" type="button" value="Find"
onclick="return doSearch('source');"
/>
@@ -142,8 +149,8 @@
</div>
<div id="dest_searcharea" style="display:none">
<div>
- <input id="dest_criteria" type="text"
- onkeypress="return enterDoSearch(event, 'dest');" />
+ <input class="requiredfield" id="dest_criteria" type="text"
+ onkeypress="return enterDoSearch(event, 'dest');" onblur="return lostFocus('dest');"/>
<input class="searchbutton" type="button" value="Find"
onclick="return doSearch('dest');"
/>
diff --git a/ipa-server/ipa-install/Makefile.am b/ipa-server/ipa-install/Makefile.am
index 1b46d354b..8a3e4a975 100644
--- a/ipa-server/ipa-install/Makefile.am
+++ b/ipa-server/ipa-install/Makefile.am
@@ -8,6 +8,7 @@ sbin_SCRIPTS = \
ipa-server-install \
ipa-replica-install \
ipa-replica-prepare \
+ ipa-server-certinstall \
$(NULL)
EXTRA_DIST = \
diff --git a/ipa-server/ipa-install/ipa-server-certinstall b/ipa-server/ipa-install/ipa-server-certinstall
new file mode 100644
index 000000000..932a6be18
--- /dev/null
+++ b/ipa-server/ipa-install/ipa-server-certinstall
@@ -0,0 +1,156 @@
+#! /usr/bin/python -E
+# 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 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
+#
+
+import sys
+sys.path.append("/usr/share/ipa")
+
+import traceback
+
+import krbV, ldap, getpass
+
+from ipaserver import certs, dsinstance, httpinstance, ipaldap, installutils
+
+def get_realm_name():
+ c = krbV.default_context()
+ return c.default_realm
+
+def parse_options():
+ from optparse import OptionParser
+ parser = OptionParser()
+
+ parser.add_option("-d", "--dirsrv", dest="dirsrv", action="store_true",
+ default=False, help="install certificate for the directory server")
+ parser.add_option("-w", "--http", dest="http", action="store_true",
+ default=False, help="install certificate for the http server")
+
+
+ options, args = parser.parse_args()
+
+ if not options.dirsrv and not options.http:
+ parser.error("you must specify dirsrv and/or http")
+
+ if len(args) != 1:
+ parser.error("you must provide a pkcs12 filename")
+
+ return options, args[0]
+
+def set_ds_cert_name(cert_name, dm_password):
+ conn = ipaldap.IPAdmin("127.0.0.1")
+ conn.simple_bind_s("cn=directory manager", dm_password)
+
+ mod = [(ldap.MOD_REPLACE, "nsSSLPersonalitySSL", cert_name)]
+
+ conn.modify_s("cn=RSA,cn=encryption,cn=config", mod)
+
+ conn.unbind()
+
+def set_http_cert_name(cert_name):
+ # find the existing cert name
+ fd = open(httpinstance.NSS_CONF)
+ nick_name = None
+ file = []
+ for line in fd:
+ if "NSSNickname" in line:
+ file.append('NSSNickname "%s"\n' % cert_name)
+ else:
+ file.append(line)
+ fd.close()
+
+ fd = open(httpinstance.NSS_CONF, "w")
+ fd.write("".join(file))
+ fd.close()
+
+
+def choose_server_cert(server_certs):
+ print "Please select the certificate to use:"
+ num = 1
+ for cert in server_certs:
+ print "%d. %s" % (num, cert[0])
+ num += 1
+
+ cert_num = 0
+ while 1:
+ cert_input = raw_input("Certificate number [1]: ")
+ print ""
+ if cert_input == "":
+ break
+ else:
+ try:
+ num = int(cert_input)
+ except ValueError:
+ print "invalid number"
+ continue
+ if num > len(server_certs):
+ print "number out of range"
+ continue
+ cert_num = num - 1
+ break
+ return server_certs[cert_num]
+
+
+def import_cert(dirname, pkcs12_fname):
+ cdb = certs.CertDB(dirname)
+ cdb.create_passwd_file(False)
+ cdb.create_certdbs()
+ try:
+ cdb.import_pkcs12(pkcs12_fname)
+ except RuntimeError, e:
+ print str(e)
+ sys.exit(1)
+
+ server_certs = cdb.find_server_certs()
+ if len(server_certs) == 0:
+ print "could not find a suitable server cert in import"
+ sys.exit(1)
+ elif len(server_certs) == 1:
+ server_cert = server_certs[0]
+ else:
+ server_cert = choose_server_cert(server_certs)
+
+ cdb.trust_root_cert(server_cert[0])
+
+ return server_cert
+
+def main():
+ options, pkcs12_fname = parse_options()
+
+ try:
+ if options.dirsrv:
+ dm_password = getpass.getpass("Directory Manager password: ")
+ realm = get_realm_name()
+ dirname = dsinstance.config_dirname(realm)
+ server_cert = import_cert(dirname, pkcs12_fname)
+ set_ds_cert_name(server_cert[0], dm_password)
+
+ if options.http:
+ dirname = httpinstance.NSS_DIR
+ server_cert = import_cert(dirname, pkcs12_fname)
+ print server_cert
+ set_http_cert_name(server_cert[0])
+
+ except Exception, e:
+ print "an unexpected error occurred: %s" % str(e)
+ traceback.print_exc()
+ return 1
+
+ return 0
+
+
+sys.exit(main())
diff --git a/ipa-server/ipa-install/ipa-server-install b/ipa-server/ipa-install/ipa-server-install
index 646512d51..ee5e929d1 100644
--- a/ipa-server/ipa-install/ipa-server-install
+++ b/ipa-server/ipa-install/ipa-server-install
@@ -46,7 +46,6 @@ import ipaserver.krbinstance
import ipaserver.bindinstance
import ipaserver.httpinstance
import ipaserver.ntpinstance
-import ipaserver.radiusinstance
import ipaserver.webguiinstance
from ipaserver import service
@@ -400,11 +399,6 @@ def main():
webgui = ipaserver.webguiinstance.WebGuiInstance()
webgui.create_instance()
- # Create a radius instance
- radius = ipaserver.radiusinstance.RadiusInstance()
- # FIXME: ldap_server should be derived, not hardcoded to localhost, also should it be a URL?
- radius.create_instance(realm_name, host_name, 'localhost')
-
bind.setup(host_name, ip_address, realm_name)
if options.setup_bind:
skipbind = False
diff --git a/ipa-server/ipa-install/share/Makefile.am b/ipa-server/ipa-install/share/Makefile.am
index 36bb54e83..5d117dec5 100644
--- a/ipa-server/ipa-install/share/Makefile.am
+++ b/ipa-server/ipa-install/share/Makefile.am
@@ -19,7 +19,7 @@ app_DATA = \
krb.con.template \
krbrealm.con.template \
ntp.conf.server.template \
- radius.radiusd.conf.template \
+ preferences.html.template \
referint-conf.ldif \
dna-posix.ldif \
master-entry.ldif \
diff --git a/ipa-server/ipa-install/share/bootstrap-template.ldif b/ipa-server/ipa-install/share/bootstrap-template.ldif
index 9642070c7..0a969de38 100644
--- a/ipa-server/ipa-install/share/bootstrap-template.ldif
+++ b/ipa-server/ipa-install/share/bootstrap-template.ldif
@@ -2,6 +2,8 @@ dn: $SUFFIX
changetype: modify
add: objectClass
objectClass: pilotObject
+-
+add: info
info: IPA V1.0
dn: cn=accounts,$SUFFIX
@@ -80,6 +82,7 @@ gidNumber: 1001
homeDirectory: /home/admin
loginShell: /bin/bash
gecos: Administrator
+nsAccountLock: False
dn: cn=radius,$SUFFIX
changetype: add
@@ -114,6 +117,7 @@ cn: admins
description: Account administrators group
gidNumber: 1001
member: uid=admin,cn=sysaccounts,cn=etc,$SUFFIX
+nsAccountLock: False
dn: cn=ipausers,cn=groups,cn=accounts,$SUFFIX
changetype: add
diff --git a/ipa-server/ipa-install/share/default-aci.ldif b/ipa-server/ipa-install/share/default-aci.ldif
index 95743eebb..5715259a1 100644
--- a/ipa-server/ipa-install/share/default-aci.ldif
+++ b/ipa-server/ipa-install/share/default-aci.ldif
@@ -1,18 +1,18 @@
# $SUFFIX (base entry)
-# FIXME: We need to allow truly anonymous access only to NIS data for older clients. We need to allow broad access to most attributes only to authewnticated users
+# FIXME: We need to allow truly anonymous access only to NIS data for older clients. We need to allow broad access to most attributes only to authenticated users
dn: $SUFFIX
changetype: modify
replace: aci
-aci: (targetattr != "userPassword || krbPrincipalKey || krbMKey || sambaLMPassword || sambaNTPassword")(version 3.0; acl "Enable anonymous access"; allow (read, search, compare) userdn = "ldap:///anyone";)
-aci: (targetattr != "userPassword || krbPrincipalKey || krbMKey || sambaLMPassword || sambaNTPassword")(version 3.0; acl "Admin can manage any entry except for passwords"; allow (all) userdn = "ldap:///uid=admin,cn=sysaccounts,cn=etc,$SUFFIX";)
-aci: (targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword")(version 3.0; acl "Admin can write passwords"; allow (write) userdn="ldap:///uid=admin,cn=sysaccounts,cn=etc,$SUFFIX";)
-aci: (targetattr = "krbPrincipalName || krbUPEnabled || krbPrincipalKey || krbMKey || krbTicketPolicyReference || krbPrincipalExpiration || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData")(version 3.0; acl "KDC System Account has access to kerberos material"; allow (read, search, compare) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";)
-aci: (targetattr = "krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount")(version 3.0; acl "KDC System Account can update some fields"; allow (read, search, compare, write) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";)
-aci: (targetattr = "userPassword || krbPrincipalKey ||sambaLMPassword || sambaNTPassword || krbPasswordExpiration || krbPwdHistory || krbLastPwdChange")(version 3.0; acl "Kpasswd access to passowrd hashes for passowrd changes"; allow (read, write) userdn = "ldap:///krbprincipalname=kadmin/changepw@$REALM,cn=$REALM,cn=kerberos,$SUFFIX";)
-aci: (targetfilter = "(|(objectClass=person)(objectClass=krbPrincipalAux)(objectClass=posixAccount)(objectClass=groupOfNames)(objectClass=posixGroup)(objectClass=radiusprofile))")(targetattr != "aci")(version 3.0; acl "Account Admins can manage Users and Groups"; allow (add, delete, read, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)
+aci: (targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMkey")(version 3.0; acl "Enable Anonymous access"; allow (read, search, compare) userdn = "ldap:///anyone";)
+aci: (targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMkey")(version 3.0; acl "Admin can manage any entry"; allow (all) userdn = "ldap:///uid=admin,cn=sysaccounts,cn=etc,$SUFFIX";)
+aci: (targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Admins can write passwords"; allow (write) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)
+aci: (targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Password change service can read/write passwords"; allow (read, write) userdn="ldap:///krbprincipalname=kadmin/changepw@$REALM,cn=$REALM,cn=kerberos,$SUFFIX";)
+aci: (targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "KDC System Account can access passwords"; allow (all) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";)
+aci: (targetattr = "krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount")(version 3.0; acl "KDC System Account can update some fields"; allow (write) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";)
+aci: (targetattr = "krbPrincipalName || krbUPEnabled || krbMKey || krbTicketPolicyReference || krbPrincipalExpiration || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData || krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount")(version 3.0; acl "Only the KDC System Account has access to kerberos material"; allow (read, search, compare) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";)
+aci: (targetfilter = "(|(objectClass=person)(objectClass=krbPrincipalAux)(objectClass=posixAccount)(objectClass=groupOfNames)(objectClass=posixGroup))")(targetattr != "aci || userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Account Admins can manage Users and Groups"; allow (add, delete, read, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)
aci: (targetfilter = "(objectClass=krbPwdPolicy)")(targetattr = "krbMaxPwdLife || krbMinPwdLife || krbPwdMinDiffChars || krbPwdMinLength || krbPwdHistoryLength")(version 3.0;acl "Admins can write password policies"; allow (read, search, compare, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)
-aci: (targetattr = "givenName || sn || cn || displayName || initials || loginShell || homePhone || mobile || pager || facsimileTelephoneNumber || telephoneNumber || street || roomNumber || l || st || postalCode || manager || description || carLicense || labeledURI || inetUserHTTPURL || seeAlso")(version 3.0;acl "Self service";allow (write) userdn = "ldap:///self";)
-aci: (target="ldap:///cn=radius,$SUFFIX")(version 3.0; acl "Only radius and admin can access radius service data"; deny (all) userdn!="ldap:///uid=admin,cn=sysaccounts,cn=etc,$SUFFIX || ldap:///krbprincipalname=radius/$FQDN@$REALM,cn=$REALM,cn=kerberos,$SUFFIX";)
+aci: (targetattr = "givenName || sn || cn || displayName || title || initials || loginShell || gecos || homePhone || mobile || pager || facsimileTelephoneNumber || telephoneNumber || street || roomNumber || l || st || postalCode || manager || secretary || description || carLicense || labeledURI || inetUserHTTPURL || seeAlso || employeeType || businessCategory || ou")(version 3.0;acl "Self service";allow (write) userdn = "ldap:///self";)
dn: cn=ipaConfig,cn=etc,$SUFFIX
changetype: modify
@@ -25,6 +25,12 @@ add: aci
aci: (targetattr = "krbMaxPwdLife || krbMinPwdLife || krbPwdMinDiffChars || krbPwdMinLength || krbPwdHistoryLength")(version 3.0;acl "Admins can write password policy"; allow (write) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)
aci: (targetattr = "aci")(version 3.0;acl "Admins can manage delegations"; allow (write, delete) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)
+dn: cn=radius,$SUFFIX
+changetype: modify
+add: aci
+aci: (targetattr = "*")(version 3.0; acl "Only radius and admin can access radius service data"; deny (all) userdn!="ldap:///uid=admin,cn=sysaccounts,cn=etc,$SUFFIX || ldap:///krbprincipalname=radius/$FQDN@$REALM,cn=$REALM,cn=kerberos,$SUFFIX";)
+aci: (targetfilter = "(objectClass=radiusprofile)")(targetattr != "aci || userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Account Admins can manage Users and Groups"; allow (add, delete, read, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)
+
dn: cn=services,cn=accounts,$SUFFIX
changetype: modify
add: aci
diff --git a/ipa-server/ipa-install/share/preferences.html.template b/ipa-server/ipa-install/share/preferences.html.template
new file mode 100644
index 000000000..2d3684dcd
--- /dev/null
+++ b/ipa-server/ipa-install/share/preferences.html.template
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <title>Automatically set browser preferences</title>
+</head>
+<body>
+<form action="undefined" method="get">
+<input type=button onclick="setPreferences()" name="prefs" value="Configure Firefox">
+</form>
+
+<script type="text/javascript">
+function setPreferences() {
+ try {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalPreferencesWrite");
+ try {
+ navigator.preference("network.negotiate-auth.using-native-gsslib", true)
+ navigator.preference("network.negotiate-auth.delegation-uris", ".$DOMAIN")
+ navigator.preference("network.negotiate-auth.trusted-uris", ".$DOMAIN")
+ navigator.preference("network.negotiate-auth.allow-proxies", true)
+ } catch (e) {
+ alert("Unable to store preferences: " + e)
+ }
+ netscape.security.PrivilegeManager.disablePrivilege("UniversalPreferencesWrite");
+ alert("Successfully configured Firefox for single sign on.")
+ } catch (e) {
+ alert("Unable to apply recommended settings.\n\nClick on the Certificate Authority link and select trust for all, then reload this page and try again.\n\nThe error returned was: " + e);
+ return;
+ }
+}
+</script>
+
+</body>
+</html>
diff --git a/ipa-server/ipa-install/share/referint-conf.ldif b/ipa-server/ipa-install/share/referint-conf.ldif
index 7a547ba50..533b97ded 100644
--- a/ipa-server/ipa-install/share/referint-conf.ldif
+++ b/ipa-server/ipa-install/share/referint-conf.ldif
@@ -2,6 +2,10 @@ dn: cn=referential integrity postoperation,cn=plugins,cn=config
changetype: modify
replace: nsslapd-pluginenabled
nsslapd-pluginenabled: on
+-
+add: nsslapd-pluginArg7
nsslapd-pluginArg7: manager
+-
+add: nsslapd-pluginArg8
nsslapd-pluginArg8: secretary
diff --git a/ipa-server/ipa-kpasswd/ipa_kpasswd.c b/ipa-server/ipa-kpasswd/ipa_kpasswd.c
index 99dfe678f..ccd17c1f0 100644
--- a/ipa-server/ipa-kpasswd/ipa_kpasswd.c
+++ b/ipa-server/ipa-kpasswd/ipa_kpasswd.c
@@ -306,7 +306,7 @@ int ldap_pwd_change(char *client_name, char *realm_name, krb5_data pwd, char **e
LDAPControl **srvctrl = NULL;
char *exterr1 = NULL;
char *exterr2 = NULL;
- char *err;
+ char *err = NULL;
int msgid;
int ret, rc;
diff --git a/ipa-server/ipa-server.spec b/ipa-server/ipa-server.spec
index f84affe86..38725cf34 100755
--- a/ipa-server/ipa-server.spec
+++ b/ipa-server/ipa-server.spec
@@ -37,7 +37,6 @@ Requires: python-krbV
Requires: TurboGears
Requires: python-tgexpandingformwidget
Requires: acl
-Requires: freeradius
Requires: pyasn1
Requires: libcap
@@ -69,12 +68,32 @@ rm %{buildroot}/%{plugin_dir}/libipa-dna-plugin.la
%clean
rm -rf %{buildroot}
+%post
+if [ $1 = 1 ]; then
+ /sbin/chkconfig --add ipa-kpasswd
+ /sbin/chkconfig --add ipa-webgui
+fi
+
+%preun
+if [ $1 = 0 ]; then
+ /sbin/chkconfig --del ipa-kpasswd
+ /sbin/chkconfig --del ipa-webgui
+ /sbin/service ipa-kpasswd stop >/dev/null 2>&1 || :
+ /sbin/service ipa-webgui stop >/dev/null 2>&1 || :
+fi
+
+%postun
+if [ "$1" -ge "1" ]; then
+ /sbin/service ipa-kpasswd condrestart >/dev/null 2>&1 || :
+ /sbin/service ipa-webgui condrestart >/dev/null 2>&1 || :
+fi
%files
%defattr(-,root,root,-)
%{_sbindir}/ipa-server-install
%{_sbindir}/ipa-replica-install
%{_sbindir}/ipa-replica-prepare
+%{_sbindir}/ipa-server-certinstall
%{_sbindir}/ipa_kpasswd
%{_sbindir}/ipa-webgui
%attr(4750,root,apache) %{_sbindir}/ipa-keytab-util
diff --git a/ipa-server/ipa-server.spec.in b/ipa-server/ipa-server.spec.in
index 874d82cfd..e43f07aa2 100644
--- a/ipa-server/ipa-server.spec.in
+++ b/ipa-server/ipa-server.spec.in
@@ -37,7 +37,6 @@ Requires: python-krbV
Requires: TurboGears
Requires: python-tgexpandingformwidget
Requires: acl
-Requires: freeradius
Requires: pyasn1
Requires: libcap
@@ -69,12 +68,32 @@ rm %{buildroot}/%{plugin_dir}/libipa-dna-plugin.la
%clean
rm -rf %{buildroot}
+%post
+if [ $1 = 1 ]; then
+ /sbin/chkconfig --add ipa-kpasswd
+ /sbin/chkconfig --add ipa-webgui
+fi
+
+%preun
+if [ $1 = 0 ]; then
+ /sbin/chkconfig --del ipa-kpasswd
+ /sbin/chkconfig --del ipa-webgui
+ /sbin/service ipa-kpasswd stop >/dev/null 2>&1 || :
+ /sbin/service ipa-webgui stop >/dev/null 2>&1 || :
+fi
+
+%postun
+if [ "$1" -ge "1" ]; then
+ /sbin/service ipa-kpasswd condrestart >/dev/null 2>&1 || :
+ /sbin/service ipa-webgui condrestart >/dev/null 2>&1 || :
+fi
%files
%defattr(-,root,root,-)
%{_sbindir}/ipa-server-install
%{_sbindir}/ipa-replica-install
%{_sbindir}/ipa-replica-prepare
+%{_sbindir}/ipa-server-certinstall
%{_sbindir}/ipa_kpasswd
%{_sbindir}/ipa-webgui
%attr(4750,root,apache) %{_sbindir}/ipa-keytab-util
diff --git a/ipa-server/ipaserver/Makefile.am b/ipa-server/ipaserver/Makefile.am
index f1c094b36..b1d00a80a 100644
--- a/ipa-server/ipaserver/Makefile.am
+++ b/ipa-server/ipaserver/Makefile.am
@@ -9,7 +9,6 @@ app_PYTHON = \
krbinstance.py \
httpinstance.py \
ntpinstance.py \
- radiusinstance.py \
webguiinstance.py \
service.py \
installutils.py \
diff --git a/ipa-server/ipaserver/bindinstance.py b/ipa-server/ipaserver/bindinstance.py
index 8a131fe79..cc99eacfa 100644
--- a/ipa-server/ipaserver/bindinstance.py
+++ b/ipa-server/ipaserver/bindinstance.py
@@ -23,10 +23,13 @@ import tempfile
import shutil
import os
import socket
-from ipa.ipautil import *
-class BindInstance:
+import service
+from ipa import ipautil
+
+class BindInstance(service.Service):
def __init__(self):
+ service.Service.__init__(self, "named")
self.fqdn = None
self.domain = None
self.host = None
@@ -52,7 +55,7 @@ class BindInstance:
return True
def create_sample_bind_zone(self):
- bind_txt = template_file(SHARE_DIR + "bind.zone.db.template", self.sub_dict)
+ 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)
@@ -73,15 +76,6 @@ class BindInstance:
except:
print "named service failed to start"
- def stop(self):
- run(["/sbin/service", "named", "stop"])
-
- def start(self):
- run(["/sbin/service", "named", "start"])
-
- def restart(self):
- run(["/sbin/service", "named", "restart"])
-
def __setup_sub_dict(self):
self.sub_dict = dict(FQDN=self.fqdn,
IP=self.ip_address,
@@ -90,7 +84,7 @@ class BindInstance:
REALM=self.realm)
def __setup_zone(self):
- zone_txt = template_file(SHARE_DIR + "bind.zone.db.template", self.sub_dict)
+ zone_txt = ipautil.template_file(ipautil.SHARE_DIR + "bind.zone.db.template", self.sub_dict)
zone_fd = open('/var/named/'+self.domain+'.zone.db', 'w')
zone_fd.write(zone_txt)
zone_fd.close()
@@ -98,7 +92,7 @@ class BindInstance:
def __setup_named_conf(self):
if os.path.exists('/etc/named.conf'):
shutil.copy2('/etc/named.conf', '/etc/named.conf.ipabkp')
- named_txt = template_file(SHARE_DIR + "bind.named.conf.template", self.sub_dict)
+ 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)
diff --git a/ipa-server/ipaserver/certs.py b/ipa-server/ipaserver/certs.py
index fb6b01d0e..eecfdf21c 100644
--- a/ipa-server/ipaserver/certs.py
+++ b/ipa-server/ipaserver/certs.py
@@ -17,7 +17,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
-import os, stat, subprocess
+import os, stat, subprocess, re
import sha
from ipa import ipautil
@@ -77,6 +77,11 @@ class CertDB(object):
new_args = new_args + args
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")
@@ -108,7 +113,7 @@ class CertDB(object):
self.run_certutil(["-S", "-n", self.cacert_name,
"-s", "cn=CAcert",
"-x",
- "-t", "CT,,",
+ "-t", "CT,,C",
"-m", self.next_serial(),
"-v", self.valid_months,
"-z", self.noise_fname,
@@ -130,7 +135,7 @@ class CertDB(object):
def load_cacert(self, cacert_fname):
self.run_certutil(["-A", "-n", self.cacert_name,
- "-t", "CT,CT,",
+ "-t", "CT,,C",
"-a",
"-i", cacert_fname])
@@ -139,7 +144,17 @@ class CertDB(object):
if not cdb:
cdb = self
self.request_cert(name)
- cdb.issue_cert(self.certreq_fname, self.certder_fname)
+ 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)
@@ -151,7 +166,7 @@ class CertDB(object):
"-z", self.noise_fname,
"-f", self.passwd_fname])
- def issue_cert(self, certreq_fname, cert_fname):
+ def issue_server_cert(self, certreq_fname, cert_fname):
p = subprocess.Popen(["/usr/bin/certutil",
"-d", self.secdir,
"-C", "-c", self.cacert_name,
@@ -179,8 +194,37 @@ class CertDB(object):
# 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",
@@ -196,6 +240,50 @@ class CertDB(object):
f.close()
self.set_perms(self.pin_fname)
+ def trust_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]
+
+ 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])
+ server_certs.append((name, flags))
+
+ return server_certs
+
+
+ def import_pkcs12(self, pkcs12_fname):
+ try:
+ ipautil.run(["/usr/bin/pk12util", "-d", self.secdir,
+ "-i", pkcs12_fname])
+ except ipautil.CalledProcessError, e:
+ if e.returncode == 17:
+ raise RuntimeError("incorrect password")
+ else:
+ raise RuntimeError("unknown error import pkcs#12 file")
+
def create_self_signed(self, passwd=True):
self.create_noise_file()
self.create_passwd_file(passwd)
@@ -208,6 +296,3 @@ class CertDB(object):
self.create_passwd_file(passwd)
self.create_certdbs()
self.load_cacert(cacert_fname)
-
-
-
diff --git a/ipa-server/ipaserver/dsinstance.py b/ipa-server/ipaserver/dsinstance.py
index 5edc3879e..6cbffcb84 100644
--- a/ipa-server/ipaserver/dsinstance.py
+++ b/ipa-server/ipaserver/dsinstance.py
@@ -35,10 +35,6 @@ import ipaldap, ldap
SERVER_ROOT_64 = "/usr/lib64/dirsrv"
SERVER_ROOT_32 = "/usr/lib/dirsrv"
-def ldap_mod(fd, dn, pwd):
- args = ["/usr/bin/ldapmodify", "-h", "127.0.0.1", "-xv", "-D", dn, "-w", pwd, "-f", fd.name]
- ipautil.run(args)
-
def realm_to_suffix(realm_name):
s = realm_name.split(".")
terms = ["dc=" + x.lower() for x in s]
@@ -139,38 +135,29 @@ class DsInstance(service.Service):
self.domain = host_name[host_name.find(".")+1:]
self.__setup_sub_dict()
- if ro_replica:
- self.start_creation(15, "Configuring directory server:")
- else:
- self.start_creation(15, "Configuring directory server:")
-
- self.__create_ds_user()
- self.__create_instance()
- self.__add_default_schemas()
+ 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)
if not ro_replica:
- self.__add_memberof_module()
- self.__add_referint_module()
- self.__add_dna_module()
- self.__create_indeces()
- self.__enable_ssl()
- self.__certmap_conf()
- try:
- self.step("restarting directory server")
- self.restart()
- except:
- # TODO: roll back here?
- logging.critical("Failed to restart the ds instance")
- self.__add_default_layout()
+ 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("creating indeces", self.__create_indeces)
+ 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)
if not ro_replica:
- self.__config_uidgid_gen_first_master()
- self.__add_master_entry_first_master()
- self.__init_memberof()
-
+ 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 directoy to start on boot")
- self.chkconfig_on()
+ self.step("configuring directory to start on boot", self.chkconfig_on)
- self.done_creation()
+ self.start_creation("Configuring directory server:")
def __setup_sub_dict(self):
server_root = find_server_root()
@@ -180,7 +167,6 @@ class DsInstance(service.Service):
SERVER_ROOT=server_root, DOMAIN=self.domain)
def __create_ds_user(self):
- self.step("creating directory server user")
try:
pwd.getpwnam(self.ds_user)
logging.debug("ds user %s exists" % self.ds_user)
@@ -194,7 +180,6 @@ class DsInstance(service.Service):
logging.critical("failed to add user %s" % e)
def __create_instance(self):
- self.step("creating directory server instance")
inf_txt = ipautil.template_str(INF_TEMPLATE, self.sub_dict)
logging.debug(inf_txt)
inf_fd = ipautil.write_tmp_file(inf_txt)
@@ -219,7 +204,6 @@ class DsInstance(service.Service):
logging.debug("failed to restart ds instance %s" % e)
def __add_default_schemas(self):
- self.step("adding default schema")
shutil.copyfile(ipautil.SHARE_DIR + "60kerberos.ldif",
schema_dirname(self.realm_name) + "60kerberos.ldif")
shutil.copyfile(ipautil.SHARE_DIR + "60samba.ldif",
@@ -229,68 +213,52 @@ class DsInstance(service.Service):
shutil.copyfile(ipautil.SHARE_DIR + "60ipaconfig.ldif",
schema_dirname(self.realm_name) + "60ipaconfig.ldif")
- def __add_memberof_module(self):
- self.step("enabling memboerof plugin")
- memberof_txt = ipautil.template_file(ipautil.SHARE_DIR + "memberof-conf.ldif", self.sub_dict)
- memberof_fd = ipautil.write_tmp_file(memberof_txt)
+ def __restart_instance(self):
try:
- ldap_mod(memberof_fd, "cn=Directory Manager", self.dm_password)
- except ipautil.CalledProcessError, e:
- logging.critical("Failed to load memberof-conf.ldif: %s" % str(e))
- memberof_fd.close()
+ self.restart()
+ except:
+ # TODO: roll back here?
+ logging.critical("Failed to restart the ds instance")
+
+ 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
+
+ args = ["/usr/bin/ldapmodify", "-h", "127.0.0.1", "-xv",
+ "-D", "cn=Directory Manager", "-w", self.dm_password, "-f", path]
- def __init_memberof(self):
- self.step("initializing group membership")
- memberof_txt = ipautil.template_file(ipautil.SHARE_DIR + "memberof-task.ldif", self.sub_dict)
- memberof_fd = ipautil.write_tmp_file(memberof_txt)
try:
- ldap_mod(memberof_fd, "cn=Directory Manager", self.dm_password)
+ ipautil.run(args)
except ipautil.CalledProcessError, e:
- logging.critical("Failed to load memberof-conf.ldif: %s" % str(e))
- memberof_fd.close()
+ logging.critical("Failed to load %s: %s" % (ldif, str(e)))
+
+ 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 __add_referint_module(self):
- self.step("enabling referential integrity plugin")
- referint_txt = ipautil.template_file(ipautil.SHARE_DIR + "referint-conf.ldif", self.sub_dict)
- referint_fd = ipautil.write_tmp_file(referint_txt)
- try:
- ldap_mod(referint_fd, "cn=Directory Manager", self.dm_password)
- except ipautil.CalledProcessError, e:
- print "Failed to load referint-conf.ldif", e
- referint_fd.close()
+ self.__ldap_mod("referint-conf.ldif")
def __add_dna_module(self):
- self.step("enabling distributed numeric assignment plugin")
- dna_txt = ipautil.template_file(ipautil.SHARE_DIR + "dna-conf.ldif", self.sub_dict)
- dna_fd = ipautil.write_tmp_file(dna_txt)
- try:
- ldap_mod(dna_fd, "cn=Directory Manager", self.dm_password)
- except ipautil.CalledProcessError, e:
- print "Failed to load dna-conf.ldif", e
- dna_fd.close()
+ self.__ldap_mod("dna-conf.ldif")
def __config_uidgid_gen_first_master(self):
- self.step("configuring Posix uid/gid generation as first master")
- dna_txt = ipautil.template_file(ipautil.SHARE_DIR + "dna-posix.ldif", self.sub_dict)
- dna_fd = ipautil.write_tmp_file(dna_txt)
- try:
- ldap_mod(dna_fd, "cn=Directory Manager", self.dm_password)
- except ipautil.CalledProcessError, e:
- print "Failed to configure Posix uid/gid generation with dna-posix.ldif", e
- dna_fd.close()
+ self.__ldap_mod("dna-posix.ldif", self.sub_dict)
def __add_master_entry_first_master(self):
- self.step("adding master entry as first master")
- master_txt = ipautil.template_file(ipautil.SHARE_DIR + "master-entry.ldif", self.sub_dict)
- master_fd = ipautil.write_tmp_file(master_txt)
- try:
- ldap_mod(master_fd, "cn=Directory Manager", self.dm_password)
- except ipautil.CalledProcessError, e:
- print "Failed to add master-entry.ldif", e
- master_fd.close()
+ self.__ldap_mod("master-entry.ldif", self.sub_dict)
def __enable_ssl(self):
- self.step("configuring ssl for ds instance")
dirname = config_dirname(self.realm_name)
ca = certs.CertDB(dirname)
ca.create_self_signed()
@@ -322,41 +290,16 @@ class DsInstance(service.Service):
conn.addEntry(entry)
conn.unbind()
-
+
def __add_default_layout(self):
- self.step("adding default layout")
- txt = ipautil.template_file(ipautil.SHARE_DIR + "bootstrap-template.ldif", self.sub_dict)
- inf_fd = ipautil.write_tmp_file(txt)
- logging.debug("adding default dfrom ipa.ipautil import *s layout")
- args = ["/usr/bin/ldapmodify", "-xv", "-D", "cn=Directory Manager",
- "-w", self.dm_password, "-f", inf_fd.name]
- try:
- ipautil.run(args)
- logging.debug("done adding default ds layout")
- except ipautil.CalledProcessError, e:
- print "Failed to add default ds layout", e
- logging.critical("Failed to add default ds layout %s" % e)
+ self.__ldap_mod("bootstrap-template.ldif", self.sub_dict)
def __create_indeces(self):
- self.step("creating indeces")
- txt = ipautil.template_file(ipautil.SHARE_DIR + "indeces.ldif", self.sub_dict)
- inf_fd = ipautil.write_tmp_file(txt)
- logging.debug("adding/updating indeces")
- args = ["/usr/bin/ldapmodify", "-xv", "-D", "cn=Directory Manager",
- "-w", self.dm_password, "-f", inf_fd.name]
- try:
- ipautil.run(args)
- logging.debug("done adding/updating indeces")
- except ipautil.CalledProcessError, e:
- logging.critical("Failed to add/update indeces %s" % str(e))
+ self.__ldap_mod("indeces.ldif")
def __certmap_conf(self):
- self.step("configuring certmap.conf")
- dirname = config_dirname(self.realm_name)
- certmap_conf = ipautil.template_file(ipautil.SHARE_DIR + "certmap.conf.template", self.sub_dict)
- certmap_fd = open(dirname+"certmap.conf", "w+")
- certmap_fd.write(certmap_conf)
- certmap_fd.close()
+ shutil.copyfile(ipautil.SHARE_DIR + "certmap.conf.template",
+ config_dirname(self.realm_name) + "certmap.conf")
def change_admin_password(self, password):
logging.debug("Changing admin password")
diff --git a/ipa-server/ipaserver/httpinstance.py b/ipa-server/ipaserver/httpinstance.py
index 1799cca07..d0329ccad 100644
--- a/ipa-server/ipaserver/httpinstance.py
+++ b/ipa-server/ipaserver/httpinstance.py
@@ -17,6 +17,8 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
+import os
+import os.path
import subprocess
import string
import tempfile
@@ -25,11 +27,13 @@ import pwd
import fileinput
import sys
import time
+import shutil
import service
import certs
import dsinstance
-from ipa.ipautil import *
+import installutils
+from ipa import ipautil
HTTPD_DIR = "/etc/httpd"
SSL_CONF = HTTPD_DIR + "/conf.d/ssl.conf"
@@ -43,52 +47,33 @@ successfully change with the command:
Try updating the policycoreutils and selinux-policy packages.
"""
-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
-
class HTTPInstance(service.Service):
def __init__(self):
service.Service.__init__(self, "httpd")
def create_instance(self, realm, fqdn):
- self.sub_dict = { "REALM" : realm, "FQDN": fqdn }
self.fqdn = fqdn
self.realm = realm
+ self.domain = fqdn[fqdn.find(".")+1:]
+ self.sub_dict = { "REALM" : realm, "FQDN": fqdn, "DOMAIN" : self.domain }
- self.start_creation(7, "Configuring the web interface")
-
- self.__disable_mod_ssl()
- self.__set_mod_nss_port()
- self.__configure_http()
- self.__create_http_keytab()
- self.__setup_ssl()
-
- self.step("restarting httpd")
- self.restart()
-
- self.step("configuring httpd to start on boot")
- self.chkconfig_on()
-
- self.done_creation()
+ 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("configuring httpd", self.__configure_http)
+ self.step("creating a keytab for httpd", self.__create_http_keytab)
+ self.step("Setting up ssl", self.__setup_ssl)
+ self.step("Setting up browser autoconfig", self.__setup_autoconfig)
+ self.step("configuring SELinux for httpd", self.__selinux_config)
+ self.step("restarting httpd", self.restart)
+ self.step("configuring httpd to start on boot", self.chkconfig_on)
+
+ self.start_creation("Configuring the web interface")
def __selinux_config(self):
- self.step("configuring SELinux for httpd")
selinux=0
try:
if (os.path.exists('/usr/sbin/selinuxenabled')):
- run(["/usr/sbin/selinuxenabled"])
+ ipautil.run(["/usr/sbin/selinuxenabled"])
selinux=1
except ipautil.CalledProcessError:
# selinuxenabled returns 1 if not enabled
@@ -98,14 +83,13 @@ class HTTPInstance(service.Service):
# Allow apache to connect to the turbogears web gui
# This can still fail even if selinux is enabled
try:
- run(["/usr/sbin/setsebool", "-P", "httpd_can_network_connect", "true"])
+ ipautil.run(["/usr/sbin/setsebool", "-P", "httpd_can_network_connect", "true"])
except:
self.print_msg(selinux_warning)
def __create_http_keytab(self):
- self.step("creating a keytab for httpd")
try:
- if file_exists("/etc/httpd/conf/ipa.keytab"):
+ if ipautil.file_exists("/etc/httpd/conf/ipa.keytab"):
os.remove("/etc/httpd/conf/ipa.keytab")
except os.error:
print "Failed to remove /etc/httpd/conf/ipa.keytab."
@@ -120,7 +104,7 @@ class HTTPInstance(service.Service):
# give kadmin time to actually write the file before we go on
retry = 0
- while not file_exists("/etc/httpd/conf/ipa.keytab"):
+ while not ipautil.file_exists("/etc/httpd/conf/ipa.keytab"):
time.sleep(1)
retry += 1
if retry > 15:
@@ -131,28 +115,51 @@ class HTTPInstance(service.Service):
os.chown("/etc/httpd/conf/ipa.keytab", pent.pw_uid, pent.pw_gid)
def __configure_http(self):
- self.step("configuring httpd")
- http_txt = template_file(SHARE_DIR + "ipa.conf", self.sub_dict)
+ http_txt = ipautil.template_file(ipautil.SHARE_DIR + "ipa.conf", self.sub_dict)
http_fd = open("/etc/httpd/conf.d/ipa.conf", "w")
http_fd.write(http_txt)
http_fd.close()
def __disable_mod_ssl(self):
- self.step("disabling mod_ssl in httpd")
if os.path.exists(SSL_CONF):
os.rename(SSL_CONF, "%s.moved_by_ipa" % SSL_CONF)
def __set_mod_nss_port(self):
- self.step("Setting mod_nss port to 443")
- if update_file(NSS_CONF, '8443', '443') != 0:
+ if installutils.update_file(NSS_CONF, '8443', '443') != 0:
print "Updating %s failed." % NSS_CONF
def __setup_ssl(self):
- self.step("Setting up ssl")
ds_ca = certs.CertDB(dsinstance.config_dirname(self.realm))
ca = certs.CertDB(NSS_DIR)
ds_ca.cur_serial = 2000
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)
+
+ 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(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)
+
+ try:
+ shutil.rmtree("/tmp/ipa")
+ except:
+ pass
+ os.mkdir("/tmp/ipa")
+ shutil.copy("/usr/share/ipa/html/preferences.html", "/tmp/ipa")
+
+ ca.run_signtool(["-k", "Signing-Cert",
+ "-Z", "/usr/share/ipa/html/configure.jar",
+ "-e", ".html",
+ "/tmp/ipa"])
+ shutil.rmtree("/tmp/ipa")
diff --git a/ipa-server/ipaserver/installutils.py b/ipa-server/ipaserver/installutils.py
index a403e8154..25cd1555c 100644
--- a/ipa-server/ipaserver/installutils.py
+++ b/ipa-server/ipaserver/installutils.py
@@ -21,6 +21,10 @@ import logging
import socket
import errno
import getpass
+import os
+import re
+import fileinput
+import sys
def get_fqdn():
fqdn = ""
@@ -105,4 +109,19 @@ def read_password(user):
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
+
diff --git a/ipa-server/ipaserver/krbinstance.py b/ipa-server/ipaserver/krbinstance.py
index 76818af7d..2f4454bad 100644
--- a/ipa-server/ipaserver/krbinstance.py
+++ b/ipa-server/ipaserver/krbinstance.py
@@ -33,6 +33,7 @@ import time
import shutil
import service
+from ipa import ipautil
from ipa import ipaerror
import ipaldap
@@ -46,18 +47,21 @@ import pyasn1.codec.ber.encoder
import pyasn1.codec.ber.decoder
import struct
import base64
-from ipa.ipautil import *
def host_to_domain(fqdn):
s = fqdn.split(".")
return ".".join(s[1:])
-def ldap_mod(fd, dn, pwd):
- args = ["/usr/bin/ldapmodify", "-h", "127.0.0.1", "-xv", "-D", dn, "-w", pwd, "-f", fd.name]
- run(args)
-
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):
@@ -89,8 +93,8 @@ class KrbInstance(service.Service):
self.host = host_name.split(".")[0]
self.ip = socket.gethostbyname(host_name)
self.domain = host_to_domain(host_name)
- self.suffix = realm_to_suffix(self.realm)
- self.kdc_password = ipa_generate_password()
+ self.suffix = ipautil.realm_to_suffix(self.realm)
+ self.kdc_password = ipautil.ipa_generate_password()
self.admin_password = admin_password
self.__setup_sub_dict()
@@ -110,58 +114,44 @@ class KrbInstance(service.Service):
pass
def __common_post_setup(self):
- try:
- self.step("starting the KDC")
- self.start()
- except:
- logging.critical("krb5kdc service failed to start")
-
- self.step("configuring KDC to start on boot")
- self.chkconfig_on()
-
- self.step("configuring ipa-kpasswd to start on boot")
- service.chkconfig_on("ipa-kpasswd")
-
- self.step("starting ipa-kpasswd")
- service.start("ipa-kpasswd")
-
+ self.step("starting the KDC", self.__start_instance)
+ self.step("configuring KDC to start on boot", self.chkconfig_on)
+ self.step("enabling and starting ipa-kpasswd", self.__enable_kpasswd)
def create_instance(self, ds_user, realm_name, host_name, admin_password, master_password):
self.master_password = master_password
self.__common_setup(ds_user, realm_name, host_name, admin_password)
- self.start_creation(11, "Configuring Kerberos KDC")
-
- self.__configure_kdc_account_password()
- self.__configure_sasl_mappings()
- self.__add_krb_entries()
- self.__create_instance()
- self.__create_ds_keytab()
- self.__export_kadmin_changepw_keytab()
- self.__add_pwd_extop_module()
+ 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 defalt ACIs", self.__add_default_acis)
+ self.step("configuring KDC", self.__create_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("exporting the kadmin keytab", self.__export_kadmin_changepw_keytab)
+ self.step("adding the password extenstion to the directory", self.__add_pwd_extop_module)
self.__common_post_setup()
- self.done_creation()
-
+ self.start_creation("Configuring Kerberos KDC")
def create_replica(self, ds_user, realm_name, host_name, admin_password, ldap_passwd_filename):
-
+ self.__copy_ldap_passwd(ldap_passwd_filename)
+
self.__common_setup(ds_user, realm_name, host_name, admin_password)
- self.start_creation(9, "Configuring Kerberos KDC")
- self.__copy_ldap_passwd(ldap_passwd_filename)
- self.__configure_sasl_mappings()
- self.__write_stash_from_ds()
- self.__create_instance(replica=True)
- self.__create_ds_keytab()
- self.__export_kadmin_changepw_keytab()
+ 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("exporting the kadmin keytab", self.__export_kadmin_changepw_keytab)
self.__common_post_setup()
- self.done_creation()
-
+ self.start_creation("Configuring Kerberos KDC")
def __copy_ldap_passwd(self, filename):
shutil.copy(filename, "/var/kerberos/krb5kdc/ldappwd")
@@ -169,7 +159,6 @@ class KrbInstance(service.Service):
def __configure_kdc_account_password(self):
- self.step("setting KDC account password")
hexpwd = ''
for x in self.kdc_password:
hexpwd += (hex(ord(x))[2:])
@@ -178,6 +167,16 @@ class KrbInstance(service.Service):
pwd_fd.close()
os.chmod("/var/kerberos/krb5kdc/ldappwd", 0600)
+ def __start_instance(self):
+ try:
+ self.start()
+ except:
+ logging.critical("krb5kdc service failed to start")
+
+ def __enable_kpasswd(self):
+ service.chkconfig_on("ipa-kpasswd")
+ service.start("ipa-kpasswd")
+
def __setup_sub_dict(self):
self.sub_dict = dict(FQDN=self.fqdn,
IP=self.ip,
@@ -187,8 +186,21 @@ class KrbInstance(service.Service):
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)
+
+ args = ["/usr/bin/ldapmodify", "-h", "127.0.0.1", "-xv",
+ "-D", "cn=Directory Manager", "-w", self.admin_password, "-f", fd.name]
+
+ try:
+ ipautil.run(args)
+ except ipautil.CalledProcessError, e:
+ logging.critical("Failed to load %s: %s" % (ldif, str(e)))
+
+ fd.close()
+
def __configure_sasl_mappings(self):
- self.step("adding sasl mappings to the directory")
# 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.
@@ -238,50 +250,38 @@ class KrbInstance(service.Service):
raise e
def __add_krb_entries(self):
- self.step("adding kerberos entries to the DS")
-
- #TODO: test that the ldif is ok with any random charcter we may use in the password
- kerberos_txt = template_file(SHARE_DIR + "kerberos.ldif", self.sub_dict)
- kerberos_fd = write_tmp_file(kerberos_txt)
- try:
- ldap_mod(kerberos_fd, "cn=Directory Manager", self.admin_password)
- except ipautil.CalledProcessError, e:
- logging.critical("Failed to load kerberos.ldif: %s" % str(e))
- kerberos_fd.close()
+ self.__ldap_mod("kerberos.ldif")
+ def __add_default_acis(self):
#Change the default ACL to avoid anonimous access to kerberos keys and othe hashes
- aci_txt = template_file(SHARE_DIR + "default-aci.ldif", self.sub_dict)
- aci_fd = write_tmp_file(aci_txt)
- try:
- ldap_mod(aci_fd, "cn=Directory Manager", self.admin_password)
- except ipautil.CalledProcessError, e:
- logging.critical("Failed to load default-aci.ldif: %s" % str(e))
- aci_fd.close()
+ self.__ldap_mod("default-aci.ldif")
+
+ def __create_replica_instance(self):
+ self.__create_instance(replace=True)
def __create_instance(self, replica=False):
- self.step("configuring KDC")
- kdc_conf = template_file(SHARE_DIR+"kdc.conf.template", self.sub_dict)
+ kdc_conf = ipautil.template_file(ipautil.SHARE_DIR+"kdc.conf.template", self.sub_dict)
kdc_fd = open("/var/kerberos/krb5kdc/kdc.conf", "w+")
kdc_fd.write(kdc_conf)
kdc_fd.close()
- krb5_conf = template_file(SHARE_DIR+"krb5.conf.template", self.sub_dict)
+ krb5_conf = ipautil.template_file(ipautil.SHARE_DIR+"krb5.conf.template", self.sub_dict)
krb5_fd = open("/etc/krb5.conf", "w+")
krb5_fd.write(krb5_conf)
krb5_fd.close()
# Windows configuration files
- krb5_ini = template_file(SHARE_DIR+"krb5.ini.template", self.sub_dict)
+ krb5_ini = ipautil.template_file(ipautil.SHARE_DIR+"krb5.ini.template", self.sub_dict)
krb5_fd = open("/usr/share/ipa/html/krb5.ini", "w+")
krb5_fd.write(krb5_ini)
krb5_fd.close()
- krb_con = template_file(SHARE_DIR+"krb.con.template", self.sub_dict)
+ krb_con = ipautil.template_file(ipautil.SHARE_DIR+"krb.con.template", self.sub_dict)
krb_fd = open("/usr/share/ipa/html/krb.con", "w+")
krb_fd.write(krb_con)
krb_fd.close()
- krb_realm = template_file(SHARE_DIR+"krbrealm.con.template", self.sub_dict)
+ krb_realm = ipautil.template_file(ipautil.SHARE_DIR+"krbrealm.con.template", self.sub_dict)
krb_fd = open("/usr/share/ipa/html/krbrealm.con", "w+")
krb_fd.write(krb_realm)
krb_fd.close()
@@ -290,12 +290,11 @@ class KrbInstance(service.Service):
#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:
- run(args)
+ ipautil.run(args)
except ipautil.CalledProcessError, e:
print "Failed to populate the realm structure in kerberos", e
def __write_stash_from_ds(self):
- self.step("writing stash file from DS")
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:
@@ -317,14 +316,7 @@ class KrbInstance(service.Service):
#add the password extop module
def __add_pwd_extop_module(self):
- self.step("adding the password extenstion to the directory")
- extop_txt = template_file(SHARE_DIR + "pwd-extop-conf.ldif", self.sub_dict)
- extop_fd = write_tmp_file(extop_txt)
- try:
- ldap_mod(extop_fd, "cn=Directory Manager", self.admin_password)
- except ipautil.CalledProcessError, e:
- logging.critical("Failed to load pwd-extop-conf.ldif: %s" % str(e))
- extop_fd.close()
+ self.__ldap_mod("pwd-extop-conf.ldif")
#get the Master Key from the stash file
try:
@@ -353,9 +345,8 @@ class KrbInstance(service.Service):
raise e
def __create_ds_keytab(self):
- self.step("creating a keytab for the directory")
try:
- if file_exists("/etc/dirsrv/ds.keytab"):
+ if ipautil.file_exists("/etc/dirsrv/ds.keytab"):
os.remove("/etc/dirsrv/ds.keytab")
except os.error:
logging.critical("Failed to remove /etc/dirsrv/ds.keytab.")
@@ -370,7 +361,7 @@ class KrbInstance(service.Service):
# give kadmin time to actually write the file before we go on
retry = 0
- while not file_exists("/etc/dirsrv/ds.keytab"):
+ while not ipautil.file_exists("/etc/dirsrv/ds.keytab"):
time.sleep(1)
retry += 1
if retry > 15:
@@ -381,10 +372,37 @@ class KrbInstance(service.Service):
pent = pwd.getpwnam(self.ds_user)
os.chown("/etc/dirsrv/ds.keytab", pent.pw_uid, pent.pw_gid)
+ def __create_host_keytab(self):
+ try:
+ if ipautil.file_exists("/etc/krb5.keytab"):
+ os.remove("/etc/krb5.keytab")
+ except os.error:
+ logging.critical("Failed to remove /etc/krb5.keytab.")
+ (kwrite, kread, kerr) = os.popen3("/usr/kerberos/sbin/kadmin.local")
+ kwrite.write("addprinc -randkey host/"+self.fqdn+"@"+self.realm+"\n")
+ kwrite.flush()
+ kwrite.write("ktadd -k /etc/krb5.keytab host/"+self.fqdn+"@"+self.realm+"\n")
+ kwrite.flush()
+ kwrite.close()
+ kread.close()
+ kerr.close()
+
+ # give kadmin time to actually write the file before we go on
+ retry = 0
+ while not ipautil.file_exists("/etc/krb5.keytab"):
+ time.sleep(1)
+ retry += 1
+ if retry > 15:
+ logging.critical("Error timed out waiting for kadmin to finish operations")
+ sys.exit(1)
+
+ # 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):
- self.step("exporting the kadmin keytab")
try:
- if file_exists("/var/kerberos/krb5kdc/kpasswd.keytab"):
+ if ipautil.file_exists("/var/kerberos/krb5kdc/kpasswd.keytab"):
os.remove("/var/kerberos/krb5kdc/kpasswd.keytab")
except os.error:
logging.critical("Failed to remove /var/kerberos/krb5kdc/kpasswd.keytab.")
@@ -404,7 +422,7 @@ class KrbInstance(service.Service):
# give kadmin time to actually write the file before we go on
retry = 0
- while not file_exists("/var/kerberos/krb5kdc/kpasswd.keytab"):
+ while not ipautil.file_exists("/var/kerberos/krb5kdc/kpasswd.keytab"):
time.sleep(1)
retry += 1
if retry > 15:
diff --git a/ipa-server/ipaserver/ntpinstance.py b/ipa-server/ipaserver/ntpinstance.py
index 46841b0b2..b321ec075 100644
--- a/ipa-server/ipaserver/ntpinstance.py
+++ b/ipa-server/ipaserver/ntpinstance.py
@@ -17,28 +17,25 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
-from ipa.ipautil import *
import shutil
import service
+from ipa import ipautil
class NTPInstance(service.Service):
def __init__(self):
service.Service.__init__(self, "ntpd")
-
- def create_instance(self):
- self.start_creation(3, "Configuring ntpd")
- self.step("writing configuration")
+ 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 file_exists("/etc/fedora-release"):
+ if ipautil.file_exists("/etc/fedora-release"):
os = "fedora."
- elif file_exists("/etc/redhat-release"):
+ elif ipautil.file_exists("/etc/redhat-release"):
os = "rhel."
sub_dict = { }
@@ -46,7 +43,7 @@ class NTPInstance(service.Service):
sub_dict["SERVERB"] = "1.%spool.ntp.org" % os
sub_dict["SERVERC"] = "2.%spool.ntp.org" % os
- ntp_conf = template_file(SHARE_DIR + "ntp.conf.server.template", sub_dict)
+ ntp_conf = ipautil.template_file(ipautil.SHARE_DIR + "ntp.conf.server.template", sub_dict)
shutil.copy("/etc/ntp.conf", "/etc/ntp.conf.ipasave")
@@ -54,11 +51,13 @@ class NTPInstance(service.Service):
fd.write(ntp_conf)
fd.close()
+ def create_instance(self):
+ self.step("writing configuration", self.__write_config)
+
# we might consider setting the date manually using ntpd -qg in case
# the current time is very far off.
- self.step("starting ntpd")
- self.start()
-
- self.step("configuring ntpd to start on boot")
- self.chkconfig_on()
+ self.step("starting ntpd", self.start)
+ self.step("configuring ntpd to start on boot", self.chkconfig_on)
+
+ self.start_creation("Configuring ntpd")
diff --git a/ipa-server/ipaserver/service.py b/ipa-server/ipaserver/service.py
index f0109488d..90d0e606a 100644
--- a/ipa-server/ipaserver/service.py
+++ b/ipa-server/ipaserver/service.py
@@ -17,24 +17,24 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
-from ipa.ipautil import *
import logging, sys
+from ipa import ipautil
def stop(service_name):
- run(["/sbin/service", service_name, "stop"])
+ ipautil.run(["/sbin/service", service_name, "stop"])
def start(service_name):
- run(["/sbin/service", service_name, "start"])
+ ipautil.run(["/sbin/service", service_name, "start"])
def restart(service_name):
- run(["/sbin/service", service_name, "restart"])
+ ipautil.run(["/sbin/service", service_name, "restart"])
def chkconfig_on(service_name):
- run(["/sbin/chkconfig", service_name, "on"])
+ ipautil.run(["/sbin/chkconfig", service_name, "on"])
def chkconfig_off(service_name):
- run(["/sbin/chkconfig", service_name, "off"])
+ ipautil.run(["/sbin/chkconfig", service_name, "off"])
def print_msg(message, output_fd=sys.stdout):
logging.debug(message)
@@ -45,8 +45,7 @@ def print_msg(message, output_fd=sys.stdout):
class Service:
def __init__(self, service_name):
self.service_name = service_name
- self.num_steps = -1
- self.current_step = -1
+ self.steps = []
self.output_fd = sys.stdout
def set_output(self, fd):
@@ -69,18 +68,19 @@ class Service:
def print_msg(self, message):
print_msg(message, self.output_fd)
-
- def start_creation(self, num_steps, message):
- self.num_steps = num_steps
- self.cur_step = 0
- self.print_msg(message)
- def step(self, message):
- self.cur_step += 1
- self.print_msg(" [%d/%d]: %s" % (self.cur_step, self.num_steps, message))
+ def step(self, message, method):
+ self.steps.append((message, method))
- def done_creation(self):
- self.cur_step = -1
- self.num_steps = -1
+ def start_creation(self, message):
+ self.print_msg(message)
+
+ step = 0
+ for (message, method) in self.steps:
+ self.print_msg(" [%d/%d]: %s" % (step, len(self.steps), message))
+ method()
+ step += 1
+
self.print_msg("done configuring %s." % self.service_name)
+ self.steps = []
diff --git a/ipa-server/ipaserver/webguiinstance.py b/ipa-server/ipaserver/webguiinstance.py
index 757b50c5d..285435587 100644
--- a/ipa-server/ipaserver/webguiinstance.py
+++ b/ipa-server/ipaserver/webguiinstance.py
@@ -17,9 +17,6 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
-import logging
-
-from ipa.ipautil import *
import service
class WebGuiInstance(service.Service):
@@ -27,14 +24,6 @@ class WebGuiInstance(service.Service):
service.Service.__init__(self, "ipa-webgui")
def create_instance(self):
- self.start_creation(2, "Configuring ipa-webgui")
-
- self.step("starting ipa-webgui")
- service.start("ipa-webgui")
-
- self.step("configuring ipa-webgui to start on boot")
- service.chkconfig_on("ipa-webgui")
-
- self.done_creation()
-
-
+ self.step("starting ipa-webgui", self.restart)
+ self.step("configuring ipa-webgui to start on boot", self.chkconfig_on)
+ self.start_creation("Configuring ipa-webgui")
diff --git a/ipa-server/xmlrpc-server/funcs.py b/ipa-server/xmlrpc-server/funcs.py
index 4943da24d..2d2bddbb4 100644
--- a/ipa-server/xmlrpc-server/funcs.py
+++ b/ipa-server/xmlrpc-server/funcs.py
@@ -25,17 +25,15 @@ import ldap
import ldap.dn
import ipaserver.dsinstance
import ipaserver.ipaldap
-import ipa.ipautil
-import xmlrpclib
import copy
import attrs
from ipa import ipaerror
+from ipa import ipautil
from urllib import quote,unquote
from ipa import radius_util
import string
from types import *
-import os
import re
import logging
import subprocess
@@ -84,7 +82,7 @@ class IPAConnPool:
# This will bind the connection
try:
conn.set_krbccache(krbccache, cprinc.name)
- except ldap.UNWILLING_TO_PERFORM, e:
+ except ldap.UNWILLING_TO_PERFORM:
raise ipaerror.gen_exception(ipaerror.CONNECTION_UNWILLING)
return conn
@@ -111,7 +109,7 @@ class IPAServer:
if _LDAPPool is None:
_LDAPPool = IPAConnPool(128)
- self.basedn = ipa.ipautil.realm_to_suffix(self.realm)
+ self.basedn = ipautil.realm_to_suffix(self.realm)
self.scope = ldap.SCOPE_SUBTREE
self.princ = None
self.krbccache = None
@@ -127,11 +125,11 @@ class IPAServer:
global _LDAPPool
princ = self.__safe_filter(princ)
- filter = "(krbPrincipalName=" + princ + ")"
+ searchfilter = "(krbPrincipalName=" + princ + ")"
# The only anonymous search we should have
conn = _LDAPPool.getConn(self.host,self.sslport,self.bindca,self.bindcert,self.bindkey,None,None,debug)
try:
- ent = conn.getEntry(self.basedn, self.scope, filter, ['dn'])
+ ent = conn.getEntry(self.basedn, self.scope, searchfilter, ['dn'])
finally:
_LDAPPool.releaseConn(conn)
@@ -220,7 +218,7 @@ class IPAServer:
# they currently restrict the data coming back without
# restricting scope. For now adding a __get_base/sub_entry()
# calls, but the API isn't great.
- def __get_entry (self, base, scope, filter, sattrs=None, opts=None):
+ def __get_entry (self, base, scope, searchfilter, sattrs=None, opts=None):
"""Get a specific entry (with a parametized scope).
Return as a dict of values.
Multi-valued fields are represented as lists.
@@ -229,28 +227,28 @@ class IPAServer:
conn = self.getConnection(opts)
try:
- ent = conn.getEntry(base, scope, filter, sattrs)
+ ent = conn.getEntry(base, scope, searchfilter, sattrs)
finally:
self.releaseConnection(conn)
return self.convert_entry(ent)
- def __get_base_entry (self, base, filter, sattrs=None, opts=None):
+ def __get_base_entry (self, base, searchfilter, sattrs=None, opts=None):
"""Get a specific entry (with a scope of BASE).
Return as a dict of values.
Multi-valued fields are represented as lists.
"""
- return self.__get_entry(base, ldap.SCOPE_BASE, filter, sattrs, opts)
+ return self.__get_entry(base, ldap.SCOPE_BASE, searchfilter, sattrs, opts)
- def __get_sub_entry (self, base, filter, sattrs=None, opts=None):
+ def __get_sub_entry (self, base, searchfilter, sattrs=None, opts=None):
"""Get a specific entry (with a scope of SUB).
Return as a dict of values.
Multi-valued fields are represented as lists.
"""
- return self.__get_entry(base, ldap.SCOPE_SUBTREE, filter, sattrs, opts)
+ return self.__get_entry(base, ldap.SCOPE_SUBTREE, searchfilter, sattrs, opts)
- def __get_list (self, base, filter, sattrs=None, opts=None):
+ def __get_list (self, base, searchfilter, sattrs=None, opts=None):
"""Gets a list of entries. Each is converted to a dict of values.
Multi-valued fields are represented as lists.
"""
@@ -258,7 +256,7 @@ class IPAServer:
conn = self.getConnection(opts)
try:
- entries = conn.getList(base, self.scope, filter, sattrs)
+ entries = conn.getList(base, self.scope, searchfilter, sattrs)
finally:
self.releaseConnection(conn)
@@ -278,7 +276,7 @@ class IPAServer:
# original
try:
moddn = oldentry['dn']
- except KeyError, e:
+ except KeyError:
raise ipaerror.gen_exception(ipaerror.LDAP_MISSING_DN)
conn = self.getConnection(opts)
@@ -316,7 +314,7 @@ class IPAServer:
# construct the giant match for all words
exact_match_filter = "(&"
- partial_match_filter = "(&"
+ partial_match_filter = "(|"
for word in criteria_words:
exact_match_filter += gen_search_pattern(word)
partial_match_filter += gen_search_pattern("*%s*" % word)
@@ -366,43 +364,66 @@ class IPAServer:
Multi-valued fields are represented as lists.
"""
- filter = "(objectClass=*)"
- return self.__get_base_entry(dn, filter, sattrs, opts)
+ if not dn:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
+ searchfilter = "(objectClass=*)"
+ return self.__get_base_entry(dn, searchfilter, sattrs, opts)
def get_entry_by_cn (self, cn, sattrs, opts=None):
"""Get a specific entry by cn. Return as a dict of values.
Multi-valued fields are represented as lists.
"""
+ if not cn:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
cn = self.__safe_filter(cn)
- filter = "(cn=" + cn + ")"
- return self.__get_sub_entry(self.basedn, filter, sattrs, opts)
+ searchfilter = "(cn=" + cn + ")"
+ return self.__get_sub_entry(self.basedn, searchfilter, sattrs, opts)
def update_entry (self, oldentry, newentry, opts=None):
- """Update an entry in LDAP"""
+ """Update an entry in LDAP
+
+ oldentry and newentry are XML-RPC structs.
+
+ If oldentry is not empty then it is used when determine what
+ has changed.
+
+ If oldentry is empty then the value of newentry is compared
+ to the current value of oldentry.
+ """
+ if not newentry:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
+
+ if not oldentry:
+ oldentry = self.get_entry_by_dn(newentry.get('dn'), None, opts)
+ if oldentry is None:
+ raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
+
return self.__update_entry(oldentry, newentry, opts)
# User support
def __is_user_unique(self, uid, opts):
- """Return 1 if the uid is unique in the tree, 0 otherwise."""
+ """Return True if the uid is unique in the tree, False otherwise."""
uid = self.__safe_filter(uid)
- filter = "(&(uid=%s)(objectclass=posixAccount))" % uid
+ searchfilter = "(&(uid=%s)(objectclass=posixAccount))" % uid
try:
- entry = self.__get_sub_entry(self.basedn, filter, ['dn','uid'], opts)
- return 0
+ entry = self.__get_sub_entry(self.basedn, searchfilter, ['dn','uid'], opts)
+ return False
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
- return 1
+ return True
def get_user_by_uid (self, uid, sattrs, opts=None):
"""Get a specific user's entry. Return as a dict of values.
Multi-valued fields are represented as lists.
"""
+ if not uid:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
uid = self.__safe_filter(uid)
- filter = "(uid=" + uid + ")"
- return self.__get_sub_entry(self.basedn, filter, sattrs, opts)
+ searchfilter = "(uid=" + uid + ")"
+ return self.__get_sub_entry(self.basedn, searchfilter, sattrs, opts)
def get_user_by_principal(self, principal, sattrs, opts=None):
"""Get a user entry searching by Kerberos Principal Name.
@@ -410,27 +431,33 @@ class IPAServer:
represented as lists.
"""
- filter = "(krbPrincipalName="+self.__safe_filter(principal)+")"
- return self.__get_sub_entry(self.basedn, filter, sattrs, opts)
+ if not principal:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
+ searchfilter = "(krbPrincipalName="+self.__safe_filter(principal)+")"
+ return self.__get_sub_entry(self.basedn, searchfilter, sattrs, opts)
def get_user_by_email (self, email, sattrs, opts=None):
"""Get a specific user's entry. Return as a dict of values.
Multi-valued fields are represented as lists.
"""
+ if not email:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
email = self.__safe_filter(email)
- filter = "(mail=" + email + ")"
- return self.__get_sub_entry(self.basedn, filter, sattrs, opts)
+ searchfilter = "(mail=" + email + ")"
+ return self.__get_sub_entry(self.basedn, searchfilter, sattrs, opts)
def get_users_by_manager (self, manager_dn, sattrs, opts=None):
"""Gets the users that report to a particular manager.
"""
+ if not manager_dn:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
manager_dn = self.__safe_filter(manager_dn)
- filter = "(&(objectClass=person)(manager=%s))" % manager_dn
+ searchfilter = "(&(objectClass=person)(manager=%s))" % manager_dn
try:
- return self.__get_list(self.basedn, filter, sattrs, opts)
+ return self.__get_list(self.basedn, searchfilter, sattrs, opts)
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
return []
@@ -438,11 +465,16 @@ class IPAServer:
"""Add a user in LDAP. Takes as input a dict where the key is the
attribute name and the value is either a string or in the case
of a multi-valued field a list of values. user_container sets
- where in the tree the user is placed."""
+ where in the tree the user is placed.
+ """
+
+ if not user:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
+
if not user_container:
user_container = DefaultUserContainer
- if self.__is_user_unique(user['uid'], opts) == 0:
+ if not self.__is_user_unique(user['uid'], opts):
raise ipaerror.gen_exception(ipaerror.LDAP_DUPLICATE)
# dn is set here, not by the user
@@ -758,6 +790,8 @@ class IPAServer:
It is displayed to the user in the order of the list.
"""
+ if not schema:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
config = self.get_ipa_config(opts)
# The schema is stored as:
@@ -783,11 +817,11 @@ class IPAServer:
"""Return a list containing a User object for each
existing user.
"""
- filter = "(objectclass=posixAccount)"
+ searchfilter = "(objectclass=posixAccount)"
conn = self.getConnection(opts)
try:
- all_users = conn.getList(self.basedn, self.scope, filter, None)
+ all_users = conn.getList(self.basedn, self.scope, searchfilter, None)
finally:
self.releaseConnection(conn)
@@ -803,6 +837,8 @@ class IPAServer:
If the results are truncated, counter will be set to -1."""
logging.debug("IPA: find users %s" % criteria)
+ if not criteria:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
config = self.get_ipa_config(opts)
if timelimit < 0:
timelimit = float(config.get('ipasearchtimelimit'))
@@ -875,6 +911,8 @@ class IPAServer:
def convert_scalar_values(self, orig_dict):
"""LDAP update dicts expect all values to be a list (except for dn).
This method converts single entries to a list."""
+ if not orig_dict or not isinstance(orig_dict, dict):
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
new_dict={}
for (k,v) in orig_dict.iteritems():
if not isinstance(v, list) and k != 'dn':
@@ -886,9 +924,23 @@ class IPAServer:
def update_user (self, oldentry, newentry, opts=None):
"""Wrapper around update_entry with user-specific handling.
+ oldentry and newentry are XML-RPC structs.
+
+ If oldentry is not empty then it is used when determine what
+ has changed.
+
+ If oldentry is empty then the value of newentry is compared
+ to the current value of oldentry.
+
If you want to change the RDN of a user you must use
this function. update_entry will fail.
"""
+ if not newentry:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
+ if not oldentry:
+ oldentry = self.get_entry_by_dn(newentry.get('dn'), None, opts)
+ if oldentry is None:
+ raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
newrdn = 0
@@ -938,6 +990,9 @@ class IPAServer:
logging.debug("IPA: activating entry %s" % dn)
+ if not dn:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
+
res = ""
# First, check the entry status
entry = self.get_entry_by_dn(dn, ['dn', 'nsAccountlock'], opts)
@@ -970,6 +1025,9 @@ class IPAServer:
logging.debug("IPA: inactivating entry %s" % dn)
+ if not dn:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
+
entry = self.get_entry_by_dn(dn, ['dn', 'nsAccountlock', 'memberOf'], opts)
if entry.get('nsaccountlock', 'false') == "true":
@@ -990,12 +1048,16 @@ class IPAServer:
def mark_user_active(self, uid, opts=None):
"""Mark a user as active"""
+ if not uid:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
user = self.get_user_by_uid(uid, ['dn', 'uid'], opts)
return self.mark_entry_active(user.get('dn'))
def mark_user_inactive(self, uid, opts=None):
"""Mark a user as inactive"""
+ if not uid:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
user = self.get_user_by_uid(uid, ['dn', 'uid'], opts)
return self.mark_entry_inactive(user.get('dn'))
@@ -1008,6 +1070,8 @@ class IPAServer:
The memberOf plugin handles removing the user from any other
groups.
"""
+ if not uid:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
user = self.get_user_by_uid(uid, ['dn', 'uid', 'objectclass'], opts)
if user is None:
raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
@@ -1026,6 +1090,8 @@ class IPAServer:
oldpass is the old password (if available)
newpass is the new password
"""
+ if not principal or not newpass:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
user = self.get_user_by_principal(principal, ['krbprincipalname'], opts)
if user is None or user['krbprincipalname'] != principal:
raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
@@ -1040,26 +1106,28 @@ class IPAServer:
# Group support
def __is_group_unique(self, cn, opts):
- """Return 1 if the cn is unique in the tree, 0 otherwise."""
+ """Return True if the cn is unique in the tree, False otherwise."""
cn = self.__safe_filter(cn)
- filter = "(&(cn=%s)(objectclass=posixGroup))" % cn
+ searchfilter = "(&(cn=%s)(objectclass=posixGroup))" % cn
try:
- entry = self.__get_sub_entry(self.basedn, filter, ['dn','cn'], opts)
- return 0
+ entry = self.__get_sub_entry(self.basedn, searchfilter, ['dn','cn'], opts)
+ return False
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
- return 1
+ return True
def get_groups_by_member (self, member_dn, sattrs, opts=None):
"""Get a specific group's entry. Return as a dict of values.
Multi-valued fields are represented as lists.
"""
+ if not member_dn:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
member_dn = self.__safe_filter(member_dn)
- filter = "(&(objectClass=posixGroup)(member=%s))" % member_dn
+ searchfilter = "(&(objectClass=posixGroup)(member=%s))" % member_dn
try:
- return self.__get_list(self.basedn, filter, sattrs, opts)
+ return self.__get_list(self.basedn, searchfilter, sattrs, opts)
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
return []
@@ -1068,10 +1136,13 @@ class IPAServer:
attribute name and the value is either a string or in the case
of a multi-valued field a list of values. group_container sets
where in the tree the group is placed."""
+ if not group:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
+
if not group_container:
group_container = DefaultGroupContainer
- if self.__is_group_unique(group['cn'], opts) == 0:
+ if not self.__is_group_unique(group['cn'], opts):
raise ipaerror.gen_exception(ipaerror.LDAP_DUPLICATE)
# Get our configuration
@@ -1102,6 +1173,8 @@ class IPAServer:
"""Return a list containing a User object for each
existing group that matches the criteria.
"""
+ if not criteria:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
config = self.get_ipa_config(opts)
if timelimit < 0:
@@ -1178,6 +1251,8 @@ class IPAServer:
def add_member_to_group(self, member_dn, group_dn, opts=None):
"""Add a member to an existing group.
"""
+ if not member_dn or not group_dn:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
old_group = self.get_entry_by_dn(group_dn, None, opts)
if old_group is None:
@@ -1186,6 +1261,8 @@ class IPAServer:
# check to make sure member_dn exists
member_entry = self.__get_base_entry(member_dn, "(objectClass=*)", ['dn','uid'], opts)
+ if not member_entry:
+ raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
if new_group.get('member') is not None:
if ((isinstance(new_group.get('member'), str)) or (isinstance(new_group.get('member'), unicode))):
@@ -1205,6 +1282,9 @@ class IPAServer:
Returns a list of the member_dns that were not added to the group.
"""
+ if not member_dns or not group_dn:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
+
failed = []
if (isinstance(member_dns, str)):
@@ -1225,6 +1305,8 @@ class IPAServer:
def remove_member_from_group(self, member_dn, group_dn, opts=None):
"""Remove a member_dn from an existing group.
"""
+ if not member_dn or not group_dn:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
old_group = self.get_entry_by_dn(group_dn, None, opts)
if old_group is None:
@@ -1255,6 +1337,8 @@ class IPAServer:
"""Given a list of member dn's remove them from the group.
Returns a list of the members not removed from the group.
"""
+ if not member_dns or not group_dn:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
failed = []
@@ -1277,6 +1361,8 @@ class IPAServer:
"""Add a user to an existing group.
"""
+ if not user_uid or not group_dn:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
user = self.get_user_by_uid(user_uid, ['dn', 'uid', 'objectclass'], opts)
if user is None:
raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
@@ -1287,6 +1373,8 @@ class IPAServer:
"""Given a list of user uid's add them to the group cn denoted by group
Returns a list of the users were not added to the group.
"""
+ if not user_uids or not group_dn:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
failed = []
@@ -1309,6 +1397,9 @@ class IPAServer:
"""Remove a user from an existing group.
"""
+ if not user_uid or not group_dn:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
+
user = self.get_user_by_uid(user_uid, ['dn', 'uid', 'objectclass'], opts)
if user is None:
raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
@@ -1319,6 +1410,8 @@ class IPAServer:
"""Given a list of user uid's remove them from the group
Returns a list of the user uids not removed from the group.
"""
+ if not user_uids or not group_dn:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
failed = []
@@ -1342,6 +1435,8 @@ class IPAServer:
Returns a list of the group dns that were not added.
"""
+ if not group_dns or not user_dn:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
failed = []
@@ -1365,6 +1460,8 @@ class IPAServer:
Returns a list of the group dns that were not removed.
"""
+ if not group_dns or not user_dn:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
failed = []
@@ -1386,9 +1483,23 @@ class IPAServer:
def update_group (self, oldentry, newentry, opts=None):
"""Wrapper around update_entry with group-specific handling.
+ oldentry and newentry are XML-RPC structs.
+
+ If oldentry is not empty then it is used when determine what
+ has changed.
+
+ If oldentry is empty then the value of newentry is compared
+ to the current value of oldentry.
+
If you want to change the RDN of a group you must use
this function. update_entry will fail.
"""
+ if not newentry:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
+ if not oldentry:
+ oldentry = self.get_entry_by_dn(newentry.get('dn'), None, opts)
+ if oldentry is None:
+ raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
newrdn = 0
@@ -1451,6 +1562,8 @@ class IPAServer:
The memberOf plugin handles removing the group from any other
groups.
"""
+ if not group_dn:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
group = self.get_entry_by_dn(group_dn, ['dn', 'cn'], opts)
if group is None:
raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
@@ -1478,6 +1591,8 @@ class IPAServer:
tgroup is the DN of the target group to be added to
"""
+ if not group or not tgroup:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
old_group = self.get_entry_by_dn(tgroup, None, opts)
if old_group is None:
raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
@@ -1514,19 +1629,21 @@ class IPAServer:
"""Do a memberOf search of groupdn and return the attributes in
attr_list (an empty list returns everything)."""
+ if not groupdn:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
config = self.get_ipa_config(opts)
timelimit = float(config.get('ipasearchtimelimit'))
searchlimit = float(config.get('ipasearchrecordslimit'))
groupdn = self.__safe_filter(groupdn)
- filter = "(memberOf=%s)" % groupdn
+ searchfilter = "(memberOf=%s)" % groupdn
conn = self.getConnection(opts)
try:
try:
results = conn.getListAsync(self.basedn, self.scope,
- filter, attr_list, 0, None, None, timelimit,
+ searchfilter, attr_list, 0, None, None, timelimit,
searchlimit)
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
results = [0]
@@ -1545,33 +1662,42 @@ class IPAServer:
def mark_group_active(self, cn, opts=None):
"""Mark a group as active"""
+ if not cn:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
group = self.get_entry_by_cn(cn, ['dn', 'cn'], opts)
return self.mark_entry_active(group.get('dn'))
def mark_group_inactive(self, cn, opts=None):
"""Mark a group as inactive"""
+ if not cn:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
group = self.get_entry_by_cn(cn, ['dn', 'uid'], opts)
return self.mark_entry_inactive(group.get('dn'))
def __is_service_unique(self, name, opts):
- """Return 1 if the uid is unique in the tree, 0 otherwise."""
+ """Return True if the uid is unique in the tree, False otherwise."""
name = self.__safe_filter(name)
- filter = "(&(krbprincipalname=%s)(objectclass=krbPrincipal))" % name
+ searchfilter = "(&(krbprincipalname=%s)(objectclass=krbPrincipal))" % name
try:
- entry = self.__get_sub_entry(self.basedn, filter, ['dn','krbprincipalname'], opts)
- return 0
+ entry = self.__get_sub_entry(self.basedn, searchfilter, ['dn','krbprincipalname'], opts)
+ return False
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
- return 1
+ return True
def add_service_principal(self, name, opts=None):
+ """Given a name of the form: service/FQDN create a service
+ principal for it in the default realm."""
+ if not name:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
+
service_container = DefaultServiceContainer
princ_name = name + "@" + self.realm
conn = self.getConnection(opts)
- if self.__is_service_unique(name, opts) == 0:
+ if not self.__is_service_unique(name, opts):
raise ipaerror.gen_exception(ipaerror.LDAP_DUPLICATE)
dn = "krbprincipalname=%s,%s,%s" % (ldap.dn.escape_dn_chars(princ_name),
@@ -1591,6 +1717,8 @@ class IPAServer:
timelimit=-1, opts=None):
"""Returns a list: counter followed by the results.
If the results are truncated, counter will be set to -1."""
+ if not criteria:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
config = self.get_ipa_config(opts)
if timelimit < 0:
@@ -1658,7 +1786,10 @@ class IPAServer:
return entries
def get_keytab(self, name, opts=None):
- """get a keytab"""
+ """Return a keytab for an existing service principal. Note that
+ this increments the secret thus invalidating any older keys."""
+ if not name:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
princ_name = name + "@" + self.realm
@@ -1699,8 +1830,24 @@ class IPAServer:
return config
def update_ipa_config(self, oldconfig, newconfig, opts=None):
- """Update the IPA configuration"""
-
+ """Update the IPA configuration.
+
+ oldconfig and newconfig are XML-RPC structs.
+
+ If oldconfig is not empty then it is used when determine what
+ has changed.
+
+ If oldconfig is empty then the value of newconfig is compared
+ to the current value of oldconfig.
+
+ """
+ if not newconfig:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
+ if not oldconfig:
+ oldconfig = self.get_entry_by_dn(newconfig.get('dn'), None, opts)
+ if oldconfig is None:
+ raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
+
# The LDAP routines want strings, not ints, so convert a few
# things. Otherwise it sees a string -> int conversion as a change.
try:
@@ -1749,7 +1896,24 @@ class IPAServer:
return policy
def update_password_policy(self, oldpolicy, newpolicy, opts=None):
- """Update the IPA configuration"""
+ """Update the IPA configuration
+
+ oldpolicy and newpolicy are XML-RPC structs.
+
+ If oldpolicy is not empty then it is used when determine what
+ has changed.
+
+ If oldpolicy is empty then the value of newpolicy is compared
+ to the current value of oldpolicy.
+
+ """
+ if not newpolicy:
+ raise ipaerror.gen_exception(ipaerror.INPUT_INVALID_PARAMETER)
+ if not oldpolicy:
+ oldpolicy = self.get_entry_by_dn(newpolicy.get('dn'), None, opts)
+ if oldpolicy is None:
+ raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
+
# The LDAP routines want strings, not ints, so convert a few
# things. Otherwise it sees a string -> int conversion as a change.
diff --git a/ipa-server/xmlrpc-server/ipa.conf b/ipa-server/xmlrpc-server/ipa.conf
index fbf26b67c..4e8bf528f 100644
--- a/ipa-server/xmlrpc-server/ipa.conf
+++ b/ipa-server/xmlrpc-server/ipa.conf
@@ -12,9 +12,12 @@ RewriteRule ^/(.*) http://$FQDN/$$1 [L,R=301]
# Redirect to the secure port if not displaying an error or retrieving
# configuration.
RewriteCond %{SERVER_PORT} !^443$$
-RewriteCond %{REQUEST_URI} !^/(errors|config)/
+RewriteCond %{REQUEST_URI} !^/(errors|config|favicon.ico)
RewriteRule ^/(.*) https://$FQDN/$$1 [L,R=301,NC]
+# This is required so the auto-configuration works with Firefox 2+
+AddType application/java-archive jar
+
<Proxy *>
AuthType Kerberos
AuthName "Kerberos Login"
diff --git a/ipa-server/xmlrpc-server/unauthorized.html b/ipa-server/xmlrpc-server/unauthorized.html
index 23a8d5c7d..eba1266ad 100644
--- a/ipa-server/xmlrpc-server/unauthorized.html
+++ b/ipa-server/xmlrpc-server/unauthorized.html
@@ -9,6 +9,20 @@ have <a href="/errors/ssbrowser.html">configured your
browser correctly</a>. If you are still unable to access
the IPA Web interface, please contact the helpdesk on for additional assistance.
</p>
+<p>
+Import the <a href="/errors/ca.crt">IPA Certificate Authority</a>.
+</p>
+<p>
+<script type="text/javascript">
+ if (navigator.userAgent.indexOf("Firefox") != -1 ||
+ navigator.userAgent.indexOf("SeaMonkey") != -1)
+ {
+ document.write("<p>You can automatically configure your browser to work with Kerberos by importing the Certificate Authority below and clicking on the Configure Browser button.</p>");
+ document.write("<p>You <strong>must</strong> reload this page after importing the Certificate Authority for the automatic settings to work</p>");
+ document.write("<object data=\"jar:/errors/configure.jar!/preferences.html\" type=\"text/html\"><\/object");
+ }
+</script>
+</p>
</ul>
</body>
</html>