summaryrefslogtreecommitdiffstats
path: root/ipa-server
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 /ipa-server
parenta0eacec8e587c0fbc7e24378cef58fa7835ae64a (diff)
parent4814c0d3f6c11971b841eb6eedcd7925d8840f26 (diff)
downloadfreeipa.git-6575aa606f18f8d998dcad5552e4f770e9addcdf.tar.gz
freeipa.git-6575aa606f18f8d998dcad5552e4f770e9addcdf.tar.xz
freeipa.git-6575aa606f18f8d998dcad5552e4f770e9addcdf.zip
Merge.
Diffstat (limited to 'ipa-server')
-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/radius.radiusd.conf.template285
-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/radiusinstance.py171
-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
31 files changed, 943 insertions, 888 deletions
diff --git a/ipa-server/ipa-gui/ipa-webgui b/ipa-server/ipa-gui/ipa-webgui
index c8e3d058..a18c2db8 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 d9d5d727..7eadfe23 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 74369a6a..43a7a547 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 cee239e7..2319b944 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 4eb846d5..3f885fa0 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 1b46d354..8a3e4a97 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 00000000..932a6be1
--- /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 646512d5..ee5e929d 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 36bb54e8..5d117dec 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 9642070c..0a969de3 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 95743eeb..5715259a 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 00000000..2d3684dc
--- /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/radius.radiusd.conf.template b/ipa-server/ipa-install/share/radius.radiusd.conf.template
deleted file mode 100644
index 3bc4927d..00000000
--- a/ipa-server/ipa-install/share/radius.radiusd.conf.template
+++ /dev/null
@@ -1,285 +0,0 @@
-#
-# WARNING: This file is automatically generated, do not edit
-#
-# $CONFIG_FILE_VERSION_INFO
-#
-prefix = /usr
-exec_prefix = /usr
-sysconfdir = /etc
-localstatedir = /var
-sbindir = /usr/sbin
-logdir = $${localstatedir}/log/radius
-raddbdir = $${sysconfdir}/raddb
-radacctdir = $${logdir}/radacct
-confdir = $${raddbdir}
-run_dir = $${localstatedir}/run/radiusd
-db_dir = $${localstatedir}/lib/radiusd
-log_file = $${logdir}/radius.log
-libdir = /usr/lib
-pidfile = $${run_dir}/radiusd.pid
-user = radiusd
-group = radiusd
-max_request_time = 30
-delete_blocked_requests = no
-cleanup_delay = 5
-max_requests = 1024
-bind_address = *
-port = 0
-hostname_lookups = no
-allow_core_dumps = no
-regular_expressions = yes
-extended_expressions = yes
-log_stripped_names = no
-log_auth = no
-log_auth_badpass = no
-log_auth_goodpass = no
-usercollide = no
-lower_user = no
-lower_pass = no
-nospace_user = no
-nospace_pass = no
-checkrad = $${sbindir}/checkrad
-security {
- max_attributes = 200
- reject_delay = 1
- status_server = no
-}
-proxy_requests = yes
-$$INCLUDE $${confdir}/proxy.conf
-$$INCLUDE $${confdir}/clients.conf
-snmp = no
-$$INCLUDE $${confdir}/snmp.conf
-thread pool {
- start_servers = 5
- max_servers = 32
- min_spare_servers = 3
- max_spare_servers = 10
- max_requests_per_server = 0
-}
-modules {
- chap {
- authtype = CHAP
- }
- pam {
- pam_auth = radiusd
- }
- unix {
- cache = no
- cache_reload = 600
- shadow = /etc/shadow
- radwtmp = $${logdir}/radwtmp
- }
-$$INCLUDE $${confdir}/eap.conf
- mschap {
- }
- ldap {
- server = "$LDAP_SERVER"
- use_sasl = yes
- sasl_mech = "GSSAPI"
- krb_keytab = "$RADIUS_KEYTAB"
- krb_principal = "$RADIUS_PRINCIPAL"
- basedn = "$RADIUS_USER_BASE_DN"
- filter = "(uid=%{Stripped-User-Name:-%{User-Name}})"
- base_filter = "(objectclass=radiusprofile)"
- start_tls = no
- profile_attribute = "radiusProfileDn"
- default_profile = "uid=ipa_default,cn=profiles,cn=radius,cn=services,cn=etc,$SUFFIX
- # FIXME: we'll want to toggle the access_attr feature on/off,
- # but it needs a control, so disable it for now.
- #access_attr = "$ACCESS_ATTRIBUTE"
- #access_attr_used_for_allow = "$ACCESS_ATTRIBUTE_DEFAULT"
- dictionary_mapping = $${raddbdir}/ldap.attrmap
- ldap_connections_number = 5
- edir_account_policy_check=no
- timeout = 4
- timelimit = 3
- net_timeout = 1
- clients_basedn = "$CLIENTS_BASEDN"
- }
- realm IPASS {
- format = prefix
- delimiter = "/"
- ignore_default = no
- ignore_null = no
- }
- realm suffix {
- format = suffix
- delimiter = "@"
- ignore_default = no
- ignore_null = no
- }
- realm realmpercent {
- format = suffix
- delimiter = "%"
- ignore_default = no
- ignore_null = no
- }
- realm ntdomain {
- format = prefix
- delimiter = "\\"
- ignore_default = no
- ignore_null = no
- }
- checkval {
- item-name = Calling-Station-Id
- check-name = Calling-Station-Id
- data-type = string
- }
- preprocess {
- huntgroups = $${confdir}/huntgroups
- hints = $${confdir}/hints
- with_ascend_hack = no
- ascend_channels_per_line = 23
- with_ntdomain_hack = no
- with_specialix_jetstream_hack = no
- with_cisco_vsa_hack = no
- }
- files {
- usersfile = $${confdir}/users
- acctusersfile = $${confdir}/acct_users
- preproxy_usersfile = $${confdir}/preproxy_users
- compat = no
- }
- detail {
- detailfile = $${radacctdir}/%{Client-IP-Address}/detail-%Y%m%d
- detailperm = 0600
- }
- acct_unique {
- key = "User-Name, Acct-Session-Id, NAS-IP-Address, Client-IP-Address, NAS-Port"
- }
- radutmp {
- filename = $${logdir}/radutmp
- username = %{User-Name}
- case_sensitive = yes
- check_with_nas = yes
- perm = 0600
- callerid = "yes"
- }
- radutmp sradutmp {
- filename = $${logdir}/sradutmp
- perm = 0644
- callerid = "no"
- }
- attr_filter {
- attrsfile = $${confdir}/attrs
- }
- counter daily {
- filename = $${db_dir}/db.daily
- key = User-Name
- count-attribute = Acct-Session-Time
- reset = daily
- counter-name = Daily-Session-Time
- check-name = Max-Daily-Session
- allowed-servicetype = Framed-User
- cache-size = 5000
- }
- sqlcounter dailycounter {
- counter-name = Daily-Session-Time
- check-name = Max-Daily-Session
- reply-name = Session-Timeout
- sqlmod-inst = sql
- key = User-Name
- reset = daily
- query = "SELECT SUM(AcctSessionTime - \
- GREATEST((%b - UNIX_TIMESTAMP(AcctStartTime)), 0)) \
- FROM radacct WHERE UserName='%{%k}' AND \
- UNIX_TIMESTAMP(AcctStartTime) + AcctSessionTime > '%b'"
- }
- sqlcounter monthlycounter {
- counter-name = Monthly-Session-Time
- check-name = Max-Monthly-Session
- reply-name = Session-Timeout
- sqlmod-inst = sql
- key = User-Name
- reset = monthly
- query = "SELECT SUM(AcctSessionTime - \
- GREATEST((%b - UNIX_TIMESTAMP(AcctStartTime)), 0)) \
- FROM radacct WHERE UserName='%{%k}' AND \
- UNIX_TIMESTAMP(AcctStartTime) + AcctSessionTime > '%b'"
- }
- always fail {
- rcode = fail
- }
- always reject {
- rcode = reject
- }
- always ok {
- rcode = ok
- simulcount = 0
- mpp = no
- }
- expr {
- }
- digest {
- }
- exec {
- wait = yes
- input_pairs = request
- }
- exec echo {
- wait = yes
- program = "/bin/echo %{User-Name}"
- input_pairs = request
- output_pairs = reply
- }
- ippool main_pool {
- range-start = 192.168.1.1
- range-stop = 192.168.3.254
- netmask = 255.255.255.0
- cache-size = 800
- session-db = $${db_dir}/db.ippool
- ip-index = $${db_dir}/db.ipindex
- override = no
- maximum-timeout = 0
- }
- krb5 {
- keytab = "$RADIUS_KEYTAB"
- service_principal = "$RADIUS_PRINCIPAL"
- }
-}
-instantiate {
- exec
- expr
-}
-authorize {
- preprocess
- chap
- mschap
- suffix
- eap
- #files
- ldap
-}
-authenticate {
- Auth-Type CHAP {
- chap
- }
- Auth-Type MS-CHAP {
- mschap
- }
- eap
- Auth-Type Kerberos {
- krb5
- }
-}
-preacct {
- preprocess
- acct_unique
- suffix
- files
-}
-accounting {
- detail
- unix
- radutmp
-}
-session {
- radutmp
-}
-post-auth {
-}
-pre-proxy {
-}
-post-proxy {
- eap
-}
diff --git a/ipa-server/ipa-install/share/referint-conf.ldif b/ipa-server/ipa-install/share/referint-conf.ldif
index 7a547ba5..533b97de 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 99dfe678..ccd17c1f 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 f84affe8..38725cf3 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 874d82cf..e43f07aa 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 f1c094b3..b1d00a80 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 8a131fe7..cc99eacf 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 fb6b01d0..eecfdf21 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 5edc3879..6cbffcb8 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 1799cca0..d0329cca 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 a403e815..25cd1555 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 76818af7..2f4454ba 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 46841b0b..b321ec07 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/radiusinstance.py b/ipa-server/ipaserver/radiusinstance.py
deleted file mode 100644
index 3b89018f..00000000
--- a/ipa-server/ipaserver/radiusinstance.py
+++ /dev/null
@@ -1,171 +0,0 @@
-#! /usr/bin/python -E
-# Authors: John Dennis <jdennis@redhat.com>
-#
-# Copyright (C) 2007 Red Hat
-# see file 'COPYING' for use and warranty information
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation; version 2 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
-import subprocess
-import string
-import tempfile
-import shutil
-import logging
-import pwd
-import time
-import sys
-from ipa.ipautil import *
-from ipa import radius_util
-
-import service
-
-import os
-import re
-
-IPA_RADIUS_VERSION = '0.0.0'
-
-# FIXME there should a utility to get the user base dn
-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:
- p = subprocess.Popen([radius_util.RADIUSD, '-v'], stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- stdout, stderr = p.communicate()
- status = p.returncode
-
- if status == 0:
- match = re.search("radiusd: FreeRADIUS Version (.+), for host", stdout)
- if match:
- version = match.group(1)
- except Exception, e:
- pass
- return version
-
-
-#-------------------------------------------------------------------------------
-
-class RadiusInstance(service.Service):
- def __init__(self):
- service.Service.__init__(self, "radiusd")
- self.fqdn = None
- self.realm = None
- self.principal = None
-
- def create_instance(self, realm_name, host_name, ldap_server):
- self.realm = realm_name.upper()
- self.suffix = 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()
- except:
- # It could have been not running
- pass
-
- self.__create_radius_keytab()
- self.__radiusd_conf()
-
- 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,
- 'RADIUS_KEYTAB' : radius_util.RADIUS_IPA_KEYTAB_FILEPATH,
- 'RADIUS_PRINCIPAL' : self.principal,
- 'RADIUS_USER_BASE_DN' : self.user_basedn,
- 'ACCESS_ATTRIBUTE' : '',
- 'ACCESS_ATTRIBUTE_DEFAULT' : 'TRUE',
- 'CLIENTS_BASEDN' : radius_util.radius_clients_basedn(None, self.suffix),
- 'SUFFIX' : self.suffix,
- }
- try:
- radiusd_conf = 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()
- except Exception, e:
- 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):
- os.remove(radius_util.RADIUS_IPA_KEYTAB_FILEPATH)
- except os.error:
- logging.error("Failed to remove %s", radius_util.RADIUS_IPA_KEYTAB_FILEPATH)
-
- (kwrite, kread, kerr) = os.popen3("/usr/kerberos/sbin/kadmin.local")
- kwrite.write("addprinc -randkey %s\n" % (self.principal))
- kwrite.flush()
- kwrite.write("ktadd -k %s %s\n" % (radius_util.RADIUS_IPA_KEYTAB_FILEPATH, self.principal))
- kwrite.flush()
- kwrite.close()
- kread.close()
- kerr.close()
-
- # give kadmin time to actually write the file before we go on
- retry = 0
- while not file_exists(radius_util.RADIUS_IPA_KEYTAB_FILEPATH):
- time.sleep(1)
- retry += 1
- if retry > 15:
- print "Error timed out waiting for kadmin to finish operations\n"
- sys.exit(1)
- try:
- pent = pwd.getpwnam(radius_util.RADIUS_USER)
- os.chown(radius_util.RADIUS_IPA_KEYTAB_FILEPATH, pent.pw_uid, pent.pw_gid)
- except Exception, e:
- logging.error("could not chown on %s to %s: %s", radius_util.RADIUS_IPA_KEYTAB_FILEPATH, radius_util.RADIUS_USER, e)
-
- #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()
-
-#-------------------------------------------------------------------------------
-
diff --git a/ipa-server/ipaserver/service.py b/ipa-server/ipaserver/service.py
index f0109488..90d0e606 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 757b50c5..28543558 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 4943da24..2d2bddbb 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 fbf26b67..4e8bf528 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 23a8d5c7..eba1266a 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>