Add missing 3.0.0 beta 2 development patches

This commit is contained in:
Martin Kosek 2012-08-06 18:17:49 +02:00
parent 23157c3804
commit 3c91c125af
80 changed files with 230385 additions and 0 deletions

View File

@ -0,0 +1,681 @@
From e5b6260008a3a7132fdaef99d800406eb8872316 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Thu, 24 May 2012 11:23:36 -0400
Subject: [PATCH 00/79] Centralize timeout for waiting for servers to start.
All service start/restart currently go through ipapython/platform so
move the "wait for service to start" code there as well.
A dictionary of known services and ports to wait on is defined in base.py
This is referenced by the platforms by instance name to determine what
to wait for. For the case of dirsrv if we get that as a plain name
(no specific instance) it is assumed to be the main IPA service.
https://fedorahosted.org/freeipa/ticket/2375
https://fedorahosted.org/freeipa/ticket/2610
---
install/tools/ipactl | 28 +++++++++-------
ipalib/constants.py | 2 ++
ipapython/ipautil.py | 54 +++++++++++++++++++++++++++++
ipapython/platform/base.py | 56 ++++++++++++++++++++-----------
ipapython/platform/fedora16.py | 4 +--
ipapython/platform/redhat.py | 22 ++++++++++--
ipapython/platform/systemd.py | 23 +++++++++++--
ipaserver/install/cainstance.py | 1 -
ipaserver/install/dsinstance.py | 3 +-
ipaserver/install/installutils.py | 52 ----------------------------
ipaserver/install/plugins/baseupdate.py | 8 +++++
ipaserver/install/plugins/updateclient.py | 4 +--
ipaserver/install/replication.py | 2 --
ipaserver/install/service.py | 10 +++---
ipaserver/install/upgradeinstance.py | 5 +++
ipaserver/ipaldap.py | 7 ++--
16 files changed, 176 insertions(+), 105 deletions(-)
diff --git a/install/tools/ipactl b/install/tools/ipactl
index c4d26b8df150119e0bc84abac020f8989a2a8ad2..22a4f6e03030e9874a533dd9978823dd3505658d 100755
--- a/install/tools/ipactl
+++ b/install/tools/ipactl
@@ -24,7 +24,8 @@ try:
from ipaserver.install import service, installutils
from ipapython import services as ipaservices
from ipaserver.install.dsinstance import config_dirname, realm_to_serverid
- from ipaserver.install.installutils import is_ipa_configured, wait_for_open_ports, wait_for_open_socket, ScriptError
+ from ipaserver.install.installutils import is_ipa_configured, ScriptError
+ from ipapython.ipautil import wait_for_open_ports, wait_for_open_socket
from ipapython import sysrestore
from ipapython import config
from ipalib import api, errors
@@ -105,22 +106,25 @@ def parse_options():
def emit_err(err):
sys.stderr.write(err + '\n')
-def get_config():
+def get_config(dirsrv):
base = "cn=%s,cn=masters,cn=ipa,cn=etc,%s" % (api.env.host,
api.env.basedn)
srcfilter = '(ipaConfigString=enabledService)'
attrs = ['cn', 'ipaConfigString']
+ if not dirsrv.is_running():
+ raise IpactlError("Failed to get list of services to probe status:\n" +
+ "Directory Server is stopped", 3)
try:
- # systemd services are so fast that we come here before
- # Directory Server actually starts listening. Wait for
- # the socket/port be really available.
+ # The start/restart functions already wait for the server to be
+ # started. What we are doing with this wait is really checking to see
+ # if the server is listening at all.
lurl = ldapurl.LDAPUrl(api.env.ldap_uri)
if lurl.urlscheme == 'ldapi':
- wait_for_open_socket(lurl.hostport, timeout=6)
+ wait_for_open_socket(lurl.hostport, timeout=api.env.startup_timeout)
else:
(host,port) = lurl.hostport.split(':')
- wait_for_open_ports(host, [int(port)], timeout=6)
+ wait_for_open_ports(host, [int(port)], timeout=api.env.startup_timeout)
con = ldap.initialize(api.env.ldap_uri)
con.sasl_interactive_bind_s('', SASL_EXTERNAL)
res = con.search_st(base,
@@ -175,7 +179,7 @@ def ipa_start(options):
svc_list = []
try:
- svc_list = get_config()
+ svc_list = get_config(dirsrv)
except Exception, e:
emit_err("Failed to read data from Directory Service: " + str(e))
emit_err("Shutting down")
@@ -219,14 +223,14 @@ def ipa_stop(options):
dirsrv = ipaservices.knownservices.dirsrv
svc_list = []
try:
- svc_list = get_config()
+ svc_list = get_config(dirsrv)
except Exception, e:
# ok if dirsrv died this may fail, so let's try to quickly restart it
# and see if we can get anything. If not throw our hands up and just
# exit
try:
dirsrv.start(capture_output=False)
- svc_list = get_config()
+ svc_list = get_config(dirsrv)
except Exception, e:
emit_err("Failed to read data from Directory Service: " + str(e))
emit_err("Shutting down")
@@ -266,7 +270,7 @@ def ipa_restart(options):
svc_list = []
try:
- svc_list = get_config()
+ svc_list = get_config(dirsrv)
except Exception, e:
emit_err("Failed to read data from Directory Service: " + str(e))
emit_err("Shutting down")
@@ -318,7 +322,7 @@ def ipa_status(options):
svc_list = []
try:
- svc_list = get_config()
+ svc_list = get_config(dirsrv)
except IpactlError, e:
raise e
except Exception, e:
diff --git a/ipalib/constants.py b/ipalib/constants.py
index f503472c9b493c6dc4e2ef22281899565d99044d..ad6d188692aa3de70cf29d5662d84672054ab4ef 100644
--- a/ipalib/constants.py
+++ b/ipalib/constants.py
@@ -111,6 +111,8 @@ DEFAULT_CONFIG = (
('xmlrpc_uri', 'http://localhost:8888/ipa/xml'),
('rpc_json_uri', 'http://localhost:8888/ipa/json'),
('ldap_uri', 'ldap://localhost:389'),
+ # Time to wait for a service to start, in seconds
+ ('startup_timeout', 120),
# Web Application mount points
('mount_ipa', '/ipa/'),
diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
index 8884e7be92f800f02c4680fb62f5824c50eb0923..e80434cfd31ddb6112e83800aca9cf5440ffaff8 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -41,6 +41,7 @@ import re
import xmlrpclib
import datetime
import netaddr
+import time
from dns import resolver, rdatatype
from dns.exception import DNSException
@@ -1010,3 +1011,56 @@ def utf8_encode_values(values):
return map(utf8_encode_value, values)
else:
return utf8_encode_value(values)
+
+def wait_for_open_ports(host, ports, timeout=0):
+ """
+ Wait until the specified port(s) on the remote host are open. Timeout
+ in seconds may be specified to limit the wait.
+ """
+ if not isinstance(ports, (tuple, list)):
+ ports = [ports]
+
+ root_logger.debug('wait_for_open_ports: %s %s timeout %d' % (host, ports, timeout))
+ op_timeout = time.time() + timeout
+ ipv6_failover = False
+
+ for port in ports:
+ while True:
+ try:
+ if ipv6_failover:
+ s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
+ else:
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ s.connect((host, port))
+ s.close()
+ break
+ except socket.error, e:
+ if e.errno == 111: # 111: Connection refused
+ if timeout and time.time() > op_timeout: # timeout exceeded
+ raise e
+ time.sleep(1)
+ elif not ipv6_failover: # fallback to IPv6 connection
+ ipv6_failover = True
+ else:
+ raise e
+
+def wait_for_open_socket(socket_name, timeout=0):
+ """
+ Wait until the specified socket on the local host is open. Timeout
+ in seconds may be specified to limit the wait.
+ """
+ op_timeout = time.time() + timeout
+
+ while True:
+ try:
+ s = socket.socket(socket.AF_UNIX)
+ s.connect(socket_name)
+ s.close()
+ break
+ except socket.error, e:
+ if e.errno in (2,111): # 111: Connection refused, 2: File not found
+ if timeout and time.time() > op_timeout: # timeout exceeded
+ raise e
+ time.sleep(1)
+ else:
+ raise e
diff --git a/ipapython/platform/base.py b/ipapython/platform/base.py
index bf76b76303d221c07c93e7b41e586e06c622696f..6f9d3867ad48360727472f8c5231c030ce9d8bc2 100644
--- a/ipapython/platform/base.py
+++ b/ipapython/platform/base.py
@@ -18,29 +18,42 @@
from ipalib.plugable import MagicDict
-# Canonical names of services as IPA wants to see them. As we need to have *some* naming,
-# set them as in Red Hat distributions. Actual implementation should make them available
-# through knownservices.<name> and take care of remapping internally, if needed
+# Canonical names of services as IPA wants to see them. As we need to have
+# *some* naming, set them as in Red Hat distributions. Actual implementation
+# should make them available through knownservices.<name> and take care of
+# re-mapping internally, if needed
wellknownservices = ['certmonger', 'dirsrv', 'httpd', 'ipa', 'krb5kdc',
'messagebus', 'nslcd', 'nscd', 'ntpd', 'portmap',
'rpcbind', 'kadmin', 'sshd', 'autofs', 'rpcgssd',
'rpcidmapd']
+# The common ports for these services. This is used to wait for the
+# service to become available.
+wellknownports = {
+ 'dirsrv@PKI-IPA.service': [7389],
+ 'PKI-IPA': [7389],
+ 'dirsrv': [389], # this is only used if the incoming instance name is blank
+ 'pki-cad': [9180],
+}
+
class AuthConfig(object):
"""
AuthConfig class implements system-independent interface to configure
system authentication resources. In Red Hat systems this is done with
authconfig(8) utility.
- AuthConfig class is nothing more than a tool to gather configuration options
- and execute their processing. These options then converted by an actual implementation
- to series of a system calls to appropriate utilities performing real configuration.
+ AuthConfig class is nothing more than a tool to gather configuration
+ options and execute their processing. These options then converted by
+ an actual implementation to series of a system calls to appropriate
+ utilities performing real configuration.
- IPA *expects* names of AuthConfig's options to follow authconfig(8) naming scheme!
+ IPA *expects* names of AuthConfig's options to follow authconfig(8)
+ naming scheme!
- Actual implementation should be done in ipapython/platform/<platform>.py by inheriting from
- platform.AuthConfig and redefining __build_args() and execute() methods.
+ Actual implementation should be done in ipapython/platform/<platform>.py
+ by inheriting from platform.AuthConfig and redefining __build_args()
+ and execute() methods.
from ipapython.platform import platform
class PlatformAuthConfig(platform.AuthConfig):
@@ -53,9 +66,11 @@ class AuthConfig(object):
authconfig = PlatformAuthConfig
....
- See ipapython/platform/redhat.py for a sample implementation that uses authconfig(8) as its backend.
+ See ipapython/platform/redhat.py for a sample implementation that uses
+ authconfig(8) as its backend.
- From IPA code perspective, the authentication configuration should be done with use of ipapython.services.authconfig:
+ From IPA code perspective, the authentication configuration should be
+ done with use of ipapython.services.authconfig:
from ipapython import services as ipaservices
auth_config = ipaservices.authconfig()
@@ -69,8 +84,8 @@ class AuthConfig(object):
add_parameter("nisdomain","foobar")
auth_config.execute()
- If you need to re-use existing AuthConfig instance for multiple runs, make sure to
- call 'AuthConfig.reset()' between the runs.
+ If you need to re-use existing AuthConfig instance for multiple runs,
+ make sure to call 'AuthConfig.reset()' between the runs.
"""
def __init__(self):
@@ -106,21 +121,21 @@ class AuthConfig(object):
class PlatformService(object):
"""
- PlatformService abstracts out external process running on the system which is possible
- to administer (start, stop, check status, etc).
+ PlatformService abstracts out external process running on the system
+ which is possible to administer (start, stop, check status, etc).
"""
def __init__(self, service_name):
self.service_name = service_name
- def start(self, instance_name="", capture_output=True):
+ def start(self, instance_name="", capture_output=True, wait=True):
return
def stop(self, instance_name="", capture_output=True):
return
- def restart(self, instance_name="", capture_output=True):
+ def restart(self, instance_name="", capture_output=True, wait=True):
return
def is_running(self, instance_name=""):
@@ -149,8 +164,9 @@ class PlatformService(object):
class KnownServices(MagicDict):
"""
- KnownServices is an abstract class factory that should give out instances of well-known
- platform services. Actual implementation must create these instances as its own attributes
- on first access (or instance creation) and cache them.
+ KnownServices is an abstract class factory that should give out instances
+ of well-known platform services. Actual implementation must create these
+ instances as its own attributes on first access (or instance creation)
+ and cache them.
"""
diff --git a/ipapython/platform/fedora16.py b/ipapython/platform/fedora16.py
index 985d368f966b0c42222d3af8474e99edbe3477f9..8b730e41cbdd63bbe9d0c9cb7809d0f6d4de8fbb 100644
--- a/ipapython/platform/fedora16.py
+++ b/ipapython/platform/fedora16.py
@@ -98,7 +98,7 @@ class Fedora16DirectoryService(Fedora16Service):
restore_context(dirsrv_systemd)
ipautil.run(["/bin/systemctl", "--system", "daemon-reload"],raiseonerr=False)
- def restart(self, instance_name="", capture_output=True):
+ def restart(self, instance_name="", capture_output=True, wait=True):
if len(instance_name) > 0:
elements = self.service_name.split("@")
srv_etc = os.path.join(self.SYSTEMD_ETC_PATH, self.service_name)
@@ -109,7 +109,7 @@ class Fedora16DirectoryService(Fedora16Service):
elif not os.path.samefile(srv_etc, srv_lnk):
os.unlink(srv_lnk)
os.symlink(srv_etc, srv_lnk)
- super(Fedora16DirectoryService, self).restart(instance_name, capture_output=capture_output)
+ super(Fedora16DirectoryService, self).restart(instance_name, capture_output=capture_output, wait=wait)
# Enforce restart of IPA services when we do enable it
# This gets around the fact that after ipa-server-install systemd thinks
diff --git a/ipapython/platform/redhat.py b/ipapython/platform/redhat.py
index 28a43e588952090007bea979a2cf72d386aa51f9..d3c23ab0debbcfa58eefa9607fe5cac8fcbf592b 100644
--- a/ipapython/platform/redhat.py
+++ b/ipapython/platform/redhat.py
@@ -26,6 +26,7 @@ import sys
import socket
from ipapython import ipautil
from ipapython.platform import base
+from ipalib import api
# All what we allow exporting directly from this module
# Everything else is made available through these symbols when they are
@@ -46,14 +47,31 @@ from ipapython.platform import base
__all__ = ['authconfig', 'service', 'knownservices', 'backup_and_replace_hostname', 'restore_context', 'check_selinux_status']
class RedHatService(base.PlatformService):
+ def __wait_for_open_ports(self, instance_name=""):
+ """
+ If this is a service we need to wait for do so.
+ """
+ ports = None
+ if instance_name in base.wellknownports:
+ ports = base.wellknownports[instance_name]
+ else:
+ if self.service_name in base.wellknownports:
+ ports = base.wellknownports[self.service_name]
+ if ports:
+ ipautil.wait_for_open_ports('localhost', ports, api.env.startup_timeout)
+
def stop(self, instance_name="", capture_output=True):
ipautil.run(["/sbin/service", self.service_name, "stop", instance_name], capture_output=capture_output)
- def start(self, instance_name="", capture_output=True):
+ def start(self, instance_name="", capture_output=True, wait=True):
ipautil.run(["/sbin/service", self.service_name, "start", instance_name], capture_output=capture_output)
+ if wait and self.is_running(instance_name):
+ self.__wait_for_open_ports(instance_name)
- def restart(self, instance_name="", capture_output=True):
+ def restart(self, instance_name="", capture_output=True, wait=True):
ipautil.run(["/sbin/service", self.service_name, "restart", instance_name], capture_output=capture_output)
+ if wait and self.is_running(instance_name):
+ self.__wait_for_open_ports(instance_name)
def is_running(self, instance_name=""):
ret = True
diff --git a/ipapython/platform/systemd.py b/ipapython/platform/systemd.py
index ae06c0227aa59a46b2d4df024fc87577b8bbab29..a233e1045e225718353adbb9bf618a1d0b73c4ac 100644
--- a/ipapython/platform/systemd.py
+++ b/ipapython/platform/systemd.py
@@ -20,6 +20,7 @@
from ipapython import ipautil
from ipapython.platform import base
import sys, os, shutil
+from ipalib import api
class SystemdService(base.PlatformService):
SYSTEMD_ETC_PATH = "/etc/systemd/system/"
@@ -73,16 +74,34 @@ class SystemdService(base.PlatformService):
return (None,None)
return dict(map(lambda x: splitter(x, separator=separator), text.split("\n")))
+ def __wait_for_open_ports(self, instance_name=""):
+ """
+ If this is a service we need to wait for do so.
+ """
+ ports = None
+ if instance_name in base.wellknownports:
+ ports = base.wellknownports[instance_name]
+ else:
+ elements = self.service_name.split("@")
+ if elements[0] in base.wellknownports:
+ ports = base.wellknownports[elements[0]]
+ if ports:
+ ipautil.wait_for_open_ports('localhost', ports, api.env.startup_timeout)
+
def stop(self, instance_name="", capture_output=True):
ipautil.run(["/bin/systemctl", "stop", self.service_instance(instance_name)], capture_output=capture_output)
- def start(self, instance_name="", capture_output=True):
+ def start(self, instance_name="", capture_output=True, wait=True):
ipautil.run(["/bin/systemctl", "start", self.service_instance(instance_name)], capture_output=capture_output)
+ if wait and self.is_running(instance_name):
+ self.__wait_for_open_ports(self.service_instance(instance_name))
- def restart(self, instance_name="", capture_output=True):
+ def restart(self, instance_name="", capture_output=True, wait=True):
# Restart command is broken before systemd-36-3.fc16
# If you have older systemd version, restart of dependent services will hang systemd indefinetly
ipautil.run(["/bin/systemctl", "restart", self.service_instance(instance_name)], capture_output=capture_output)
+ if wait and self.is_running(instance_name):
+ self.__wait_for_open_ports(self.service_instance(instance_name))
def is_running(self, instance_name=""):
ret = True
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index af8d39aa524ee801fb1ff5b2b83bee65b1eacb70..62c1dc4d082df740f675d8447a7dd13d69f2ec88 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -681,7 +681,6 @@ class CAInstance(service.Service):
def __restart_instance(self):
try:
self.restart(PKI_INSTANCE_NAME)
- installutils.wait_for_open_ports('localhost', 9180, 300)
except Exception:
# TODO: roll back here?
root_logger.critical("Failed to restart the certificate server. See the installation log for details.")
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index d74ee8987a3387b78ec7203c9b8c70059b35a812..9c137af030e2d86fa3df3e0e987e57d75d53c5d4 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -416,7 +416,6 @@ class DsInstance(service.Service):
if not is_ds_running(instance):
root_logger.critical("Failed to restart the directory server. See the installation log for details.")
sys.exit(1)
- installutils.wait_for_open_ports('localhost', self.open_ports, 300)
except SystemExit, e:
raise e
except Exception, e:
@@ -667,7 +666,7 @@ class DsInstance(service.Service):
# (re)start them.
for ds_instance in get_ds_instances():
try:
- ipaservices.knownservices.dirsrv.restart(ds_instance)
+ ipaservices.knownservices.dirsrv.restart(ds_instance, wait=False)
except Exception, e:
root_logger.error('Unable to restart ds instance %s: %s', ds_instance, e)
diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py
index 313761777cddcbf5ad9dd134556d72931e51a2b3..b65958eda1b2b6da4db942d77bca63eee1c616f6 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -414,58 +414,6 @@ def create_keytab(path, principal):
kadmin("ktadd -k " + path + " " + principal)
-def wait_for_open_ports(host, ports, timeout=0):
- """
- Wait until the specified port(s) on the remote host are open. Timeout
- in seconds may be specified to limit the wait.
- """
- if not isinstance(ports, (tuple, list)):
- ports = [ports]
-
- op_timeout = time.time() + timeout
- ipv6_failover = False
-
- for port in ports:
- while True:
- try:
- if ipv6_failover:
- s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
- else:
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- s.connect((host, port))
- s.close()
- break;
- except socket.error, e:
- if e.errno == 111: # 111: Connection refused
- if timeout and time.time() > op_timeout: # timeout exceeded
- raise e
- time.sleep(1)
- elif not ipv6_failover: # fallback to IPv6 connection
- ipv6_failover = True
- else:
- raise e
-
-def wait_for_open_socket(socket_name, timeout=0):
- """
- Wait until the specified socket on the local host is open. Timeout
- in seconds may be specified to limit the wait.
- """
- op_timeout = time.time() + timeout
-
- while True:
- try:
- s = socket.socket(socket.AF_UNIX)
- s.connect(socket_name)
- s.close()
- break;
- except socket.error, e:
- if e.errno in (2,111): # 111: Connection refused, 2: File not found
- if timeout and time.time() > op_timeout: # timeout exceeded
- raise e
- time.sleep(1)
- else:
- raise e
-
def resolve_host(host_name):
try:
addrinfos = socket.getaddrinfo(host_name, None,
diff --git a/ipaserver/install/plugins/baseupdate.py b/ipaserver/install/plugins/baseupdate.py
index 227dc917aa14ddea898015ef8c16d084860c94df..f91cf5dece314f28bcfb5f4fa8de8716400136ae 100644
--- a/ipaserver/install/plugins/baseupdate.py
+++ b/ipaserver/install/plugins/baseupdate.py
@@ -34,6 +34,14 @@ class DSRestart(service.Service):
"""
service.Service.__init__(self, "dirsrv")
+ def start(self, instance_name="", capture_output=True, wait=True):
+ """
+ During upgrades the server is listening only on the socket so
+ we don't want to wait on ports. The caller is responsible for
+ waiting for the socket to be ready.
+ """
+ super(DSRestart, self).start(wait=False)
+
def create_instance(self):
self.step("stopping directory server", self.stop)
self.step("starting directory server", self.start)
diff --git a/ipaserver/install/plugins/updateclient.py b/ipaserver/install/plugins/updateclient.py
index 10d899abcad091a3396d4315d877b5656068775e..e237694711ea5f22d29c0b5ac52f161231951c2d 100644
--- a/ipaserver/install/plugins/updateclient.py
+++ b/ipaserver/install/plugins/updateclient.py
@@ -18,11 +18,11 @@
#
import os
-from ipaserver.install import installutils
from ipaserver.install.plugins import FIRST, MIDDLE, LAST
from ipaserver.install.plugins import POST_UPDATE
from ipaserver.install.plugins.baseupdate import DSRestart
from ipaserver.install.ldapupdate import LDAPUpdate
+from ipapython.ipautil import wait_for_open_socket
from ipalib import api
from ipalib import backend
import ldap as _ldap
@@ -161,7 +161,7 @@ class updateclient(backend.Executioner):
if live_run:
self.destroy_context()
dsrestart.create_instance()
- installutils.wait_for_open_socket(socket_name)
+ wait_for_open_socket(socket_name)
self.create_context(dm_password)
else:
self.log.warn("Test mode, skipping restart")
diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py
index 03758dfcbe302e1d437293f544677fca93e3b21f..417b7a0c5ee29615d2479842efc6862e39a7c3df 100644
--- a/ipaserver/install/replication.py
+++ b/ipaserver/install/replication.py
@@ -25,7 +25,6 @@ import sys
import ldap
from ipaserver import ipaldap
from ipapython import services as ipaservices
-import installutils
from ldap import modlist
from ipalib import api, util, errors
from ipapython import ipautil
@@ -92,7 +91,6 @@ def enable_replication_version_checking(hostname, realm, dirman_passwd):
conn.unbind()
serverid = "-".join(realm.split("."))
ipaservices.knownservices.dirsrv.restart(instance_name=serverid)
- installutils.wait_for_open_ports('localhost', [389, 636], 300)
else:
conn.unbind()
diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py
index 5cc7ae639db3fe2aa3805a90e0902f10f277064c..5c2699e3fa4c115c972528d4c2cc6aa170711837 100644
--- a/ipaserver/install/service.py
+++ b/ipaserver/install/service.py
@@ -35,6 +35,8 @@ from ipapython.ipa_log_manager import *
CACERT = "/etc/ipa/ca.crt"
+# The service name as stored in cn=masters,cn=ipa,cn=etc. In the tuple
+# the first value is the *nix service name, the second the start order.
SERVICE_LIST = {
'KDC':('krb5kdc', 10),
'KPASSWD':('kadmin', 20),
@@ -198,11 +200,11 @@ class Service(object):
def stop(self, instance_name="", capture_output=True):
self.service.stop(instance_name, capture_output=capture_output)
- def start(self, instance_name="", capture_output=True):
- self.service.start(instance_name, capture_output=capture_output)
+ def start(self, instance_name="", capture_output=True, wait=True):
+ self.service.start(instance_name, capture_output=capture_output, wait=wait)
- def restart(self, instance_name="", capture_output=True):
- self.service.restart(instance_name, capture_output=capture_output)
+ def restart(self, instance_name="", capture_output=True, wait=True):
+ self.service.restart(instance_name, capture_output=capture_output, wait=wait)
def is_running(self):
return self.service.is_running()
diff --git a/ipaserver/install/upgradeinstance.py b/ipaserver/install/upgradeinstance.py
index b04d92afcb31d66c3f4c98e80b1bc54d4887e518..f1f702b1c51eed0277fd4f02f5c1d4048292d894 100644
--- a/ipaserver/install/upgradeinstance.py
+++ b/ipaserver/install/upgradeinstance.py
@@ -60,6 +60,11 @@ class IPAUpgrade(service.Service):
self.badsyntax = False
self.upgradefailed = False
+ def start(self, instance_name="", capture_output=True, wait=True):
+ # Don't wait here because we've turned off port 389. The connection
+ # we make will wait for the socket.
+ super(IPAUpgrade, self).start(instance_name, capture_output, wait=False)
+
def create_instance(self):
self.step("stopping directory server", self.stop)
self.step("saving configuration", self.__save_config)
diff --git a/ipaserver/ipaldap.py b/ipaserver/ipaldap.py
index 8b5451c730f0a4cc72a597f934a940dc2b143a05..e4fa2c644c660e34a1d675497a22837255a36b75 100644
--- a/ipaserver/ipaldap.py
+++ b/ipaserver/ipaldap.py
@@ -36,10 +36,9 @@ from ldap.controls import LDAPControl
from ldap.ldapobject import SimpleLDAPObject
from ipapython import ipautil
from ipalib import errors
-from ipapython.ipautil import format_netloc
+from ipapython.ipautil import format_netloc, wait_for_open_socket, wait_for_open_ports
from ipapython.entity import Entity
from ipaserver.plugins.ldap2 import IPASimpleLDAPObject
-from ipaserver.install import installutils
# Global variable to define SASL auth
SASL_AUTH = ldap.sasl.sasl({},'GSSAPI')
@@ -337,10 +336,10 @@ class IPAdmin(IPAEntryLDAPObject):
def __wait_for_connection(self, timeout):
lurl = ldapurl.LDAPUrl(self._uri)
if lurl.urlscheme == 'ldapi':
- installutils.wait_for_open_socket(lurl.hostport, timeout)
+ wait_for_open_socket(lurl.hostport, timeout)
else:
(host,port) = lurl.hostport.split(':')
- installutils.wait_for_open_ports(host, int(port), timeout)
+ wait_for_open_ports(host, int(port), timeout)
def __bind_with_wait(self, bind_func, timeout, *args, **kwargs):
try:
--
1.7.11.2

View File

@ -0,0 +1,312 @@
From e88049ecee0bf5ca5741eaf94dd5a7341eec061e Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Wed, 4 Jul 2012 20:47:03 +0300
Subject: [PATCH 01/79] ipasam: improve SASL bind callback
SASL bind callback due to refactoring was referencing local variable which
didn't exist all the time. Fix that by including a copy of service principals
into ipasam long term private struct.
Rework ccache handling to avoid re-initing every time callback is called
---
daemons/ipa-sam/ipa_sam.c | 180 ++++++++++++++++++++++++++++++----------
install/share/smb.conf.template | 1 -
2 files changed, 137 insertions(+), 44 deletions(-)
diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c
index 9baac1b2d35a640c36fe7f95a6154ec8582649d8..1f2d94ed4da552a7f4ede443fe9944839c633e59 100644
--- a/daemons/ipa-sam/ipa_sam.c
+++ b/daemons/ipa-sam/ipa_sam.c
@@ -177,6 +177,8 @@ struct ipasam_privates {
char *trust_dn;
char *flat_name;
char *fallback_primary_group;
+ char *server_princ;
+ char *client_princ;
};
static LDAP *priv2ld(struct ldapsam_privates *priv)
@@ -3125,12 +3127,20 @@ static int ldap_sasl_interact(LDAP *ld, unsigned flags, void *priv_data, void *s
return ret;
}
-static void bind_callback_cleanup(struct ipasam_sasl_interact_priv *data)
+static void bind_callback_cleanup(struct ipasam_sasl_interact_priv *data, krb5_error_code rc)
{
+ const char *errstring = NULL;
+
if (!data->context) {
return;
}
+ if (rc) {
+ errstring = krb5_get_error_message(data->context, rc);
+ DEBUG(0,("kerberos error: code=%d, message=%s\n", rc, errstring));
+ krb5_free_error_message(data->context, errstring);
+ }
+
krb5_free_cred_contents(data->context, &data->creds);
if (data->options) {
@@ -3157,22 +3167,27 @@ static void bind_callback_cleanup(struct ipasam_sasl_interact_priv *data)
data->context = NULL;
}
-extern const char *lp_parm_const_string(int snum, const char *type, const char *option, const char *def);
-static int bind_callback(LDAP *ldap_struct, struct smbldap_state *ldap_state, void* ipasam_principal)
+static int bind_callback(LDAP *ldap_struct, struct smbldap_state *ldap_state, void* ipasam_priv)
{
- char *ccache_name = NULL;
krb5_error_code rc;
+ krb5_creds *out_creds = NULL;
+ krb5_creds in_creds;
struct ipasam_sasl_interact_priv data;
+ struct ipasam_privates *ipasam_private = NULL;
int ret;
memset(&data, 0, sizeof(struct ipasam_sasl_interact_priv));
- data.name = (const char*)ipasam_principal;
- if (data.name == NULL) {
- DEBUG(0, ("bind_callback: ipasam:principal is not set, cannot use GSSAPI bind\n"));
+ memset(&in_creds, 0, sizeof(krb5_creds));
+
+ ipasam_private = (struct ipasam_privates*)ipasam_priv;
+
+ if ((ipasam_private->client_princ == NULL) || (ipasam_private->server_princ == NULL)) {
+ DEBUG(0, ("bind_callback: ipasam service principals are not set, cannot use GSSAPI bind\n"));
return LDAP_LOCAL_ERROR;
}
+ data.name = ipasam_private->client_princ;
data.name_len = strlen(data.name);
rc = krb5_init_context(&data.context);
@@ -3182,60 +3197,60 @@ static int bind_callback(LDAP *ldap_struct, struct smbldap_state *ldap_state, vo
rc = krb5_parse_name(data.context, data.name, &data.principal);
if (rc) {
- bind_callback_cleanup(&data);
+ bind_callback_cleanup(&data, rc);
return LDAP_LOCAL_ERROR;
}
rc = krb5_cc_default(data.context, &data.ccache);
- if (rc) {
- bind_callback_cleanup(&data);
- return LDAP_LOCAL_ERROR;
- }
-
- rc = krb5_cc_initialize(data.context, data.ccache, data.principal);
- if (rc) {
- bind_callback_cleanup(&data);
- return LDAP_LOCAL_ERROR;
- }
-
- rc = krb5_cc_get_full_name(data.context, data.ccache, &ccache_name);
- if (rc) {
- if (ccache_name) {
- krb5_free_string(data.context, ccache_name);
- }
- bind_callback_cleanup(&data);
- return LDAP_LOCAL_ERROR;
- }
- rc = krb5_cc_set_default_name(data.context, ccache_name);
if (rc) {
- bind_callback_cleanup(&data);
+ bind_callback_cleanup(&data, rc);
return LDAP_LOCAL_ERROR;
}
rc = krb5_kt_resolve(data.context, "FILE:/etc/samba/samba.keytab", &data.keytab);
if (rc) {
- bind_callback_cleanup(&data);
+ bind_callback_cleanup(&data, rc);
return LDAP_LOCAL_ERROR;
}
- rc = krb5_get_init_creds_opt_alloc(data.context, &data.options);
+ rc = krb5_parse_name(data.context, ipasam_private->client_princ, &in_creds.client);
if (rc) {
- bind_callback_cleanup(&data);
+ krb5_free_principal(data.context, data.creds.client);
+ bind_callback_cleanup(&data, rc);
return LDAP_LOCAL_ERROR;
}
- rc = krb5_get_init_creds_opt_set_out_ccache(data.context, data.options, data.ccache);
+ rc = krb5_parse_name(data.context, ipasam_private->server_princ, &in_creds.server);
if (rc) {
- bind_callback_cleanup(&data);
+ krb5_free_principal(data.context, in_creds.server);
+ bind_callback_cleanup(&data, rc);
return LDAP_LOCAL_ERROR;
}
- rc = krb5_get_init_creds_keytab(data.context, &data.creds, data.principal, data.keytab,
- 0, NULL, data.options);
+ rc = krb5_get_credentials(data.context, KRB5_GC_CACHED, data.ccache, &in_creds, &out_creds);
+ krb5_free_principal(data.context, in_creds.server);
+ krb5_free_principal(data.context, in_creds.client);
+
if (rc) {
- bind_callback_cleanup(&data);
- return LDAP_LOCAL_ERROR;
+ rc = krb5_get_init_creds_opt_alloc(data.context, &data.options);
+ if (rc) {
+ bind_callback_cleanup(&data, rc);
+ return LDAP_LOCAL_ERROR;
+ }
+
+ rc = krb5_get_init_creds_opt_set_out_ccache(data.context, data.options, data.ccache);
+ if (rc) {
+ bind_callback_cleanup(&data, rc);
+ return LDAP_LOCAL_ERROR;
+ }
+
+ rc = krb5_get_init_creds_keytab(data.context, &data.creds, data.principal, data.keytab,
+ 0, NULL, data.options);
+ if (rc) {
+ bind_callback_cleanup(&data, rc);
+ return LDAP_LOCAL_ERROR;
+ }
}
ret = ldap_sasl_interactive_bind_s(ldap_struct,
@@ -3247,10 +3262,90 @@ static int bind_callback(LDAP *ldap_struct, struct smbldap_state *ldap_state, vo
DEBUG(0, ("bind_callback: cannot perform interactive SASL bind with GSSAPI\n"));
}
- bind_callback_cleanup(&data);
+ if (out_creds) {
+ krb5_free_creds(data.context, out_creds);
+ }
+ bind_callback_cleanup(&data, 0);
return ret;
}
+static NTSTATUS ipasam_generate_principals(struct ipasam_privates *privates) {
+
+ krb5_error_code rc;
+ int ret;
+ krb5_context context;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ char hostname[255];
+ char *default_realm = NULL;
+
+ if (!privates) {
+ return status;
+ }
+
+ rc = krb5_init_context(&context);
+ if (rc) {
+ return status;
+ }
+
+ ret = gethostname(hostname, sizeof(hostname));
+ if (ret == -1) {
+ DEBUG(1, ("gethostname failed.\n"));
+ goto done;
+ }
+ hostname[sizeof(hostname)-1] = '\0';
+
+ rc = krb5_get_default_realm(context, &default_realm);
+ if (rc) {
+ goto done;
+ };
+
+ if (privates->client_princ) {
+ talloc_free(privates->client_princ);
+ privates->client_princ = NULL;
+ }
+
+ privates->client_princ = talloc_asprintf(privates,
+ "cifs/%s@%s",
+ hostname,
+ default_realm);
+
+ if (privates->client_princ == NULL) {
+ DEBUG(0, ("Failed to create ipasam client principal.\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ if (privates->server_princ) {
+ talloc_free(privates->server_princ);
+ privates->server_princ = NULL;
+ }
+
+ privates->server_princ = talloc_asprintf(privates,
+ "ldap/%s@%s",
+ hostname,
+ default_realm);
+
+ if (privates->server_princ == NULL) {
+ DEBUG(0, ("Failed to create ipasam server principal.\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ status = NT_STATUS_OK;
+
+done:
+
+ if (default_realm) {
+ krb5_free_default_realm(context, default_realm);
+ }
+
+ if (context) {
+ krb5_free_context(context);
+ }
+ return status;
+}
+
+
static NTSTATUS pdb_init_ipasam(struct pdb_methods **pdb_method,
const char *location)
{
@@ -3263,7 +3358,6 @@ static NTSTATUS pdb_init_ipasam(struct pdb_methods **pdb_method,
struct dom_sid ldap_domain_sid;
char *bind_dn = NULL;
char *bind_secret = NULL;
- const char *service_principal = NULL;
LDAPMessage *result = NULL;
LDAPMessage *entry = NULL;
@@ -3293,9 +3387,9 @@ static NTSTATUS pdb_init_ipasam(struct pdb_methods **pdb_method,
}
trim_char( uri, '\"', '\"' );
- service_principal = lp_parm_const_string(-1, "ipasam", "principal", NULL);
+ status = ipasam_generate_principals(ldap_state->ipasam_privates);
- if (service_principal == NULL) {
+ if (!NT_STATUS_IS_OK(status)) {
if (!fetch_ldap_pw(&bind_dn, &bind_secret)) {
DEBUG(0, ("pdb_init_ipasam: Failed to retrieve LDAP password from secrets.tdb\n"));
return NT_STATUS_NO_MEMORY;
@@ -3310,7 +3404,7 @@ static NTSTATUS pdb_init_ipasam(struct pdb_methods **pdb_method,
&ldap_state->smbldap_state);
if (NT_STATUS_IS_OK(status)) {
ldap_state->smbldap_state->bind_callback = bind_callback;
- ldap_state->smbldap_state->bind_callback_data = service_principal;
+ ldap_state->smbldap_state->bind_callback_data = ldap_state->ipasam_privates;
}
}
diff --git a/install/share/smb.conf.template b/install/share/smb.conf.template
index 3107350aa6e94514354b73f0152846e1d01e1e68..086b0fcfe5cff2bc3582f2a89962a99c9095b4bb 100644
--- a/install/share/smb.conf.template
+++ b/install/share/smb.conf.template
@@ -18,7 +18,6 @@ ldap suffix = $SUFFIX
ldap user suffix = cn=users,cn=accounts
ldap group suffix = cn=groups,cn=accounts
ldap machine suffix = cn=computers,cn=accounts
-ipasam:principal = cifs/$FQDN@$REALM
rpc_server:epmapper = external
rpc_server:lsarpc = external
rpc_server:lsass = external
--
1.7.11.2

View File

@ -0,0 +1,24 @@
From 7fb9ca23a1e9f80aca3d23bb4a52a1428f4fb79d Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 4 Jul 2012 12:15:05 +0200
Subject: [PATCH 02/79] Allow silent build if available
---
daemons/configure.ac | 1 +
1 file changed, 1 insertion(+)
diff --git a/daemons/configure.ac b/daemons/configure.ac
index b94673026a2c6b71670a67b1f629d9960d8fad31..ebf625ebffd8a92e0a3b050955b9376e002ed6c9 100644
--- a/daemons/configure.ac
+++ b/daemons/configure.ac
@@ -7,6 +7,7 @@ AC_INIT([ipa-server],
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([foreign])
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES])
AM_MAINTAINER_MODE
AC_PROG_CC
--
1.7.11.2

View File

@ -0,0 +1,120 @@
From abe40284cf5dda1e34e3ba73711448f61eea67b9 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 4 Jul 2012 16:18:21 +0200
Subject: [PATCH 03/79] ipasam: fixes for clang warnings
---
daemons/ipa-sam/ipa_sam.c | 48 ++++++++++++++++++++---------------------------
1 file changed, 20 insertions(+), 28 deletions(-)
diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c
index 1f2d94ed4da552a7f4ede443fe9944839c633e59..50d2b0ea7432db262faf867b5a2265a38669e189 100644
--- a/daemons/ipa-sam/ipa_sam.c
+++ b/daemons/ipa-sam/ipa_sam.c
@@ -100,19 +100,6 @@ bool sid_peek_check_rid(const struct dom_sid *exp_dom_sid, const struct dom_sid
char *escape_ldap_string(TALLOC_CTX *mem_ctx, const char *s); /* available in libsmbconf.so */
extern const struct dom_sid global_sid_Builtin; /* available in libsecurity.so */
bool secrets_store(const char *key, const void *data, size_t size); /* available in libpdb.so */
-/* from smb_macros.h */
-#define SMB_REALLOC_ARRAY(p,type,count) (type *)realloc_array((p),sizeof(type),(count),true) /* Always frees p on error or s == 0 */
-#define ADD_TO_ARRAY(mem_ctx, type, elem, array, num) \
-do { \
- *(array) = ((mem_ctx) != NULL) ? \
- talloc_realloc(mem_ctx, (*(array)), type, (*(num))+1) : \
- SMB_REALLOC_ARRAY((*(array)), type, (*(num))+1); \
- SMB_ASSERT((*(array)) != NULL); \
- (*(array))[*(num)] = (elem); \
- (*(num)) += 1; \
-} while (0)
-
-
#define LDAP_SUFFIX "dc=ipa,dc=devel" /* FIXME !!! */
#define LDAP_PAGE_SIZE 1024
#define LDAP_OBJ_SAMBASAMACCOUNT "ipaNTUserAttrs"
@@ -1217,8 +1204,6 @@ static bool ldapsam_search_grouptype(struct pdb_methods *methods,
return false;
}
- state->connection = ldap_state->smbldap_state;
-
state->base = talloc_strdup(search, LDAP_SUFFIX);
state->connection = ldap_state->smbldap_state;
state->scope = LDAP_SCOPE_SUBTREE;
@@ -1403,7 +1388,9 @@ static int set_cross_realm_pw(struct ldapsam_privates *ldap_state,
goto done;
}
- ret = create_keys(krbctx, service_princ, discard_const(pwd), NULL, &keys, &err_msg);
+ ret = create_keys(krbctx, service_princ, discard_const(pwd), NULL,
+ &keys, &err_msg);
+ krb5_free_principal(krbctx, service_princ);
if (!ret) {
if (err_msg != NULL) {
DEBUG(1, ("create_keys returned [%s]\n", err_msg));
@@ -1438,7 +1425,6 @@ done:
ber_bvfree(reqdata);
}
free_keys_contents(krbctx, &keys);
- krb5_free_principal(krbctx, service_princ);
krb5_free_context(krbctx);
return ret;
@@ -2246,6 +2232,7 @@ static NTSTATUS ipasam_enum_trusted_domains(struct pdb_methods *methods,
int scope = LDAP_SCOPE_SUBTREE;
LDAPMessage *result = NULL;
LDAPMessage *entry = NULL;
+ struct pdb_trusted_domain **tmp;
filter = talloc_asprintf(mem_ctx, "(objectClass=%s)",
LDAP_OBJ_TRUSTED_DOMAIN);
@@ -2286,16 +2273,20 @@ static NTSTATUS ipasam_enum_trusted_domains(struct pdb_methods *methods,
if (!fill_pdb_trusted_domain(*domains, ldap_state, entry,
&dom_info)) {
+ talloc_free(*domains);
return NT_STATUS_UNSUCCESSFUL;
}
- ADD_TO_ARRAY(*domains, struct pdb_trusted_domain *, dom_info,
- domains, num_domains);
-
- if (*domains == NULL) {
- DEBUG(1, ("talloc failed\n"));
+ tmp = talloc_realloc(*domains, *domains,
+ struct pdb_trusted_domain *,
+ (*(num_domains))+1);
+ if (tmp == NULL) {
+ talloc_free(*domains);
return NT_STATUS_NO_MEMORY;
}
+ *domains = tmp;
+ (*(domains))[*(num_domains)] = dom_info;
+ (*(num_domains)) += 1;
}
DEBUG(5, ("ipasam_enum_trusted_domains: got %d domains\n", *num_domains));
@@ -2700,14 +2691,15 @@ static bool ipasam_get_trusteddom_pw(struct pdb_methods *methods,
goto done;
}
+ status = get_trust_pwd(tmp_ctx, &td->trust_auth_incoming,
+ &trustpw, &last_update);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ goto done;
+ }
+
/* trusteddom_pw routines do not use talloc yet... */
if (pwd != NULL) {
- status = get_trust_pwd(tmp_ctx, &td->trust_auth_incoming,
- &trustpw, &last_update);
- if (!NT_STATUS_IS_OK(status)) {
- ret = false;
- goto done;
- }
*pwd = strdup(trustpw);
memset(trustpw, 0, strlen(trustpw));
talloc_free(trustpw);
--
1.7.11.2

View File

@ -0,0 +1,50 @@
From 76d809574bfb43cba2248225870644937546e33e Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 4 Jul 2012 16:19:03 +0200
Subject: [PATCH 04/79] ipasam: replace testing code
---
daemons/ipa-sam/ipa_sam.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c
index 50d2b0ea7432db262faf867b5a2265a38669e189..153733dbfea35cf1426f73827fb83753c259491b 100644
--- a/daemons/ipa-sam/ipa_sam.c
+++ b/daemons/ipa-sam/ipa_sam.c
@@ -100,7 +100,7 @@ bool sid_peek_check_rid(const struct dom_sid *exp_dom_sid, const struct dom_sid
char *escape_ldap_string(TALLOC_CTX *mem_ctx, const char *s); /* available in libsmbconf.so */
extern const struct dom_sid global_sid_Builtin; /* available in libsecurity.so */
bool secrets_store(const char *key, const void *data, size_t size); /* available in libpdb.so */
-#define LDAP_SUFFIX "dc=ipa,dc=devel" /* FIXME !!! */
+
#define LDAP_PAGE_SIZE 1024
#define LDAP_OBJ_SAMBASAMACCOUNT "ipaNTUserAttrs"
#define LDAP_OBJ_TRUSTED_DOMAIN "ipaNTTrustedDomain"
@@ -1045,12 +1045,12 @@ static bool ldapsam_search_users(struct pdb_methods *methods,
state->connection = ldap_state->smbldap_state;
if ((acct_flags != 0) && ((acct_flags & ACB_NORMAL) != 0))
- state->base = LDAP_SUFFIX;
+ state->base = ldap_state->ipasam_privates->base_dn;
else if ((acct_flags != 0) &&
((acct_flags & (ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST)) != 0))
- state->base = LDAP_SUFFIX;
+ state->base = ldap_state->ipasam_privates->base_dn;
else
- state->base = LDAP_SUFFIX;
+ state->base = ldap_state->ipasam_privates->base_dn;
state->acct_flags = acct_flags;
state->base = talloc_strdup(search, state->base);
@@ -1204,7 +1204,7 @@ static bool ldapsam_search_grouptype(struct pdb_methods *methods,
return false;
}
- state->base = talloc_strdup(search, LDAP_SUFFIX);
+ state->base = talloc_strdup(search, ldap_state->ipasam_privates->base_dn);
state->connection = ldap_state->smbldap_state;
state->scope = LDAP_SCOPE_SUBTREE;
state->filter = talloc_asprintf(search, "(&(objectclass=%s)"
--
1.7.11.2

View File

@ -0,0 +1,34 @@
From 75cb9bb0e15f31940576e3a366b58a340c6953d8 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Fri, 6 Jul 2012 12:43:50 +0300
Subject: [PATCH 05/79] Use smb.conf 'dedicated keytab file' parameter instead
of hard-coded value
---
daemons/ipa-sam/ipa_sam.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c
index 153733dbfea35cf1426f73827fb83753c259491b..29fc95e457179716c1c70c6f061b1cde9e3f472b 100644
--- a/daemons/ipa-sam/ipa_sam.c
+++ b/daemons/ipa-sam/ipa_sam.c
@@ -3159,6 +3159,7 @@ static void bind_callback_cleanup(struct ipasam_sasl_interact_priv *data, krb5_e
data->context = NULL;
}
+extern const char * lp_dedicated_keytab_file(void);
static int bind_callback(LDAP *ldap_struct, struct smbldap_state *ldap_state, void* ipasam_priv)
{
krb5_error_code rc;
@@ -3200,7 +3201,7 @@ static int bind_callback(LDAP *ldap_struct, struct smbldap_state *ldap_state, vo
return LDAP_LOCAL_ERROR;
}
- rc = krb5_kt_resolve(data.context, "FILE:/etc/samba/samba.keytab", &data.keytab);
+ rc = krb5_kt_resolve(data.context, lp_dedicated_keytab_file(), &data.keytab);
if (rc) {
bind_callback_cleanup(&data, rc);
return LDAP_LOCAL_ERROR;
--
1.7.11.2

View File

@ -0,0 +1,35 @@
From 8c5504d26ac3a2bbbb2cc9112eece70dac22a658 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Fri, 6 Jul 2012 12:48:27 +0300
Subject: [PATCH 06/79] reduce redundant checks in ldapsam_search_users() to a
single statement
---
daemons/ipa-sam/ipa_sam.c | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c
index 29fc95e457179716c1c70c6f061b1cde9e3f472b..86ed3fbd3e6d1894fd398c3c1c94d34c2b7ec273 100644
--- a/daemons/ipa-sam/ipa_sam.c
+++ b/daemons/ipa-sam/ipa_sam.c
@@ -1044,16 +1044,9 @@ static bool ldapsam_search_users(struct pdb_methods *methods,
state->connection = ldap_state->smbldap_state;
- if ((acct_flags != 0) && ((acct_flags & ACB_NORMAL) != 0))
- state->base = ldap_state->ipasam_privates->base_dn;
- else if ((acct_flags != 0) &&
- ((acct_flags & (ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST)) != 0))
- state->base = ldap_state->ipasam_privates->base_dn;
- else
- state->base = ldap_state->ipasam_privates->base_dn;
+ state->base = talloc_strdup(search, ldap_state->ipasam_privates->base_dn);
state->acct_flags = acct_flags;
- state->base = talloc_strdup(search, state->base);
state->scope = LDAP_SCOPE_SUBTREE;
state->filter = get_ldap_filter(search, "*");
state->attrs = talloc_attrs(search, "uid", LDAP_ATTRIBUTE_SID,
--
1.7.11.2

View File

@ -0,0 +1,32 @@
From 61c3b86d734389b2cd77b73030bd5293111e2cc5 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvoborni@redhat.com>
Date: Wed, 4 Jul 2012 15:15:10 +0200
Subject: [PATCH 07/79] Moved configuration to last position in navigation
Configaration was the last navigation item in IPA server tab. Trusts changed it. It was wrong because configuration is like 'other settings' and so it should be last.
This patch moves configuration navigation item to the last position again.
https://fedorahosted.org/freeipa/ticket/2900
---
install/ui/webui.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/install/ui/webui.js b/install/ui/webui.js
index 9b7c31be4c4f5edd2f3bd4bfab3559a5cb2aef4c..0be4b1b630888010f6c0e5dc95307acc335a47f6 100644
--- a/install/ui/webui.js
+++ b/install/ui/webui.js
@@ -84,8 +84,8 @@ IPA.admin_navigation = function(spec) {
]},
{entity: 'selfservice'},
{entity: 'delegation'},
- {entity: 'config'},
- {entity: 'trust'}
+ {entity: 'trust'},
+ {entity: 'config'}
]}];
var that = IPA.navigation(spec);
--
1.7.11.2

View File

@ -0,0 +1,25 @@
From 6ffb35d0f592414226d4ba4fd3620569e77c20ca Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce@redhat.com>
Date: Fri, 6 Jul 2012 16:11:32 -0400
Subject: [PATCH 08/79] Fix wrong check after allocation.
---
daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_encoding.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_encoding.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_encoding.c
index 5720d3e6e0a7e6b1520e51a5ee319bcc47354fc9..9c1623a3b28932fba48c878dc6084862a2ba7831 100644
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_encoding.c
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_encoding.c
@@ -446,7 +446,7 @@ int ipapwd_gen_hashes(struct ipapwd_krbcfg *krbcfg,
if (is_ipant) {
*ntvals = (Slapi_Value **)calloc(2, sizeof(Slapi_Value *));
- if (!svals) {
+ if (!*ntvals) {
LOG_OOM();
rc = LDAP_OPERATIONS_ERROR;
goto done;
--
1.7.11.2

View File

@ -0,0 +1,26 @@
From 0ffb2022fe2c485fce99c335e6b5f1f8c768152c Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Tue, 26 Jun 2012 09:58:01 +0200
Subject: [PATCH 09/79] Fix typo
Signed-off-by: Simo Sorce <ssorce@redhat.com>
---
daemons/ipa-kdb/ipa_kdb_mspac.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
index f640b545a636a2c58e3eb31951de142e5b0ffbe2..1c7487c3c8f75d02466a2e0746fbef5d36e3d995 100644
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
@@ -1267,7 +1267,7 @@ krb5_error_code ipadb_sign_authdata(krb5_context context,
kerr = krb5_encode_authdata_container(context,
KRB5_AUTHDATA_IF_RELEVANT,
- &authdata,
+ authdata,
signed_auth_data);
if (kerr != 0) {
goto done;
--
1.7.11.2

View File

@ -0,0 +1,35 @@
From 5ba8eeb970a8a72ec189e80e369bb7f70091e409 Mon Sep 17 00:00:00 2001
From: Martin Kosek <mkosek@redhat.com>
Date: Mon, 9 Jul 2012 14:27:07 +0200
Subject: [PATCH 10/79] Do not change LDAPObject objectclass list
__json__ method of LDAPObject may inadvertently append a list of possible
objectclasses to a list of basic objectclasses and thus change a behavior
of all subsequent LDAPSearch command. The command may only return objects
where all "possible" objectclasses are present and thus returning an
incomplete list.
Make sure that the LDAPObject object_class list is not modified during
the __json__ method.
https://fedorahosted.org/freeipa/ticket/2906
---
ipalib/plugins/baseldap.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py
index b841435fdcb5e28195fd38a6792233fdc4b7e32a..6a37995c57cd9d57280186d15f209426aa0776f2 100644
--- a/ipalib/plugins/baseldap.py
+++ b/ipalib/plugins/baseldap.py
@@ -635,7 +635,7 @@ class LDAPObject(Object):
objectclasses = config.get(
self.object_class_config, objectclasses
)
- objectclasses += self.possible_objectclasses
+ objectclasses = objectclasses + self.possible_objectclasses
# Get list of available attributes for this object for use
# in the ACI UI.
attrs = self.api.Backend.ldap2.schema.attribute_types(objectclasses)
--
1.7.11.2

View File

@ -0,0 +1,319 @@
From 29fd982f7f3bf4b94a8420fdfb307ed9c43c515c Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Tue, 3 Jul 2012 17:37:22 -0400
Subject: [PATCH 11/79] Make client server option multi-valued, allow
disabling DNS discovery
Let the --server option be specified multiple times on the command line.
The first one passed in is the one we enroll against.
Do additional verification before setting dnsok so we can be sure that
the record(s) were actually discovered in DNS.
If servers are provided on the CLI and --fixed-primary is set then
_srv_ is not added to ipa_server in sssd.conf.
https://fedorahosted.org/freeipa/ticket/2841
---
ipa-client/ipa-install/ipa-client-install | 101 +++++++++++++++++++-----------
ipa-client/ipaclient/ipadiscovery.py | 3 +
ipa-client/man/ipa-client-install.1 | 4 +-
3 files changed, 70 insertions(+), 38 deletions(-)
diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install
index 4b8d826ddad4bdee3b352833225768fa8c5f05b5..ef0dc293c994cdf8165a610f0701ade5b14942e6 100755
--- a/ipa-client/ipa-install/ipa-client-install
+++ b/ipa-client/ipa-install/ipa-client-install
@@ -65,7 +65,7 @@ def parse_options():
basic_group = OptionGroup(parser, "basic options")
basic_group.add_option("--domain", dest="domain", help="domain name")
- basic_group.add_option("--server", dest="server", help="IPA server")
+ basic_group.add_option("--server", dest="server", help="IPA server", action="append")
basic_group.add_option("--realm", dest="realm_name", help="realm name")
basic_group.add_option("--fixed-primary", dest="primary", action="store_true",
default=False, help="Configure sssd to use fixed server as primary IPA server")
@@ -487,8 +487,8 @@ def configure_ipa_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server):
defopts = [{'name':'basedn', 'type':'option', 'value':cli_basedn},
{'name':'realm', 'type':'option', 'value':cli_realm},
{'name':'domain', 'type':'option', 'value':cli_domain},
- {'name':'server', 'type':'option', 'value':cli_server},
- {'name':'xmlrpc_uri', 'type':'option', 'value':'https://%s/ipa/xml' % ipautil.format_netloc(cli_server)},
+ {'name':'server', 'type':'option', 'value':cli_server[0]},
+ {'name':'xmlrpc_uri', 'type':'option', 'value':'https://%s/ipa/xml' % ipautil.format_netloc(cli_server[0])},
{'name':'enable_ra', 'type':'option', 'value':'True'}]
opts.append({'name':'global', 'type':'section', 'value':defopts})
@@ -525,7 +525,7 @@ def configure_ldap_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server, d
if options.on_master:
opts.append({'name':'uri', 'type':'option', 'value':'ldap://localhost'})
else:
- opts.append({'name':'uri', 'type':'option', 'value':'ldap://'+ipautil.format_netloc(cli_server)})
+ opts.append({'name':'uri', 'type':'option', 'value':'ldap://'+ipautil.format_netloc(cli_server[0])})
else:
opts.append({'name':'nss_srv_domain', 'type':'option', 'value':cli_domain})
@@ -564,7 +564,7 @@ def configure_nslcd_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server,
if options.on_master:
opts.append({'name':'uri', 'type':'option', 'value':'ldap://localhost'})
else:
- opts.append({'name':'uri', 'type':'option', 'value':'ldap://'+ipautil.format_netloc(cli_server)})
+ opts.append({'name':'uri', 'type':'option', 'value':'ldap://'+ipautil.format_netloc(cli_server[0])})
else:
opts.append({'name':'uri', 'type':'option', 'value':'DNS'})
@@ -604,7 +604,7 @@ def configure_openldap_conf(fstore, cli_basedn, cli_server):
opts = [{'name':'comment', 'type':'comment', 'value':'File modified by ipa-client-install'},
{'name':'empty', 'type':'empty'},
- {'name':'URI', 'type':'option', 'value':'ldaps://'+ cli_server},
+ {'name':'URI', 'type':'option', 'value':'ldaps://'+ cli_server[0]},
{'name':'BASE', 'type':'option', 'value':cli_basedn},
{'name':'TLS_CACERT', 'type':'option', 'value':'/etc/ipa/ca.crt'},
{'name':'empty', 'type':'empty'}]
@@ -625,13 +625,13 @@ def hardcode_ldap_server(cli_server):
ldapconf = ipaclient.ipachangeconf.IPAChangeConf("IPA Installer")
ldapconf.setOptionAssignment(" ")
- opts = [{'name':'uri', 'type':'option', 'action':'set', 'value':'ldap://'+ipautil.format_netloc(cli_server)},
+ opts = [{'name':'uri', 'type':'option', 'action':'set', 'value':'ldap://'+ipautil.format_netloc(cli_server[0])},
{'name':'empty', 'type':'empty'}]
# Errors raised by this should be caught by the caller
ldapconf.changeConf("/etc/ldap.conf", opts)
root_logger.info("Changed configuration of /etc/ldap.conf to use " +
- "hardcoded server name: %s", cli_server)
+ "hardcoded server name: %s", cli_server[0])
return
@@ -662,13 +662,13 @@ def configure_krb5_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server, c
opts.append({'name':'empty', 'type':'empty'})
#the following are necessary only if DNS discovery does not work
+ kropts = []
if not dnsok or not cli_kdc or options.force:
#[realms]
- kropts =[{'name':'kdc', 'type':'option', 'value':ipautil.format_netloc(cli_server, 88)},
- {'name':'admin_server', 'type':'option', 'value':ipautil.format_netloc(cli_server, 749)},
- {'name':'default_domain', 'type':'option', 'value':cli_domain}]
- else:
- kropts = []
+ for server in cli_server:
+ kropts.append({'name':'kdc', 'type':'option', 'value':ipautil.format_netloc(server, 88)})
+ kropts.append({'name':'admin_server', 'type':'option', 'value':ipautil.format_netloc(server, 749)})
+ kropts.append({'name':'default_domain', 'type':'option', 'value':cli_domain})
kropts.append({'name':'pkinit_anchors', 'type':'option', 'value':'FILE:/etc/ipa/ca.crt'})
ropts = [{'name':cli_realm, 'type':'subsection', 'value':kropts}]
@@ -814,12 +814,12 @@ def configure_sssd_conf(fstore, cli_realm, cli_domain, cli_server, options, clie
if not options.on_master:
if options.primary:
- domain.set_option('ipa_server', '%s, _srv_' % cli_server)
+ domain.set_option('ipa_server', ', '.join(cli_server))
else:
- domain.set_option('ipa_server', '_srv_, %s' % cli_server)
+ domain.set_option('ipa_server', '_srv_, %s' % ', '.join(cli_server))
else:
# the master should only use itself for Kerberos
- domain.set_option('ipa_server', cli_server)
+ domain.set_option('ipa_server', cli_server[0])
domain.set_option('ipa_domain', cli_domain)
domain.set_option('ipa_hostname', client_hostname)
if cli_domain.lower() != cli_realm.lower():
@@ -1169,6 +1169,8 @@ def install(options, env, fstore, statestore):
# Create the discovery instance
ds = ipadiscovery.IPADiscovery()
+ # Do discovery on the first server passed in, we'll do sanity checking
+ # on any others
ret = ds.search(domain=options.domain, server=options.server, hostname=hostname)
if ret == ipadiscovery.BAD_HOST_CONFIG:
@@ -1227,21 +1229,37 @@ def install(options, env, fstore, statestore):
return CLIENT_INSTALL_ERROR
else:
root_logger.debug("DNS discovery failed to find the IPA Server")
- cli_server = user_input("Provide your IPA server name (ex: ipa.example.com)", allow_empty = False)
+ cli_server = [user_input("Provide your IPA server name (ex: ipa.example.com)", allow_empty = False)]
cli_server_source = 'Provided interactively'
- root_logger.debug("will use interactively provided server: %s", cli_server)
+ root_logger.debug("will use interactively provided server: %s", cli_server[0])
ret = ds.search(domain=cli_domain, server=cli_server, hostname=hostname)
+
else:
- dnsok = True
+ # Only set dnsok to True if we were not passed in one or more servers
+ # and if DNS discovery actually worked.
+ if not options.server:
+ (server, domain) = ds.check_domain(ds.domain, set(), "Validating DNS Discovery")
+ if server and domain:
+ root_logger.debug("DNS validated, enabling discovery")
+ dnsok = True
+ else:
+ root_logger.debug("DNS discovery failed, disabling discovery")
+ else:
+ root_logger.debug("Using servers from command line, disabling DNS discovery")
+
if not cli_server:
- if ds.server:
- cli_server = ds.server
+ if options.server:
+ cli_server = options.server
+ cli_server_source = 'Provided as option'
+ root_logger.debug("will use provided server: %s", ', '.join(options.server))
+ elif ds.server:
+ cli_server = [ds.server]
cli_server_source = ds.server_source
- root_logger.debug("will use discovered server: %s", cli_server)
+ root_logger.debug("will use discovered server: %s", cli_server[0])
if ret == ipadiscovery.NOT_IPA_SERVER:
- root_logger.error("%s is not an IPA v2 Server.", cli_server)
- root_logger.debug("(%s: %s)", cli_server, cli_server_source)
+ root_logger.error("%s is not an IPA v2 Server.", cli_server[0])
+ root_logger.debug("(%s: %s)", cli_server[0], cli_server_source)
return CLIENT_INSTALL_ERROR
if ret == ipadiscovery.NO_ACCESS_TO_LDAP:
@@ -1253,10 +1271,10 @@ def install(options, env, fstore, statestore):
if ret != 0:
root_logger.error("Failed to verify that %s is an IPA Server.",
- cli_server)
+ cli_server[0])
root_logger.error("This may mean that the remote server is not up " +
"or is not reachable due to network or firewall settings.")
- root_logger.debug("(%s: %s)", cli_server, cli_server_source)
+ root_logger.debug("(%s: %s)", cli_server[0], cli_server_source)
return CLIENT_INSTALL_ERROR
cli_kdc = ds.kdc
@@ -1269,8 +1287,10 @@ def install(options, env, fstore, statestore):
if dnsok:
root_logger.info("Discovery was successful!")
elif not options.unattended:
- root_logger.warning("The failure to use DNS to find your IPA server " +
- "indicates that your resolv.conf file is not properly configured.")
+ if not options.server:
+ root_logger.warning("The failure to use DNS to find your IPA" +
+ " server indicates that your resolv.conf file is not properly" +
+ " configured.")
root_logger.info("Autodiscovery of servers for failover cannot work " +
"with this configuration.")
root_logger.info("If you proceed with the installation, services " +
@@ -1296,13 +1316,22 @@ def install(options, env, fstore, statestore):
root_logger.debug("will use discovered basedn: %s", cli_basedn)
subject_base = "O=%s" % cli_realm
+ # Now do a sanity check on the other servers
+ if options.server and len(options.server) > 1:
+ for server in options.server[1:]:
+ ret = ds.search(domain=cli_domain, server=server, hostname=hostname)
+ if ret == ipadiscovery.NOT_IPA_SERVER:
+ root_logger.error("%s is not an IPA v2 Server.", server)
+ root_logger.debug("(%s: %s)", server, cli_server_source)
+ return CLIENT_INSTALL_ERROR
+
root_logger.info("Hostname: %s", hostname)
root_logger.debug("Hostname source: %s", hostname_source)
root_logger.info("Realm: %s", cli_realm)
root_logger.debug("Realm source: %s", cli_realm_source)
root_logger.info("DNS Domain: %s", cli_domain)
root_logger.debug("DNS Domain source: %s", cli_domain_source)
- root_logger.info("IPA Server: %s", cli_server)
+ root_logger.info("IPA Server: %s", ', '.join(cli_server))
root_logger.debug("IPA Server source: %s", cli_server_source)
root_logger.info("BaseDN: %s", cli_basedn)
root_logger.debug("BaseDN source: %s", cli_basedn_source)
@@ -1347,10 +1376,10 @@ def install(options, env, fstore, statestore):
pass
try:
- run(["/usr/bin/wget", "-O", "/etc/ipa/ca.crt", "http://%s/ipa/config/ca.crt" % ipautil.format_netloc(cli_server)])
+ run(["/usr/bin/wget", "-O", "/etc/ipa/ca.crt", "http://%s/ipa/config/ca.crt" % ipautil.format_netloc(cli_server[0])])
except CalledProcessError, e:
root_logger.error(
- 'Retrieving CA from %s failed: %s', cli_server, str(e))
+ 'Retrieving CA from %s failed: %s', cli_server[0], str(e))
return CLIENT_INSTALL_ERROR
if not options.on_master:
@@ -1369,7 +1398,7 @@ def install(options, env, fstore, statestore):
if synced_ntp:
break
if not synced_ntp:
- synced_ntp = ipaclient.ntpconf.synconce_ntp(cli_server, debug=True)
+ synced_ntp = ipaclient.ntpconf.synconce_ntp(cli_server[0], debug=True)
if not synced_ntp:
root_logger.warning("Unable to sync time with IPA NTP " +
"server, assuming the time is in sync.")
@@ -1379,7 +1408,7 @@ def install(options, env, fstore, statestore):
root_logger.error("Test kerberos configuration failed")
return CLIENT_INSTALL_ERROR
env['KRB5_CONFIG'] = krb_name
- join_args = ["/usr/sbin/ipa-join", "-s", cli_server, "-b", realm_to_suffix(cli_realm)]
+ join_args = ["/usr/sbin/ipa-join", "-s", cli_server[0], "-b", realm_to_suffix(cli_realm)]
if options.debug:
join_args.append("-d")
env['XMLRPC_TRACE_CURL'] = 'yes'
@@ -1542,10 +1571,10 @@ def install(options, env, fstore, statestore):
return CLIENT_INSTALL_ERROR
if not options.on_master:
- client_dns(cli_server, hostname, options.dns_updates)
+ client_dns(cli_server[0], hostname, options.dns_updates)
configure_certmonger(fstore, subject_base, cli_realm, hostname, options)
- update_ssh_keys(cli_server, hostname, ipaservices.knownservices.sshd.get_config_dir(), options.create_sshfp)
+ update_ssh_keys(cli_server[0], hostname, ipaservices.knownservices.sshd.get_config_dir(), options.create_sshfp)
try:
os.remove(CCACHE_FILE)
@@ -1677,7 +1706,7 @@ def install(options, env, fstore, statestore):
if options.ntp_server:
ntp_server = options.ntp_server
else:
- ntp_server = cli_server
+ ntp_server = cli_server[0]
ipaclient.ntpconf.config_ntp(ntp_server, fstore, statestore)
root_logger.info("NTP enabled")
diff --git a/ipa-client/ipaclient/ipadiscovery.py b/ipa-client/ipaclient/ipadiscovery.py
index f8c8b5c6db14ccbc24b0eb3becad9fa868d8c3aa..ca13d9c1902771bb45aca4f3d2b83720007c1f48 100644
--- a/ipa-client/ipaclient/ipadiscovery.py
+++ b/ipa-client/ipaclient/ipadiscovery.py
@@ -141,6 +141,9 @@ class IPADiscovery(object):
'Starting IPA discovery with domain=%s, server=%s, hostname=%s',
domain, server, hostname)
+ if type(server) in (list, tuple):
+ server = server[0]
+
if not server:
if not domain: #domain not provided do full DNS discovery
diff --git a/ipa-client/man/ipa-client-install.1 b/ipa-client/man/ipa-client-install.1
index caf59571926d293d05cf87d6a94746207f04c51f..2ee5a1a04d45ef2e85db708c2ae0786cca363991 100644
--- a/ipa-client/man/ipa-client-install.1
+++ b/ipa-client/man/ipa-client-install.1
@@ -42,13 +42,13 @@ Client must use a \fBstatic hostname\fR. If the machine hostname changes for exa
Set the domain name to DOMAIN
.TP
\fB\-\-server\fR=\fISERVER\fR
-Set the IPA server to connect to
+Set the IPA server to connect to. May be specified multiple times to add multiple servers to ipa_server value in sssd.conf. Only the first value is considered when used with \-\-no\-sssd.
.TP
\fB\-\-realm\fR=\fIREALM_NAME\fR
Set the IPA realm name to REALM_NAME
.TP
\fB\-\-fixed\-primary\fR
-Configure sssd to use a fixed server as the primary IPA server. The default is to use DNS SRV records to determine the primary server to use and fall back to the server the client is enrolled with.
+Configure sssd to use a fixed server as the primary IPA server. The default is to use DNS SRV records to determine the primary server to use and fall back to the server the client is enrolled with. When used in conjunction with \-\-server then no _srv_ value is set in the ipa_server option in sssd.conf.
.TP
\fB\-p\fR, \fB\-\-principal\fR
Authorized kerberos principal to use to join the IPA realm.
--
1.7.11.2

View File

@ -0,0 +1,100 @@
From 05cf7c53a69b7c999ac68c2869db924e2dccc3a0 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvoborni@redhat.com>
Date: Thu, 28 Jun 2012 14:42:29 +0200
Subject: [PATCH 12/79] Display loginas information only after login
Message 'Logged in as: user@FREEIPA.ORG' was displayed before user was logged in. It was wrong.
Now 'Logged in as: XXX' is displayed only when user XXX is logged in. So no more user@FREEIPA.ORG :) .
https://fedorahosted.org/freeipa/ticket/2882
---
install/ui/index.html | 6 +++---
install/ui/ipa.css | 4 ++++
install/ui/ipa.js | 6 +++++-
install/ui/webui.js | 5 ++++-
4 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/install/ui/index.html b/install/ui/index.html
index 33c0923c197d53824d79591488b18dda2ea90ad2..cfa7a4c8136639e05f4345352a9bf4188ed2af89 100644
--- a/install/ui/index.html
+++ b/install/ui/index.html
@@ -71,10 +71,10 @@
</span>
<span class="header-right">
<span class="header-passwordexpires"></span>
- <span id="loggedinas" class="header-loggedinas">
- <a href="#"><span id="login_header">Logged in as</span>: <strong>user@FREEIPA.ORG</strong></a>
+ <span id="loggedinas" class="header-loggedinas" style="visibility:hidden;">
+ <a href="#"><span id="login_header">Logged in as</span>: <span class="login"></span></a>
</span>
- <span class="header-loggedinas">
+ <span class="header-loggedinas" style="visibility:hidden;">
| <a href="#logout" id="logout">Logout</a>
</span>
<span id="header-network-activity-indicator" class="network-activity-indicator">
diff --git a/install/ui/ipa.css b/install/ui/ipa.css
index dac345ac39c92c30aa6b8c9754eb325c41152c28..d6ad5806038f47919404615f224f5ed75a917563 100644
--- a/install/ui/ipa.css
+++ b/install/ui/ipa.css
@@ -262,6 +262,10 @@ body {
color: #fff;
}
+.header-loggedinas .login {
+ font-weight: bold;
+}
+
/* ---- Navigation ---- */
#navigation {
position: absolute;
diff --git a/install/ui/ipa.js b/install/ui/ipa.js
index aadea8d2af07c1d0c7f5ae1b8168a36966c546c5..2547a24d283a40480660b9b8d22d1c91e5edbbe8 100644
--- a/install/ui/ipa.js
+++ b/install/ui/ipa.js
@@ -157,7 +157,6 @@ var IPA = function() {
on_success: function(data, text_status, xhr) {
that.whoami = batch ? data.result[0] : data.result.result[0];
that.principal = that.whoami.krbprincipalname[0];
- that.update_password_expiration();
}
});
};
@@ -516,6 +515,11 @@ IPA.password_selfservice = function() {
self_service: true,
on_success: function() {
var command = IPA.get_whoami_command();
+ var orig_on_success = command.on_success;
+ command.on_success = function(data, text_status, xhr) {
+ orig_on_success.call(this, data, text_status, xhr);
+ IPA.update_password_expiration();
+ };
command.execute();
alert(IPA.messages.password.password_change_complete);
diff --git a/install/ui/webui.js b/install/ui/webui.js
index 0be4b1b630888010f6c0e5dc95307acc335a47f6..66efdb2cf7c90780cb2647ccdbb93ebb5bf79540 100644
--- a/install/ui/webui.js
+++ b/install/ui/webui.js
@@ -167,7 +167,7 @@ $(function() {
var whoami = IPA.whoami;
IPA.whoami_pkey = whoami.uid[0];
- $('#loggedinas strong').text(whoami.cn[0]);
+ $('#loggedinas .login').text(whoami.cn[0]);
$('#loggedinas a').fragment(
{'user-facet': 'details', 'user-pkey': IPA.whoami_pkey}, 2);
@@ -176,6 +176,9 @@ $(function() {
return false;
}).text(IPA.messages.login.logout);
+ $('.header-loggedinas').css('visibility','visible');
+ IPA.update_password_expiration();
+
IPA.nav = create_navigation();
IPA.nav.create();
IPA.nav.update();
--
1.7.11.2

View File

@ -0,0 +1,183 @@
From 848bd0e9e738a4590049a223868dcfe6749a9154 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvoborni@redhat.com>
Date: Mon, 9 Jul 2012 16:58:00 +0200
Subject: [PATCH 13/79] Password policy measurement units.
When filling password policy it may be unclear what value to enter because user may not remember field's measurement unit.
This patch adds support for declaring measurement units. It's done in field's/widget's spec by entering key for unit's string (which is in IPA.messages.measurement_units[key]).
Measurement units in table layout are displayed in parenthesis after label. It is to be consistent with some fields which have measurement unit integrated in label.
This patch defines measurement units for password policy's 'History size', 'Failure reset interval' and 'Lockout duration' fields.
https://fedorahosted.org/freeipa/ticket/2437
---
install/ui/field.js | 6 ++++--
install/ui/policy.js | 15 ++++++++++++---
install/ui/test/data/ipa_init.json | 4 ++++
install/ui/user.js | 9 ++++++---
install/ui/widget.js | 15 ++++++++++++++-
ipalib/plugins/internal.py | 4 ++++
6 files changed, 44 insertions(+), 9 deletions(-)
diff --git a/install/ui/field.js b/install/ui/field.js
index 84ec0c4dfa5c77b72da06eb4d2ff64ccac633f65..fb292ff2a6c5fb29b84262236fd5be2c7c7f7e42 100644
--- a/install/ui/field.js
+++ b/install/ui/field.js
@@ -35,6 +35,7 @@ IPA.field = function(spec) {
that.param = spec.param || spec.name;
that.label = spec.label;
that.tooltip = spec.tooltip;
+ that.measurement_unit = spec.measurement_unit;
that.formatter = spec.formatter;
that.widget = null;
@@ -348,8 +349,9 @@ IPA.field = function(spec) {
that.set_widget_flags = function() {
if (that.widget) {
- if(that.label) that.widget.label = that.label;
- if(that.title) that.widget.title = that.title;
+ if (that.label) that.widget.label = that.label;
+ if (that.title) that.widget.title = that.title;
+ if (that.measurement_unit) that.widget.measurement_unit = that.measurement_unit;
that.widget.undo = that.undo;
that.widget.writable = that.writable;
that.widget.read_only = that.read_only;
diff --git a/install/ui/policy.js b/install/ui/policy.js
index 604664f1263e97a7e0007b26b392372fb87b0923..acad0c8c2c2ba6f2f8c26407627b56c75d79dfb5 100644
--- a/install/ui/policy.js
+++ b/install/ui/policy.js
@@ -48,12 +48,21 @@ IPA.pwpolicy.entity = function(spec) {
},
'krbmaxpwdlife',
'krbminpwdlife',
- 'krbpwdhistorylength',
+ {
+ name: 'krbpwdhistorylength',
+ measurement_unit: 'number_of_passwords'
+ },
'krbpwdmindiffchars',
'krbpwdminlength',
'krbpwdmaxfailure',
- 'krbpwdfailurecountinterval',
- 'krbpwdlockoutduration',
+ {
+ name: 'krbpwdfailurecountinterval',
+ measurement_unit: 'seconds'
+ },
+ {
+ name: 'krbpwdlockoutduration',
+ measurement_unit: 'seconds'
+ },
'cospriority'
]
}]}).
diff --git a/install/ui/test/data/ipa_init.json b/install/ui/test/data/ipa_init.json
index 85ff9366ce4ad293b95829d864653561a55d6429..527d09163eda854bd779c1362b8272582150e90e 100644
--- a/install/ui/test/data/ipa_init.json
+++ b/install/ui/test/data/ipa_init.json
@@ -138,6 +138,10 @@
"password": "Password",
"username": "Username"
},
+ "measurement_units": {
+ "number_of_passwords": "number of passwords",
+ "seconds": "seconds"
+ },
"objects": {
"aci": {
"attribute": "Attribute"
diff --git a/install/ui/user.js b/install/ui/user.js
index 02f6f73e45e50b8c5501ccad57209a681100082d..24873ecf55d5e9159d77dc061d73f3d2e318e30d 100644
--- a/install/ui/user.js
+++ b/install/ui/user.js
@@ -149,7 +149,8 @@ IPA.user.entity = function(spec) {
{
name: 'krbpwdhistorylength',
label: IPA.get_entity_param('pwpolicy', 'krbpwdhistorylength').label,
- read_only: true
+ read_only: true,
+ measurement_unit: 'number_of_passwords'
},
{
name: 'krbpwdmindiffchars',
@@ -169,12 +170,14 @@ IPA.user.entity = function(spec) {
{
name: 'krbpwdfailurecountinterval',
label: IPA.get_entity_param('pwpolicy', 'krbpwdfailurecountinterval').label,
- read_only: true
+ read_only: true,
+ measurement_unit: 'seconds'
},
{
name: 'krbpwdlockoutduration',
label: IPA.get_entity_param('pwpolicy', 'krbpwdlockoutduration').label,
- read_only: true
+ read_only: true,
+ measurement_unit: 'seconds'
}
]
},
diff --git a/install/ui/widget.js b/install/ui/widget.js
index a55cc347f49cc2e61f00422f12c47ab4c1c70449..64547da7d439cb622c03d6f73afb310be83a6338 100644
--- a/install/ui/widget.js
+++ b/install/ui/widget.js
@@ -36,6 +36,7 @@ IPA.widget = function(spec) {
that.id = spec.id;
that.label = spec.label;
that.tooltip = spec.tooltip;
+ that.measurement_unit = spec.measurement_unit;
that.entity = IPA.get_entity(spec.entity); //some old widgets still need it
that.facet = spec.facet;
@@ -2688,10 +2689,12 @@ IPA.table_layout = function(spec) {
title: widget.label
}).appendTo(tr);
+ var label_text = widget.label + that.get_measurement_unit_text(widget) + ':';
+
$('<label/>', {
name: widget.name,
'class': that.label_class,
- text: widget.label+':'
+ text: label_text
}).appendTo(td);
if(widget.create_required) {
@@ -2713,6 +2716,16 @@ IPA.table_layout = function(spec) {
return table;
};
+
+ that.get_measurement_unit_text = function(widget) {
+
+ if (widget.measurement_unit) {
+ var unit = IPA.messages.measurement_units[widget.measurement_unit];
+ return ' (' + unit + ')';
+ }
+ return '';
+ };
+
return that;
};
diff --git a/ipalib/plugins/internal.py b/ipalib/plugins/internal.py
index a4d87b1d744afe38b5e4ca1b6789724b33d6aa57..eb48b3bfa44ca681920daaf4c0f8a8ccfa86f3fa 100644
--- a/ipalib/plugins/internal.py
+++ b/ipalib/plugins/internal.py
@@ -273,6 +273,10 @@ class i18n_messages(Command):
"password": _("Password"),
"username": _("Username"),
},
+ "measurement_units": {
+ "number_of_passwords": _("number of passwords"),
+ "seconds": _("seconds"),
+ },
"objects": {
"aci": {
"attribute": _("Attribute"),
--
1.7.11.2

View File

@ -0,0 +1,58 @@
From 0d11b8b0567e8440f9cb553a99e1f66e545509d0 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvoborni@redhat.com>
Date: Mon, 9 Jul 2012 17:28:08 +0200
Subject: [PATCH 14/79] Web UI: kerberos ticket policy measurement units
Added measurement units for kerberos ticket policy.
https://fedorahosted.org/freeipa/ticket/2444
---
install/ui/policy.js | 10 ++++++++--
install/ui/user.js | 6 ++++--
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/install/ui/policy.js b/install/ui/policy.js
index acad0c8c2c2ba6f2f8c26407627b56c75d79dfb5..ff932bec4a2219d4199298f7da6d28a5b5eba1f8 100644
--- a/install/ui/policy.js
+++ b/install/ui/policy.js
@@ -100,8 +100,14 @@ IPA.krbtpolicy.entity = function(spec) {
{
name: 'identity',
fields: [
- 'krbmaxrenewableage',
- 'krbmaxticketlife'
+ {
+ name: 'krbmaxrenewableage',
+ measurement_unit: 'seconds'
+ },
+ {
+ name: 'krbmaxticketlife',
+ measurement_unit: 'seconds'
+ }
]
}
],
diff --git a/install/ui/user.js b/install/ui/user.js
index 24873ecf55d5e9159d77dc061d73f3d2e318e30d..7bb5a57073f3f3178e8c0ad2eee52e20f0b21cc1 100644
--- a/install/ui/user.js
+++ b/install/ui/user.js
@@ -188,12 +188,14 @@ IPA.user.entity = function(spec) {
{
name: 'krbmaxrenewableage',
label: IPA.get_entity_param('krbtpolicy', 'krbmaxrenewableage').label,
- read_only: true
+ read_only: true,
+ measurement_unit: 'seconds'
},
{
name: 'krbmaxticketlife',
label: IPA.get_entity_param('krbtpolicy', 'krbmaxticketlife').label,
- read_only: true
+ read_only: true,
+ measurement_unit: 'seconds'
}
]
},
--
1.7.11.2

View File

@ -0,0 +1,28 @@
From e494650b2cdb6ac7e1eda3da7cf03d4c36f2739a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Sp=C3=A5ngberg?= <david@tunna.org>
Date: Wed, 4 Jul 2012 10:28:43 +0200
Subject: [PATCH 15/79] Indirect roles in WebUI
Add a check in the WebUI to use the admin navigation if a user is a
indirect member of a role.
---
install/ui/webui.js | 3 +++
1 file changed, 3 insertions(+)
diff --git a/install/ui/webui.js b/install/ui/webui.js
index 66efdb2cf7c90780cb2647ccdbb93ebb5bf79540..9df6f76f1b728bdee83206afc3771ca98ab141c8 100644
--- a/install/ui/webui.js
+++ b/install/ui/webui.js
@@ -151,6 +151,9 @@ $(function() {
} else if (whoami.hasOwnProperty('memberof_role') &&
whoami.memberof_role.length > 0) {
factory = IPA.admin_navigation;
+ } else if (whoami.hasOwnProperty('memberofindirect_role') &&
+ whoami.memberofindirect_role.length > 0) {
+ factory = IPA.admin_navigation;
} else {
factory = IPA.self_serv_navigation;
}
--
1.7.11.2

View File

@ -0,0 +1,136 @@
From 5f69a06d1a78242a65164a94d752380613e73e44 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori@redhat.com>
Date: Wed, 4 Jul 2012 08:39:21 -0400
Subject: [PATCH 16/79] Fix batch command error reporting
The Batch command did not report errors correctly: it reported
the text of *all* errors, not just PublicError, used unicode(e)
instead of e.strerror (which results in incorrect i18n), and only
reported the text of error messages, not their type and code.
Fix these problems. Update tests.
https://fedorahosted.org/freeipa/ticket/2874
https://fedorahosted.org/freeipa/ticket/2901
---
ipalib/plugins/batch.py | 11 +++++--
tests/test_xmlrpc/test_batch_plugin.py | 60 ++++++++++++++++++++++++++++------
2 files changed, 59 insertions(+), 12 deletions(-)
diff --git a/ipalib/plugins/batch.py b/ipalib/plugins/batch.py
index 8abad5e1eeab5eeed46c5dc09f17bda1857f9562..db9c08f1052524b58a693f22b123b55637629034 100644
--- a/ipalib/plugins/batch.py
+++ b/ipalib/plugins/batch.py
@@ -102,8 +102,6 @@ class batch(Command):
)
result['error']=None
except Exception, e:
- result = dict()
- result['error'] = unicode(e)
if isinstance(e, errors.RequirementError) or \
isinstance(e, errors.CommandError):
self.info(
@@ -113,6 +111,15 @@ class batch(Command):
self.info(
'%s: batch: %s(%s): %s', context.principal, name, ', '.join(api.Command[name]._repr_iter(**params)), e.__class__.__name__
)
+ if isinstance(e, errors.PublicError):
+ reported_error = e
+ else:
+ reported_error = errors.InternalError()
+ result = dict(
+ error=reported_error.strerror,
+ error_code=reported_error.errno,
+ error_name=unicode(type(reported_error).__name__),
+ )
results.append(result)
return dict(count=len(results) , results=results)
diff --git a/tests/test_xmlrpc/test_batch_plugin.py b/tests/test_xmlrpc/test_batch_plugin.py
index d69bfd9c4193af2b8d96bd1f3178dc5566145a35..19728adda40efa7412ad33f0f4be8a5b212120b7 100644
--- a/tests/test_xmlrpc/test_batch_plugin.py
+++ b/tests/test_xmlrpc/test_batch_plugin.py
@@ -121,8 +121,16 @@ class test_batch(Declarative):
expected=dict(
count=2,
results=[
- dict(error=u'%s: group not found' % group1),
- dict(error=u'%s: group not found' % group1),
+ dict(
+ error=u'%s: group not found' % group1,
+ error_name=u'NotFound',
+ error_code=4001,
+ ),
+ dict(
+ error=u'%s: group not found' % group1,
+ error_name=u'NotFound',
+ error_code=4001,
+ ),
],
),
),
@@ -137,7 +145,11 @@ class test_batch(Declarative):
expected=dict(
count=2,
results=deepequal_list(
- dict(error=u'%s: group not found' % group1),
+ dict(
+ error=u'%s: group not found' % group1,
+ error_name=u'NotFound',
+ error_code=4001,
+ ),
dict(
value=group1,
summary=u'Added group "testgroup1"',
@@ -180,13 +192,41 @@ class test_batch(Declarative):
expected=dict(
count=7,
results=deepequal_list(
- dict(error=u"unknown command 'nonexistent_ipa_command'"),
- dict(error=u"unknown command 'user-del'"),
- dict(error=u"'method' is required"),
- dict(error=u"'params' is required"),
- dict(error=u"'givenname' is required"),
- dict(error=u"'description' is required"),
- dict(error=Fuzzy(u"invalid 'gid'.*")),
+ dict(
+ error=u"unknown command 'nonexistent_ipa_command'",
+ error_name=u'CommandError',
+ error_code=905,
+ ),
+ dict(
+ error=u"unknown command 'user-del'",
+ error_name=u'CommandError',
+ error_code=905,
+ ),
+ dict(
+ error=u"'method' is required",
+ error_name=u'RequirementError',
+ error_code=3007,
+ ),
+ dict(
+ error=u"'params' is required",
+ error_name=u'RequirementError',
+ error_code=3007,
+ ),
+ dict(
+ error=u"'givenname' is required",
+ error_name=u'RequirementError',
+ error_code=3007,
+ ),
+ dict(
+ error=u"'description' is required",
+ error_name=u'RequirementError',
+ error_code=3007,
+ ),
+ dict(
+ error=Fuzzy(u"invalid 'gid'.*"),
+ error_name=u'ConversionError',
+ error_code=3008,
+ ),
),
),
),
--
1.7.11.2

View File

@ -0,0 +1,26 @@
From 7e606b01d5b40c90a83b03a790d34ff3bd8dc94e Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori@redhat.com>
Date: Wed, 11 Jul 2012 09:19:31 -0400
Subject: [PATCH 17/79] Fix wrong option name in ipa-managed-entries man page
The page said `-y` but the actual option is `-p`.
---
install/tools/man/ipa-managed-entries.1 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/install/tools/man/ipa-managed-entries.1 b/install/tools/man/ipa-managed-entries.1
index 59b04c39477b2115fd458f520573185a72a293df..e46b693176d87d772853e3254b664403d386e4c8 100644
--- a/install/tools/man/ipa-managed-entries.1
+++ b/install/tools/man/ipa-managed-entries.1
@@ -29,7 +29,7 @@ Run the command with the \fBdisable\fR option to disable the Managed Entry plugi
Run the command with the \fBstatus\fR to determine the current status of the Managed Entry plugin.
-In all cases the user will be prompted to provide the Directory Manager's password unless option \fB\-y\fR is used.
+In all cases the user will be prompted to provide the Directory Manager's password unless option \fB\-p\fR is used.
Directory Server will need to be restarted after the Managed Entry plugin has been enabled.
--
1.7.11.2

View File

@ -0,0 +1,433 @@
From 14ac2193fec38b6f87dcf04b0c365d01805b0cae Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvoborni@redhat.com>
Date: Tue, 3 Jul 2012 14:18:03 +0200
Subject: [PATCH 18/79] Add and remove dns per-domain permission in Web UI
This patch adds support for new per-domain permissions to Web UI.
User with assigned permission (through role,priviledge) can edit DNS zone. These permissions can be added/remove by ipa dnszone-{add/remove}permission $dnszone command.
For adding/removing of this permission in Web UI new actions in DNS zone action list were created. DNS zone object doesn't contain information about existance of related permission. Such information is required for enabling/disabling of new actions. Web UI has to search for the permission to get it. DNS zone facet was modified to use batch command, in a same way as user facet, for loading dnszone and the permission at the same time - on load.
Batch command has a feature to report all errors. Such behavior is unwanted because we expect that permission-show command will fail when the permission doesn't exist. Batch command was therefore modified to not report commands which has retry attribute set to false. This attr was chosen because it has similar purpose in single command execution.
New actions should be enabled only for users with appropriate rights. It is not possible to obtain rights for certain action in advance so an approximation is used: write right for dns zones' managedby attribute.
https://fedorahosted.org/freeipa/ticket/2851
---
install/ui/details.js | 4 +-
install/ui/dns.js | 160 +++++++++++++++++++++-
install/ui/ipa.js | 7 +-
install/ui/test/data/dnszone_details_refresh.json | 119 ++++++++++++++++
install/ui/test/data/ipa_init.json | 4 +-
ipalib/plugins/internal.py | 2 +
6 files changed, 285 insertions(+), 11 deletions(-)
create mode 100644 install/ui/test/data/dnszone_details_refresh.json
diff --git a/install/ui/details.js b/install/ui/details.js
index 618d02f573e38f2573b532440265ff934e91f8c3..176e7883ebfa0593276d9397d47e5383a894ab12 100644
--- a/install/ui/details.js
+++ b/install/ui/details.js
@@ -996,7 +996,9 @@ IPA.acl_state_evaluator = function(spec) {
rights = record.attributelevelrights[that.attribute];
}
- rights = rights || '';
+ // Full rights if we don't know the rights. Better to allow action and
+ // then to show error dialog than not be able to do something.
+ rights = rights || 'rscwo';
for (i=0; i<rights.length; i++) {
state = that.attribute + '_' + rights.charAt(i);
diff --git a/install/ui/dns.js b/install/ui/dns.js
index 492d8c4f7ded27191f60d7fa154882db231e6f1d..1f4ba8ccdb98cda3e67d9d006139d42f99a3399e 100644
--- a/install/ui/dns.js
+++ b/install/ui/dns.js
@@ -26,7 +26,9 @@
/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js,
* net.js, widget.js */
-IPA.dns = {};
+IPA.dns = {
+ zone_permission_name: 'Manage DNS zone ${dnszone}'
+};
IPA.dns.config_entity = function(spec) {
@@ -230,15 +232,23 @@ IPA.dns.zone_entity = function(spec) {
IPA.select_action,
IPA.enable_action,
IPA.disable_action,
- IPA.delete_action
+ IPA.delete_action,
+ IPA.dns.add_permission_action,
+ IPA.dns.remove_permission_action
],
- header_actions: ['select_action', 'enable', 'disable', 'delete'],
+ header_actions: ['select_action', 'enable', 'disable', 'delete',
+ 'add_permission', 'remove_permission'],
state: {
evaluators: [
{
factory: IPA.enable_state_evaluator,
field: 'idnszoneactive'
- }
+ },
+ {
+ factory: IPA.acl_state_evaluator,
+ attribute: 'managedby'
+ },
+ IPA.dns.zone_has_permission_evaluator
],
summary_conditions: [
IPA.enabled_summary_cond(),
@@ -319,11 +329,69 @@ IPA.dns.zone_entity = function(spec) {
return that;
};
-IPA.dnszone_details_facet = function(spec) {
+IPA.dnszone_details_facet = function(spec, no_init) {
spec = spec || {};
- var that = IPA.details_facet(spec);
+ var that = IPA.details_facet(spec, true);
+ that.permission_load = IPA.observer();
+ that.permission_status = 'unknown'; // [unknown, set, none]
+
+ that.refresh_on_success = function(data, text_status, xhr) {
+ // do not load data from batch
+
+ that.show_content();
+ };
+
+ that.create_refresh_command = function() {
+
+ var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+
+ var batch = IPA.batch_command({
+ name: 'dnszone_details_refresh'
+ });
+
+ var dnszone_command = that.details_facet_create_refresh_command();
+
+ dnszone_command.on_success = function(data, text_status, xhr) {
+ // create data that mimics dnszone-show output
+ var dnszone_data = {};
+ dnszone_data.result = data;
+ that.load(dnszone_data);
+ };
+
+ batch.add_command(dnszone_command);
+
+ var permission_name = IPA.dns.zone_permission_name.replace('${dnszone}', pkey);
+
+ var permission_command = IPA.command({
+ entity: 'permission',
+ method: 'show',
+ args: [permission_name],
+ options: {},
+ retry: false
+ });
+
+ permission_command.on_success = function(data, text_status, xhr) {
+ that.permission_status = 'set';
+ that.permission_load.notify([that.permission_status], that);
+ };
+
+ permission_command.on_error = function(xhr, text_status, error_thrown) {
+ if (error_thrown && error_thrown.code === 4001) {
+ //NotFound error
+ that.permission_status = 'none';
+ } else {
+ that.permission_status = 'unknown';
+ }
+
+ that.permission_load.notify([that.permission_status], that);
+ };
+
+ batch.add_command(permission_command);
+
+ return batch;
+ };
that.update_on_success = function(data, text_status, xhr) {
that.refresh();
@@ -334,6 +402,8 @@ IPA.dnszone_details_facet = function(spec) {
that.refresh();
};
+ if (!no_init) that.init_details_facet();
+
return that;
};
@@ -528,6 +598,84 @@ IPA.dnszone_adder_dialog = function(spec) {
return that;
};
+IPA.dns.add_permission_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'add_permission';
+ spec.label = spec.label || IPA.messages.objects.dnszone.add_permission;
+ spec.enable_cond = spec.enable_cond || ['permission-none', 'managedby_w'];
+
+ var that = IPA.action(spec);
+
+ that.execute_action = function(facet) {
+
+ var pkey = IPA.nav.get_state('dnszone-pkey');
+
+ var command = IPA.command({
+ entity: 'dnszone',
+ method: 'add_permission',
+ args: [pkey],
+ options: {},
+ on_success: function() {
+ facet.refresh();
+ }
+ });
+
+ command.execute();
+ };
+
+ return that;
+};
+
+IPA.dns.remove_permission_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'remove_permission';
+ spec.label = spec.label || IPA.messages.objects.dnszone.remove_permission;
+ spec.enable_cond = spec.enable_cond || ['permission-set', 'managedby_w'];
+
+ var that = IPA.action(spec);
+
+ that.execute_action = function(facet) {
+
+ var pkey = IPA.nav.get_state('dnszone-pkey');
+
+ var command = IPA.command({
+ entity: 'dnszone',
+ method: 'remove_permission',
+ args: [pkey],
+ options: {},
+ on_success: function() {
+ facet.refresh();
+ }
+ });
+
+ command.execute();
+ };
+
+ return that;
+};
+
+IPA.dns.zone_has_permission_evaluator = function(spec) {
+ spec = spec || {};
+
+ spec.event = spec.event || 'permission_load';
+
+ var that = IPA.state_evaluator(spec);
+
+ that.on_event = function(permission_status) {
+
+ var old_state = that.state;
+ that.state = [
+ 'permission-'+permission_status
+ ];
+
+ that.notify_on_change(old_state);
+ };
+
+ return that;
+};
+
IPA.dns.record_search_facet = function(spec) {
var that = IPA.nested_search_facet(spec);
diff --git a/install/ui/ipa.js b/install/ui/ipa.js
index 2547a24d283a40480660b9b8d22d1c91e5edbbe8..413951ff16446852d47cf1fc509106018f897f45 100644
--- a/install/ui/ipa.js
+++ b/install/ui/ipa.js
@@ -929,10 +929,11 @@ IPA.batch_command = function (spec) {
);
} else if (result.error) {
- name = IPA.get_message('errors.ipa_error', 'IPA Error')+(result.error.code ? ' '+result.error.code : '');
+ var code = result.error.code || result.error_code;
+ name = IPA.get_message('errors.ipa_error', 'IPA Error')+(code ? ' '+code : '');
message = result.error.message || result.error;
- that.errors.add(command, name, message, text_status);
+ if (command.retry) that.errors.add(command, name, message, text_status);
if (command.on_error) command.on_error.call(
this,
@@ -940,7 +941,7 @@ IPA.batch_command = function (spec) {
text_status,
{
name: name,
- code: result.error.code,
+ code: code,
message: message,
data: result
}
diff --git a/install/ui/test/data/dnszone_details_refresh.json b/install/ui/test/data/dnszone_details_refresh.json
new file mode 100644
index 0000000000000000000000000000000000000000..dcc2f8c2507f1758114b5f2cdb96e344c9c51a3f
--- /dev/null
+++ b/install/ui/test/data/dnszone_details_refresh.json
@@ -0,0 +1,119 @@
+{
+ "error": null,
+ "id": null,
+ "result": {
+ "count": 2,
+ "results": [
+ {
+ "error": null,
+ "result": {
+ "attributelevelrights": {
+ "a6record": "rscwo",
+ "aaaarecord": "rscwo",
+ "aci": "rscwo",
+ "afsdbrecord": "rscwo",
+ "arecord": "rscwo",
+ "certrecord": "rscwo",
+ "cn": "rscwo",
+ "cnamerecord": "rscwo",
+ "dnamerecord": "rscwo",
+ "dnsclass": "rscwo",
+ "dnsttl": "rscwo",
+ "dsrecord": "rscwo",
+ "hinforecord": "rscwo",
+ "idnsallowdynupdate": "rscwo",
+ "idnsallowquery": "rscwo",
+ "idnsallowsyncptr": "rscwo",
+ "idnsallowtransfer": "rscwo",
+ "idnsforwarders": "rscwo",
+ "idnsforwardpolicy": "rscwo",
+ "idnsname": "rscwo",
+ "idnssoaexpire": "rscwo",
+ "idnssoaminimum": "rscwo",
+ "idnssoamname": "rscwo",
+ "idnssoarefresh": "rscwo",
+ "idnssoaretry": "rscwo",
+ "idnssoarname": "rscwo",
+ "idnssoaserial": "rscwo",
+ "idnsupdatepolicy": "rscwo",
+ "idnszoneactive": "rscwo",
+ "keyrecord": "rscwo",
+ "kxrecord": "rscwo",
+ "locrecord": "rscwo",
+ "managedby": "rscwo",
+ "mdrecord": "rscwo",
+ "minforecord": "rscwo",
+ "mxrecord": "rscwo",
+ "naptrrecord": "rscwo",
+ "nsaccountlock": "rscwo",
+ "nsecrecord": "rscwo",
+ "nsrecord": "rscwo",
+ "nxtrecord": "rscwo",
+ "objectclass": "rscwo",
+ "ptrrecord": "rscwo",
+ "rrsigrecord": "rscwo",
+ "sigrecord": "rscwo",
+ "srvrecord": "rscwo",
+ "sshfprecord": "rscwo",
+ "txtrecord": "rscwo"
+ },
+ "dn": "idnsname=example.com,cn=dns,dc=example,dc=com",
+ "idnsallowdynupdate": [
+ "FALSE"
+ ],
+ "idnsallowquery": [
+ "any;"
+ ],
+ "idnsallowtransfer": [
+ "none;"
+ ],
+ "idnsname": [
+ "example.com"
+ ],
+ "idnssoaexpire": [
+ "1209600"
+ ],
+ "idnssoaminimum": [
+ "3600"
+ ],
+ "idnssoamname": [
+ "test.example.com."
+ ],
+ "idnssoarefresh": [
+ "3600"
+ ],
+ "idnssoaretry": [
+ "900"
+ ],
+ "idnssoarname": [
+ "hostmaster.example.com."
+ ],
+ "idnssoaserial": [
+ "2012070401"
+ ],
+ "idnsupdatepolicy": [
+ "grant EXAMPLE.COM krb5-self * A; grant EXAMPLE.COM krb5-self * AAAA; grant EXAMPLE.COM krb5-self * SSHFP;"
+ ],
+ "idnszoneactive": [
+ "TRUE"
+ ],
+ "nsrecord": [
+ "test.example.com."
+ ],
+ "objectclass": [
+ "top",
+ "idnsrecord",
+ "idnszone"
+ ]
+ },
+ "summary": null,
+ "value": "example.com"
+ },
+ {
+ "error": "Manage DNS zone example.com: permission not found",
+ "error_code": 4001,
+ "error_name": "NotFound"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/install/ui/test/data/ipa_init.json b/install/ui/test/data/ipa_init.json
index 527d09163eda854bd779c1362b8272582150e90e..2cc1130f0dbc783a74f108629f1b13ca42e904d1 100644
--- a/install/ui/test/data/ipa_init.json
+++ b/install/ui/test/data/ipa_init.json
@@ -240,7 +240,9 @@
"type": "Record Type"
},
"dnszone": {
- "identity": "DNS Zone Settings"
+ "identity": "DNS Zone Settings",
+ "add_permission": "Add Permission",
+ "remove_permission": "Remove Permission"
},
"entitle": {
"account": "Account",
diff --git a/ipalib/plugins/internal.py b/ipalib/plugins/internal.py
index eb48b3bfa44ca681920daaf4c0f8a8ccfa86f3fa..fc7f9dddf92b5290b3e26f3cec81e220e6fc8513 100644
--- a/ipalib/plugins/internal.py
+++ b/ipalib/plugins/internal.py
@@ -378,6 +378,8 @@ class i18n_messages(Command):
},
"dnszone": {
"identity": _("DNS Zone Settings"),
+ "add_permission":_("Add Permission"),
+ "remove_permission": _("Remove Permission"),
},
"entitle": {
"account": _("Account"),
--
1.7.11.2

View File

@ -0,0 +1,102 @@
From 4760c15cb2c8692b0e258ef62234aa18ab5fc193 Mon Sep 17 00:00:00 2001
From: Martin Kosek <mkosek@redhat.com>
Date: Tue, 10 Jul 2012 15:27:37 +0200
Subject: [PATCH 19/79] Add automount map/key update permissions
Add missing permissions that can be used to delegate write access
to existing automount maps or keys.
Since automount key RDN has been changed in the past from "automountkey"
to "description" and there can be LDAP entries with both RDNs,
structure of relevant ACI need to be changed to different scheme. Now,
it rather targets a DN of parent automount map object and uses
targetfilter to limit the target to automount key objects only.
https://fedorahosted.org/freeipa/ticket/2687
---
install/share/delegation.ldif | 22 ++++++++++++++++++++--
install/updates/40-delegation.update | 21 +++++++++++++++++++++
2 files changed, 41 insertions(+), 2 deletions(-)
diff --git a/install/share/delegation.ldif b/install/share/delegation.ldif
index c612408412cdf1f4e2ec3b7e524fe1d7aa329fca..f62062fe498634d56128ebf78874c3ba91d7d09b 100644
--- a/install/share/delegation.ldif
+++ b/install/share/delegation.ldif
@@ -417,6 +417,14 @@ objectClass: ipapermission
cn: Remove Automount maps
member: cn=Automount Administrators,cn=privileges,cn=pbac,$SUFFIX
+dn: cn=Modify Automount maps,cn=permissions,cn=pbac,$SUFFIX
+changetype: add
+objectClass: top
+objectClass: groupofnames
+objectClass: ipapermission
+cn: Modify Automount maps
+member: cn=Automount Administrators,cn=privileges,cn=pbac,$SUFFIX
+
dn: cn=Add Automount keys,cn=permissions,cn=pbac,$SUFFIX
changetype: add
objectClass: top
@@ -425,6 +433,14 @@ objectClass: ipapermission
cn: Add Automount keys
member: cn=Automount Administrators,cn=privileges,cn=pbac,$SUFFIX
+dn: cn=Modify Automount keys,cn=permissions,cn=pbac,$SUFFIX
+changetype: add
+objectClass: top
+objectClass: groupofnames
+objectClass: ipapermission
+cn: Modify Automount keys
+member: cn=Automount Administrators,cn=privileges,cn=pbac,$SUFFIX
+
dn: cn=Remove Automount keys,cn=permissions,cn=pbac,$SUFFIX
changetype: add
objectClass: top
@@ -636,8 +652,10 @@ changetype: modify
add: aci
aci: (target = "ldap:///automountmapname=*,cn=automount,$SUFFIX")(version 3.0;acl "permission:Add Automount maps";allow (add) groupdn = "ldap:///cn=Add Automount maps,cn=permissions,cn=pbac,$SUFFIX";)
aci: (target = "ldap:///automountmapname=*,cn=automount,$SUFFIX")(version 3.0;acl "permission:Remove Automount maps";allow (delete) groupdn = "ldap:///cn=Remove Automount maps,cn=permissions,cn=pbac,$SUFFIX";)
-aci: (target = "ldap:///automountkey=*,automountmapname=*,cn=automount,$SUFFIX")(version 3.0;acl "permission:Add Automount keys";allow (add) groupdn = "ldap:///cn=Add Automount keys,cn=permissions,cn=pbac,$SUFFIX";)
-aci: (target = "ldap:///automountkey=*,automountmapname=*,cn=automount,$SUFFIX")(version 3.0;acl "permission:Remove Automount keys";allow (delete) groupdn = "ldap:///cn=Remove Automount keys,cn=permissions,cn=pbac,$SUFFIX";)
+aci: (targetattr = "automountmapname || description")(target = "ldap:///automountmapname=*,cn=automount,$SUFFIX")(version 3.0;acl "permission:Modify Automount maps";allow (write) groupdn = "ldap:///cn=Modify Automount maps,cn=permissions,cn=pbac,$SUFFIX";)
+aci: (targetfilter = "(objectclass=automount)")(target = "ldap:///automountmapname=*,cn=automount,$SUFFIX")(version 3.0;acl "permission:Add Automount keys";allow (add) groupdn = "ldap:///cn=Add Automount keys,cn=permissions,cn=pbac,$SUFFIX";)
+aci: (targetfilter = "(objectclass=automount)")(target = "ldap:///automountmapname=*,cn=automount,$SUFFIX")(version 3.0;acl "permission:Remove Automount keys";allow (delete) groupdn = "ldap:///cn=Remove Automount keys,cn=permissions,cn=pbac,$SUFFIX";)
+aci: (targetattr = "automountkey || automountinformation || description")(targetfilter = "(objectclass=automount)")(target = "ldap:///automountmapname=*,cn=automount,$SUFFIX")(version 3.0;acl "permission:Modify Automount keys";allow (write) groupdn = "ldap:///cn=Modify Automount keys,cn=permissions,cn=pbac,$SUFFIX";)
# Netgroup administration
diff --git a/install/updates/40-delegation.update b/install/updates/40-delegation.update
index 09b8056871adbc44bf1430d54fc0b044dba11b38..de112d99d9a5bdbe553d9ec94016e852524494d6 100644
--- a/install/updates/40-delegation.update
+++ b/install/updates/40-delegation.update
@@ -306,6 +306,27 @@ add:aci:'(target = "ldap:///ipauniqueid=*,cn=usermap,cn=selinux,$SUFFIX")(versio
dn: $SUFFIX
add:aci:'(targetattr = "cn || memberuser || memberhost || seealso || ipaselinuxuser || ipaenabledflag")(target = "ldap:///ipauniqueid=*,cn=usermap,cn=selinux,$SUFFIX")(version 3.0;acl "permission:Modify SELinux User Maps";allow (write) groupdn = "ldap:///cn=Modify SELinux User Maps,cn=permissions,cn=pbac,$SUFFIX";)'
+# Automount maps and keys
+dn: cn=Modify Automount maps,cn=permissions,cn=pbac,$SUFFIX
+default:objectClass: top
+default:objectClass: groupofnames
+default:objectClass: ipapermission
+default:cn: Modify Automount maps
+default:member: cn=Automount Administrators,cn=privileges,cn=pbac,$SUFFIX
+
+dn: cn=Modify Automount keys,cn=permissions,cn=pbac,$SUFFIX
+default:objectClass: top
+default:objectClass: groupofnames
+default:objectClass: ipapermission
+default:cn: Modify Automount keys
+default:member: cn=Automount Administrators,cn=privileges,cn=pbac,$SUFFIX
+
+dn: $SUFFIX
+add:aci:'(targetattr = "automountmapname || description")(target = "ldap:///automountmapname=*,cn=automount,$SUFFIX")(version 3.0;acl "permission:Modify Automount maps";allow (write) groupdn = "ldap:///cn=Modify Automount maps,cn=permissions,cn=pbac,$SUFFIX";)'
+add:aci:'(targetattr = "automountkey || automountinformation || description")(targetfilter = "(objectclass=automount)")(target = "ldap:///automountmapname=*,cn=automount,$SUFFIX")(version 3.0;acl "permission:Modify Automount keys";allow (write) groupdn = "ldap:///cn=Modify Automount keys,cn=permissions,cn=pbac,$SUFFIX";)'
+replace:aci:'(target = "ldap:///automountkey=*,automountmapname=*,cn=automount,$SUFFIX")(version 3.0;acl "permission:Add Automount keys";allow (add) groupdn = "ldap:///cn=Add Automount keys,cn=permissions,cn=pbac,$SUFFIX";)::(targetfilter = "(objectclass=automount)")(target = "ldap:///automountmapname=*,cn=automount,$SUFFIX")(version 3.0;acl "permission:Add Automount keys";allow (add) groupdn = "ldap:///cn=Add Automount keys,cn=permissions,cn=pbac,$SUFFIX";)'
+replace:aci:'(target = "ldap:///automountkey=*,automountmapname=*,cn=automount,$SUFFIX")(version 3.0;acl "permission:Remove Automount keys";allow (delete) groupdn = "ldap:///cn=Remove Automount keys,cn=permissions,cn=pbac,$SUFFIX";)::(targetfilter = "(objectclass=automount)")(target = "ldap:///automountmapname=*,cn=automount,$SUFFIX")(version 3.0;acl "permission:Remove Automount keys";allow (delete) groupdn = "ldap:///cn=Remove Automount keys,cn=permissions,cn=pbac,$SUFFIX";)'
+
# SSH public keys
dn: cn=Manage User SSH Public Keys,cn=permissions,cn=pbac,$SUFFIX
default:objectClass: top
--
1.7.11.2

View File

@ -0,0 +1,25 @@
From 17c638b70e31be71a129684f8ac36861bd1eae0e Mon Sep 17 00:00:00 2001
From: Gowrishankar Rajaiyan <gsr@redhat.com>
Date: Thu, 12 Jul 2012 15:09:08 +0530
Subject: [PATCH 20/79] Adding exit status 3 & 4 to ipa-client-install man
page
---
ipa-client/man/ipa-client-install.1 | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/ipa-client/man/ipa-client-install.1 b/ipa-client/man/ipa-client-install.1
index 2ee5a1a04d45ef2e85db708c2ae0786cca363991..c3ec6de5270ea9be6fd707b758deb89371915fe6 100644
--- a/ipa-client/man/ipa-client-install.1
+++ b/ipa-client/man/ipa-client-install.1
@@ -161,3 +161,7 @@ Files updated, existing content is maintained:
1 if an error occurred
2 if uninstalling and the client is not configured
+
+3 if installing and the client is already configured
+
+4 if an uninstall error occurred
--
1.7.11.2

View File

@ -0,0 +1,28 @@
From 5c54dd5b03681428040af51ef3e05c10bec91d3f Mon Sep 17 00:00:00 2001
From: Martin Kosek <mkosek@redhat.com>
Date: Thu, 12 Jul 2012 15:07:53 +0200
Subject: [PATCH 21/79] Fix ipa-managed-entries man page typo
Extra new line in .TH section of the man page caused invalid
wrapping.
---
install/tools/man/ipa-managed-entries.1 | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/install/tools/man/ipa-managed-entries.1 b/install/tools/man/ipa-managed-entries.1
index e46b693176d87d772853e3254b664403d386e4c8..3d5ca22b87846d2b46122c7171016019aa07028e 100644
--- a/install/tools/man/ipa-managed-entries.1
+++ b/install/tools/man/ipa-managed-entries.1
@@ -16,8 +16,7 @@
.\"
.\" Author: Jr Aquino <jr.aquino@citrix.com>
.\"
-.TH "ipa-managed-entries" "1" "Feb 06 2012" "FreeIPA" "FreeIPA Manual
-Pages"
+.TH "ipa-managed-entries" "1" "Feb 06 2012" "FreeIPA" "FreeIPA Manual Pages"
.SH "NAME"
ipa\-managed\-entries \- Enables or disables the schema Managed Entry plugins
.SH "SYNOPSIS"
--
1.7.11.2

View File

@ -0,0 +1,532 @@
From 4879c68d68634715b9d08a08a4c7be882634409f Mon Sep 17 00:00:00 2001
From: Martin Kosek <mkosek@redhat.com>
Date: Tue, 3 Jul 2012 16:49:10 +0200
Subject: [PATCH 22/79] Improve address family handling in sockets
Many functions use low-level socket interface for connection or
various checks. However, most of the time we don't respect
automatic address family detection but rather try to force our
values. This may cause either redundat connection tries when an
address family is disabled on system tries or even crashes
when socket exceptions are not properly caught.
Instead of forcing address families to socket, rather use
getaddrinfo interface to automatically retrieve a list of all
relevant address families and other connection settings when
connecting to remote/local machine or binding to a local port.
Now, we will also fill correctly all connection parameters like
flowinfo and scopeid for IPv6 connections which will for example
prevent issues with scoped IPv6 addresses.
bind_port_responder function was changed to at first try to bind
to IPv6 wildcard address before IPv4 as IPv6 socket is able to
accept both IPv4 and IPv6 connections (unlike IPv4 socket).
nsslib connection was refactored to use nss.io.AddrInfo class to
get all the available connections. Socket is now not created by
default in NSSConnection class initializer, but rather when the
actual connection is being made, becase we do not an address family
where connection is successful.
https://fedorahosted.org/freeipa/ticket/2913
https://fedorahosted.org/freeipa/ticket/2695
---
install/tools/ipa-replica-conncheck | 12 +--
ipa-client/ipa-install/ipa-client-install | 51 ++++++++----
ipapython/ipautil.py | 128 +++++++++++++++++-------------
ipapython/nsslib.py | 92 ++++++++-------------
ipaserver/install/dsinstance.py | 11 ++-
ipaserver/install/installutils.py | 30 -------
6 files changed, 161 insertions(+), 163 deletions(-)
diff --git a/install/tools/ipa-replica-conncheck b/install/tools/ipa-replica-conncheck
index 6ec3be2a919c4a8a8a32cbf76f54b12d6652ff5e..8e4536cf67cafb907a3e330607a81b4bc034015b 100755
--- a/install/tools/ipa-replica-conncheck
+++ b/install/tools/ipa-replica-conncheck
@@ -236,15 +236,15 @@ class PortResponder(threading.Thread):
self._stop_request = True
def port_check(host, port_list):
- ip = installutils.resolve_host(host)
-
- if not ip:
- raise RuntimeError("Port check failed! Unable to resolve host name '%s'" % host)
-
ports_failed = []
ports_udp_warning = [] # conncheck could not verify that port is open
for port in port_list:
- if ipautil.host_port_open(host, port.port, port.port_type, socket_timeout=CONNECT_TIMEOUT):
+ try:
+ port_open = ipautil.host_port_open(host, port.port,
+ port.port_type, socket_timeout=CONNECT_TIMEOUT)
+ except socket.gaierror:
+ raise RuntimeError("Port check failed! Unable to resolve host name '%s'" % host)
+ if port_open:
result = "OK"
else:
if port.port_type == socket.SOCK_DGRAM:
diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install
index ef0dc293c994cdf8165a610f0701ade5b14942e6..081ae7f281a04bae29c4a1cd27c125d879732e23 100755
--- a/ipa-client/ipa-install/ipa-client-install
+++ b/ipa-client/ipa-install/ipa-client-install
@@ -979,19 +979,36 @@ def configure_ssh(fstore, ssh_dir, options):
def resolve_ipaddress(server):
""" Connect to the server's LDAP port in order to determine what ip
address this machine uses as "public" ip (relative to the server).
+
+ Returns a tuple with the IP address and address family when
+ connection was successful. Socket error is raised otherwise.
"""
+ last_socket_error = None
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
- try:
- s.connect((server, 389))
- addr, port = s.getsockname()
- except socket.gaierror:
- s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM, socket.IPPROTO_TCP)
- s.connect((server, 389))
- addr, port, foo, bar = s.getsockname()
- s.close()
-
- return addr
+ for res in socket.getaddrinfo(server, 389, socket.AF_UNSPEC,
+ socket.SOCK_STREAM):
+ af, socktype, proto, canonname, sa = res
+ try:
+ s = socket.socket(af, socktype, proto)
+ except socket.error, e:
+ last_socket_error = e
+ s = None
+ continue
+
+ try:
+ s.connect(sa)
+ sockname = s.getsockname()
+
+ # For both IPv4 and IPv6 own IP address is always the first item
+ return (sockname[0], af)
+ except socket.error, e:
+ last_socket_error = e
+ finally:
+ if s:
+ s.close()
+
+ if last_socket_error is not None:
+ raise last_socket_error # pylint: disable=E0702
def do_nsupdate(update_txt):
root_logger.debug("Writing nsupdate commands to %s:", UPDATE_FILE)
@@ -1037,7 +1054,13 @@ CCACHE_FILE = "/etc/ipa/.dns_ccache"
def update_dns(server, hostname):
- ip = resolve_ipaddress(server)
+ try:
+ (ip, af) = resolve_ipaddress(server)
+ except socket.gaierror, e:
+ root_logger.debug("update_dns: could not connect to server: %s", e)
+ root_logger.error("Cannot update DNS records! "
+ "Failed to connect to server '%s'.", server)
+ return
sub_dict = dict(HOSTNAME=hostname,
IPADDRESS=ip,
@@ -1045,9 +1068,9 @@ def update_dns(server, hostname):
ZONE='.'.join(hostname.split('.')[1:])
)
- if len(ip.split('.')) == 4:
+ if af == socket.AF_INET:
template = UPDATE_TEMPLATE_A
- elif ':' in ip:
+ elif af == socket.AF_INET6:
template = UPDATE_TEMPLATE_AAAA
else:
root_logger.info("Failed to determine this machine's ip address.")
diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
index e80434cfd31ddb6112e83800aca9cf5440ffaff8..22c8e2937a731252ffcac77c9bd7e0bf636e61ff 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -48,6 +48,7 @@ from dns.exception import DNSException
from ipapython.ipa_log_manager import *
from ipapython import ipavalidate
from ipapython import config
+
try:
from subprocess import CalledProcessError
except ImportError:
@@ -672,72 +673,103 @@ def get_gsserror(e):
def host_port_open(host, port, socket_type=socket.SOCK_STREAM, socket_timeout=None):
- families = (socket.AF_INET, socket.AF_INET6)
- success = False
-
- for family in families:
+ for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket_type):
+ af, socktype, proto, canonname, sa = res
try:
try:
- s = socket.socket(family, socket_type)
+ s = socket.socket(af, socktype, proto)
except socket.error:
+ s = None
continue
if socket_timeout is not None:
s.settimeout(socket_timeout)
- s.connect((host, port))
+ s.connect(sa)
if socket_type == socket.SOCK_DGRAM:
s.send('')
s.recv(512)
- success = True
+ return True
except socket.error, e:
pass
finally:
- s.close()
-
- if success:
- return True
+ if s:
+ s.close()
return False
def bind_port_responder(port, socket_type=socket.SOCK_STREAM, socket_timeout=None, responder_data=None):
- families = (socket.AF_INET, socket.AF_INET6)
+ host = None # all available interfaces
+ last_socket_error = None
- host = '' # all available interfaces
+ # At first try to create IPv6 socket as it is able to accept both IPv6 and
+ # IPv4 connections (when not turned off)
+ families = (socket.AF_INET6, socket.AF_INET)
+ s = None
for family in families:
try:
- s = socket.socket(family, socket_type)
+ addr_infos = socket.getaddrinfo(host, port, family, socket_type, 0,
+ socket.AI_PASSIVE)
except socket.error, e:
- if family == families[-1]: # last available family
- raise e
+ last_socket_error = e
+ continue
+ for res in addr_infos:
+ af, socktype, proto, canonname, sa = res
+ try:
+ s = socket.socket(af, socktype, proto)
+ except socket.error, e:
+ last_socket_error = e
+ s = None
+ continue
- if socket_timeout is not None:
- s.settimeout(socket_timeout)
+ if socket_timeout is not None:
+ s.settimeout(1)
- if socket_type == socket.SOCK_STREAM:
- s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ if af == socket.AF_INET6:
+ try:
+ # Make sure IPv4 clients can connect to IPv6 socket
+ s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
+ except socket.error:
+ pass
- try:
- s.bind((host, port))
+ if socket_type == socket.SOCK_STREAM:
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- if socket_type == socket.SOCK_STREAM:
- s.listen(1)
- connection, client_address = s.accept()
try:
- if responder_data:
- connection.sendall(responder_data) #pylint: disable=E1101
+ s.bind(sa)
+
+ while True:
+ if socket_type == socket.SOCK_STREAM:
+ s.listen(1)
+ connection, client_address = s.accept()
+ try:
+ if responder_data:
+ connection.sendall(responder_data) #pylint: disable=E1101
+ finally:
+ connection.close()
+ elif socket_type == socket.SOCK_DGRAM:
+ data, addr = s.recvfrom(1)
+
+ if responder_data:
+ s.sendto(responder_data, addr)
+ except socket.timeout:
+ # Timeout is expectable as it was requested by caller, raise
+ # the exception back to him
+ raise
+ except socket.error, e:
+ last_socket_error = e
+ s.close()
+ s = None
+ continue
finally:
- connection.close()
- elif socket_type == socket.SOCK_DGRAM:
- data, addr = s.recvfrom(1)
+ if s:
+ s.close()
- if responder_data:
- s.sendto(responder_data, addr)
- finally:
- s.close()
+ if s is None and last_socket_error is not None:
+ raise last_socket_error # pylint: disable=E0702
def is_host_resolvable(fqdn):
for rdtype in (rdatatype.A, rdatatype.AAAA):
@@ -1015,34 +1047,24 @@ def utf8_encode_values(values):
def wait_for_open_ports(host, ports, timeout=0):
"""
Wait until the specified port(s) on the remote host are open. Timeout
- in seconds may be specified to limit the wait.
+ in seconds may be specified to limit the wait. If the timeout is
+ exceeded, socket.timeout exception is raised.
"""
if not isinstance(ports, (tuple, list)):
ports = [ports]
- root_logger.debug('wait_for_open_ports: %s %s timeout %d' % (host, ports, timeout))
+ root_logger.debug('wait_for_open_ports: %s %s timeout %d', host, ports, timeout)
op_timeout = time.time() + timeout
- ipv6_failover = False
for port in ports:
while True:
- try:
- if ipv6_failover:
- s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
- else:
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- s.connect((host, port))
- s.close()
+ port_open = host_port_open(host, port)
+
+ if port_open:
break
- except socket.error, e:
- if e.errno == 111: # 111: Connection refused
- if timeout and time.time() > op_timeout: # timeout exceeded
- raise e
- time.sleep(1)
- elif not ipv6_failover: # fallback to IPv6 connection
- ipv6_failover = True
- else:
- raise e
+ if timeout and time.time() > op_timeout: # timeout exceeded
+ raise socket.timeout()
+ time.sleep(1)
def wait_for_open_socket(socket_name, timeout=0):
"""
diff --git a/ipapython/nsslib.py b/ipapython/nsslib.py
index aae24467ff7313092040e062867b70ed1563c16f..06bcba64895b0ba7a6b814ed6748eff8bf5ff9b3 100644
--- a/ipapython/nsslib.py
+++ b/ipapython/nsslib.py
@@ -115,6 +115,12 @@ def client_auth_data_callback(ca_names, chosen_nickname, password, certdb):
return False
return False
+_af_dict = {
+ socket.AF_INET: io.PR_AF_INET,
+ socket.AF_INET6: io.PR_AF_INET6,
+ socket.AF_UNSPEC: io.PR_AF_UNSPEC
+}
+
class NSSAddressFamilyFallback(object):
def __init__(self, family):
self.sock_family = family
@@ -124,67 +130,39 @@ class NSSAddressFamilyFallback(object):
"""
Translate a family from python socket module to nss family.
"""
- if sock_family in [ socket.AF_INET, socket.AF_UNSPEC ]:
- return io.PR_AF_INET
- elif sock_family == socket.AF_INET6:
- return io.PR_AF_INET6
- else:
+ try:
+ return _af_dict[sock_family]
+ except KeyError:
raise ValueError('Uknown socket family %d\n', sock_family)
- def _get_next_family(self):
- if self.sock_family == socket.AF_UNSPEC and \
- self.family == io.PR_AF_INET:
- return io.PR_AF_INET6
-
- return None
-
def _create_socket(self):
self.sock = io.Socket(family=self.family)
- def _connect_socket_family(self, host, port, family):
- root_logger.debug("connect_socket_family: host=%s port=%s family=%s",
- host, port, io.addr_family_name(family))
- try:
- addr_info = [ ai for ai in io.AddrInfo(host) if ai.family == family ]
- # No suitable families
- if len(addr_info) == 0:
- raise NSPRError(error.PR_ADDRESS_NOT_SUPPORTED_ERROR,
- "Cannot resolve %s using family %s" % (host, io.addr_family_name(family)))
-
- # Try connecting to the NetworkAddresses
- for net_addr in addr_info:
- net_addr.port = port
- root_logger.debug("connecting: %s", net_addr)
- try:
- self.sock.connect(net_addr)
- except Exception, e:
- root_logger.debug("Could not connect socket to %s, error: %s, retrying..",
- net_addr, str(e))
- continue
- else:
- return
-
- # Could not connect with any of NetworkAddresses
- raise NSPRError(error.PR_ADDRESS_NOT_SUPPORTED_ERROR,
- "Could not connect to %s using any address" % host)
- except ValueError, e:
- raise NSPRError(error.PR_ADDRESS_NOT_SUPPORTED_ERROR, e.message)
-
def connect_socket(self, host, port):
try:
- self._connect_socket_family(host, port, self.family)
- except NSPRError, e:
- if e.errno == error.PR_ADDRESS_NOT_SUPPORTED_ERROR:
- next_family = self._get_next_family()
- if next_family:
- self.family = next_family
- self._create_socket()
- self._connect_socket_family(host, port, self.family)
- else:
- root_logger.debug('No next family to try..')
- raise e
- else:
- raise e
+ addr_info = io.AddrInfo(host, family=self.family)
+ except Exception:
+ raise NSPRError(error.PR_ADDRESS_NOT_SUPPORTED_ERROR,
+ "Cannot resolve %s using family %s" % (host,
+ io.addr_family_name(self.family)))
+
+ for net_addr in addr_info:
+ root_logger.debug("Connecting: %s", net_addr)
+ net_addr.port = port
+ self.family = net_addr.family
+ try:
+ self._create_socket()
+ self.sock.connect(net_addr)
+ return
+ except Exception, e:
+ root_logger.debug("Could not connect socket to %s, error: %s",
+ net_addr, str(e))
+ root_logger.debug("Try to continue with next family...")
+ continue
+
+ raise NSPRError(error.PR_ADDRESS_NOT_SUPPORTED_ERROR,
+ "Could not connect to %s using any address" % host)
+
class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback):
default_port = httplib.HTTPSConnection.default_port
@@ -218,12 +196,10 @@ class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback):
nss.nss_init(dbdir)
ssl.set_domestic_policy()
nss.set_password_callback(self.password_callback)
- self._create_socket()
def _create_socket(self):
-
- #TODO remove the try block once python-nss is guaranteed to
- #contain these values
+ # TODO: remove the try block once python-nss is guaranteed to contain
+ # these values
try :
ssl_enable_renegotiation = SSL_ENABLE_RENEGOTIATION #pylint: disable=E0602
ssl_require_safe_negotiation = SSL_REQUIRE_SAFE_NEGOTIATION #pylint: disable=E0602
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 9c137af030e2d86fa3df3e0e987e57d75d53c5d4..25c449a6e865de01d789a739b31906cb70c6f212 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -119,8 +119,15 @@ def get_ds_instances():
return instances
def check_ports():
- ds_unsecure = installutils.port_available(389)
- ds_secure = installutils.port_available(636)
+ """
+ Check of Directory server ports are open.
+
+ Returns a tuple with two booleans, one for unsecure port 389 and one for
+ secure port 636. True means that the port is free, False means that the
+ port is taken.
+ """
+ ds_unsecure = not ipautil.host_port_open(None, 389)
+ ds_secure = not ipautil.host_port_open(None, 636)
return (ds_unsecure, ds_secure)
def is_ds_running(server_id=''):
diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py
index b65958eda1b2b6da4db942d77bca63eee1c616f6..903e8f185c54182e800eda547b80b380f24ae8e4 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -256,36 +256,6 @@ def read_dns_forwarders():
return addrs
-def port_available(port):
- """Try to bind to a port on the wildcard host
- Return 1 if the port is available
- Return 0 if the port is in use
- """
- rv = 1
-
- try:
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- fcntl.fcntl(s, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
- s.bind(('', port))
- s.close()
- except socket.error, e:
- if e[0] == errno.EADDRINUSE:
- rv = 0
-
- if rv:
- try:
- s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
- s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- fcntl.fcntl(s, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
- s.bind(('', port))
- s.close()
- except socket.error, e:
- if e[0] == errno.EADDRINUSE:
- rv = 0
-
- return rv
-
def get_password(prompt):
if os.isatty(sys.stdin.fileno()):
return getpass.getpass(prompt)
--
1.7.11.2

View File

@ -0,0 +1,483 @@
From 9d69db80a3d1fc46236a4546988176cdd7939b82 Mon Sep 17 00:00:00 2001
From: Martin Kosek <mkosek@redhat.com>
Date: Thu, 28 Jun 2012 16:46:48 +0200
Subject: [PATCH 23/79] Enable SOA serial autoincrement
SOA serial autoincrement is a requirement for major DNS features,
e.g. zone transfers or DNSSEC. Enable it by default in named.conf
both for new and upgraded installations. Name of the bind-dyndb-ldap
option is "serial_autoincrement".
From now on, idnsSOAserial attribute also has to be put to
replication agreement exclude list as serial will be incremented
on each DNS server separately and won't be shared. Exclude list
has to be updated both for new replication agreements and the
current ones.
Minimum number of connections for bind-dyndb-ldap has been rised
to 4 connections, the setting will be updated during package upgrade.
https://fedorahosted.org/freeipa/ticket/2554
---
install/share/bind.named.conf.template | 1 +
install/tools/ipa-dns-install | 10 +++-
install/tools/ipa-server-install | 12 +++-
install/tools/ipa-upgradeconfig | 68 +++++++++++++++++++++--
install/tools/man/ipa-dns-install.1 | 5 +-
install/tools/man/ipa-server-install.1 | 5 +-
ipalib/plugins/dns.py | 11 +++-
ipaserver/install/bindinstance.py | 11 +++-
ipaserver/install/plugins/fix_replica_memberof.py | 51 ++++++++---------
ipaserver/install/replication.py | 22 ++++----
10 files changed, 145 insertions(+), 51 deletions(-)
diff --git a/install/share/bind.named.conf.template b/install/share/bind.named.conf.template
index f133b089a9eb428e9ad76b66a3ff162b45e5a779..9fdd91319947f6cfd3034f8d2a4fe8bb60d1af77 100644
--- a/install/share/bind.named.conf.template
+++ b/install/share/bind.named.conf.template
@@ -46,4 +46,5 @@ dynamic-db "ipa" {
arg "sasl_user DNS/$FQDN";
arg "zone_refresh $ZONE_REFRESH";
arg "psearch $PERSISTENT_SEARCH";
+ arg "serial_autoincrement $SERIAL_AUTOINCREMENT";
};
diff --git a/install/tools/ipa-dns-install b/install/tools/ipa-dns-install
index 6e9b9989792aba6f7607348da4693cf605dc0b76..47bffdf8354fa509d64af0ba0e15d5880010e425 100755
--- a/install/tools/ipa-dns-install
+++ b/install/tools/ipa-dns-install
@@ -62,6 +62,9 @@ def parse_options():
default=0, type="int",
help="When set to non-zero the name server will use DNS zone "
"detection based on polling instead of a persistent search")
+ parser.add_option("--no-serial-autoincrement", dest="serial_autoincrement",
+ default=True, action="store_false",
+ help="Do not enable SOA serial autoincrement")
parser.add_option("-U", "--unattended", dest="unattended", action="store_true",
default=False, help="unattended installation never prompts the user")
@@ -85,6 +88,10 @@ def parse_options():
if options.zone_notif:
print >>sys.stderr, "WARNING: --zone-notif option is deprecated and has no effect"
+ if options.serial_autoincrement and not options.persistent_search:
+ parser.error('persistent search feature is required for '
+ 'DNS SOA serial autoincrement')
+
return safe_options, options
def main():
@@ -224,7 +231,8 @@ def main():
bind.setup(api.env.host, ip_address, api.env.realm, api.env.domain,
dns_forwarders, conf_ntp, reverse_zone, zonemgr=options.zonemgr,
zone_refresh=options.zone_refresh,
- persistent_search=options.persistent_search)
+ persistent_search=options.persistent_search,
+ serial_autoincrement=options.serial_autoincrement)
bind.create_instance()
# Restart http instance to make sure that python-dns has the right resolver
diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install
index 6dc02f684e0b6fc21f150eadef1c286f2a326233..d7de7063111936550ae1f14cf93ebfd46754c829 100755
--- a/install/tools/ipa-server-install
+++ b/install/tools/ipa-server-install
@@ -210,7 +210,10 @@ def parse_options():
default=False,
help="Do not use DNS for hostname lookup during installation")
dns_group.add_option("--no-dns-sshfp", dest="create_sshfp", default=True, action="store_false",
- help="do not automatically create DNS SSHFP records")
+ help="Do not automatically create DNS SSHFP records")
+ dns_group.add_option("--no-serial-autoincrement", dest="serial_autoincrement",
+ default=True, action="store_false",
+ help="Do not enable SOA serial autoincrement")
parser.add_option_group(dns_group)
uninstall_group = OptionGroup(parser, "uninstall options")
@@ -304,6 +307,10 @@ def parse_options():
elif options.zone_refresh > 0:
options.persistent_search = False # mutually exclusive features
+ if options.serial_autoincrement and not options.persistent_search:
+ parser.error('persistent search feature is required for '
+ 'DNS SOA serial autoincrement')
+
if options.zone_notif:
print >>sys.stderr, "WARNING: --zone-notif option is deprecated and has no effect"
@@ -1036,7 +1043,8 @@ def main():
bind.setup(host_name, ip_address, realm_name, domain_name, dns_forwarders,
options.conf_ntp, reverse_zone, zonemgr=options.zonemgr,
zone_refresh=options.zone_refresh,
- persistent_search=options.persistent_search)
+ persistent_search=options.persistent_search,
+ serial_autoincrement=options.serial_autoincrement)
if options.setup_dns:
api.Backend.ldap2.connect(bind_dn="cn=Directory Manager", bind_pw=dm_password)
diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig
index 248232ac6e8048b6091c56a7824025f39a275fba..b82f039d4ce8db05ce41193212951d4d79fca79b 100644
--- a/install/tools/ipa-upgradeconfig
+++ b/install/tools/ipa-upgradeconfig
@@ -302,7 +302,7 @@ def upgrade_httpd_selinux(fstore):
http = httpinstance.HTTPInstance(fstore)
http.configure_selinux_for_httpd()
-def enable_psearch_for_named():
+def named_enable_psearch():
"""
From IPA 3.0, persistent search is a preferred mechanism for new DNS zone
detection and is also needed for other features (DNSSEC, SOA serial
@@ -322,11 +322,13 @@ def enable_psearch_for_named():
return
try:
- psearch = bindinstance.named_conf_get_directive('psearch').lower()
+ psearch = bindinstance.named_conf_get_directive('psearch')
except IOError, e:
root_logger.debug('Cannot retrieve psearch option from %s: %s',
bindinstance.NAMED_CONF, e)
return
+ else:
+ psearch = None if psearch is None else psearch.lower()
if not sysupgrade.get_upgrade_state('named.conf', 'psearch_enabled'):
if psearch != "yes":
try:
@@ -343,7 +345,8 @@ def enable_psearch_for_named():
# make sure number of connections is right
minimum_connections = 2
if psearch == 'yes':
- minimum_connections = 3
+ # serial_autoincrement increased the minimal number of connections to 4
+ minimum_connections = 4
try:
connections = bindinstance.named_conf_get_directive('connections')
except IOError, e:
@@ -373,6 +376,59 @@ def enable_psearch_for_named():
root_logger.debug('No changes made')
return changed
+def named_enable_serial_autoincrement():
+ """
+ Serial autoincrement is a requirement for zone transfers or DNSSEC. It
+ should be enabled both for new installs and upgraded servers.
+
+ When some change in named.conf is done, this functions returns True
+ """
+ changed = False
+
+ root_logger.info('[Enabling serial autoincrement in DNS]')
+
+ if not bindinstance.named_conf_exists():
+ # DNS service may not be configured
+ root_logger.debug('DNS not configured')
+ return changed
+
+ try:
+ psearch = bindinstance.named_conf_get_directive('psearch')
+ serial_autoincrement = bindinstance.named_conf_get_directive(
+ 'serial_autoincrement')
+ except IOError, e:
+ root_logger.debug('Cannot retrieve psearch option from %s: %s',
+ bindinstance.NAMED_CONF, e)
+ return changed
+ else:
+ psearch = None if psearch is None else psearch.lower()
+ serial_autoincrement = None if serial_autoincrement is None \
+ else serial_autoincrement.lower()
+
+ # enable SOA serial autoincrement
+ if not sysupgrade.get_upgrade_state('named.conf', 'autoincrement_enabled'):
+ if psearch != "yes": # psearch is required
+ root_logger.debug('Persistent search is disabled, '
+ 'serial autoincrement cannot be enabled')
+ else:
+ if serial_autoincrement != 'yes':
+ try:
+ bindinstance.named_conf_set_directive('serial_autoincrement', 'yes')
+ except IOError, e:
+ root_logger.error('Cannot enable serial_autoincrement in %s: %s',
+ bindinstance.NAMED_CONF, e)
+ return changed
+ else:
+ root_logger.debug('Serial autoincrement enabled')
+ changed = True
+ else:
+ root_logger.debug('Serial autoincrement is alredy enabled')
+ sysupgrade.set_upgrade_state('named.conf', 'autoincrement_enabled', True)
+ else:
+ root_logger.debug('Skip serial autoincrement check')
+
+ return changed
+
def main():
"""
Get some basics about the system. If getting those basics fail then
@@ -435,9 +491,11 @@ def main():
cleanup_kdc(fstore)
upgrade_ipa_profile(krbctx.default_realm)
- changed = enable_psearch_for_named()
- if changed:
+ changed_psearch = named_enable_psearch()
+ changed_autoincrement = named_enable_serial_autoincrement()
+ if changed_psearch or changed_autoincrement:
# configuration has changed, restart the name server
+ root_logger.info('Changes to named.conf have been made, restart named')
bindinstance.BindInstance(fstore).restart()
if __name__ == '__main__':
diff --git a/install/tools/man/ipa-dns-install.1 b/install/tools/man/ipa-dns-install.1
index 9fe89ed1ea267cde7216e9e28e95cfea2349172b..b0bdca94f4aea4a17fecc3362a92a9885bbafed0 100644
--- a/install/tools/man/ipa-dns-install.1
+++ b/install/tools/man/ipa-dns-install.1
@@ -16,7 +16,7 @@
.\"
.\" Author: Rob Crittenden <rcritten@redhat.com>
.\"
-.TH "ipa-dns-install" "1" "Sep 9, 2010" "FreeIPA" "FreeIPA Manual Pages"
+.TH "ipa-dns-install" "1" "Jun 28, 2012" "FreeIPA" "FreeIPA Manual Pages"
.SH "NAME"
ipa\-dns\-install \- Add DNS as a service to an IPA server
.SH "SYNOPSIS"
@@ -55,6 +55,9 @@ Do not enable persistent search mechanism for updating the list of DNS zones in
\fB\-\-zone\-refresh=\fIZONE_REFRESH\fR
When set to non-zero value, persistent search zone update mechanism will be disabled and the name server will use a polling mechanism to load new DNS zones every \fIZONE_REFRESH\fR seconds.
.TP
+\fB\-\-no\-serial\-autoincrement\fR
+Do not enable SOA serial autoincrement feature. SOA serial will have to be updated automatically or other DNS features like zone transfer od DNSSEC will not function properly. This feature requires persistent search zone update mechanism.
+.TP
\fB\-U\fR, \fB\-\-unattended\fR
An unattended installation that will never prompt for user input
.SH "EXIT STATUS"
diff --git a/install/tools/man/ipa-server-install.1 b/install/tools/man/ipa-server-install.1
index 77d40685059fe74bed8d0693c38d2904909c01f3..61b7c669ca26d5fecbdbd9e30fccad4c1d4d9701 100644
--- a/install/tools/man/ipa-server-install.1
+++ b/install/tools/man/ipa-server-install.1
@@ -16,7 +16,7 @@
.\"
.\" Author: Rob Crittenden <rcritten@redhat.com>
.\"
-.TH "ipa-server-install" "1" "Sep 5 2011" "FreeIPA" "FreeIPA Manual Pages"
+.TH "ipa-server-install" "1" "Jun 28 2012" "FreeIPA" "FreeIPA Manual Pages"
.SH "NAME"
ipa\-server\-install \- Configure an IPA server
.SH "SYNOPSIS"
@@ -156,6 +156,9 @@ Do not use DNS for hostname lookup during installation
.TP
\fB\-\-no\-dns\-sshfp\fR
Do not automatically create DNS SSHFP records.
+.TP
+\fB\-\-no\-serial\-autoincrement\fR
+Do not enable SOA serial autoincrement feature. SOA serial will have to be updated automatically or other DNS features like zone transfer od DNSSEC will not function properly. This feature requires persistent search zone update mechanism.
.SS "UNINSTALL OPTIONS"
.TP
diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py
index c2bf13a2ff5e1c05cb21d07ce9d63e9881ef0da2..857814917f9ce75886aee571885a3dd718427ef3 100644
--- a/ipalib/plugins/dns.py
+++ b/ipalib/plugins/dns.py
@@ -244,8 +244,15 @@ def _rname_validator(ugettext, zonemgr):
return None
def _create_zone_serial():
- """ Generate serial number for zones. The format follows RFC 1912 """
- return int('%s01' % time.strftime('%Y%m%d'))
+ """
+ Generate serial number for zones. bind-dyndb-ldap expects unix time in
+ to be used for SOA serial.
+
+ SOA serial in a date format would also work, but it may be set to far
+ future when many DNS updates are done per day (more than 100). Unix
+ timestamp is more resilient to this issue.
+ """
+ return int(time.time())
def _reverse_zone_name(netstr):
net = netaddr.IPNetwork(netstr)
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index 3ff593298979534cad79fa35f2626991db82cec7..9faf17698d3cb806ed601f728c3870bfe28c9424 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -467,7 +467,7 @@ class BindInstance(service.Service):
def setup(self, fqdn, ip_address, realm_name, domain_name, forwarders, ntp,
reverse_zone, named_user="named", zonemgr=None,
- zone_refresh=0, persistent_search=True):
+ zone_refresh=0, persistent_search=True, serial_autoincrement=True):
self.named_user = named_user
self.fqdn = fqdn
self.ip_address = ip_address
@@ -480,6 +480,7 @@ class BindInstance(service.Service):
self.reverse_zone = reverse_zone
self.zone_refresh = zone_refresh
self.persistent_search = persistent_search
+ self.serial_autoincrement = True
if not zonemgr:
self.zonemgr = 'hostmaster.%s' % self.domain
@@ -576,7 +577,10 @@ class BindInstance(service.Service):
optional_ntp += "_ntp._udp\t\tIN SRV 0 100 123\t%s""" % self.host_in_rr
else:
optional_ntp = ""
- persistent_search = "yes" if self.persistent_search else "no"
+
+ boolean_var = {}
+ for var in ('persistent_search', 'serial_autoincrement'):
+ boolean_var[var] = "yes" if getattr(self, var, False) else "no"
self.sub_dict = dict(FQDN=self.fqdn,
IP=self.ip_address,
@@ -589,7 +593,8 @@ class BindInstance(service.Service):
OPTIONAL_NTP=optional_ntp,
ZONEMGR=self.zonemgr,
ZONE_REFRESH=self.zone_refresh,
- PERSISTENT_SEARCH=persistent_search)
+ PERSISTENT_SEARCH=boolean_var['persistent_search'],
+ SERIAL_AUTOINCREMENT=boolean_var['serial_autoincrement'],)
def __setup_dns_container(self):
self._ldap_mod("dns.ldif", self.sub_dict)
diff --git a/ipaserver/install/plugins/fix_replica_memberof.py b/ipaserver/install/plugins/fix_replica_memberof.py
index 04152d36021f7d962b335a7553861a13ba03a769..23bde0c9f8b0991e702c27315ebda5e0d3b88424 100644
--- a/ipaserver/install/plugins/fix_replica_memberof.py
+++ b/ipaserver/install/plugins/fix_replica_memberof.py
@@ -25,28 +25,24 @@ from ipaserver import ipaldap
from ipaserver.install import replication
from ipalib import api
-class update_replica_memberof(PreUpdate):
+class update_replica_exclude_attribute_list(PreUpdate):
"""
- Run through all replication agreements and ensure that memberOf is
- included in the EXCLUDE list so we don't cause replication storms.
+ Run through all replication agreements and ensure that EXCLUDE list
+ has all the required attributes so that we don't cause replication
+ storms.
"""
order=MIDDLE
def execute(self, **options):
- totalexcludes = ('entryusn',
- 'krblastsuccessfulauth',
- 'krblastfailedauth',
- 'krbloginfailedcount')
- excludes = ('memberof', ) + totalexcludes
-
# We need an IPAdmin connection to the backend
+ self.log.debug("Start replication agreement exclude list update task")
conn = ipaldap.IPAdmin(api.env.host, ldapi=True, realm=api.env.realm)
conn.do_external_bind(pwd.getpwuid(os.geteuid()).pw_name)
repl = replication.ReplicationManager(api.env.realm, api.env.host,
None, conn=conn)
entries = repl.find_replication_agreements()
- self.log.debug("Found %d agreement(s)" % len(entries))
+ self.log.debug("Found %d agreement(s)", len(entries))
for replica in entries:
self.log.debug(replica.description)
attrlist = replica.getValue('nsDS5ReplicatedAttributeList')
@@ -55,28 +51,33 @@ class update_replica_memberof(PreUpdate):
current = replica.toDict()
# Need to add it altogether
replica.setValues('nsDS5ReplicatedAttributeList',
- '(objectclass=*) $ EXCLUDE %s' % " ".join(excludes))
+ '(objectclass=*) $ EXCLUDE %s' % " ".join(replication.EXCLUDES))
replica.setValues('nsDS5ReplicatedAttributeListTotal',
- '(objectclass=*) $ EXCLUDE %s' % " ".join(totalexcludes))
+ '(objectclass=*) $ EXCLUDE %s' % " ".join(replication.TOTAL_EXCLUDES))
try:
repl.conn.updateEntry(replica.dn, current, replica.toDict())
self.log.debug("Updated")
except Exception, e:
- self.log.error("Error caught updating replica: %s" % str(e))
- elif 'memberof' not in attrlist.lower():
- self.log.debug("Attribute list needs updating")
- current = replica.toDict()
- replica.setValue('nsDS5ReplicatedAttributeList',
- replica.nsDS5ReplicatedAttributeList + ' memberof')
- try:
- repl.conn.updateEntry(replica.dn, current, replica.toDict())
- self.log.debug("Updated")
- except Exception, e:
- self.log.error("Error caught updating replica: %s" % str(e))
+ self.log.error("Error caught updating replica: %s", str(e))
else:
- self.log.debug("No update necessary")
+ attrlist_normalized = attrlist.lower()
+ missing = [attr for attr in replication.EXCLUDES
+ if attr not in attrlist_normalized]
+
+ if missing:
+ self.log.debug("Attribute list needs updating")
+ current = replica.toDict()
+ replica.setValue('nsDS5ReplicatedAttributeList',
+ replica.nsDS5ReplicatedAttributeList + ' %s' % ' '.join(missing))
+ try:
+ repl.conn.updateEntry(replica.dn, current, replica.toDict())
+ self.log.debug("Updated")
+ except Exception, e:
+ self.log.error("Error caught updating replica: %s", str(e))
+ else:
+ self.log.debug("No update necessary")
self.log.debug("Done updating agreements")
return (False, False, []) # No restart, no apply now, no updates
-api.register(update_replica_memberof)
+api.register(update_replica_exclude_attribute_list)
diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py
index 417b7a0c5ee29615d2479842efc6862e39a7c3df..38abfe21071e99b0dcc6dce1e6862912361e56e8 100644
--- a/ipaserver/install/replication.py
+++ b/ipaserver/install/replication.py
@@ -43,6 +43,15 @@ REPL_MAN_DN = "cn=replication manager,cn=config"
IPA_REPLICA = 1
WINSYNC = 2
+# List of attributes that need to be excluded from replication initialization.
+TOTAL_EXCLUDES = ('entryusn',
+ 'krblastsuccessfulauth',
+ 'krblastfailedauth',
+ 'krbloginfailedcount')
+
+# List of attributes that need to be excluded from normal replication.
+EXCLUDES = ('memberof', 'idnssoaserial') + TOTAL_EXCLUDES
+
def replica_conn_check(master_host, host_name, realm, check_ca,
admin_password=None):
"""
@@ -467,15 +476,6 @@ class ReplicationManager(object):
except errors.NotFound:
pass
- # List of attributes that need to be excluded from replication initialization.
- totalexcludes = ('entryusn',
- 'krblastsuccessfulauth',
- 'krblastfailedauth',
- 'krbloginfailedcount')
-
- # List of attributes that need to be excluded from normal replication.
- excludes = ('memberof', ) + totalexcludes
-
entry = ipaldap.Entry(dn)
entry.setValues('objectclass', "nsds5replicationagreement")
entry.setValues('cn', cn)
@@ -485,7 +485,7 @@ class ReplicationManager(object):
entry.setValues('nsds5replicaroot', self.suffix)
if master is None:
entry.setValues('nsDS5ReplicatedAttributeList',
- '(objectclass=*) $ EXCLUDE %s' % " ".join(excludes))
+ '(objectclass=*) $ EXCLUDE %s' % " ".join(EXCLUDES))
entry.setValues('description', "me to %s" % b_hostname)
if isgssapi:
entry.setValues('nsds5replicatransportinfo', 'LDAP')
@@ -503,7 +503,7 @@ class ReplicationManager(object):
try:
mod = [(ldap.MOD_ADD, 'nsDS5ReplicatedAttributeListTotal',
- '(objectclass=*) $ EXCLUDE %s' % " ".join(totalexcludes))]
+ '(objectclass=*) $ EXCLUDE %s' % " ".join(TOTAL_EXCLUDES))]
a_conn.modify_s(dn, mod)
except ldap.LDAPError, e:
# Apparently there are problems set the total list
--
1.7.11.2

View File

@ -0,0 +1,187 @@
From 34f8ff47932c49ab3a2b19a64c84b7d3ae0b514a Mon Sep 17 00:00:00 2001
From: Martin Kosek <mkosek@redhat.com>
Date: Wed, 11 Jul 2012 14:09:17 +0200
Subject: [PATCH 24/79] Add range-mod command
range plugin was missing range-mod command that could be used for
example to fix a size for a range generated during upgrades. The
range should be updated with a caution though, a misconfiguration
could break trusts.
iparangetype is now also handled better and filled in all commands
instead of just range-show. objectclass attribute is deleted only
when really needed now.
---
API.txt | 19 ++++++++++++++++
VERSION | 2 +-
ipalib/plugins/range.py | 41 +++++++++++++++++++++++++++++-----
tests/test_xmlrpc/test_range_plugin.py | 23 +++++++++++++++++--
4 files changed, 76 insertions(+), 9 deletions(-)
diff --git a/API.txt b/API.txt
index 54313404142129a863792c67b706262973a268d6..691a9c4dec69f1006e52eafd3a94e351750165b7 100644
--- a/API.txt
+++ b/API.txt
@@ -2411,6 +2411,25 @@ output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: ListOfEntries('result', (<type 'list'>, <type 'tuple'>), Gettext('A list of LDAP entries', domain='ipa', localedir=None))
output: Output('count', <type 'int'>, None)
output: Output('truncated', <type 'bool'>, None)
+command: range_mod
+args: 1,13,3
+arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
+option: Int('ipabaseid', attribute=True, autofill=False, cli_name='base_id', multivalue=False, required=False)
+option: Int('ipaidrangesize', attribute=True, autofill=False, cli_name='range_size', multivalue=False, required=False)
+option: Int('ipabaserid', attribute=True, autofill=False, cli_name='rid_base', multivalue=False, required=False)
+option: Int('ipasecondarybaserid', attribute=True, autofill=False, cli_name='secondary_rid_base', multivalue=False, required=False)
+option: Str('ipanttrusteddomainsid', attribute=True, autofill=False, cli_name='dom_sid', multivalue=False, required=False)
+option: Str('iparangetype', attribute=True, autofill=False, cli_name='iparangetype', multivalue=False, required=False)
+option: Str('setattr*', cli_name='setattr', exclude='webui')
+option: Str('addattr*', cli_name='addattr', exclude='webui')
+option: Str('delattr*', cli_name='delattr', exclude='webui')
+option: Flag('rights', autofill=True, default=False)
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('version?', exclude='webui')
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+output: Output('value', <type 'unicode'>, None)
command: range_show
args: 1,4,3
arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
diff --git a/VERSION b/VERSION
index 542dd5fcaa6627711cb59f93d1a7585f6a02241a..8d9efe6573bd148f2e74961c6ce7247f9bc3393d 100644
--- a/VERSION
+++ b/VERSION
@@ -79,4 +79,4 @@ IPA_DATA_VERSION=20100614120000
# #
########################################################
IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=39
+IPA_API_VERSION_MINOR=40
diff --git a/ipalib/plugins/range.py b/ipalib/plugins/range.py
index 4448aad818ea4c9065c387e11035e165d52e4328..39849b661e35cc9092221b3d2bf7d13fb27f506c 100644
--- a/ipalib/plugins/range.py
+++ b/ipalib/plugins/range.py
@@ -80,6 +80,16 @@ class range(LDAPObject):
)
)
+ def handle_iparangetype(self, entry_attrs, options, keep_objectclass=False):
+ if not options.get('pkey_only', False):
+ if 'ipatrustedaddomainrange' in entry_attrs.get('objectclass', []):
+ entry_attrs['iparangetype'] = [unicode(_('Active Directory domain range'))]
+ else:
+ entry_attrs['iparangetype'] = [unicode(_(u'local domain range'))]
+ if not keep_objectclass:
+ if not options.get('all', False) or options.get('pkey_only', False):
+ entry_attrs.pop('objectclass', None)
+
class range_add(LDAPCreate):
__doc__ = _('Add new ID range.')
@@ -99,6 +109,10 @@ class range_add(LDAPCreate):
return dn
+ def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ self.obj.handle_iparangetype(entry_attrs, options, keep_objectclass=True)
+ return dn
+
class range_del(LDAPDelete):
__doc__ = _('Delete an ID range.')
@@ -114,8 +128,14 @@ class range_find(LDAPSearch):
# Since all range types are stored within separate containers under
# 'cn=ranges,cn=etc' search can be done on a one-level scope
def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **options):
+ attrs_list.append('objectclass')
return (filters, base_dn, ldap.SCOPE_ONELEVEL)
+ def post_callback(self, ldap, entries, truncated, *args, **options):
+ for dn,entry in entries:
+ self.obj.handle_iparangetype(entry, options)
+ return truncated
+
class range_show(LDAPRetrieve):
__doc__ = _('Display information about a range.')
@@ -124,16 +144,25 @@ class range_show(LDAPRetrieve):
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
- if 'ipatrustedaddomainrange' in entry_attrs['objectclass']:
- entry_attrs['iparangetype']=(u'Active Directory domain range')
- else:
- entry_attrs['iparangetype']=(u'local domain range')
- del entry_attrs['objectclass']
+ self.obj.handle_iparangetype(entry_attrs, options)
+ return dn
+
+class range_mod(LDAPUpdate):
+ __doc__ = _('Modify ID range.')
+
+ msg_summary = _('Modified ID range "%(value)s"')
+
+ def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ attrs_list.append('objectclass')
+ return dn
+
+ def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ self.obj.handle_iparangetype(entry_attrs, options)
return dn
api.register(range)
api.register(range_add)
-#api.register(range_mod)
+api.register(range_mod)
api.register(range_del)
api.register(range_find)
api.register(range_show)
diff --git a/tests/test_xmlrpc/test_range_plugin.py b/tests/test_xmlrpc/test_range_plugin.py
index 7c95cd57a4a2fdd91862a7659cb2aac19c5edfcc..76ffc58b724e50529b8617f7d2d96923342eb0d8 100644
--- a/tests/test_xmlrpc/test_range_plugin.py
+++ b/tests/test_xmlrpc/test_range_plugin.py
@@ -49,7 +49,8 @@ class test_range(Declarative):
ipabaseid=[u'900000'],
ipabaserid=[u'1000'],
ipasecondarybaserid=[u'20000'],
- ipaidrangesize=[u'99999']
+ ipaidrangesize=[u'99999'],
+ iparangetype=[u'local domain range'],
),
value=testrange1,
summary=u'Added ID range "%s"' % (testrange1),
@@ -69,11 +70,29 @@ class test_range(Declarative):
ipabaserid=[u'1000'],
ipasecondarybaserid=[u'20000'],
ipaidrangesize=[u'99999'],
- iparangetype=u'local domain range',
+ iparangetype=[u'local domain range'],
),
value=testrange1,
summary=None,
),
),
+
+ dict(
+ desc='Modify range %r' % (testrange1),
+ command=('range_mod', [testrange1], dict(ipaidrangesize=90000)),
+ expected=dict(
+ result=dict(
+ cn=[testrange1],
+ ipabaseid=[u'900000'],
+ ipabaserid=[u'1000'],
+ ipasecondarybaserid=[u'20000'],
+ ipaidrangesize=[u'90000'],
+ iparangetype=[u'local domain range'],
+ ),
+ value=testrange1,
+ summary=u'Modified ID range "%s"' % (testrange1),
+ ),
+ ),
+
]
--
1.7.11.2

View File

@ -0,0 +1,127 @@
From 378238b14e9faec4b871ff0178aa78e62e9b3580 Mon Sep 17 00:00:00 2001
From: Martin Kosek <mkosek@redhat.com>
Date: Wed, 11 Jul 2012 16:13:25 +0200
Subject: [PATCH 25/79] Warn user if an ID range with incorrect size was
created
IPA 3.0 introduced range ID objects in replicated space which specify
a range of IDs assigned via DNA plugin. ipa-ldap-updater generates the
default ID range which should correspond with IDs assigned to IPA
users.
However, since correct range size is not known, we should at least
warn that a range with invalid size was created so that user can
amend it.
https://fedorahosted.org/freeipa/ticket/2892
---
ipalib/constants.py | 2 ++
ipaserver/install/plugins/adtrust.py | 59 ++++++++++++++++++++++++++++++++----
2 files changed, 55 insertions(+), 6 deletions(-)
diff --git a/ipalib/constants.py b/ipalib/constants.py
index ad6d188692aa3de70cf29d5662d84672054ab4ef..f0f89a3b3ff51e06709809d4d606af96d13a7063 100644
--- a/ipalib/constants.py
+++ b/ipalib/constants.py
@@ -105,6 +105,8 @@ DEFAULT_CONFIG = (
('container_trusts', 'cn=trusts'),
('container_adtrusts', 'cn=ad,cn=trusts'),
('container_ranges', 'cn=ranges,cn=etc'),
+ ('container_dna', 'cn=dna,cn=ipa,cn=etc'),
+ ('container_dna_posix_ids', 'cn=posix-ids,cn=dna,cn=ipa,cn=etc'),
# Ports, hosts, and URIs:
# FIXME: let's renamed xmlrpc_uri to rpc_xml_uri
diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py
index abd676a2bcbec57f59eb6710560281d945cf0cea..c32d82e3a8814840e75c74b86618e4098b2fb351 100644
--- a/ipaserver/install/plugins/adtrust.py
+++ b/ipaserver/install/plugins/adtrust.py
@@ -23,6 +23,8 @@ from ipalib import api, errors
from ipalib.dn import DN
from ipapython.ipa_log_manager import *
+DEFAULT_ID_RANGE_SIZE = 200000
+
class update_default_range(PostUpdate):
"""
Create default ID range for upgraded servers.
@@ -46,18 +48,19 @@ class update_default_range(PostUpdate):
try:
(dn, admins_entry) = ldap.get_entry(dn, ['gidnumber'])
except errors.NotFound:
- root_logger.error("No local ID range and no admins group found. "
- "Cannot create default ID range")
+ root_logger.error("default_range: No local ID range and no admins "
+ "group found. Cannot create default ID range")
return (False, False, [])
- base_id = admins_entry['gidnumber'][0]
- id_range_size = 200000
+ id_range_base_id = admins_entry['gidnumber'][0]
+ id_range_name = '%s_id_range' % api.env.realm
+ id_range_size = DEFAULT_ID_RANGE_SIZE
range_entry = ['objectclass:top',
'objectclass:ipaIDrange',
'objectclass:ipaDomainIDRange',
- 'cn:%s_id_range' % api.env.realm,
- 'ipabaseid:%s' % base_id,
+ 'cn:%s' % id_range_name,
+ 'ipabaseid:%s' % id_range_base_id,
'ipaidrangesize:%s' % id_range_size,
]
@@ -69,6 +72,50 @@ class update_default_range(PostUpdate):
range_entry = map(str, range_entry)
updates[dn] = {'dn' : dn, 'default' : range_entry}
+ # Default range entry has a hard-coded range size to 200000 which is
+ # a default range size in ipa-server-install. This could cause issues
+ # if user did not use a default range, but rather defined an own,
+ # bigger range (option --idmax).
+ # We should make our best to check if this is the case and provide
+ # user with an information how to fix it.
+ dn = str(DN(api.env.container_dna_posix_ids, api.env.basedn))
+ search_filter = "objectclass=dnaSharedConfig"
+ attrs = ['dnaHostname', 'dnaRemainingValues']
+ try:
+ (entries, truncated) = ldap.find_entries(search_filter, attrs, dn)
+ except errors.NotFound:
+ root_logger.warning("default_range: no dnaSharedConfig object found. "
+ "Cannot check default range size.")
+ else:
+ masters = set()
+ remaining_values_sum = 0
+ for entry_dn, entry in entries:
+ hostname = entry.get('dnahostname', [None])[0]
+ if hostname is None or hostname in masters:
+ continue
+ remaining_values = entry.get('dnaremainingvalues', [''])[0]
+ try:
+ remaining_values = int(remaining_values)
+ except ValueError:
+ root_logger.warning("default_range: could not parse "
+ "remaining values from '%s'", remaining_values)
+ continue
+ else:
+ remaining_values_sum += remaining_values
+
+ masters.add(hostname)
+
+ if remaining_values_sum > DEFAULT_ID_RANGE_SIZE:
+ msg = ['could not verify default ID range size',
+ 'Please use the following command to set correct ID range size',
+ ' $ ipa range-mod %s --range-size=RANGE_SIZE' % id_range_name,
+ 'RANGE_SIZE may be computed from --idstart and --idmax options '
+ 'used during IPA server installation:',
+ ' RANGE_SIZE = (--idmax) - (--idstart) + 1'
+ ]
+
+ root_logger.error("default_range: %s", "\n".join(msg))
+
return (False, True, [updates])
api.register(update_default_range)
--
1.7.11.2

View File

@ -0,0 +1,78 @@
From c20d4c71b87365b3b8d9c53418a79f992e68cd00 Mon Sep 17 00:00:00 2001
From: Martin Kosek <mkosek@redhat.com>
Date: Wed, 11 Jul 2012 16:22:13 +0200
Subject: [PATCH 26/79] Print ipa-ldap-updater errors during RPM upgrade
ipa-ldap-updater does a lot of essential LDAP changes and if it
fails, user may be surprised after the upgrade why things does not
work.
Modify ipa-ldap-updater to print ERROR logging messages by default
and modify RPM upgrade scriptlet to show these errors to user. Console
error messages are now formated in a more user-friendly way.
Information message stating that IPA is not configured and i.e. there
is nothing to be updated is not printer to stderr so that it does
not pop up for every freeipa-server package update when IPA is not
configured.
https://fedorahosted.org/freeipa/ticket/2892
---
freeipa.spec.in | 2 +-
install/tools/ipa-ldap-updater | 16 ++++++++++++----
2 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/freeipa.spec.in b/freeipa.spec.in
index deeb3341b9379a2cc82e50ca37889287c4c74813..7106310915c8a4e52a009036f7152a38a4c5f18d 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -465,7 +465,7 @@ fi
%posttrans server
# This must be run in posttrans so that updates from previous
# execution that may no longer be shipped are not applied.
-/usr/sbin/ipa-ldap-updater --upgrade >/dev/null 2>&1 || :
+/usr/sbin/ipa-ldap-updater --upgrade >/dev/null || :
%preun server
if [ $1 = 0 ]; then
diff --git a/install/tools/ipa-ldap-updater b/install/tools/ipa-ldap-updater
index 197b840b07867269340f56e32989820d8af59ae1..8f5c76645d9ba2b204f3b1051d9dc8b23eacce9d 100755
--- a/install/tools/ipa-ldap-updater
+++ b/install/tools/ipa-ldap-updater
@@ -96,10 +96,15 @@ def main():
run_plugins = True
if os.getegid() == 0:
- installutils.check_server_configuration()
+ try:
+ installutils.check_server_configuration()
+ except RuntimeError, e:
+ print unicode(e)
+ sys.exit(1)
else:
if not os.path.exists('/etc/ipa/default.conf'):
- sys.exit("IPA is not configured on this system.")
+ print "IPA is not configured on this system."
+ sys.exit(1)
if options.upgrade:
sys.exit('Upgrade can only be done as root')
if run_plugins:
@@ -115,10 +120,13 @@ def main():
if dirman_password is None:
sys.exit("\nDirectory Manager password required")
+ console_format = '%(levelname)s: %(message)s'
if options.upgrade:
- standard_logging_setup('/var/log/ipaupgrade.log', verbose=True, debug=options.debug, filemode='a')
+ standard_logging_setup('/var/log/ipaupgrade.log', debug=options.debug,
+ console_format=console_format, filemode='a')
else:
- standard_logging_setup(None, verbose=True, debug=options.debug)
+ standard_logging_setup(None, console_format=console_format,
+ debug=options.debug)
cfg = dict (
in_server=True,
--
1.7.11.2

View File

@ -0,0 +1,262 @@
From 854b7636754643291800ec9d76ab081a870415e5 Mon Sep 17 00:00:00 2001
From: Martin Kosek <mkosek@redhat.com>
Date: Fri, 13 Jul 2012 12:23:38 +0200
Subject: [PATCH 27/79] Enforce CNAME constrains for DNS commands
RFC 1912 states that no record (besides PTR) is allowed to coexist
with any other record type. When BIND detects this situation, it
refuses to load such records.
Enforce the constrain for dnsrecord-mod and dnsrecord-add commands.
https://fedorahosted.org/freeipa/ticket/2601
---
ipalib/plugins/dns.py | 50 +++++++++++++++++++------
tests/test_xmlrpc/test_dns_plugin.py | 72 +++++++++++++++++++++++++++++-------
2 files changed, 98 insertions(+), 24 deletions(-)
diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py
index 857814917f9ce75886aee571885a3dd718427ef3..6727d052f25c720eca8a73412353a6f4a9c1566c 100644
--- a/ipalib/plugins/dns.py
+++ b/ipalib/plugins/dns.py
@@ -2155,6 +2155,26 @@ class dnsrecord(LDAPObject):
processed.append(rrparam.name)
yield rrparam
+ def check_record_type_collisions(self, old_entry, entry_attrs):
+ # Test that only allowed combination of record types was created
+ attrs = set(attr for attr in entry_attrs if attr in _record_attributes
+ and entry_attrs[attr])
+ attrs.update(attr for attr in old_entry if attr not in entry_attrs)
+ try:
+ attrs.remove('cnamerecord')
+ except KeyError:
+ rec_has_cname = False
+ else:
+ rec_has_cname = True
+ # CNAME and PTR record combination is allowed
+ attrs.discard('ptrrecord')
+ rec_has_other_types = True if attrs else False
+
+ if rec_has_cname and rec_has_other_types:
+ raise errors.ValidationError(name='cnamerecord',
+ error=_('CNAME record is not allowed to coexist with any other '
+ 'records except PTR'))
+
api.register(dnsrecord)
@@ -2297,11 +2317,16 @@ class dnsrecord_add(LDAPCreate):
# new attributes only and not for all attributes in the LDAP entry
setattr(context, 'dnsrecord_precallback_attrs', precallback_attrs)
+ # We always want to retrieve all DNS record attributes to test for
+ # record type collisions (#2601)
try:
(dn_, old_entry) = ldap.get_entry(
- dn, entry_attrs.keys(),
+ dn, _record_attributes,
normalize=self.obj.normalize_dn)
- for attr in old_entry.keys():
+ except errors.NotFound:
+ pass
+ else:
+ for attr in entry_attrs:
if attr not in _record_attributes:
continue
if entry_attrs[attr] is None:
@@ -2310,9 +2335,9 @@ class dnsrecord_add(LDAPCreate):
vals = [entry_attrs[attr]]
else:
vals = list(entry_attrs[attr])
- entry_attrs[attr] = list(set(old_entry[attr] + vals))
- except errors.NotFound:
- pass
+ entry_attrs[attr] = list(set(old_entry.get(attr, []) + vals))
+
+ self.obj.check_record_type_collisions(old_entry, entry_attrs)
return dn
def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs):
@@ -2386,14 +2411,16 @@ class dnsrecord_mod(LDAPUpdate):
# Run pre_callback validators
self.obj.run_precallback_validators(dn, entry_attrs, *keys, **options)
- if len(updated_attrs):
- try:
- (dn_, old_entry) = ldap.get_entry(
- dn, updated_attrs.keys(),
- normalize=self.obj.normalize_dn)
- except errors.NotFound:
+ # current entry is needed in case of per-dns-record-part updates and
+ # for record type collision check
+ try:
+ (dn_, old_entry) = ldap.get_entry(dn, _record_attributes,
+ normalize=self.obj.normalize_dn)
+ except errors.NotFound:
+ if updated_attrs:
self.obj.handle_not_found(*keys)
+ if updated_attrs:
for attr in updated_attrs:
param = self.params[attr]
old_dnsvalue, new_parts = updated_attrs[attr]
@@ -2411,6 +2438,7 @@ class dnsrecord_mod(LDAPUpdate):
new_dnsvalue = [param._convert_scalar(modified_parts)]
entry_attrs[attr] = list(set(old_entry[attr] + new_dnsvalue))
+ self.obj.check_record_type_collisions(old_entry, entry_attrs)
return dn
def execute(self, *keys, **options):
diff --git a/tests/test_xmlrpc/test_dns_plugin.py b/tests/test_xmlrpc/test_dns_plugin.py
index d121b2f0fb625c5bbe25a58874500e77065bd21e..9c9b223921246e4a2a6715055e3c855b44f165a8 100644
--- a/tests/test_xmlrpc/test_dns_plugin.py
+++ b/tests/test_xmlrpc/test_dns_plugin.py
@@ -48,6 +48,8 @@ dnsrev1 = u'80'
dnsrev1_dn = DN(('idnsname',dnsrev1), revdnszone1_dn)
dnsrev2 = u'81'
dnsrev2_dn = DN(('idnsname',dnsrev2), revdnszone1_dn)
+dnsrescname = u'testcnamerec'
+dnsrescname_dn = DN(('idnsname',dnsrescname), dnszone1_dn)
class test_dns(Declarative):
@@ -746,30 +748,64 @@ class test_dns(Declarative):
),
dict(
- desc='Try to add invalid CNAME record %r using dnsrecord_add' % (dnsres1),
- command=('dnsrecord_add', [dnszone1, dnsres1], {'cnamerecord': u'-.example.com' }),
+ desc='Try to add CNAME record to %r using dnsrecord_add' % (dnsres1),
+ command=('dnsrecord_add', [dnszone1, dnsres1], {'cnamerecord': u'foo-1.example.com.'}),
+ expected=errors.ValidationError(name='cnamerecord',
+ error=u'CNAME record is not allowed to coexist with any other records except PTR'),
+ ),
+
+ dict(
+ desc='Try to add invalid CNAME record %r using dnsrecord_add' % (dnsrescname),
+ command=('dnsrecord_add', [dnszone1, dnsrescname], {'cnamerecord': u'-.example.com'}),
expected=errors.ValidationError(name='hostname',
error=u'invalid domain-name: only letters, numbers, and - ' +
u'are allowed. DNS label may not start or end with -'),
),
dict(
- desc='Add CNAME record to %r using dnsrecord_add' % (dnsres1),
- command=('dnsrecord_add', [dnszone1, dnsres1], {'cnamerecord': u'foo-1.example.com.' }),
+ desc='Add CNAME record to %r using dnsrecord_add' % (dnsrescname),
+ command=('dnsrecord_add', [dnszone1, dnsrescname], {'cnamerecord': u'foo-1.example.com.'}),
expected={
- 'value': dnsres1,
+ 'value': dnsrescname,
'summary': None,
'result': {
'objectclass': objectclasses.dnsrecord,
- 'dn': unicode(dnsres1_dn),
- 'idnsname': [dnsres1],
- 'arecord': [u'10.10.0.1'],
+ 'dn': unicode(dnsrescname_dn),
+ 'idnsname': [dnsrescname],
'cnamerecord': [u'foo-1.example.com.'],
},
},
),
dict(
+ desc='Try to add other record to CNAME record %r using dnsrecord_add' % (dnsrescname),
+ command=('dnsrecord_add', [dnszone1, dnsrescname], {'arecord': u'10.0.0.1'}),
+ expected=errors.ValidationError(name='cnamerecord',
+ error=u'CNAME record is not allowed to coexist with any other records except PTR'),
+ ),
+
+ dict(
+ desc='Try to add other record to CNAME record %r using dnsrecord_mod' % (dnsrescname),
+ command=('dnsrecord_mod', [dnszone1, dnsrescname], {'arecord': u'10.0.0.1'}),
+ expected=errors.ValidationError(name='cnamerecord',
+ error=u'CNAME record is not allowed to coexist with any other records except PTR'),
+ ),
+
+ dict(
+ desc='Add A record and delete CNAME record in %r with dnsrecord_mod' % (dnsrescname),
+ command=('dnsrecord_mod', [dnszone1, dnsrescname], {'arecord': u'10.0.0.1',
+ 'cnamerecord': None}),
+ expected={
+ 'value': dnsrescname,
+ 'summary': None,
+ 'result': {
+ 'idnsname': [dnsrescname],
+ 'arecord': [u'10.0.0.1'],
+ },
+ },
+ ),
+
+ dict(
desc='Try to add invalid KX record %r using dnsrecord_add' % (dnsres1),
command=('dnsrecord_add', [dnszone1, dnsres1], {'kxrecord': u'foo-1.example.com' }),
expected=errors.ValidationError(name='kx_rec',
@@ -788,7 +824,6 @@ class test_dns(Declarative):
'dn': unicode(dnsres1_dn),
'idnsname': [dnsres1],
'arecord': [u'10.10.0.1'],
- 'cnamerecord': [u'foo-1.example.com.'],
'kxrecord': [u'1 foo-1'],
},
},
@@ -805,7 +840,6 @@ class test_dns(Declarative):
'dn': unicode(dnsres1_dn),
'idnsname': [dnsres1],
'arecord': [u'10.10.0.1'],
- 'cnamerecord': [u'foo-1.example.com.'],
'kxrecord': [u'1 foo-1'],
'txtrecord': [u'foo bar'],
},
@@ -825,7 +859,6 @@ class test_dns(Declarative):
'dn': unicode(dnsres1_dn),
'idnsname': [dnsres1],
'arecord': [u'10.10.0.1'],
- 'cnamerecord': [u'foo-1.example.com.'],
'kxrecord': [u'1 foo-1'],
'txtrecord': [u'foo bar'],
'nsecrecord': [dnszone1 + u' TXT A'],
@@ -857,7 +890,6 @@ class test_dns(Declarative):
'dn': unicode(dnsres1_dn),
'idnsname': [dnsres1],
'arecord': [u'10.10.0.1'],
- 'cnamerecord': [u'foo-1.example.com.'],
'kxrecord': [u'1 foo-1'],
'txtrecord': [u'foo bar'],
'nsecrecord': [dnszone1 + u' TXT A'],
@@ -882,7 +914,6 @@ class test_dns(Declarative):
'result': {
'idnsname': [dnsres1_renamed],
'arecord': [u'10.10.0.1'],
- 'cnamerecord': [u'foo-1.example.com.'],
'kxrecord': [u'1 foo-1'],
'txtrecord': [u'foo bar'],
'nsecrecord': [dnszone1 + u' TXT A'],
@@ -976,6 +1007,21 @@ class test_dns(Declarative):
},
),
+ dict(
+ desc='Test that CNAME/PTR record type combination in record %r is allowed' % (dnsrev1),
+ command=('dnsrecord_add', [revdnszone1, dnsrev1], {'cnamerecord': u'foo-1.example.com.' }),
+ expected={
+ 'value': dnsrev1,
+ 'summary': None,
+ 'result': {
+ 'objectclass': objectclasses.dnsrecord,
+ 'dn': unicode(dnsrev1_dn),
+ 'idnsname': [dnsrev1],
+ 'ptrrecord': [u'foo-1.example.com.'],
+ 'cnamerecord': [u'foo-1.example.com.'],
+ },
+ },
+ ),
dict(
desc='Update global DNS settings',
--
1.7.11.2

View File

@ -0,0 +1,50 @@
From 7fcca4fa52196ea0082942f9ac39937c097a2064 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvoborni@redhat.com>
Date: Thu, 12 Jul 2012 14:43:47 +0200
Subject: [PATCH 28/79] Differentiation of widget type and text_widget input
type
There was a clash of 'type' attribute in widget's spec. Usually 'type' is used for telling a builder which field and widget to build. Text widget used this attribute also for definion of html input type. It was problematic for some special widgets, which defined own field and used text_widget, like service_type or dnszone_name. In those and possibly other cases it used widget type for specifying input type which lead to execution error in Internet Explorer. Firefox and Chrome took it.
This patch is changing text_widget's 'type' to 'input_type' which removes the collision and hence fixes the problem.
https://fedorahosted.org/freeipa/ticket/2806
and half of: https://fedorahosted.org/freeipa/ticket/2834
---
install/ui/widget.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/install/ui/widget.js b/install/ui/widget.js
index 64547da7d439cb622c03d6f73afb310be83a6338..6864d88f5f08a4064b9b5b1cded527d5e99504ff 100644
--- a/install/ui/widget.js
+++ b/install/ui/widget.js
@@ -231,7 +231,7 @@ IPA.text_widget = function(spec) {
var that = IPA.input_widget(spec);
that.size = spec.size || 30;
- that.type = spec.type || 'text';
+ that.input_type = spec.input_type || 'text';
that.select_range = function(start, end){
IPA.select_range(that.input, start, end);
@@ -249,7 +249,7 @@ IPA.text_widget = function(spec) {
}).appendTo(container);
that.input = $('<input/>', {
- type: that.type,
+ type: that.input_type,
name: that.name,
disabled: that.disabled,
size: that.size,
@@ -330,7 +330,7 @@ IPA.text_widget = function(spec) {
IPA.password_widget = function(spec) {
spec = spec || {};
- spec.type = 'password';
+ spec.input_type = 'password';
var that = IPA.text_widget(spec);
return that;
--
1.7.11.2

View File

@ -0,0 +1,141 @@
From a14d243fcdd18bb7bd5409d1a8804bf06929824d Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvoborni@redhat.com>
Date: Fri, 13 Jul 2012 17:49:13 +0200
Subject: [PATCH 29/79] Fixed display of attributes_widget in IE9
Attributes widget is using overflow css rule in tbody element. IE9 doesn't handle it well.
To fix the issue, attributes widget was slightly modified and conditional css stylesheet was added just for fixing IE problems.
https://fedorahosted.org/freeipa/ticket/2822
---
install/ui/Makefile.am | 1 +
install/ui/aci.js | 6 +++++-
install/ui/ie.css | 23 +++++++++++++++++++++++
install/ui/index.html | 12 +++++++++---
install/ui/ipa.css | 7 ++++++-
5 files changed, 44 insertions(+), 5 deletions(-)
create mode 100644 install/ui/ie.css
diff --git a/install/ui/Makefile.am b/install/ui/Makefile.am
index 7eb9b04ceb73288efa169080b05994fb781b8c5e..73f746a39de974b0e94e81d562f88ea87767bcc9 100644
--- a/install/ui/Makefile.am
+++ b/install/ui/Makefile.am
@@ -30,6 +30,7 @@ app_DATA = \
host.js \
hostgroup.js \
index.html \
+ ie.css \
ipa.css \
ipa.js \
jquery-ui.css \
diff --git a/install/ui/aci.js b/install/ui/aci.js
index 953116c3f1e6f8450c0f8b308f1f2851b704e203..b2e5e19e54fe083093171d29fe894df321bb4c88 100644
--- a/install/ui/aci.js
+++ b/install/ui/aci.js
@@ -473,13 +473,17 @@ IPA.attributes_widget = function(spec) {
that.create = function(container) {
that.container = container;
+ var attr_container = $('<div/>', {
+ 'class': 'aci-attribute-table-container'
+ }).appendTo(container);
+
that.table = $('<table/>', {
id:id,
'class':'search-table aci-attribute-table scrollable'
}).
append('<thead/>').
append('<tbody/>').
- appendTo(container);
+ appendTo(attr_container);
var tr = $('<tr></tr>').appendTo($('thead', that.table));
diff --git a/install/ui/ie.css b/install/ui/ie.css
new file mode 100644
index 0000000000000000000000000000000000000000..00e573ba516358d247b725256f3098d80f1c1162
--- /dev/null
+++ b/install/ui/ie.css
@@ -0,0 +1,23 @@
+/* Authors:
+* Petr Vobornik <pvobornik@redhat.com>
+*
+* Copyright (C) 2012 Red Hat
+*
+* Styles for IE only
+*/
+
+.aci-attribute-table-container {
+ overflow: auto !important;
+ overflow-x: hidden !important;
+ width: 348px !important;
+}
+
+.aci-attribute-table {
+ float: left;
+ margin: 0;
+ width: 332px !important;
+}
+
+.aci-attribute-table tbody {
+ height: auto !important;
+}
\ No newline at end of file
diff --git a/install/ui/index.html b/install/ui/index.html
index cfa7a4c8136639e05f4345352a9bf4188ed2af89..24e8cac3668cd81fb064f6a8ad2b1685c847f5c8 100644
--- a/install/ui/index.html
+++ b/install/ui/index.html
@@ -4,6 +4,15 @@
<meta charset="utf-8">
<title>IPA: Identity Policy Audit</title>
+
+ <link rel="stylesheet" type="text/css" href="jquery-ui.css" />
+ <link rel="stylesheet" type="text/css" href="ipa.css" />
+ <!--ie only stylesheet -->
+ <!--[if IE]>
+ <link rel="stylesheet" type="text/css" href="ie.css" />
+ <![endif]-->
+ <link rel="icon" type="image/ico" href="favicon.ico">
+
<script type="text/javascript" src="json2.js"></script>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery-ui.js"></script>
@@ -48,9 +57,6 @@
<script type="text/javascript" src="ext/extension.js"></script>
<script type="text/javascript" src="webui.js"></script>
- <link rel="stylesheet" type="text/css" href="jquery-ui.css" />
- <link rel="stylesheet" type="text/css" href="ipa.css" />
- <link rel="icon" type="image/ico" href="favicon.ico">
</head>
<body>
diff --git a/install/ui/ipa.css b/install/ui/ipa.css
index d6ad5806038f47919404615f224f5ed75a917563..a3b93078b64fc057ba81271abbe093717d766149 100644
--- a/install/ui/ipa.css
+++ b/install/ui/ipa.css
@@ -1082,13 +1082,18 @@ span.main-separator{
.aci-attribute-table tbody {
border-bottom: 1px solid #8a8a8a;
- height:10em;
+ height: 10em;
}
.aci-attribute-table .aci-attribute-column {
width: 200em; /* it will fit actual width */
}
+.aci-attribute-table-container {
+ height: 13.5em;
+ overflow: hidden;
+}
+
.entity-views{
list-style-type:none;
}
--
1.7.11.2

View File

@ -0,0 +1,48 @@
From 3adebcf919e81ead95c68995db52f7c2da999792 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvoborni@redhat.com>
Date: Mon, 16 Jul 2012 13:40:52 +0200
Subject: [PATCH 30/79] Bigger textarea for permission type=subtree
Adder dialog and details facet for permission type=subtree have small textarea for defining subtree filter. It was unconfortable to define the filter. This difference was removed.
https://fedorahosted.org/freeipa/ticket/2832
---
install/ui/aci.js | 2 --
install/ui/ipa.css | 8 ++++++++
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/install/ui/aci.js b/install/ui/aci.js
index b2e5e19e54fe083093171d29fe894df321bb4c88..63181efac5f335d28a4c23bfa1ae2da95b9a0e75 100644
--- a/install/ui/aci.js
+++ b/install/ui/aci.js
@@ -688,8 +688,6 @@ IPA.permission_target_widget = function(spec) {
that.subtree_textarea = IPA.textarea_widget({
entity: that.entity,
name: 'subtree',
- cols: 30,
- rows: 1,
hidden: true
});
diff --git a/install/ui/ipa.css b/install/ui/ipa.css
index a3b93078b64fc057ba81271abbe093717d766149..76ce265f0f5c90404046726fe55bd54d73c9b365 100644
--- a/install/ui/ipa.css
+++ b/install/ui/ipa.css
@@ -1307,6 +1307,14 @@ table.scrollable tbody {
width: 250px;
}
+.textarea-widget textarea {
+ width: 250px;
+}
+
+.facet-content .textarea-widget textarea {
+ width: 400px;
+}
+
.combobox-widget-input {
display: inline-block;
position: relative;
--
1.7.11.2

View File

@ -0,0 +1,43 @@
From 2d75d8cc055887f354db947aac1d33e961e9c80c Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Mon, 16 Jul 2012 12:43:47 +0300
Subject: [PATCH 31/79] ipalib/plugins/trust.py: ValidationError takes 'error'
named argument, not 'reason'
https://fedorahosted.org/freeipa/ticket/2865
---
ipalib/plugins/trust.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py
index 40bd93e654c0365ad202abfd82e84345583459dd..2932835e038d99d9c48f1822e76fbc2e1570f92f 100644
--- a/ipalib/plugins/trust.py
+++ b/ipalib/plugins/trust.py
@@ -182,13 +182,13 @@ class trust_add(LDAPCreate):
realm_admin = options['realm_admin']
if 'realm_passwd' not in options:
- raise errors.ValidationError(name=_('AD Trust setup'), reason=_('Realm administrator password should be specified'))
+ raise errors.ValidationError(name=_('AD Trust setup'), error=_('Realm administrator password should be specified'))
realm_passwd = options['realm_passwd']
result = trustinstance.join_ad_full_credentials(keys[-1], realm_server, realm_admin, realm_passwd)
if result is None:
- raise errors.ValidationError(name=_('AD Trust setup'), reason=_('Unable to verify write permissions to the AD'))
+ raise errors.ValidationError(name=_('AD Trust setup'), error=_('Unable to verify write permissions to the AD'))
return dict(result=dict(), value=trustinstance.remote_domain.info['dns_domain'])
@@ -198,7 +198,7 @@ class trust_add(LDAPCreate):
if 'trust_secret' in options:
result = trustinstance.join_ad_ipa_half(keys[-1], realm_server, options['trust_secret'])
return dict(result=dict(), value=trustinstance.remote_domain.info['dns_domain'])
- raise errors.ValidationError(name=_('AD Trust setup'), reason=_('Not enough arguments specified to perform trust setup'))
+ raise errors.ValidationError(name=_('AD Trust setup'), error=_('Not enough arguments specified to perform trust setup'))
class trust_del(LDAPDelete):
__doc__ = _('Delete a trust.')
--
1.7.11.2

View File

@ -0,0 +1,68 @@
From dadfbf9d153bcf8f7ce659981698ffa2292b3967 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Mon, 16 Jul 2012 13:12:42 +0300
Subject: [PATCH 32/79] Handle various forms of admin accounts when
establishing trusts
Realm administrator account may be specified using different form:
Administrator, DOM\Administrator, Administrator@DOMAIN
This patch introduces handling of the second two forms:
- In DOM\Administrator only user name is used, short domain name
is then taken from a discovered record from the AD DC
- In Administrator@DOMAIN first DOMAIN is verified to be the same
as the domain we are establishing trust to, and then user name
is taken, together with short domain name taken from a discovered
record from the AD DC
Note that we do not support using to-be-trusted domain's trusted domains'
accounts to establish trust as there is basically zero chance to verify
that things will work with them. In addition, in order to establish trust
one needs to belong to Enterprise Admins group in AD or have specially
delegated permissions. These permissions are unlikely delegated to the
ones in already trusted domain.
https://fedorahosted.org/freeipa/ticket/2864
---
ipalib/plugins/trust.py | 8 ++++++++
ipaserver/dcerpc.py | 5 +++++
2 files changed, 13 insertions(+)
diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py
index 2932835e038d99d9c48f1822e76fbc2e1570f92f..792e6cac2a2f9ebb61f84cc74d01be325995863e 100644
--- a/ipalib/plugins/trust.py
+++ b/ipalib/plugins/trust.py
@@ -180,6 +180,14 @@ class trust_add(LDAPCreate):
# generate random trustdom password to do work on both sides
if 'realm_admin' in options:
realm_admin = options['realm_admin']
+ names = realm_admin.split('@')
+ if len(names) > 1:
+ # realm admin name is in UPN format, user@realm, check that
+ # realm is the same as the one that we are attempting to trust
+ if keys[-1].lower() != names[-1].lower():
+ raise errors.ValidationError(name=_('AD Trust setup'),
+ error=_('Trusted domain and administrator account use different realms'))
+ realm_admin = names[0]
if 'realm_passwd' not in options:
raise errors.ValidationError(name=_('AD Trust setup'), error=_('Realm administrator password should be specified'))
diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
index 07e40c2d35b41a2665232f3e6d853b47aef707bb..6b830f65b854b74fcf080b071212e7658f334adf 100644
--- a/ipaserver/dcerpc.py
+++ b/ipaserver/dcerpc.py
@@ -363,6 +363,11 @@ class TrustDomainJoins(object):
rd.read_only = True
if realm_admin and realm_passwd:
if 'name' in rd.info:
+ names = realm_admin.split('\\')
+ if len(names) > 1:
+ # realm admin is in DOMAIN\user format
+ # strip DOMAIN part as we'll enforce the one discovered
+ realm_admin = names[-1]
auth_string = u"%s\%s%%%s" % (rd.info['name'], realm_admin, realm_passwd)
td = get_instance(self)
td.creds.parse_string(auth_string)
--
1.7.11.2

View File

@ -0,0 +1,63 @@
From 61b2f0a5d066a14e22033ff9815a712716f12a96 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Wed, 18 Jul 2012 15:52:33 +0300
Subject: [PATCH 33/79] Follow change in samba4 beta4 for sid_check_is_domain
to sid_check_is_our_sam
With c43505b621725c9a754f0ee98318d451b093f2ed in samba git master
the function sid_check_is_domain() was renamed to sid_check_is_our_sam().
https://fedorahosted.org/freeipa/ticket/2929
---
daemons/ipa-sam/ipa_sam.c | 4 +++-
freeipa.spec.in | 5 ++++-
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c
index 86ed3fbd3e6d1894fd398c3c1c94d34c2b7ec273..ab4b116c5f2b3b8dae6e8309403afba5fdf86708 100644
--- a/daemons/ipa-sam/ipa_sam.c
+++ b/daemons/ipa-sam/ipa_sam.c
@@ -83,6 +83,8 @@ enum ndr_err_code ndr_pull_trustAuthInOutBlob(struct ndr_pull *ndr, int ndr_flag
bool fetch_ldap_pw(char **dn, char** pw); /* available in libpdb.so */
void nt_lm_owf_gen(const char *pwd, uint8_t nt_p16[16], uint8_t p16[16]); /* available in libcliauth.so */
bool sid_check_is_builtin(const struct dom_sid *sid); /* available in libpdb.so */
+/* available in libpdb.so, renamed from sid_check_is_domain() in c43505b621725c9a754f0ee98318d451b093f2ed */
+bool sid_check_is_our_sam(const struct dom_sid *sid);
void strlower_m(char *s); /* available in libutil_str.so */
char *talloc_asprintf_strupper_m(TALLOC_CTX *t, const char *fmt, ...); /* available in libutil_str.so */
void sid_copy(struct dom_sid *dst, const struct dom_sid *src); /* available in libsecurity.so */
@@ -300,7 +302,7 @@ static NTSTATUS ldapsam_lookup_rids(struct pdb_methods *methods,
}
if (!sid_check_is_builtin(domain_sid) &&
- !sid_check_is_domain(domain_sid)) {
+ !sid_check_is_our_sam(domain_sid)) {
result = NT_STATUS_INVALID_PARAMETER;
goto done;
}
diff --git a/freeipa.spec.in b/freeipa.spec.in
index 7106310915c8a4e52a009036f7152a38a4c5f18d..f4903c01354764f0c6b8755824512edbc1ff930b 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -31,7 +31,7 @@ BuildRequires: policycoreutils >= %{POLICYCOREUTILSVER}
%if 0%{?fedora} >= 16
BuildRequires: systemd-units
%endif
-BuildRequires: samba4-devel
+BuildRequires: samba4-devel >= 4.0.0-128
BuildRequires: samba4-python
%endif
BuildRequires: nspr-devel
@@ -743,6 +743,9 @@ fi
%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/ca.crt
%changelog
+* Wed Jul 18 2012 Alexander Bokovoy <abokovoy@redhat.com> - 2.99.0-38
+- Require samba4-devel >= 4.0.0-128 due to passdb API change in beta4
+
* Fri Jun 29 2012 Rob Crittenden <rcritten@redhat.com> - 2.99.0-37
- Add Requires on openssl
- Set minimum tomcat6 to 6.0.35-4 in F-18
--
1.7.11.2

View File

@ -0,0 +1,26 @@
From 67dbde01567f5df414d4e5f6ac694c9b04170c45 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Wed, 18 Jul 2012 10:32:50 -0400
Subject: [PATCH 34/79] Don't hardcode serial_autoincrement to True.
https://fedorahosted.org/freeipa/ticket/2554
---
ipaserver/install/bindinstance.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index 9faf17698d3cb806ed601f728c3870bfe28c9424..c348cdbb278f222dfbc034cbe1220df26262cb9d 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -480,7 +480,7 @@ class BindInstance(service.Service):
self.reverse_zone = reverse_zone
self.zone_refresh = zone_refresh
self.persistent_search = persistent_search
- self.serial_autoincrement = True
+ self.serial_autoincrement = serial_autoincrement
if not zonemgr:
self.zonemgr = 'hostmaster.%s' % self.domain
--
1.7.11.2

View File

@ -0,0 +1,30 @@
From 87040c0af1e76b5477cd53d515ed8071d941ce24 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce@redhat.com>
Date: Thu, 12 Jul 2012 14:27:55 -0400
Subject: [PATCH 35/79] Fix safety checks to prevent orphaning replicas
This is just a typo, we were checking one side twice and never the other
side. So depending on which side you run the command you'd be able or not
to remove the replication agreement even if it was the last one.
First part of ticket: https://fedorahosted.org/freeipa/ticket/2925
---
install/tools/ipa-replica-manage | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage
index e2378173821457ed05dae2722223d148266ef822..a039ccaa26976262d8f05ac068403b73c6ca735b 100755
--- a/install/tools/ipa-replica-manage
+++ b/install/tools/ipa-replica-manage
@@ -211,7 +211,7 @@ def del_link(realm, replica1, replica2, dirman_passwd, force=False):
try:
repl2 = replication.ReplicationManager(realm, replica2, dirman_passwd)
- repl_list = repl1.find_ipa_replication_agreements()
+ repl_list = repl2.find_ipa_replication_agreements()
if not force and len(repl_list) <= 1:
print "Cannot remove the last replication link of '%s'" % replica2
print "Please use the 'del' command to remove it from the domain"
--
1.7.11.2

View File

@ -0,0 +1,62 @@
From 32c1aa45b3d41e15adb2ca8f8713e774046bc340 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce@redhat.com>
Date: Thu, 12 Jul 2012 15:04:03 -0400
Subject: [PATCH 36/79] Fix detection of deleted masters
When setting up agreements we need to be careful in not allowing to
'reconnect' a master that was previously completely deleted as it would
misses entries that are vital for proper functioning. This change in code
fixes 2 problems with the current approach.
1) it removes false positives when we are tryig to reconnect a replica that
was previosuly merely disconnected but was still part of the domain and just
replicating via a different topology and not a direct link
2) adds checks for entries that are deleted when an actual removal is
performed. so that we cannot 'reconnect' previously unrelated replicas when
one of the 2 has been permanently deleted from the masters tree.
Second part of ticket https://fedorahosted.org/freeipa/ticket/2925
---
install/tools/ipa-replica-manage | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage
index a039ccaa26976262d8f05ac068403b73c6ca735b..b095daf03aa0dfd7dd93f4809496467c83cfc5e3 100755
--- a/install/tools/ipa-replica-manage
+++ b/install/tools/ipa-replica-manage
@@ -401,18 +401,24 @@ def add_link(realm, replica1, replica2, dirman_passwd, options):
options.passsync, options.win_subtree,
options.cacert)
else:
- # First see if we already exist on the remote master. If so this was
- # a previously deleted connection.
+ # Check if the master entry exists for both servers.
+ # If one of the tree misses one of the entries, it means one of the
+ # replicas was fully deleted previously and needs to be reinstalled
+ # from scratch
try:
+ masters_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), (api.env.basedn))
+ master1_dn = str(DN(('cn', replica1), masters_dn))
+ master2_dn = str(DN(('cn', replica2), masters_dn))
+
+ repl1.conn.getEntry(master1_dn, ldap.SCOPE_BASE)
+ repl1.conn.getEntry(master2_dn, ldap.SCOPE_BASE)
+
repl2 = replication.ReplicationManager(realm, replica2, dirman_passwd)
- master_dn = repl2.replica_dn()
- binddn = str(DN(('krbprincipalname','ldap/%s@%s' % (replica1, api.env.realm)),(api.env.container_service),(api.env.basedn)))
- master = repl2.conn.getEntry(master_dn, ldap.SCOPE_BASE)
- binddns = master.getValues('nsDS5ReplicaBindDN')
- if binddns and binddn in binddns:
- sys.exit("You cannot connect to a previously deleted master")
+ repl2.conn.getEntry(master1_dn, ldap.SCOPE_BASE)
+ repl2.conn.getEntry(master2_dn, ldap.SCOPE_BASE)
+
except errors.NotFound:
- pass
+ sys.exit("You cannot connect to a previously deleted master")
repl1.setup_gssapi_replication(replica2, "cn=Directory Manager", dirman_passwd)
print "Connected '%s' to '%s'" % (replica1, replica2)
--
1.7.11.2

View File

@ -0,0 +1,115 @@
From 429edcfb72674d113edddddc448e80a390210311 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Mon, 16 Jul 2012 10:40:12 -0400
Subject: [PATCH 37/79] Support per-principal sessions and handle session
update failures
User had a system that refused to store keys into the kernel keyring.
Any operation at all on the keyring would return "Key has been revoked".
Wrap the operations in a try/except so we can ignore keyring failures.
This also adds per-principal sessions. The principal name is stored
in the session key so switching principals in the ccache doesn't
require clearing the keyring.
https://fedorahosted.org/freeipa/ticket/2880
---
ipalib/rpc.py | 34 +++++++++++++++++++++++-----------
1 file changed, 23 insertions(+), 11 deletions(-)
diff --git a/ipalib/rpc.py b/ipalib/rpc.py
index 6518cb27de7777b621d8daf31862b7e5fae33bb4..8a6a5108800517338c33962a4c44ea817675b0df 100644
--- a/ipalib/rpc.py
+++ b/ipalib/rpc.py
@@ -46,6 +46,7 @@ from ipalib.backend import Connectible
from ipalib.errors import public_errors, PublicError, UnknownError, NetworkError, KerberosError, XMLRPCMarshallError
from ipalib import errors
from ipalib.request import context, Connection
+from ipalib.util import get_current_principal
from ipapython import ipautil
from ipapython import kernel_keyring
@@ -57,6 +58,8 @@ from urllib2 import urlparse
from ipalib.krb_utils import KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN, KRB5KRB_AP_ERR_TKT_EXPIRED, \
KRB5_FCC_PERM, KRB5_FCC_NOFILE, KRB5_CC_FORMAT, KRB5_REALM_CANT_RESOLVE
+COOKIE_NAME = 'ipa_session_cookie:%s'
+
def xml_wrap(value):
"""
Wrap all ``str`` in ``xmlrpclib.Binary``.
@@ -258,12 +261,6 @@ class SSLTransport(LanguageAwareTransport):
conn.connect()
return conn
- def parse_response(self, response):
- session_cookie = response.getheader('Set-Cookie')
- if session_cookie:
- kernel_keyring.update_key('ipa_session_cookie', session_cookie)
- return LanguageAwareTransport.parse_response(self, response)
-
class KerbTransport(SSLTransport):
"""
@@ -327,6 +324,18 @@ class KerbTransport(SSLTransport):
return (host, extra_headers, x509)
+ def parse_response(self, response):
+ session_cookie = response.getheader('Set-Cookie')
+ if session_cookie:
+ principal = getattr(context, 'principal', None)
+ try:
+ kernel_keyring.update_key(COOKIE_NAME % principal, session_cookie)
+ except ValueError, e:
+ # Not fatal, we just can't use the session cookie we were
+ # sent.
+ pass
+ return SSLTransport.parse_response(self, response)
+
class DelegatedKerbTransport(KerbTransport):
"""
@@ -400,10 +409,12 @@ class xmlclient(Connectible):
session = False
session_data = None
xmlrpc_uri = self.env.xmlrpc_uri
+ principal = get_current_principal()
+ setattr(context, 'principal', principal)
# We have a session cookie, try using the session URI to see if it
# is still valid
if not delegate:
- session_data = kernel_keyring.read_key('ipa_session_cookie')
+ session_data = kernel_keyring.read_key(COOKIE_NAME % principal)
setattr(context, 'session_data', session_data)
(scheme, netloc, path, params, query, fragment) = urlparse.urlparse(self.env.xmlrpc_uri)
xmlrpc_uri = urlparse.urlunparse((scheme, netloc, '/ipa/session/xml', params, query, fragment))
@@ -453,9 +464,9 @@ class xmlclient(Connectible):
except ProtocolError, e:
if session_data and e.errcode == 401:
# Unauthorized. Remove the session and try again.
+ delattr(context, 'session_data')
try:
- kernel_keyring.del_key('ipa_session_cookie')
- delattr(context, 'session_data')
+ kernel_keyring.del_key(COOKIE_NAME % principal)
except ValueError:
# This shouldn't happen if we have a session but
# it isn't fatal.
@@ -519,9 +530,10 @@ class xmlclient(Connectible):
session_data = getattr(context, 'session_data', None)
if session_data and e.errcode == 401:
# Unauthorized. Remove the session and try again.
+ delattr(context, 'session_data')
try:
- kernel_keyring.del_key('ipa_session_cookie')
- delattr(context, 'session_data')
+ principal = getattr(context, 'principal', None)
+ kernel_keyring.del_key(COOKIE_NAME % principal)
except ValueError:
# This shouldn't happen if we have a session but
# it isn't fatal.
--
1.7.11.2

View File

@ -0,0 +1,83 @@
From e578183ea25a40aedf6dcc3e1ee4bcb19b73e70f Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori@redhat.com>
Date: Wed, 18 Jul 2012 06:47:07 -0400
Subject: [PATCH 38/79] Fix updating minimum_connections in ipa-upgradeconfig
The upgrade script set the "psearch" directive in some circumstances,
but did not remember that it was set, so later, when setting
minimum_connections, it assumed psearch is not set.
Also, the script did not set minimum_connections if the directive wasn't
already there. It should be set in that case.
Related to https://fedorahosted.org/freeipa/ticket/2554
---
install/tools/ipa-upgradeconfig | 37 +++++++++++++++++++------------------
1 file changed, 19 insertions(+), 18 deletions(-)
diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig
index b82f039d4ce8db05ce41193212951d4d79fca79b..cfb9a19e324c47b9c68caa76fb87c5977476f742 100644
--- a/install/tools/ipa-upgradeconfig
+++ b/install/tools/ipa-upgradeconfig
@@ -339,6 +339,7 @@ def named_enable_psearch():
bindinstance.NAMED_CONF, e)
else:
changed = True
+ psearch = "yes"
sysupgrade.set_upgrade_state('named.conf', 'psearch_enabled', True)
root_logger.debug('Persistent search enabled')
@@ -353,24 +354,24 @@ def named_enable_psearch():
root_logger.debug('Cannot retrieve connections option from %s: %s',
bindinstance.NAMED_CONF, e)
return
- if connections is not None:
- try:
+ try:
+ if connections is not None:
connections = int(connections)
- except ValueError:
- # this should not happend, but there is some bad value in
- # "connections" option, bail out
- pass
- else:
- if connections < minimum_connections:
- try:
- bindinstance.named_conf_set_directive('connections',
- minimum_connections)
- root_logger.debug('Connections set to %d', minimum_connections)
- except IOError, e:
- root_logger.error('Cannot update connections in %s: %s',
- bindinstance.NAMED_CONF, e)
- else:
- changed = True
+ except ValueError:
+ # this should not happend, but there is some bad value in
+ # "connections" option, bail out
+ pass
+ else:
+ if connections is None or connections < minimum_connections:
+ try:
+ bindinstance.named_conf_set_directive('connections',
+ minimum_connections)
+ root_logger.debug('Connections set to %d', minimum_connections)
+ except IOError, e:
+ root_logger.error('Cannot update connections in %s: %s',
+ bindinstance.NAMED_CONF, e)
+ else:
+ changed = True
if not changed:
root_logger.debug('No changes made')
@@ -408,7 +409,7 @@ def named_enable_serial_autoincrement():
# enable SOA serial autoincrement
if not sysupgrade.get_upgrade_state('named.conf', 'autoincrement_enabled'):
if psearch != "yes": # psearch is required
- root_logger.debug('Persistent search is disabled, '
+ root_logger.error('Persistent search is disabled, '
'serial autoincrement cannot be enabled')
else:
if serial_autoincrement != 'yes':
--
1.7.11.2

View File

@ -0,0 +1,31 @@
From 78810f906873c261277189b279d4da33dbd05eb2 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Thu, 19 Jul 2012 00:41:01 -0400
Subject: [PATCH 39/79] Default to no when trying trying to install a replica
on wrong server.
When installing a replica file on the wrong server we warn that this will
likely fail and prompt to Continue. This prompt should default to
False, not True.
https://fedorahosted.org/freeipa/ticket/2325
---
install/tools/ipa-replica-install | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install
index d162b01f281177454240e17140f12b49a24890c4..063eea023b2d4a6d43996210e63f90859d048a0c 100755
--- a/install/tools/ipa-replica-install
+++ b/install/tools/ipa-replica-install
@@ -336,7 +336,7 @@ def main():
if config.host_name != host:
try:
print "This replica was created for '%s' but this machine is named '%s'" % (config.host_name, host)
- if not ipautil.user_input("This may cause problems. Continue?", True):
+ if not ipautil.user_input("This may cause problems. Continue?", False):
sys.exit(0)
config.host_name = host
print ""
--
1.7.11.2

View File

@ -0,0 +1,810 @@
From b5c1ce88a4a3b35adb3b22bc68fb10b49322641a Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori@redhat.com>
Date: Fri, 20 Apr 2012 04:39:59 -0400
Subject: [PATCH 40/79] Framework for admin/install tools, with
ipa-ldap-updater
Currently, FreeIPA's install/admin scripts are long pieces of code
that aren't very reusable, importable, or testable.
They have been extended over time with features such as logging and
error handling, but since each tool was extended individually, there
is much inconsistency and code duplication.
This patch starts a framework which the admin tools can use, and
converts ipa-ldap-updater to use the framework.
Common tasks the tools do -- option parsing, validation, logging
setup, error handling -- are represented as methods. Individual
tools can extend, override or reuse the defaults as they see fit.
The ipa-ldap-updater has two modes (normal and --upgrade) that
don't share much functionality. They are represented by separate
classes. Option parsing, and selecting which class to run, happens
before they're instantiated.
All code is moved to importable modules to aid future testing. The
only thing that remains in the ipa-ldap-updater script is a two-line
call to the library.
First part of the work for:
https://fedorahosted.org/freeipa/ticket/2652
---
install/tools/ipa-ldap-updater | 160 +-----------------------
ipapython/admintool.py | 229 ++++++++++++++++++++++++++++++++++
ipaserver/install/installutils.py | 92 ++++++--------
ipaserver/install/ipa_ldap_updater.py | 189 ++++++++++++++++++++++++++++
ipaserver/install/ldapupdate.py | 2 +-
make-lint | 1 +
6 files changed, 463 insertions(+), 210 deletions(-)
create mode 100644 ipapython/admintool.py
create mode 100644 ipaserver/install/ipa_ldap_updater.py
diff --git a/install/tools/ipa-ldap-updater b/install/tools/ipa-ldap-updater
index 8f5c76645d9ba2b204f3b1051d9dc8b23eacce9d..0fc5a5bc448d04eb9ce8562ee1feebbf8f0fe356 100755
--- a/install/tools/ipa-ldap-updater
+++ b/install/tools/ipa-ldap-updater
@@ -20,162 +20,6 @@
# Documentation can be found at http://freeipa.org/page/LdapUpdate
-# TODO
-# save undo files?
+from ipaserver.install.ipa_ldap_updater import LDAPUpdater
-import os
-import sys
-try:
- from ipapython.config import IPAOptionParser
- from ipapython import ipautil, config
- from ipaserver.install import installutils
- from ipaserver.install.ldapupdate import LDAPUpdate, BadSyntax, UPDATES_DIR
- from ipaserver.install.upgradeinstance import IPAUpgrade
- from ipapython import sysrestore
- import krbV
- from ipalib import api
- from ipapython.ipa_log_manager import *
-except ImportError:
- print >> sys.stderr, """\
-There was a problem importing one of the required Python modules. The
-error was:
-
- %s
-""" % sys.exc_value
- sys.exit(1)
-
-def parse_options():
- usage = "%prog [options] input_file(s)\n"
- usage += "%prog [options]\n"
- parser = IPAOptionParser(usage=usage, formatter=config.IPAFormatter())
-
- parser.add_option("-d", "--debug", action="store_true", dest="debug",
- help="Display debugging information about the update(s)",
- default=False)
- parser.add_option("-t", "--test", action="store_true", dest="test",
- help="Run through the update without changing anything",
- default=False)
- parser.add_option("-y", dest="password",
- help="File containing the Directory Manager password")
- parser.add_option("-l", '--ldapi', action="store_true", dest="ldapi",
- default=False, help="Connect to the LDAP server using the ldapi socket")
- parser.add_option("-u", '--upgrade', action="store_true", dest="upgrade",
- default=False, help="Upgrade an installed server in offline mode")
- parser.add_option("-p", '--plugins', action="store_true", dest="plugins",
- default=False, help="Execute update plugins. Always true when applying all update files.")
- parser.add_option("-W", '--password', action="store_true",
- dest="ask_password",
- help="Prompt for the Directory Manager password")
-
- options, args = parser.parse_args()
- safe_options = parser.get_safe_opts(options)
-
- return safe_options, options, args
-
-def get_dirman_password():
- """Prompt the user for the Directory Manager password and verify its
- correctness.
- """
- password = installutils.read_password("Directory Manager", confirm=False, validate=False)
-
- return password
-
-def main():
- badsyntax = False
- upgradefailed = False
-
- safe_options, options, args = parse_options()
-
- run_plugins = options.plugins
-
- files = []
- if len(args) > 0:
- files = args
-
- if len(files) < 1:
- run_plugins = True
-
- if os.getegid() == 0:
- try:
- installutils.check_server_configuration()
- except RuntimeError, e:
- print unicode(e)
- sys.exit(1)
- else:
- if not os.path.exists('/etc/ipa/default.conf'):
- print "IPA is not configured on this system."
- sys.exit(1)
- if options.upgrade:
- sys.exit('Upgrade can only be done as root')
- if run_plugins:
- sys.exit('Plugins can only be run as root.')
-
- dirman_password = ""
- if options.password:
- pw = ipautil.template_file(options.password, [])
- dirman_password = pw.strip()
- else:
- if (options.ask_password or not options.ldapi) and not options.upgrade:
- dirman_password = get_dirman_password()
- if dirman_password is None:
- sys.exit("\nDirectory Manager password required")
-
- console_format = '%(levelname)s: %(message)s'
- if options.upgrade:
- standard_logging_setup('/var/log/ipaupgrade.log', debug=options.debug,
- console_format=console_format, filemode='a')
- else:
- standard_logging_setup(None, console_format=console_format,
- debug=options.debug)
-
- cfg = dict (
- in_server=True,
- context='updates',
- debug=options.debug,
- )
- api.bootstrap(**cfg)
- api.finalize()
-
- updates = None
- if options.upgrade:
- root_logger.debug('%s was invoked with arguments %s and options: %s' % (sys.argv[0], args, safe_options))
- realm = krbV.default_context().default_realm
- upgrade = IPAUpgrade(realm, files, live_run=not options.test)
- upgrade.create_instance()
- modified = upgrade.modified
- badsyntax = upgrade.badsyntax
- upgradefailed = upgrade.upgradefailed
- else:
- ld = LDAPUpdate(dm_password=dirman_password, sub_dict={}, live_run=not options.test, ldapi=options.ldapi, plugins=run_plugins)
- if len(files) < 1:
- files = ld.get_all_files(UPDATES_DIR)
- modified = ld.update(files)
-
- if badsyntax:
- root_logger.info('Bad syntax detected in upgrade file(s).')
- print 'Bad syntax detected in upgrade file(s).'
- return 1
- elif upgradefailed:
- root_logger.info('IPA upgrade failed.')
- print 'IPA upgrade failed.'
- return 1
- elif modified and options.test:
- root_logger.info('Update complete, changes to be made, test mode')
- return 2
- else:
- root_logger.info('Update complete')
- return 0
-
-try:
- if __name__ == "__main__":
- sys.exit(main())
-except BadSyntax, e:
- print "There is a syntax error in this update file:"
- print " %s" % e
- sys.exit(1)
-except RuntimeError, e:
- sys.exit(e)
-except SystemExit, e:
- sys.exit(e)
-except KeyboardInterrupt, e:
- sys.exit(1)
+LDAPUpdater.run_cli()
diff --git a/ipapython/admintool.py b/ipapython/admintool.py
new file mode 100644
index 0000000000000000000000000000000000000000..60096e083ef209e943886cbe33189e5cdf063787
--- /dev/null
+++ b/ipapython/admintool.py
@@ -0,0 +1,229 @@
+# Authors:
+# Petr Viktorin <pviktori@redhat.com>
+#
+# Copyright (C) 2012 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""A common framework for command-line admin tools, e.g. install scripts
+
+Handles common operations like option parsing and logging
+"""
+
+import sys
+import os
+import traceback
+from optparse import OptionGroup
+
+from ipapython import version
+from ipapython import config
+from ipapython import ipa_log_manager
+
+
+class ScriptError(StandardError):
+ """An exception that records an error message and a return value
+ """
+ def __init__(self, msg='', rval=1):
+ self.msg = msg
+ self.rval = rval
+
+ def __str__(self):
+ return self.msg or ''
+
+
+class AdminTool(object):
+ """Base class for command-line admin tools
+
+ To run the tool, call the main() classmethod with a list of command-line
+ arguments.
+ Alternatively, call run_cli() to run with command-line arguments in
+ sys.argv, and call sys.exit() with the return value.
+
+ Some commands actually represent multiple related tools, e.g.
+ ``ipa-server-install`` and ``ipa-server-install --uninstall`` would be
+ represented by separate classes. Only their options are the same.
+
+ To handle this, AdminTool provides classmethods for option parsing
+ and selecting the appropriate command class.
+
+ A class-wide option parser is made by calling add_options.
+ The options are then parsed into options and arguments, and
+ get_command_class is called with those to retrieve the class.
+ That class is then instantiated and run.
+
+ Running consists of a few steps:
+ - validating options or the environment (validate_options)
+ - setting up logging (setup_logging)
+ - running the actual command (run)
+
+ Any unhandled exceptions are handled in handle_error.
+ And at the end, either log_success or log_failure is called.
+
+ Class attributes to define in subclasses:
+ command_name - shown in logs
+ log_file_name - if None, logging is to stderr only
+ needs_root - if true, non-root users can't run the tool
+ usage - text shown in help
+ """
+ command_name = None
+ log_file_name = None
+ needs_root = False
+ usage = None
+
+ _option_parsers = dict()
+
+ @classmethod
+ def make_parser(cls):
+ """Create an option parser shared across all instances of this class"""
+ parser = config.IPAOptionParser(version=version.VERSION,
+ usage=cls.usage, formatter=config.IPAFormatter())
+ cls.option_parser = parser
+ cls.add_options(parser)
+
+ @classmethod
+ def add_options(cls, parser):
+ """Add command-specific options to the option parser"""
+ parser.add_option("-d", "--debug", dest="debug", default=False,
+ action="store_true", help="print debugging information")
+
+ @classmethod
+ def run_cli(cls):
+ """Run this command with sys.argv, exit process with the return value
+ """
+ sys.exit(cls.main(sys.argv))
+
+ @classmethod
+ def main(cls, argv):
+ """The main entry point
+
+ Parses command-line arguments, selects the actual command class to use
+ based on them, and runs that command.
+
+ :param argv: Command-line arguments.
+ :return: Command exit code
+ """
+ if cls not in cls._option_parsers:
+ # We use cls._option_parsers, a dictionary keyed on class, to check
+ # if we need to create a parser. This is because cls.option_parser
+ # can refer to the parser of a superclass.
+ cls.make_parser()
+ cls._option_parsers[cls] = cls.option_parser
+
+ options, args = cls.option_parser.parse_args(argv[1:])
+
+ command_class = cls.get_command_class(options, args)
+ command = command_class(options, args)
+
+ return command.execute()
+
+ @classmethod
+ def get_command_class(cls, options, args):
+ return cls
+
+ def __init__(self, options, args):
+ self.options = options
+ self.args = args
+ self.safe_options = self.option_parser.get_safe_opts(options)
+
+ def execute(self):
+ """Do everything needed after options are parsed
+
+ This includes validating options, setting up logging, doing the
+ actual work, and handling the result.
+ """
+ try:
+ self.validate_options()
+ self.ask_for_options()
+ self.setup_logging()
+ return_value = self.run()
+ except BaseException, exception:
+ traceback = sys.exc_info()[2]
+ error_message, return_value = self.handle_error(exception)
+ if return_value:
+ self.log_failure(error_message, return_value, exception,
+ traceback)
+ return return_value
+ self.log_success()
+ return return_value
+
+ def validate_options(self):
+ """Validate self.options
+
+ It's also possible to compute and store information that will be
+ useful later, but no changes to the system should be made here.
+ """
+ if self.needs_root and os.getegid() != 0:
+ raise ScriptError('Must be root to run %s' % self.command_name, 1)
+
+ def ask_for_options(self):
+ """Ask for missing options interactively
+
+ Similar to validate_options. This is separate method because we want
+ any validation errors to abort the script before bothering the user
+ with prompts.
+ """
+ pass
+
+ def setup_logging(self):
+ """Set up logging"""
+ ipa_log_manager.standard_logging_setup(
+ self.log_file_name, debug=self.options.debug)
+ ipa_log_manager.log_mgr.get_logger(self, True)
+
+ def handle_error(self, exception):
+ """Given an exception, return a message (or None) and process exit code
+ """
+ if isinstance(exception, ScriptError):
+ return exception.msg, exception.rval or 1
+ elif isinstance(exception, SystemExit):
+ if isinstance(exception.code, int):
+ return None, exception.code
+ return str(exception.code), 1
+
+ return str(exception), 1
+
+ def run(self):
+ """Actual running of the command
+
+ This is where the hard work is done. The base implementation logs
+ the invocation of the command.
+
+ If this method returns (i.e. doesn't raise an exception), the tool is
+ assumed to have run successfully, and the return value is used as the
+ SystemExit code.
+ """
+ self.debug('%s was invoked with arguments %s and options: %s',
+ self.command_name, self.args, self.safe_options)
+
+ def log_failure(self, error_message, return_value, exception, backtrace):
+ try:
+ self.log
+ except AttributeError:
+ # Logging was not set up yet
+ print >> sys.stderr, '\n', error_message
+ else:
+ self.info(''.join(traceback.format_tb(backtrace)))
+ self.info('The %s command failed, exception: %s: %s',
+ self.command_name, type(exception).__name__, exception)
+ if error_message:
+ self.error(error_message)
+
+ def log_success(self):
+ try:
+ self.log
+ except AttributeError:
+ pass
+ else:
+ self.info('The %s command was successful', self.command_name)
diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py
index 903e8f185c54182e800eda547b80b380f24ae8e4..388a11e26000a045a13c35ec54e02a2b5a2ea41e 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -32,12 +32,14 @@ import tempfile
import shutil
from ConfigParser import SafeConfigParser
import traceback
+import textwrap
from dns import resolver, rdatatype
from dns.exception import DNSException
import ldap
-from ipapython import ipautil, sysrestore
+from ipapython import ipautil, sysrestore, admintool
+from ipapython.admintool import ScriptError
from ipapython.ipa_log_manager import *
from ipalib.util import validate_hostname
from ipapython import config
@@ -61,18 +63,6 @@ class HostReverseLookupError(HostLookupError):
class HostnameLocalhost(HostLookupError):
pass
-
-class ScriptError(StandardError):
- """An exception that records an error message and a return value
- """
- def __init__(self, msg = '', rval = 1):
- self.msg = msg
- self.rval = rval
-
- def __str__(self):
- return self.msg
-
-
class ReplicaConfig:
def __init__(self):
self.realm_name = ""
@@ -639,65 +629,65 @@ def run_script(main_function, operation_name, log_file_name=None,
sys.exit(return_value)
except BaseException, error:
- handle_error(error, log_file_name)
+ message, exitcode = handle_error(error, log_file_name)
+ if message:
+ print >> sys.stderr, message
+ sys.exit(exitcode)
def handle_error(error, log_file_name=None):
- """Handle specific errors"""
+ """Handle specific errors. Returns a message and return code"""
if isinstance(error, SystemExit):
- sys.exit(error)
+ if isinstance(error.code, int):
+ return None, error.code
+ elif error.code is None:
+ return None, 0
+ else:
+ return str(error), 1
if isinstance(error, RuntimeError):
- sys.exit(error)
+ return str(error), 1
if isinstance(error, KeyboardInterrupt):
- print >> sys.stderr, "Cancelled."
- sys.exit(1)
+ return "Cancelled.", 1
- if isinstance(error, ScriptError):
- if error.msg:
- print >> sys.stderr, error.msg
- sys.exit(error.rval)
+ if isinstance(error, admintool.ScriptError):
+ return error.msg, error.rval
if isinstance(error, socket.error):
- print >> sys.stderr, error
- sys.exit(1)
+ return error, 1
if isinstance(error, ldap.INVALID_CREDENTIALS):
- print >> sys.stderr, "Invalid password"
- sys.exit(1)
+ return "Invalid password", 1
if isinstance(error, ldap.INSUFFICIENT_ACCESS):
- print >> sys.stderr, "Insufficient access"
- sys.exit(1)
+ return "Insufficient access", 1
if isinstance(error, ldap.LOCAL_ERROR):
- print >> sys.stderr, error.args[0]['info']
- sys.exit(1)
+ return error.args[0]['info'], 1
if isinstance(error, ldap.SERVER_DOWN):
- print >> sys.stderr, error.args[0]['desc']
- sys.exit(1)
+ return error.args[0]['desc'], 1
if isinstance(error, ldap.LDAPError):
- print >> sys.stderr, 'LDAP error: %s' % type(error).__name__
- print >> sys.stderr, error.args[0]['info']
- sys.exit(1)
+ return 'LDAP error: %s\n%s' % (
+ type(error).__name__, error.args[0]['info']), 1
if isinstance(error, config.IPAConfigError):
- print >> sys.stderr, "An IPA server to update cannot be found. Has one been configured yet?"
- print >> sys.stderr, "The error was: %s" % error
- sys.exit(1)
+ message = "An IPA server to update cannot be found. Has one been configured yet?"
+ message += "\nThe error was: %s" % error
+ return message, 1
if isinstance(error, errors.LDAPError):
- print >> sys.stderr, "An error occurred while performing operations: %s" % error
- sys.exit(1)
+ return "An error occurred while performing operations: %s" % error, 1
if isinstance(error, HostnameLocalhost):
- print >> sys.stderr, "The hostname resolves to the localhost address (127.0.0.1/::1)"
- print >> sys.stderr, "Please change your /etc/hosts file so that the hostname"
- print >> sys.stderr, "resolves to the ip address of your network interface."
- print >> sys.stderr, ""
- print >> sys.stderr, "Please fix your /etc/hosts file and restart the setup program"
- sys.exit(1)
+ message = textwrap.dedent("""
+ The hostname resolves to the localhost address (127.0.0.1/::1)
+ Please change your /etc/hosts file so that the hostname
+ resolves to the ip address of your network interface.
+
+ Please fix your /etc/hosts file and restart the setup program
+ """).strip()
+ return message, 1
if log_file_name:
- print >> sys.stderr, "Unexpected error - see %s for details:" % log_file_name
+ message = "Unexpected error - see %s for details:" % log_file_name
else:
- print >> sys.stderr, "Unexpected error"
- print >> sys.stderr, '%s: %s' % (type(error).__name__, error)
- sys.exit(1)
+ message = "Unexpected error"
+ message += '\n%s: %s' % (type(error).__name__, error)
+ return message, 1
diff --git a/ipaserver/install/ipa_ldap_updater.py b/ipaserver/install/ipa_ldap_updater.py
new file mode 100644
index 0000000000000000000000000000000000000000..0c7d940be9b0d9777b7739dc5b63a0fe79b534b9
--- /dev/null
+++ b/ipaserver/install/ipa_ldap_updater.py
@@ -0,0 +1,189 @@
+#!/usr/bin/python
+# Authors: Rob Crittenden <rcritten@redhat.com>
+# Petr Viktorin <pviktori@redhat.com>
+#
+# Copyright (C) 2008 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# Documentation can be found at http://freeipa.org/page/LdapUpdate
+
+# TODO
+# save undo files?
+
+import os
+
+import krbV
+
+from ipalib import api
+from ipapython import ipautil, admintool
+from ipaserver.install import installutils
+from ipaserver.install.ldapupdate import LDAPUpdate, UPDATES_DIR
+from ipaserver.install.upgradeinstance import IPAUpgrade
+from ipapython import ipa_log_manager
+
+
+class LDAPUpdater(admintool.AdminTool):
+ command_name = 'ipa-ldap-updater'
+
+ usage = "%prog [options] input_file(s)\n"
+ usage += "%prog [options]\n"
+
+ @classmethod
+ def add_options(cls, parser):
+ super(LDAPUpdater, cls).add_options(parser)
+
+ parser.add_option("-t", "--test", action="store_true", dest="test",
+ default=False,
+ help="Run through the update without changing anything")
+ parser.add_option("-y", dest="password",
+ help="File containing the Directory Manager password")
+ parser.add_option("-l", '--ldapi', action="store_true", dest="ldapi",
+ default=False,
+ help="Connect to the LDAP server using the ldapi socket")
+ parser.add_option("-u", '--upgrade', action="store_true",
+ dest="upgrade", default=False,
+ help="Upgrade an installed server in offline mode")
+ parser.add_option("-p", '--plugins', action="store_true",
+ dest="plugins", default=False,
+ help="Execute update plugins. " +
+ "Always true when applying all update files.")
+ parser.add_option("-W", '--password', action="store_true",
+ dest="ask_password",
+ help="Prompt for the Directory Manager password")
+
+ @classmethod
+ def get_command_class(cls, options, args):
+ if options.upgrade:
+ return LDAPUpdater_Upgrade
+ else:
+ return LDAPUpdater_NonUpgrade
+
+ def validate_options(self):
+ options = self.options
+ super(LDAPUpdater, self).validate_options()
+
+ self.files = self.args
+
+ for filename in self.files:
+ if not os.path.exists(filename):
+ raise admintool.ScriptError("%s: file not found" % filename)
+
+ if os.getegid() == 0:
+ installutils.check_server_configuration()
+ elif not os.path.exists('/etc/ipa/default.conf'):
+ raise admintool.ScriptError(
+ "IPA is not configured on this system.")
+
+ if options.password:
+ pw = ipautil.template_file(options.password, [])
+ self.dirman_password = pw.strip()
+ else:
+ self.dirman_password = None
+
+ def setup_logging(self):
+ ipa_log_manager.standard_logging_setup(self.log_file_name,
+ console_format='%(levelname)s: %(message)s',
+ debug=self.options.debug, filemode='a')
+ ipa_log_manager.log_mgr.get_logger(self, True)
+
+ def run(self):
+ super(LDAPUpdater, self).run()
+
+ api.bootstrap(
+ in_server=True,
+ context='updates',
+ debug=self.options.debug,
+ )
+ api.finalize()
+
+ def handle_error(self, exception):
+ return installutils.handle_error(exception, self.log_file_name)
+
+
+class LDAPUpdater_Upgrade(LDAPUpdater):
+ needs_root = True
+ log_file_name = '/var/log/ipaupgrade.log'
+
+ def validate_options(self):
+ if os.getegid() != 0:
+ raise admintool.ScriptError('Must be root to do an upgrade.', 1)
+
+ super(LDAPUpdater_Upgrade, self).validate_options()
+
+ def run(self):
+ super(LDAPUpdater_Upgrade, self).run()
+ options = self.options
+
+ updates = None
+ realm = krbV.default_context().default_realm
+ upgrade = IPAUpgrade(realm, self.files, live_run=not options.test)
+ upgrade.create_instance()
+ upgradefailed = upgrade.upgradefailed
+
+ if upgrade.badsyntax:
+ raise admintool.ScriptError(
+ 'Bad syntax detected in upgrade file(s).', 1)
+ elif upgrade.upgradefailed:
+ raise admintool.ScriptError('IPA upgrade failed.', 1)
+ elif upgrade.modified and options.test:
+ self.info('Update complete, changes to be made, test mode')
+ return 2
+
+
+class LDAPUpdater_NonUpgrade(LDAPUpdater):
+ def validate_options(self):
+ super(LDAPUpdater_NonUpgrade, self).validate_options()
+ options = self.options
+
+ # Only run plugins if no files are given
+ self.run_plugins = not self.files or options.plugins
+
+ # Need root for running plugins
+ if self.run_plugins and os.getegid() != 0:
+ raise admintool.ScriptError('Plugins can only be run as root.', 1)
+
+ def ask_for_options(self):
+ super(LDAPUpdater_NonUpgrade, self).ask_for_options()
+ options = self.options
+ if not self.dirman_password:
+ if options.ask_password or not options.ldapi:
+ password = installutils.read_password("Directory Manager",
+ confirm=False, validate=False)
+ if password is None:
+ raise admintool.ScriptError(
+ "Directory Manager password required")
+ self.dirman_password = password
+
+ def run(self):
+ super(LDAPUpdater_NonUpgrade, self).run()
+ options = self.options
+
+ ld = LDAPUpdate(
+ dm_password=self.dirman_password,
+ sub_dict={},
+ live_run=not options.test,
+ ldapi=options.ldapi,
+ plugins=options.plugins or self.run_plugins)
+
+ if not self.files:
+ self.files = ld.get_all_files(UPDATES_DIR)
+
+ modified = ld.update(self.files)
+
+ if modified and options.test:
+ self.info('Update complete, changes to be made, test mode')
+ return 2
diff --git a/ipaserver/install/ldapupdate.py b/ipaserver/install/ldapupdate.py
index e75ee804a1d201512f2770156eef73cf1bb1e7bb..c64139889d9f84866ac0cd358ed3a3a7d95af7dc 100644
--- a/ipaserver/install/ldapupdate.py
+++ b/ipaserver/install/ldapupdate.py
@@ -825,7 +825,7 @@ class LDAPUpdate:
data = self.read_file(f)
except Exception, e:
print e
- sys.exit(1)
+ sys.exit(e)
(all_updates, dn_list) = self.parse_update_file(data, all_updates, dn_list)
diff --git a/make-lint b/make-lint
index f619260434e33886175f5b7d5a1d008466f92a54..05a1bb14f3e1cfdb5404d9a0987f699f6d63428c 100755
--- a/make-lint
+++ b/make-lint
@@ -73,6 +73,7 @@ class IPATypeChecker(TypeChecker):
'ipalib.session.SessionManager' : ['log', 'debug', 'info', 'warning', 'error', 'critical', 'exception'],
'ipalib.session.SessionCCache' : ['log', 'debug', 'info', 'warning', 'error', 'critical', 'exception'],
'ipalib.session.MemcacheSessionManager' : ['log', 'debug', 'info', 'warning', 'error', 'critical', 'exception'],
+ 'ipapython.admintool.AdminTool' : ['log', 'debug', 'info', 'warning', 'error', 'critical', 'exception'],
}
def _related_classes(self, klass):
--
1.7.11.2

View File

@ -0,0 +1,24 @@
From dedb180ddc773baf42bb31efc07a1dda698631bb Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce@redhat.com>
Date: Tue, 24 Jul 2012 14:25:43 -0400
Subject: [PATCH 41/79] Add libtalloc-devel as spec file BuildRequire
---
freeipa.spec.in | 1 +
1 file changed, 1 insertion(+)
diff --git a/freeipa.spec.in b/freeipa.spec.in
index f4903c01354764f0c6b8755824512edbc1ff930b..45149c65f2333512fe21e40be903a3e6144d7084 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -83,6 +83,7 @@ BuildRequires: python-dns
BuildRequires: python-crypto
BuildRequires: check >= 0.9.5
BuildRequires: libsss_idmap-devel
+BuildRequires: libtalloc-devel
%description
IPA is an integrated solution to provide centrally managed Identity (machine,
--
1.7.11.2

View File

@ -0,0 +1,212 @@
From 65bd82eaa1a0d8e377b58ebc6b5d96ea9364c993 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvoborni@redhat.com>
Date: Thu, 19 Jul 2012 14:47:48 +0200
Subject: [PATCH 42/79] IDs and names for dialogs
It's hard to detect if or which type dialog is displayed becouse not all dialogs have IDs.
On dialog open, it's id or name (if id is not set) is used for containing element id. Many of dialog types were missing id or name so name was added to each dialog type.
In HTML, element's id should be unique. Our framework allows opening two dialogs with the same id. It may lead to state where getElementById method may have unpredicted behaviour. Therefore attribute 'data-name' with dialog's name was added to dialog's containing element. Automation framework can search more reliable by using this attribute instead of id.
https://fedorahosted.org/freeipa/ticket/2853
---
install/ui/add.js | 2 ++
install/ui/details.js | 1 +
install/ui/dialog.js | 31 +++++++++++++++++++++----------
install/ui/ipa.js | 8 +++++++-
install/ui/sudo.js | 1 +
install/ui/widget.js | 1 +
6 files changed, 33 insertions(+), 11 deletions(-)
diff --git a/install/ui/add.js b/install/ui/add.js
index eafcd0d57887d9e06a2d48fbfc71757f283c2332..4ca0f04182f37e56b5e47e7fb84de1d4bc485ea0 100644
--- a/install/ui/add.js
+++ b/install/ui/add.js
@@ -27,6 +27,8 @@ IPA.entity_adder_dialog = function(spec) {
spec = spec || {};
+ spec.name = spec.name || 'entity_adder_dialog';
+
var that = IPA.dialog(spec);
that.method = spec.method || 'add';
diff --git a/install/ui/details.js b/install/ui/details.js
index 176e7883ebfa0593276d9397d47e5383a894ab12..e652fa3e5f31f921aab8b324c67c77169ec597b6 100644
--- a/install/ui/details.js
+++ b/install/ui/details.js
@@ -576,6 +576,7 @@ IPA.details_facet = function(spec, no_init) {
that.show_validation_error = function() {
var dialog = IPA.message_dialog({
+ name: 'validation_error',
title: IPA.messages.dialogs.validation_title,
message: IPA.messages.dialogs.validation_message
});
diff --git a/install/ui/dialog.js b/install/ui/dialog.js
index 2af9ee3329327e39df9484f5e0606bf6e3ca9f32..878218419a5b75789c59e42029aa662cc09867b0 100644
--- a/install/ui/dialog.js
+++ b/install/ui/dialog.js
@@ -61,7 +61,7 @@ IPA.dialog = function(spec) {
var that = {};
that.entity = IPA.get_entity(spec.entity);
- that.name = spec.name;
+ that.name = spec.name || 'dialog';
that.id = spec.id;
that.title = spec.title;
that.width = spec.width || 500;
@@ -107,6 +107,12 @@ IPA.dialog = function(spec) {
return valid;
};
+ that.get_id = function() {
+ if (that.id) return that.id;
+ if (that.name) return that.name;
+ return null;
+ };
+
/**
* Create content layout
@@ -147,7 +153,11 @@ IPA.dialog = function(spec) {
*/
that.open = function(container) {
- that.container = $('<div/>', { id : that.id });
+ that.container = $('<div/>', {
+ id : that.get_id(),
+ 'data-name': that.name
+ });
+
if (container) {
container.append(that.container);
}
@@ -286,6 +296,8 @@ IPA.adder_dialog = function(spec) {
spec = spec || {};
+ spec.name = spec.name || 'adder_dialog';
+
var that = IPA.dialog(spec);
that.external = spec.external;
@@ -557,6 +569,7 @@ IPA.adder_dialog = function(spec) {
IPA.deleter_dialog = function (spec) {
spec = spec || {};
+ spec.name = spec.name || 'deleter_dialog';
var that = IPA.dialog(spec);
@@ -639,13 +652,13 @@ IPA.deleter_dialog = function (spec) {
IPA.message_dialog = function(spec) {
+ spec = spec || {};
+
+ spec.name = spec.name || 'message_dialog';
+
var that = IPA.dialog(spec);
-
- var init = function() {
- spec = spec || {};
- that.message = spec.message || '';
- that.on_ok = spec.on_ok;
- };
+ that.message = spec.message || '';
+ that.on_ok = spec.on_ok;
that.create = function() {
$('<p/>', {
@@ -664,8 +677,6 @@ IPA.message_dialog = function(spec) {
}
});
- init();
-
that.message_dialog_create = that.create;
return that;
diff --git a/install/ui/ipa.js b/install/ui/ipa.js
index 413951ff16446852d47cf1fc509106018f897f45..8a690c98447ab1dd3d4e704f068ab7e1b62b1227 100644
--- a/install/ui/ipa.js
+++ b/install/ui/ipa.js
@@ -331,6 +331,7 @@ IPA.logout = function() {
function show_error(message) {
var dialog = IPA.message_dialog({
+ name: 'logout_error',
message: message,
title: IPA.messages.login.logout_error
});
@@ -1023,6 +1024,7 @@ IPA.concurrent_command = function(spec) {
command = command_info.command;
if(!command) {
var dialog = IPA.message_dialog({
+ name: 'internal_error',
title: IPA.get_message('errors.error', 'Error'),
message: IPA.get_message('errors.internal_error', 'Internal error.')
});
@@ -1118,6 +1120,7 @@ IPA.concurrent_command = function(spec) {
} else {
var dialog = IPA.message_dialog({
+ name: 'operation_error',
title: IPA.get_message('dialogs.batch_error_title', 'Operations Error'),
message: IPA.get_message('dialogs.batch_error_message', 'Some operations failed.')
});
@@ -1377,7 +1380,7 @@ IPA.error_dialog = function(spec) {
var init = function() {
spec = spec || {};
- that.id = 'error_dialog';
+ that.id = spec.id || 'error_dialog';
that.xhr = spec.xhr || {};
that.text_status = spec.text_status || '';
that.error_thrown = spec.error_thrown || {};
@@ -1554,6 +1557,7 @@ IPA.create_4304_error_handler = function(adder_dialog) {
if (data && data.error && data.error.code === 4304) {
dialog = IPA.message_dialog({
+ name: 'error_4304_info',
message: data.error.message,
title: adder_dialog.title,
on_ok: function() {
@@ -1621,6 +1625,8 @@ IPA.unauthorized_dialog = function(spec) {
];
spec.visible_buttons = spec.visible_buttons || ['retry'];
+ spec.name = spec.name || 'unauthorized_dialog';
+ spec.id = spec.id || spec.name;
var that = IPA.error_dialog(spec);
diff --git a/install/ui/sudo.js b/install/ui/sudo.js
index a586c4349a8002eddbe48c33895e7ee9578445c2..0dcf432280c1f61fba7a845501eb37489947f6db 100644
--- a/install/ui/sudo.js
+++ b/install/ui/sudo.js
@@ -798,6 +798,7 @@ IPA.sudo.options_section = function(spec) {
title = title.replace('${entity}', label);
var dialog = IPA.dialog({
+ name: 'option-adder-dialog',
title: title,
sections: [
{
diff --git a/install/ui/widget.js b/install/ui/widget.js
index 6864d88f5f08a4064b9b5b1cded527d5e99504ff..0889ee0be2d21fbeb0be14ff45d9337f5fc73b7c 100644
--- a/install/ui/widget.js
+++ b/install/ui/widget.js
@@ -3297,6 +3297,7 @@ IPA.sshkey_widget = function(spec) {
that.create_edit_dialog = function() {
var dialog = IPA.dialog({
+ name: 'sshkey-edit-dialog',
title: IPA.messages.objects.sshkeystore.set_dialog_title,
width: 500,
height: 380
--
1.7.11.2

View File

@ -0,0 +1,55 @@
From 123573912270dd28871766d235ed9f2f15216363 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvoborni@redhat.com>
Date: Mon, 23 Jul 2012 10:32:26 +0200
Subject: [PATCH 43/79] Fix autoscroll to top in tables in IE
In IE when a window is small (horizontal scrollbar is displayed) click or keyboard input on various parts of UI makes search tables scroll to top. It prevents from selecting items in a table. This issue happens when using absolute positioned element with overflow style. It's a bug in IE.
Two workarounds were added to make UI usable in IE.
Adding position:relative; style to body element fixes the problem in search pages. It doesn't help in association dialogs though.
The bug doesn't occur when some child element has focus. It's possible to set focus to first visible checkbox while scrolling down but user experience is very bad. Better solution seems to scroll back when IE scrolls to top on mousedown. That way mouse click event happens on the target element and it can gain focus and therefore be selected. Some glitches still remains but is usable.
https://fedorahosted.org/freeipa/ticket/2835
---
install/ui/ipa.css | 1 +
install/ui/widget.js | 12 ++++++++++++
2 files changed, 13 insertions(+)
diff --git a/install/ui/ipa.css b/install/ui/ipa.css
index 76ce265f0f5c90404046726fe55bd54d73c9b365..4f9d35c1d2a5e458903793423c6fad4de657554e 100644
--- a/install/ui/ipa.css
+++ b/install/ui/ipa.css
@@ -39,6 +39,7 @@ html {
body {
overflow: auto;
+ position: relative;
background: url(images/outer-background.png);
background-repeat: repeat-x;
background-position: left top;
diff --git a/install/ui/widget.js b/install/ui/widget.js
index 0889ee0be2d21fbeb0be14ff45d9337f5fc73b7c..41767118e78dce3f2ff4c30bdcf8368e0d1e976a 100644
--- a/install/ui/widget.js
+++ b/install/ui/widget.js
@@ -1371,6 +1371,18 @@ IPA.table_widget = function (spec) {
that.tbody = $('<tbody/>').appendTo(that.table);
+ // workaround for #2835
+ if ($.browser.msie) {
+ that.tbody.mousedown(function(event) {
+ that.scroll_top = that.tbody.scrollTop();
+ window.setTimeout(function() {
+ if (that.tbody.scrollTop() === 0) {
+ that.tbody.scrollTop(that.scroll_top);
+ }
+ }, 0);
+ });
+ }
+
if (that.height) {
that.tbody.css('height', that.height);
}
--
1.7.11.2

View File

@ -0,0 +1,67 @@
From cc42d19e35ee54b9fcf82e70b7897a6d386d08b9 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Tue, 24 Jul 2012 12:07:23 +0300
Subject: [PATCH 44/79] Rework task naming in LDAP updates to avoid
conflicting names in certain cases
There are two problems in task naming in LDAP updates:
1. Randomness may be scarce in virtual machines
2. Random number is added to the time value rounded to a second
The second issue leads to values that may repeat themselves as time
only grows and random number is non-negative as well, so
t2+r2 can be equal to t1+t2 generated earlier.
Since task name is a DN, there is no strict requirement to use an integer value.
Instead, we generate an UUID and use its 60-bit time, 14-bit sequential number,
and attribute name.
https://fedorahosted.org/freeipa/ticket/2942
---
ipaserver/install/ldapupdate.py | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/ipaserver/install/ldapupdate.py b/ipaserver/install/ldapupdate.py
index c64139889d9f84866ac0cd358ed3a3a7d95af7dc..949b86ad99bce97fe3d09baef7fa42dbbc55ac26 100644
--- a/ipaserver/install/ldapupdate.py
+++ b/ipaserver/install/ldapupdate.py
@@ -29,9 +29,11 @@ from ipaserver.install import installutils
from ipaserver.install import service
from ipaserver import ipaldap
from ipapython import entity, ipautil
+import uuid
from ipalib import util
from ipalib import errors
from ipalib import api
+from ipalib.dn import DN
import ldap
from ldap.dn import escape_dn_chars
from ipapython.ipa_log_manager import *
@@ -328,16 +330,14 @@ class LDAPUpdate:
if self.live_run:
time.sleep(5)
- r = random.SystemRandom()
+ cn_uuid = uuid.uuid1()
+ # cn_uuid.time is in nanoseconds, but other users of LDAPUpdate expect
+ # seconds in 'TIME' so scale the value down
+ self.sub_dict['TIME'] = int(cn_uuid.time/1e9)
+ cn = "indextask_%s_%s_%s" % (attribute, cn_uuid.time, cn_uuid.clock_seq)
+ dn = DN(('cn', cn), ('cn', 'index'), ('cn', 'tasks'), ('cn', 'config'))
- # Refresh the time to make uniqueness more probable. Add on some
- # randomness for good measure.
- self.sub_dict['TIME'] = int(time.time()) + r.randint(0,10000)
-
- cn = self._template_str("indextask_$TIME")
- dn = "cn=%s, cn=index, cn=tasks, cn=config" % cn
-
- e = ipaldap.Entry(dn)
+ e = ipaldap.Entry(str(dn))
e.setValues('objectClass', ['top', 'extensibleObject'])
e.setValue('cn', cn)
--
1.7.11.2

View File

@ -0,0 +1,206 @@
From 23e188f2260f60e05cc7c33b029440db2253a170 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori@redhat.com>
Date: Wed, 20 Jun 2012 06:38:16 -0400
Subject: [PATCH 45/79] Arrange stripping .po files
The .po files we use for translations have two shortcomings when used in Git:
- They include file locations, which change each time the source is updated.
This results in large, unreadable diffs that don't merge well.
- They include source strings for untranslated messages, wasting space
unnecessarily.
Update the Makefile so that the extraneous information is stripped when the
files are updated or pulled form Transifex, and empty translation files are
removed entirely.
Also, translations are normalized to a common style. This should help diffs
and merges.
The validator requires file location comments to identify the programming
language, and to produce good error reports.
To make this work, merge the comments in before validation.
First patch for: https://fedorahosted.org/freeipa/ticket/2435
---
install/configure.ac | 5 +++++
install/po/Makefile.in | 22 ++++++++++++++++++++--
install/po/README | 16 ++++++++++++++--
tests/i18n.py | 12 ++++++++++--
4 files changed, 49 insertions(+), 6 deletions(-)
diff --git a/install/configure.ac b/install/configure.ac
index 827ddbab411a4aa8abbdd4488e217ce67046bd6b..9e781a684429191b3c5eb46aed4fceecc9be6586 100644
--- a/install/configure.ac
+++ b/install/configure.ac
@@ -48,6 +48,11 @@ if test "x$MSGCMP" = "xno"; then
AC_MSG_ERROR([msgcmp not found, install gettext])
fi
+AC_PATH_PROG(MSGATTRIB, msgattrib, [no])
+if test "x$MSGATTRIB" = "xno"; then
+ AC_MSG_ERROR([msgattrib not found, install gettext])
+fi
+
AC_PATH_PROG(TX, tx, [/usr/bin/tx])
AC_ARG_WITH([gettext_domain],
diff --git a/install/po/Makefile.in b/install/po/Makefile.in
index 9a3dde78a20a6beb35ab08230331f28b7ea3161d..bc91a933b9e10e4178cb4190e62140549da06591 100644
--- a/install/po/Makefile.in
+++ b/install/po/Makefile.in
@@ -14,6 +14,7 @@ MSGFMT = @MSGFMT@
MSGINIT = @MSGINIT@
MSGMERGE = @MSGMERGE@
MSGCMP = @MSGCMP@
+MSGATTRIB = @MSGATTRIB@
TX = @TX@
IPA_TEST_I18N = ../../tests/i18n.py
@@ -67,7 +68,7 @@ C_POTFILES = $(C_FILES) $(H_FILES)
.SUFFIXES:
.SUFFIXES: .po .mo
-.PHONY: all create-po update-po update-pot install mostlyclean clean distclean test mo-files debug
+.PHONY: all create-po update-po update-pot install mostlyclean clean distclean test mo-files debug strip-po merge-po $(po_files)
all:
@@ -86,6 +87,19 @@ $(po_files): $(DOMAIN).pot
echo Merging $(DOMAIN).pot into $@; \
$(MSGMERGE) --no-fuzzy-matching -o $@ $@ $(DOMAIN).pot
+strip-po:
+ @for po_file in $(po_files); do \
+ echo Stripping $$po_file; \
+ $(MSGATTRIB) --translated --no-fuzzy --no-location $$po_file > $$po_file.tmp; \
+ mv $$po_file.tmp $$po_file; \
+ done
+ @export FILES_TO_REMOVE=`find . -name '*.po' -empty`; \
+ if [ "$$FILES_TO_REMOVE" != "" ]; then \
+ echo Removing empty translation files; \
+ rm -v $$FILES_TO_REMOVE; \
+ echo; echo Please remove the deleted files from LINGUAS!; echo; \
+ fi
+
create-po: $(DOMAIN).pot
@for po_file in $(po_files); do \
if [ ! -e $$po_file ]; then \
@@ -98,10 +112,14 @@ create-po: $(DOMAIN).pot
pull-po:
cd ../..; $(TX) pull -f
+ $(MAKE) strip-po
-update-po: update-pot
+merge-po: update-pot
$(MAKE) $(po_files)
+update-po: merge-po
+ $(MAKE) strip-po
+
update-pot:
@rm -f $(DOMAIN).pot.update
@pushd ../.. ; \
diff --git a/install/po/README b/install/po/README
index ada7df40e3f294b204a5d44c267ee57ebe734042..6894a06337fac68675cb1a852ca828c54da74f96 100644
--- a/install/po/README
+++ b/install/po/README
@@ -6,10 +6,17 @@ A: Edit Makefile.in and add the source file to the appropriate *_POTFILES list.
NOTE: Now this i only necessary for python files that lack the .py
extension. All .py, .c and .h files are automatically sourced.
+Q: Untranslated strings and file locations are missing from my .po file.
+ How do I add them?
+
+A: make merge-po
+ Untranslated strings are left out of the files in SCM. The merge-po command
+ runs msgmerge to add them again.
+
Q: How do I pick up new strings to translate from the source files after the
source have been modified?
-A: make update-po
+A: make merge-po
This regenerates the pot template file by scanning all the source files.
Then the new strings are merged into each .po file from the new pot file.
@@ -18,6 +25,11 @@ Q: How do I just regenerate the pot template file without regenerating all the
A: make update-pot
+Q: I am done translating. How do I commit my changes?
+
+A: Run `make strip-po` to remove unneeded information from the po files, then
+ add your changes to SCM.
+
Q: How do I add a new language for translation?
A: Edit the LINGUAS file and add the new language. Then run "make create-po".
@@ -27,7 +39,7 @@ A: Edit the LINGUAS file and add the new language. Then run "make create-po".
http://www.gnu.org/software/hello/manual/gettext/Plural-forms.html
However, if this line is wrong, it is often an indicator that the locale
value is incorrect. For example, using 'jp' for Japanese in stead of 'ja'
- will result in an invailid Plural's line.
+ will result in an invalid Plurals line.
Q: What files must be under source code control?
diff --git a/tests/i18n.py b/tests/i18n.py
index 703dc8bbb0962612fdd29f35c7fde06ffcd58406..9c8479bb0a7b2a32d413a58fb5b052afa2866f35 100755
--- a/tests/i18n.py
+++ b/tests/i18n.py
@@ -367,7 +367,7 @@ def validate_positional_substitutions(s, prog_langs, s_name='string'):
return errors
-def validate_file(file_path, validation_mode):
+def validate_file(file_path, validation_mode, reference_pot=None):
'''
Given a pot or po file scan all it's entries looking for problems
with variable substitutions. See the following functions for
@@ -378,6 +378,9 @@ def validate_file(file_path, validation_mode):
* validate_positional_substitutions()
Returns the number of entries with errors.
+
+ For po files, ``reference_pot`` gives a pot file to merge with (to recover
+ comments and file locations)
'''
def emit_messages():
@@ -419,6 +422,9 @@ def validate_file(file_path, validation_mode):
emit_messages()
return Result(n_entries=n_entries, n_msgids=n_msgids, n_msgstrs=n_msgstrs, n_warnings=n_warnings, n_errors=n_errors)
+ if validation_mode == 'po' and reference_pot:
+ # Merge the .pot file for comments and file locations
+ po.merge(reference_pot)
if validation_mode == 'po':
plural_forms = po.metadata.get('Plural-Forms')
@@ -754,12 +760,14 @@ def main():
if not files:
files = [options.pot_file]
validation_mode = 'pot'
+ reference_pot = None
elif options.mode == 'validate_po':
files = args
if not files:
print >> sys.stderr, 'ERROR: no po files specified'
return 1
validation_mode = 'po'
+ reference_pot = polib.pofile(options.pot_file)
else:
print >> sys.stderr, 'ERROR: unknown validation mode "%s"' % (options.mode)
return 1
@@ -771,7 +779,7 @@ def main():
total_errors = 0
for f in files:
- result = validate_file(f, validation_mode)
+ result = validate_file(f, validation_mode, reference_pot)
total_entries += result.n_entries
total_msgids += result.n_msgids
total_msgstrs += result.n_msgstrs
--
1.7.11.2

View File

@ -0,0 +1,35 @@
From cc466e98ffd67d8ced2d14734d654f331c477037 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce@redhat.com>
Date: Wed, 25 Jul 2012 11:23:11 -0400
Subject: [PATCH 46/79] Add all external samba libraries to BuildRequires
Also move them in the right spot (if ! only client) so that they are required
only when building the server.
---
freeipa.spec.in | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/freeipa.spec.in b/freeipa.spec.in
index 45149c65f2333512fe21e40be903a3e6144d7084..719932d4bca61a8ef4a29f0ea060fffcaa403fce 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -33,6 +33,8 @@ BuildRequires: systemd-units
%endif
BuildRequires: samba4-devel >= 4.0.0-128
BuildRequires: samba4-python
+BuildRequires: libtalloc-devel
+BuildRequires: libtevent-devel
%endif
BuildRequires: nspr-devel
BuildRequires: nss-devel
@@ -83,7 +85,6 @@ BuildRequires: python-dns
BuildRequires: python-crypto
BuildRequires: check >= 0.9.5
BuildRequires: libsss_idmap-devel
-BuildRequires: libtalloc-devel
%description
IPA is an integrated solution to provide centrally managed Identity (machine,
--
1.7.11.2

View File

@ -0,0 +1,47 @@
From 9d853483fe3366b8af28de6b8318720339bde89d Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce@redhat.com>
Date: Thu, 26 Jul 2012 14:30:39 -0400
Subject: [PATCH 47/79] Do not check for DNA magic values
The DNA magic value can be arbitrarily changed by admins so we cannot use a
const value to check. And we relly do not need to check at all. If the DNA
plugin is broken and leaves magic values to reach the post-op stage we have
bigger problems. So just simply get rid of this check.
---
daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h | 2 --
daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c | 6 ------
2 files changed, 8 deletions(-)
diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h
index cfb624bde5750d406d631cb1c250c08d1a4366a2..dec2a652464ec451ca7d32b9a82dd958202298e5 100644
--- a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h
+++ b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h
@@ -54,8 +54,6 @@
#define IPANT_USER_ATTRS "ipantuserattrs"
#define IPANT_GROUP_ATTRS "ipantgroupattrs"
-#define IPA_DNA_MAGIC 999
-
#define IPA_PLUGIN_NAME "ipa-sidgen-postop"
#define IPA_SIDGEN_FEATURE_DESC "IPA SIDGEN postop plugin"
#define IPA_SIDGEN_PLUGIN_DESC "Add a SID to newly added or modified " \
diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c
index cbbb2ef183f2d94826a9ead20ca1fc39daa09599..d7e6ac39a57ce26cf6ac7196a1797c44e5a65f77 100644
--- a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c
+++ b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c
@@ -479,12 +479,6 @@ int find_sid_for_ldap_entry(struct slapi_entry *entry,
goto done;
}
- if (uid_number == IPA_DNA_MAGIC || gid_number == IPA_DNA_MAGIC) {
- LOG_FATAL("Looks that DNA plugin was not run before.\n");
- ret = LDAP_OPERATIONS_ERROR;
- goto done;
- }
-
if (uid_number >= UINT32_MAX || gid_number >= UINT32_MAX) {
LOG_FATAL("ID value too large.\n");
ret = LDAP_CONSTRAINT_VIOLATION;
--
1.7.11.2

View File

@ -0,0 +1,116 @@
From e345ad12eb05e53246c2eca54616f9001765c291 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Tue, 24 Jul 2012 22:55:27 -0400
Subject: [PATCH 48/79] Fix validator for SELinux user map settings in config
plugin.
We need to compare two values and need to be aware of where those
values are coming from. They may come from options, setattr or
existing config. The format of that data is going to be different
depending on its source (always a list internally).
One may also set both at the same time so a standard validator cannot
be used because it lacks the context of the other value being set.
https://fedorahosted.org/freeipa/ticket/2938
https://fedorahosted.org/freeipa/ticket/2940
---
ipalib/plugins/config.py | 35 +++++++++++++++++++--------------
tests/test_xmlrpc/test_config_plugin.py | 28 ++++++++++++++++++++++++++
2 files changed, 48 insertions(+), 15 deletions(-)
diff --git a/ipalib/plugins/config.py b/ipalib/plugins/config.py
index c8230e23a779163bca447594206a65b6062d4b37..d632e2edf964919c4f99ee509b31e3bea7d373a3 100644
--- a/ipalib/plugins/config.py
+++ b/ipalib/plugins/config.py
@@ -250,30 +250,35 @@ class config_mod(LDAPUpdate):
error=_('%(obj)s default attribute %(attr)s would not be allowed!') \
% dict(obj=obj, attr=obj_attr))
- if 'ipaselinuxusermapdefault' in options and options['ipaselinuxusermapdefault'] is None:
- raise errors.ValidationError(name='ipaselinuxusermapdefault',
- error=_('SELinux user map default user may not be empty'))
-
- # Make sure the default user is in the list
- if 'ipaselinuxusermapdefault' in options or \
- 'ipaselinuxusermaporder' in options:
+ # Combine the current entry and options into a single object to
+ # evaluate. This covers changes via setattr and options.
+ # Note: this is not done in a validator because we may be changing
+ # the default user and map list at the same time and we don't
+ # have both values in a validator.
+ validate = dict(options)
+ validate.update(entry_attrs)
+ if ('ipaselinuxusermapdefault' in validate or
+ 'ipaselinuxusermaporder' in validate):
config = None
- if 'ipaselinuxusermapdefault' in options:
- defaultuser = options['ipaselinuxusermapdefault']
+ failedattr = 'ipaselinuxusermaporder'
+ if 'ipaselinuxusermapdefault' in validate:
+ defaultuser = validate['ipaselinuxusermapdefault']
+ failedattr = 'ipaselinuxusermapdefault'
else:
config = ldap.get_ipa_config()[1]
- defaultuser = config['ipaselinuxusermapdefault']
+ defaultuser = config['ipaselinuxusermapdefault'][0]
- if 'ipaselinuxusermaporder' in options:
- order = options['ipaselinuxusermaporder']
+ if 'ipaselinuxusermaporder' in validate:
+ order = validate['ipaselinuxusermaporder']
+ userlist = order.split('$')
else:
if not config:
config = ldap.get_ipa_config()[1]
order = config['ipaselinuxusermaporder']
- userlist = order[0].split('$')
+ userlist = order[0].split('$')
if defaultuser not in userlist:
- raise errors.ValidationError(name='ipaselinuxusermaporder',
- error=_('Default SELinux user map default user not in order list'))
+ raise errors.ValidationError(name=failedattr,
+ error=_('SELinux user map default user not in order list'))
return dn
diff --git a/tests/test_xmlrpc/test_config_plugin.py b/tests/test_xmlrpc/test_config_plugin.py
index da549bfb3efb56b05546ba32e7ce57414a586160..6d83f047e0e647270712003d77c40f3c1014f90f 100644
--- a/tests/test_xmlrpc/test_config_plugin.py
+++ b/tests/test_xmlrpc/test_config_plugin.py
@@ -60,4 +60,32 @@ class test_config(Declarative):
expected=errors.RequirementError(name='ipausersearchfields'),
),
+ dict(
+ desc='Try to set invalid ipaselinuxusermapdefault',
+ command=('config_mod', [],
+ dict(ipaselinuxusermapdefault=u'unknown_u:s0')),
+ expected=errors.ValidationError(name='ipaselinuxusermapdefault', error='SELinux user map default user not in order list'),
+ ),
+
+ dict(
+ desc='Try to set invalid ipaselinuxusermapdefault with setattr',
+ command=('config_mod', [],
+ dict(setattr=u'ipaselinuxusermapdefault=unknown_u:s0')),
+ expected=errors.ValidationError(name='ipaselinuxusermapdefault', error='SELinux user map default user not in order list'),
+ ),
+
+ dict(
+ desc='Try to set invalid ipaselinuxusermaporder',
+ command=('config_mod', [],
+ dict(ipaselinuxusermaporder=u'notfound_u:s0')),
+ expected=errors.ValidationError(name='ipaselinuxusermaporder', error='SELinux user map default user not in order list'),
+ ),
+
+ dict(
+ desc='Try to set new selinux order and invalid default user',
+ command=('config_mod', [],
+ dict(ipaselinuxusermaporder=u'$xguest_u:s0$guest_u:s0$user_u:s0-s0:c0.c1023$staff_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023', ipaselinuxusermapdefault=u'unknown_u:s0')),
+ expected=errors.ValidationError(name='ipaselinuxusermapdefault', error='SELinux user map default user not in order list'),
+ ),
+
]
--
1.7.11.2

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,357 @@
From 505bc85ec31ad8cfa66be0dc99d19599cd1a9497 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce@redhat.com>
Date: Fri, 6 Jul 2012 11:15:15 -0400
Subject: [PATCH 50/79] Move code into common krb5 utils
This moves the decoding function that reads the keys from the ber format
into a structure in the common krb5 util code right below the function
that encodes the same data structure into a ber format.
This way the 2 functions are in the same place and can be both used by
all ia components.
---
daemons/ipa-kdb/ipa_kdb_principals.c | 148 ++--------------------------------
util/ipa_krb5.c | 150 +++++++++++++++++++++++++++++++++++
util/ipa_krb5.h | 2 +
3 files changed, 159 insertions(+), 141 deletions(-)
diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c
index d87d6fe9f82b479db6ab8e6b59a8b5ee580b9a27..6f8b296fa4cb19cbfe5c37536316d6f0e7f83b9c 100644
--- a/daemons/ipa-kdb/ipa_kdb_principals.c
+++ b/daemons/ipa-kdb/ipa_kdb_principals.c
@@ -205,152 +205,18 @@ static int ipadb_ldap_attr_to_key_data(LDAP *lcontext, LDAPMessage *le,
krb5_kvno *res_mkvno)
{
struct berval **vals;
- krb5_key_data *keys = NULL;
- BerElement *be = NULL;
- void *tmp;
- int i = 0;
- int ret = ENOENT;
+ int mkvno;
+ int ret;
vals = ldap_get_values_len(lcontext, le, attrname);
- if (vals) {
- ber_tag_t tag;
- ber_int_t major_vno;
- ber_int_t minor_vno;
- ber_int_t kvno;
- ber_int_t mkvno;
- ber_int_t type;
- ber_tag_t seqtag;
- ber_len_t seqlen;
- ber_len_t setlen;
- ber_tag_t retag;
- ber_tag_t opttag;
- struct berval tval;
-
- be = ber_alloc_t(LBER_USE_DER);
- if (!be) {
- return ENOMEM;
- }
-
- /* reinit the ber element with the new val */
- ber_init2(be, vals[0], LBER_USE_DER);
-
- /* fill key_data struct with the data */
- retag = ber_scanf(be, "{t[i]t[i]t[i]t[i]t[{",
- &tag, &major_vno,
- &tag, &minor_vno,
- &tag, &kvno,
- &tag, &mkvno,
- &seqtag);
- if (retag == LBER_ERROR ||
- major_vno != 1 ||
- minor_vno != 1 ||
- seqtag != (LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 4)) {
- ret = EINVAL;
- goto done;
- }
-
- retag = ber_skip_tag(be, &seqlen);
-
- /* sequence of keys */
- for (i = 0; retag == LBER_SEQUENCE; i++) {
-
- tmp = realloc(keys, (i + 1) * sizeof(krb5_key_data));
- if (!tmp) {
- ret = ENOMEM;
- goto done;
- }
- keys = tmp;
-
- memset(&keys[i], 0, sizeof(krb5_key_data));
-
- keys[i].key_data_kvno = kvno;
-
- /* do we have a salt type ? (optional) */
- retag = ber_scanf(be, "t", &opttag);
- if (retag == LBER_ERROR) {
- ret = EINVAL;
- goto done;
- }
- if (opttag == (LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 0)) {
- keys[i].key_data_ver = 2;
-
- retag = ber_scanf(be, "[l{tl[i]",
- &seqlen, &tag, &setlen, &type);
- if (tag != (LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 0)) {
- ret = EINVAL;
- goto done;
- }
- keys[i].key_data_type[1] = type;
-
- /* do we have salt data ? (optional) */
- if (seqlen > setlen + 2) {
- retag = ber_scanf(be, "t[o]", &tag, &tval);
- if (retag == LBER_ERROR ||
- tag != (LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 1)) {
- ret = EINVAL;
- goto done;
- }
- keys[i].key_data_length[1] = tval.bv_len;
- keys[i].key_data_contents[1] = (krb5_octet *)tval.bv_val;
- }
-
- retag = ber_scanf(be, "}]t", &opttag);
- if (retag == LBER_ERROR) {
- ret = EINVAL;
- goto done;
- }
-
- } else {
- keys[i].key_data_ver = 1;
- }
-
- if (opttag != (LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 1)) {
- ret = EINVAL;
- goto done;
- }
-
- /* get the key */
- retag = ber_scanf(be, "[{t[i]t[o]}]", &tag, &type, &tag, &tval);
- if (retag == LBER_ERROR) {
- ret = EINVAL;
- goto done;
- }
- keys[i].key_data_type[0] = type;
- keys[i].key_data_length[0] = tval.bv_len;
- keys[i].key_data_contents[0] = (krb5_octet *)tval.bv_val;
-
- /* check for sk2params */
- retag = ber_peek_tag(be, &setlen);
- if (retag == (LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 2)) {
- /* not supported yet, skip */
- retag = ber_scanf(be, "t[x]}");
- } else {
- retag = ber_scanf(be, "}");
- }
- if (retag == LBER_ERROR) {
- ret = EINVAL;
- goto done;
- }
-
- retag = ber_skip_tag(be, &seqlen);
- }
- *result = keys;
- *num = i;
- *res_mkvno = mkvno;
- ret = 0;
+ if (!vals) {
+ return ENOENT;
}
-done:
- ber_free(be, 0); /* internal buffer is 'vals[0]' */
+ ret = ber_decode_krb5_key_data(vals[0], &mkvno, num, result);
ldap_value_free_len(vals);
- if (ret) {
- for (i -= 1; keys && i >= 0; i--) {
- free(keys[i].key_data_contents[0]);
- free(keys[i].key_data_contents[1]);
- }
- free(keys);
- *result = NULL;
- *num = 0;
+ if (ret == 0) {
+ *res_mkvno = mkvno;
}
return ret;
}
diff --git a/util/ipa_krb5.c b/util/ipa_krb5.c
index 0240c079ecd38271e5dbb36ec8c6a091001cfce7..934fd27d80cdd846f4de631b2dd587b0ad0f325c 100644
--- a/util/ipa_krb5.c
+++ b/util/ipa_krb5.c
@@ -427,6 +427,156 @@ done:
return ret;
}
+int ber_decode_krb5_key_data(struct berval *encoded, int *m_kvno,
+ int *numk, krb5_key_data **data)
+{
+ krb5_key_data *keys = NULL;
+ BerElement *be = NULL;
+ void *tmp;
+ int i = 0;
+ ber_tag_t tag;
+ ber_int_t major_vno;
+ ber_int_t minor_vno;
+ ber_int_t kvno;
+ ber_int_t mkvno;
+ ber_int_t type;
+ ber_tag_t seqtag;
+ ber_len_t seqlen;
+ ber_len_t setlen;
+ ber_tag_t retag;
+ ber_tag_t opttag;
+ struct berval tval;
+ int ret;
+
+ be = ber_alloc_t(LBER_USE_DER);
+ if (!be) {
+ return ENOMEM;
+ }
+
+ /* reinit the ber element with the new val */
+ ber_init2(be, encoded, LBER_USE_DER);
+
+ /* fill key_data struct with the data */
+ retag = ber_scanf(be, "{t[i]t[i]t[i]t[i]t[{",
+ &tag, &major_vno,
+ &tag, &minor_vno,
+ &tag, &kvno,
+ &tag, &mkvno,
+ &seqtag);
+ if (retag == LBER_ERROR ||
+ major_vno != 1 ||
+ minor_vno != 1 ||
+ seqtag != (LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 4)) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ retag = ber_skip_tag(be, &seqlen);
+
+ /* sequence of keys */
+ for (i = 0; retag == LBER_SEQUENCE; i++) {
+
+ tmp = realloc(keys, (i + 1) * sizeof(krb5_key_data));
+ if (!tmp) {
+ ret = ENOMEM;
+ goto done;
+ }
+ keys = tmp;
+
+ memset(&keys[i], 0, sizeof(krb5_key_data));
+
+ keys[i].key_data_kvno = kvno;
+
+ /* do we have a salt type ? (optional) */
+ retag = ber_scanf(be, "t", &opttag);
+ if (retag == LBER_ERROR) {
+ ret = EINVAL;
+ goto done;
+ }
+ if (opttag == (LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 0)) {
+ keys[i].key_data_ver = 2;
+
+ retag = ber_scanf(be, "[l{tl[i]",
+ &seqlen, &tag, &setlen, &type);
+ if (tag != (LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 0)) {
+ ret = EINVAL;
+ goto done;
+ }
+ keys[i].key_data_type[1] = type;
+
+ /* do we have salt data ? (optional) */
+ if (seqlen > setlen + 2) {
+ retag = ber_scanf(be, "t[o]", &tag, &tval);
+ if (retag == LBER_ERROR ||
+ tag != (LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 1)) {
+ ret = EINVAL;
+ goto done;
+ }
+ keys[i].key_data_length[1] = tval.bv_len;
+ keys[i].key_data_contents[1] = (krb5_octet *)tval.bv_val;
+ }
+
+ retag = ber_scanf(be, "}]t", &opttag);
+ if (retag == LBER_ERROR) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ } else {
+ keys[i].key_data_ver = 1;
+ }
+
+ if (opttag != (LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 1)) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ /* get the key */
+ retag = ber_scanf(be, "[{t[i]t[o]}]", &tag, &type, &tag, &tval);
+ if (retag == LBER_ERROR) {
+ ret = EINVAL;
+ goto done;
+ }
+ keys[i].key_data_type[0] = type;
+ keys[i].key_data_length[0] = tval.bv_len;
+ keys[i].key_data_contents[0] = (krb5_octet *)tval.bv_val;
+
+ /* check for sk2params */
+ retag = ber_peek_tag(be, &setlen);
+ if (retag == (LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 2)) {
+ /* not supported yet, skip */
+ retag = ber_scanf(be, "t[x]}");
+ } else {
+ retag = ber_scanf(be, "}");
+ }
+ if (retag == LBER_ERROR) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ retag = ber_skip_tag(be, &seqlen);
+ }
+
+ ret = 0;
+
+done:
+ ber_free(be, 0); /* internal buffer is 'encoded' */
+ if (ret) {
+ for (i -= 1; keys && i >= 0; i--) {
+ free(keys[i].key_data_contents[0]);
+ free(keys[i].key_data_contents[1]);
+ }
+ free(keys);
+ keys = NULL;
+ mkvno = 0;
+ }
+ *m_kvno = mkvno;
+ *numk = i;
+ *data = keys;
+ return ret;
+}
+
+
krb5_error_code parse_bval_key_salt_tuples(krb5_context kcontext,
const char * const *vals,
int n_vals,
diff --git a/util/ipa_krb5.h b/util/ipa_krb5.h
index 97ffc47b5017507cd58e130755cfe050a287b30c..7fb0355724e3c4f522097df417d2686b85619319 100644
--- a/util/ipa_krb5.h
+++ b/util/ipa_krb5.h
@@ -49,6 +49,8 @@ void ipa_krb5_free_key_data(krb5_key_data *keys, int num_keys);
int ber_encode_krb5_key_data(krb5_key_data *data,
int numk, int mkvno,
struct berval **encoded);
+int ber_decode_krb5_key_data(struct berval *encoded, int *m_kvno,
+ int *numk, krb5_key_data **data);
krb5_error_code parse_bval_key_salt_tuples(krb5_context kcontext,
const char * const *vals,
--
1.7.11.2

View File

@ -0,0 +1,261 @@
From 86d83654dcef4a83ff18f18c6ba09f2e4bb0a703 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce@redhat.com>
Date: Fri, 6 Jul 2012 17:03:19 -0400
Subject: [PATCH 51/79] Improve loops around slapi mods
Avoid the need to allocate/free a Slapi_Mod and avoid checking for attribute
equvalence after a match (use if/else)
---
.../ipa-pwd-extop/ipapwd_prepost.c | 130 ++++++++++-----------
1 file changed, 62 insertions(+), 68 deletions(-)
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c
index 181bd0ee785784c52865c03cb696a8a72fb9905a..deae6477772f82edcc4674a1c9580661c3dae94b 100644
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c
@@ -394,7 +394,7 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
struct ipapwd_krbcfg *krbcfg = NULL;
char *errMesg = NULL;
LDAPMod **mods;
- Slapi_Mod *smod, *tmod;
+ LDAPMod *lmod;
Slapi_Mods *smods = NULL;
char *userpw = NULL;
char *unhashedpw = NULL;
@@ -434,52 +434,43 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
/* In the first pass,
* only check there is anything we are interested in */
is_pwd_op = 0;
- tmod = slapi_mod_new();
- smod = slapi_mods_get_first_smod(smods, tmod);
- while (smod) {
+ lmod = slapi_mods_get_first_mod(smods);
+ while (lmod) {
struct berval *bv;
- const char *type;
- int mop;
- type = slapi_mod_get_type(smod);
- if (slapi_attr_types_equivalent(type, SLAPI_USERPWD_ATTR)) {
- mop = slapi_mod_get_operation(smod);
+ if (slapi_attr_types_equivalent(lmod->mod_type, SLAPI_USERPWD_ATTR)) {
/* check op filtering out LDAP_MOD_BVALUES */
- switch (mop & 0x0f) {
+ switch (lmod->mod_op & 0x0f) {
case LDAP_MOD_ADD:
case LDAP_MOD_REPLACE:
is_pwd_op = 1;
default:
break;
}
- }
-
- /* we check for unahsehd password here so that we are sure to catch them
- * early, before further checks go on, this helps checking
- * LDAP_MOD_DELETE operations in some corner cases later */
- /* we keep only the last one if multiple are provided for any absurd
- * reason */
- if (slapi_attr_types_equivalent(type, "unhashed#user#password")) {
- bv = slapi_mod_get_first_value(smod);
- if (!bv) {
- slapi_mod_free(&tmod);
+ } else if (slapi_attr_types_equivalent(lmod->mod_type,
+ "unhashed#user#password")) {
+ /* we check for unahsehd password here so that we are sure to
+ * catch them early, before further checks go on, this helps
+ * checking LDAP_MOD_DELETE operations in some corner cases later.
+ * We keep only the last one if multiple are provided for any
+ * reason */
+ if (!lmod->mod_bvalues ||
+ !lmod->mod_bvalues[0]) {
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
+ bv = lmod->mod_bvalues[0];
slapi_ch_free_string(&unhashedpw);
unhashedpw = slapi_ch_malloc(bv->bv_len+1);
if (!unhashedpw) {
- slapi_mod_free(&tmod);
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
memcpy(unhashedpw, bv->bv_val, bv->bv_len);
unhashedpw[bv->bv_len] = '\0';
}
- slapi_mod_done(tmod);
- smod = slapi_mods_get_next_smod(smods, tmod);
+ lmod = slapi_mods_get_next_mod(smods);
}
- slapi_mod_free(&tmod);
/* If userPassword is not modified we are done here */
if (! is_pwd_op) {
@@ -487,7 +478,7 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
goto done;
}
- /* OK swe have something interesting here, start checking for
+ /* OK we have something interesting here, start checking for
* pre-requisites */
/* Get target DN */
@@ -532,33 +523,27 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
}
/* run through the mods again and adjust flags if operations affect them */
- tmod = slapi_mod_new();
- smod = slapi_mods_get_first_smod(smods, tmod);
- while (smod) {
+ lmod = slapi_mods_get_first_mod(smods);
+ while (lmod) {
struct berval *bv;
- const char *type;
- int mop;
- type = slapi_mod_get_type(smod);
- if (slapi_attr_types_equivalent(type, SLAPI_USERPWD_ATTR)) {
- mop = slapi_mod_get_operation(smod);
+ if (slapi_attr_types_equivalent(lmod->mod_type, SLAPI_USERPWD_ATTR)) {
/* check op filtering out LDAP_MOD_BVALUES */
- switch (mop & 0x0f) {
+ switch (lmod->mod_op & 0x0f) {
case LDAP_MOD_ADD:
/* FIXME: should we try to track cases where we would end up
* with multiple userPassword entries ?? */
case LDAP_MOD_REPLACE:
is_pwd_op = 1;
- bv = slapi_mod_get_first_value(smod);
- if (!bv) {
- slapi_mod_free(&tmod);
+ if (!lmod->mod_bvalues ||
+ !lmod->mod_bvalues[0]) {
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
+ bv = lmod->mod_bvalues[0];
slapi_ch_free_string(&userpw);
userpw = slapi_ch_malloc(bv->bv_len+1);
if (!userpw) {
- slapi_mod_free(&tmod);
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
@@ -569,23 +554,27 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
/* reset only if we are deleting all values, or the exact
* same value previously set, otherwise we are just trying to
* add a new value and delete an existing one */
- bv = slapi_mod_get_first_value(smod);
- if (!bv) {
+ if (!lmod->mod_bvalues ||
+ !lmod->mod_bvalues[0]) {
is_pwd_op = 0;
} else {
- if ((userpw && 0 == strncmp(userpw, bv->bv_val, bv->bv_len)) ||
- (unhashedpw && 0 == strncmp(unhashedpw, bv->bv_val, bv->bv_len)))
+ bv = lmod->mod_bvalues[0];
+ if ((userpw &&
+ strncmp(userpw, bv->bv_val, bv->bv_len) == 0) ||
+ (unhashedpw &&
+ strncmp(unhashedpw, bv->bv_val, bv->bv_len) == 0)) {
is_pwd_op = 0;
+ }
}
default:
break;
}
- }
- if (slapi_attr_types_equivalent(type, SLAPI_ATTR_OBJECTCLASS)) {
- mop = slapi_mod_get_operation(smod);
+ } else if (slapi_attr_types_equivalent(lmod->mod_type,
+ SLAPI_ATTR_OBJECTCLASS)) {
+ int i;
/* check op filtering out LDAP_MOD_BVALUES */
- switch (mop & 0x0f) {
+ switch (lmod->mod_op & 0x0f) {
case LDAP_MOD_REPLACE:
/* if objectclasses are replaced we need to start clean with
* flags, so we sero them out and see if they get set again */
@@ -594,20 +583,23 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
is_ipant = 0;
case LDAP_MOD_ADD:
- bv = slapi_mod_get_first_value(smod);
- if (!bv) {
- slapi_mod_free(&tmod);
+ if (!lmod->mod_bvalues ||
+ !lmod->mod_bvalues[0]) {
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
- do {
- if (0 == strncasecmp("krbPrincipalAux", bv->bv_val, bv->bv_len))
+ for (i = 0; (bv = lmod->mod_bvalues[i]) != NULL; i++) {
+ if (strncasecmp("krbPrincipalAux",
+ bv->bv_val, bv->bv_len) == 0) {
is_krb = 1;
- if (0 == strncasecmp("sambaSamAccount", bv->bv_val, bv->bv_len))
+ } else if (strncasecmp("sambaSamAccount",
+ bv->bv_val, bv->bv_len) == 0) {
is_smb = 1;
- if (0 == strncasecmp("ipaNTUserAttrs", bv->bv_val, bv->bv_len))
+ } else if (strncasecmp("ipaNTUserAttrs",
+ bv->bv_val, bv->bv_len) == 0) {
is_ipant = 1;
- } while ((bv = slapi_mod_get_next_value(smod)) != NULL);
+ }
+ }
break;
@@ -620,32 +612,34 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
default:
break;
}
- }
- /* if we are getting a krbPrincipalKey, also avoid regenerating the keys,
- * it means kadmin has alredy done the job and is simply keeping
- * userPassword and sambaXXPAssword in sync */
- if (slapi_attr_types_equivalent(type, "krbPrincipalKey")) {
+ } else if (slapi_attr_types_equivalent(lmod->mod_type,
+ "krbPrincipalKey")) {
+
+ /* if we are getting a krbPrincipalKey, also avoid regenerating
+ * the keys, it means kadmin has alredy done the job and is simply
+ * keeping userPassword and sambaXXPAssword in sync */
+
/* we also check we have enough authority */
if (is_root) {
has_krb_keys = 1;
}
- }
- /* if we are getting a passwordHistory, also avoid regenerating the hashes,
- * it means kadmin has alredy done the job and is simply keeping
- * userPassword and sambaXXPAssword in sync */
- if (slapi_attr_types_equivalent(type, "passwordHistory")) {
+ } else if (slapi_attr_types_equivalent(lmod->mod_type,
+ "passwordHistory")) {
+
+ /* if we are getting a passwordHistory, also avoid regenerating
+ * the hashes, it means kadmin has alredy done the job and is
+ * simply keeping userPassword and sambaXXPAssword in sync */
+
/* we also check we have enough authority */
if (is_root) {
has_history = 1;
}
}
- slapi_mod_done(tmod);
- smod = slapi_mods_get_next_smod(smods, tmod);
+ lmod = slapi_mods_get_next_mod(smods);
}
- slapi_mod_free(&tmod);
if (is_krb) {
if (has_krb_keys) {
--
1.7.11.2

View File

@ -0,0 +1,221 @@
From 38d98fd3aa80f864d8f2ecb9a0a3393462d3caa2 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce@redhat.com>
Date: Fri, 6 Jul 2012 16:18:29 -0400
Subject: [PATCH 52/79] Add special modify op to regen ipaNTHash
The NT Hash is the same thing as the RC4-HMAC key, so we add a function to
extract it from krb5 keys if they are available to avoid forcing a password
change when configuring trust relationships.
---
.../ipa-pwd-extop/ipapwd_prepost.c | 146 ++++++++++++++++++++-
1 file changed, 143 insertions(+), 3 deletions(-)
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c
index deae6477772f82edcc4674a1c9580661c3dae94b..e4909c94585b6fac6b7f8347b806a8841107f3d0 100644
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c
@@ -41,7 +41,12 @@
# include <config.h>
#endif
-#define _XOPEN_SOURCE /* strptime needs this */
+/* strptime needs _XOPEN_SOURCE and endian.h needs __USE_BSD
+ * _GNU_SOURCE imply both, and we use it elsewhere, so use this */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
#include <stdio.h>
#include <string.h>
#include <strings.h>
@@ -53,6 +58,7 @@
#include <dirsrv/slapi-plugin.h>
#include <lber.h>
#include <time.h>
+#include <endian.h>
#include "ipapwd.h"
#include "util.h"
@@ -379,6 +385,12 @@ done:
return 0;
}
+#define NTHASH_REGEN_VAL "MagicRegen"
+#define NTHASH_REGEN_LEN sizeof(NTHASH_REGEN_VAL)
+static int ipapwd_regen_nthash(Slapi_PBlock *pb, Slapi_Mods *smods,
+ char *dn, struct slapi_entry *entry,
+ struct ipapwd_krbcfg *krbcfg);
+
/* PRE MOD Operation:
* Gets the clean text password (fail the operation if the password came
* pre-hashed, unless this is a replicated operation).
@@ -407,6 +419,7 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
int has_krb_keys = 0;
int has_history = 0;
int gen_krb_keys = 0;
+ int is_magic_regen = 0;
int ret, rc;
LOG_TRACE( "=>\n");
@@ -447,6 +460,27 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
default:
break;
}
+ } else if (slapi_attr_types_equivalent(lmod->mod_type, "ipaNTHash")) {
+ /* check op filtering out LDAP_MOD_BVALUES */
+ switch (lmod->mod_op & 0x0f) {
+ case LDAP_MOD_ADD:
+ if (!lmod->mod_bvalues ||
+ !lmod->mod_bvalues[0]) {
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+ bv = lmod->mod_bvalues[0];
+ if ((bv->bv_len >= NTHASH_REGEN_LEN -1) &&
+ (bv->bv_len <= NTHASH_REGEN_LEN) &&
+ (strncmp(NTHASH_REGEN_VAL,
+ bv->bv_val, bv->bv_len) == 0)) {
+ is_magic_regen = 1;
+ /* make sure the database will later ignore this mod */
+ slapi_mods_remove(smods);
+ }
+ default:
+ break;
+ }
} else if (slapi_attr_types_equivalent(lmod->mod_type,
"unhashed#user#password")) {
/* we check for unahsehd password here so that we are sure to
@@ -472,8 +506,9 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
lmod = slapi_mods_get_next_mod(smods);
}
- /* If userPassword is not modified we are done here */
- if (! is_pwd_op) {
+ /* If userPassword is not modified check if this is a request to generate
+ * NT hashes otherwise we are done here */
+ if (!is_pwd_op && !is_magic_regen) {
rc = LDAP_SUCCESS;
goto done;
}
@@ -522,6 +557,22 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb)
goto done;
}
+ if (!is_pwd_op) {
+ /* This may be a magic op to ask us to generate the NT hashes */
+ if (is_magic_regen) {
+ /* Make sense to call only if this entry has krb keys to source
+ * the nthash from */
+ if (is_krb) {
+ rc = ipapwd_regen_nthash(pb, smods, dn, e, krbcfg);
+ } else {
+ rc = LDAP_UNWILLING_TO_PERFORM;
+ }
+ } else {
+ rc = LDAP_OPERATIONS_ERROR;
+ }
+ goto done;
+ }
+
/* run through the mods again and adjust flags if operations affect them */
lmod = slapi_mods_get_first_mod(smods);
while (lmod) {
@@ -831,6 +882,95 @@ done:
return 0;
}
+static int ipapwd_regen_nthash(Slapi_PBlock *pb, Slapi_Mods *smods,
+ char *dn, struct slapi_entry *entry,
+ struct ipapwd_krbcfg *krbcfg)
+{
+ Slapi_Attr *attr;
+ Slapi_Value *value;
+ const struct berval *val;
+ struct berval *ntvals[2] = { NULL, NULL };
+ struct berval bval;
+ krb5_key_data *keys;
+ int num_keys;
+ int mkvno;
+ int ret;
+ int i;
+
+ ret = slapi_entry_attr_find(entry, "ipaNTHash", &attr);
+ if (ret == 0) {
+ /* We refuse to regen if there is already a value */
+ return LDAP_CONSTRAINT_VIOLATION;
+ }
+
+ /* ok let's see if we can find the RC4 hash in the keys */
+ ret = slapi_entry_attr_find(entry, "krbPrincipalKey", &attr);
+ if (ret) {
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+
+ ret = slapi_attr_first_value(attr, &value);
+ if (ret) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ val = slapi_value_get_berval(value);
+ if (!val) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ ret = ber_decode_krb5_key_data((struct berval *)val,
+ &mkvno, &num_keys, &keys);
+ if (ret) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ ret = LDAP_UNWILLING_TO_PERFORM;
+
+ for (i = 0; i < num_keys; i++) {
+ char nthash[16];
+ krb5_enc_data cipher;
+ krb5_data plain;
+ krb5_int16 t;
+
+ if (keys[i].key_data_type[0] != ENCTYPE_ARCFOUR_HMAC) {
+ continue;
+ }
+
+ memcpy(&t, keys[i].key_data_contents[0], 2);
+ plain.length = le16toh(t);
+ if (plain.length != 16) {
+ continue;
+ }
+ plain.data = nthash;
+
+ memset(&cipher, 0, sizeof(krb5_enc_data));
+ cipher.enctype = krbcfg->kmkey->enctype;
+ cipher.ciphertext.length = keys[i].key_data_length[0] - 2;
+ cipher.ciphertext.data = ((char *)keys[i].key_data_contents[0]) + 2;
+
+ ret = krb5_c_decrypt(krbcfg->krbctx, krbcfg->kmkey,
+ 0, NULL, &cipher, &plain);
+ if (ret) {
+ ret = LDAP_OPERATIONS_ERROR;
+ break;
+ }
+
+ bval.bv_val = nthash;
+ bval.bv_len = 16;
+ ntvals[0] = &bval;
+
+ slapi_mods_add_modbvps(smods, LDAP_MOD_ADD, "ipaNTHash", ntvals);
+
+ ret = LDAP_SUCCESS;
+ break;
+ }
+
+ ipa_krb5_free_key_data(keys, num_keys);
+
+ return ret;
+}
+
static int ipapwd_post_op(Slapi_PBlock *pb)
{
void *op;
--
1.7.11.2

View File

@ -0,0 +1,140 @@
From 051eb5f7e4969bf6c2f45346df2f07324fa21882 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Thu, 26 Jul 2012 22:05:25 +0300
Subject: [PATCH 53/79] When ipaNTHash is missing, ask IPA to generate it from
kerberos keys
Signed-off-by: Simo Sorce <ssorce@redhat.com>
---
daemons/ipa-sam/ipa_sam.c | 96 +++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 93 insertions(+), 3 deletions(-)
diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c
index ab4b116c5f2b3b8dae6e8309403afba5fdf86708..aa54429b5bec4b26906b2a34e59ff95299a67f80 100644
--- a/daemons/ipa-sam/ipa_sam.c
+++ b/daemons/ipa-sam/ipa_sam.c
@@ -2400,6 +2400,74 @@ static bool init_sam_from_td(struct samu *user, struct pdb_trusted_domain *td,
return true;
}
+static bool ipasam_nthash_retrieve(struct ldapsam_privates *ldap_state,
+ TALLOC_CTX *mem_ctx,
+ char *entry_dn,
+ DATA_BLOB *nthash)
+{
+ int ret;
+ bool retval;
+ LDAPMessage *result;
+ LDAPMessage *entry = NULL;
+ int count;
+ struct smbldap_state *smbldap_state = ldap_state->smbldap_state;
+ const char *attr_list[] = {
+ LDAP_ATTRIBUTE_NTHASH,
+ NULL
+ };
+
+ ret = smbldap_search(smbldap_state, entry_dn,
+ LDAP_SCOPE_BASE, "", attr_list, 0,
+ &result);
+ if (ret != LDAP_SUCCESS) {
+ DEBUG(1, ("Failed to get NT hash: %s\n",
+ ldap_err2string (ret)));
+ return false;
+ }
+
+ count = ldap_count_entries(smbldap_state->ldap_struct, result);
+
+ if (count != 1) {
+ DEBUG(1, ("Unexpected number of results [%d] for NT hash "
+ "of the single entry search.\n", count));
+ ldap_msgfree(result);
+ return false;
+ }
+
+ entry = ldap_first_entry(smbldap_state->ldap_struct, result);
+ if (entry == NULL) {
+ DEBUG(0, ("Could not get entry\n"));
+ ldap_msgfree(result);
+ return false;
+ }
+
+ retval = smbldap_talloc_single_blob(mem_ctx,
+ smbldap_state->ldap_struct,
+ entry, LDAP_ATTRIBUTE_NTHASH,
+ nthash);
+ ldap_msgfree(result);
+ return retval;
+}
+
+static bool ipasam_nthash_regen(struct ldapsam_privates *ldap_state,
+ TALLOC_CTX *mem_ctx,
+ char * entry_dn)
+{
+ LDAPMod **mods;
+ int ret;
+
+ mods = NULL;
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct,
+ NULL, &mods, LDAP_ATTRIBUTE_NTHASH, "MagicRegen");
+
+ talloc_autofree_ldapmod(mem_ctx, mods);
+ ret = smbldap_add(ldap_state->smbldap_state, entry_dn, mods);
+ if (ret != LDAP_SUCCESS) {
+ DEBUG(5, ("ipasam: attempt to regen ipaNTHash failed\n"));
+ }
+ return (ret == LDAP_SUCCESS);
+}
+
static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state,
struct samu * sampass,
LDAPMessage * entry)
@@ -2414,6 +2482,7 @@ static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state,
char *profile_path = NULL;
char *temp = NULL;
bool ret = false;
+ bool retval = false;
DATA_BLOB nthash;
TALLOC_CTX *tmp_ctx = talloc_init("init_sam_from_ldap");
@@ -2504,14 +2573,35 @@ static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state,
pdb_set_acct_ctrl(sampass, ACB_NORMAL, PDB_SET);
- if (!smbldap_talloc_single_blob(tmp_ctx,
+ retval = smbldap_talloc_single_blob(tmp_ctx,
ldap_state->smbldap_state->ldap_struct,
entry, LDAP_ATTRIBUTE_NTHASH,
- &nthash)) {
+ &nthash);
+ if (!retval) {
+ /* NT Hash is not in place. Attempt to retrieve it from
+ * the RC4-HMAC key if that exists in Kerberos credentials.
+ * IPA 389-ds plugin allows to ask for it by setting
+ * ipaNTHash to MagicRegen value.
+ * */
+ temp = smbldap_talloc_dn(tmp_ctx, ldap_state->smbldap_state->ldap_struct, entry);
+ if (temp) {
+ retval = ipasam_nthash_regen(tmp_ctx,
+ ldap_state->smbldap_state->ldap_struct,
+ temp);
+ if (retval) {
+ retval = ipasam_nthash_retrieve(tmp_ctx,
+ ldap_state->smbldap_state->ldap_struct,
+ temp, &nthash);
+ }
+ }
+ }
+
+ if (!retval) {
DEBUG(5, ("Failed to read NT hash form LDAP response.\n"));
}
+
if (nthash.length != NT_HASH_LEN && nthash.length != 0) {
- DEBUG(5, ("NT hash from LDAP has the wrong size.\n"));
+ DEBUG(5, ("NT hash from LDAP has the wrong size. Perhaps password was not re-set?\n"));
} else {
if (!pdb_set_nt_passwd(sampass, nthash.data, PDB_SET)) {
DEBUG(5, ("Failed to set NT hash.\n"));
--
1.7.11.2

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,462 @@
From 68d5fe1ec7d785f127b3513f84cc632cdb1f9167 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Fri, 13 Jul 2012 18:12:48 +0300
Subject: [PATCH 55/79] Ensure ipa-adtrust-install is run with Kerberos ticket
for admin user
When setting up AD trusts support, ipa-adtrust-install utility
needs to be run as:
- root, for performing Samba configuration and using LDAPI/autobind
- kinit-ed IPA admin user, to ensure proper ACIs are granted to
fetch keytab
As result, we can get rid of Directory Manager credentials in ipa-adtrust-install
https://fedorahosted.org/freeipa/ticket/2815
---
install/tools/ipa-adtrust-install | 46 +++++++------
install/tools/man/ipa-adtrust-install.1 | 3 -
ipaserver/install/adtrustinstance.py | 21 +++---
ipaserver/install/bindinstance.py | 2 +-
ipaserver/install/cainstance.py | 3 +-
ipaserver/install/dsinstance.py | 2 +-
ipaserver/install/krbinstance.py | 2 +-
ipaserver/install/service.py | 114 +++++++++++++++++++++-----------
8 files changed, 116 insertions(+), 77 deletions(-)
diff --git a/install/tools/ipa-adtrust-install b/install/tools/ipa-adtrust-install
index 6678018e6346d75d5042894cfb833d38079d3f21..02a309306fb5743c94b651ab22afa06b5eb2cc8b 100755
--- a/install/tools/ipa-adtrust-install
+++ b/install/tools/ipa-adtrust-install
@@ -24,7 +24,7 @@
from ipaserver.plugins.ldap2 import ldap2
from ipaserver.install import adtrustinstance
from ipaserver.install.installutils import *
-from ipaserver.install import installutils
+from ipaserver.install import service
from ipapython import version
from ipapython import ipautil, sysrestore
from ipalib import api, errors, util
@@ -37,8 +37,6 @@ log_file_name = "/var/log/ipaserver-install.log"
def parse_options():
parser = IPAOptionParser(version=version.VERSION)
- parser.add_option("-p", "--ds-password", dest="dm_password",
- sensitive=True, help="directory manager password")
parser.add_option("-d", "--debug", dest="debug", action="store_true",
default=False, help="print debugging information")
parser.add_option("--ip-address", dest="ip_address",
@@ -98,7 +96,7 @@ def main():
root_logger.debug('%s was invoked with options: %s' % (sys.argv[0], safe_options))
root_logger.debug("missing options might be asked for interactively later\n")
- installutils.check_server_configuration()
+ check_server_configuration()
global fstore
fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore')
@@ -194,24 +192,34 @@ def main():
if not options.unattended and ( not netbios_name or not options.netbios_name):
netbios_name = read_netbios_name(netbios_name)
- dm_password = options.dm_password or read_password("Directory Manager",
- confirm=False, validate=False)
- smb = adtrustinstance.ADTRUSTInstance(fstore, dm_password)
+ try:
+ ctx = krbV.default_context()
+ ccache = ctx.default_ccache()
+ principal = ccache.principal()
+ except krbV.Krb5Error, e:
+ sys.exit("Must have Kerberos credentials to setup AD trusts on server")
- # try the connection
try:
- smb.ldap_connect()
- smb.ldap_disconnect()
- except ldap.INVALID_CREDENTIALS, e:
- sys.exit("Password is not valid!")
+ api.Backend.ldap2.connect(ccache.name)
+ except errors.ACIError, e:
+ sys.exit("Outdated Kerberos credentials. Use kdestroy and kinit to update your ticket")
+ except errors.DatabaseError, e:
+ sys.exit("Cannot connect to the LDAP database. Please check if IPA is running")
- if smb.dm_password:
- api.Backend.ldap2.connect(bind_dn="cn=Directory Manager", bind_pw=smb.dm_password)
- else:
- # See if our LDAP server is up and we can talk to it over GSSAPI
- ccache = krbV.default_context().default_ccache().name
- api.Backend.ldap2.connect(ccache)
+ try:
+ user = api.Command.user_show(unicode(principal[0]))['result']
+ group = api.Command.group_show(u'admins')['result']
+ if not (user['uid'][0] in group['member_user'] and
+ group['cn'][0] in user['memberof_group']):
+ raise errors.RequirementError(name='admins group membership')
+ except errors.RequirementError, e:
+ sys.exit("Must have administrative privileges to setup AD trusts on server")
+ except Exception, e:
+ sys.exit("Unrecognized error during check of admin rights: %s" % (str(e)))
+ smb = adtrustinstance.ADTRUSTInstance(fstore)
+ smb.realm = api.env.realm
+ smb.autobind = service.ENABLED
smb.setup(api.env.host, ip_address, api.env.realm, api.env.domain,
netbios_name, options.rid_base, options.secondary_rid_base,
options.no_msdcs)
@@ -250,5 +258,5 @@ information"""
return 0
if __name__ == '__main__':
- installutils.run_script(main, log_file_name=log_file_name,
+ run_script(main, log_file_name=log_file_name,
operation_name='ipa-adtrust-install')
diff --git a/install/tools/man/ipa-adtrust-install.1 b/install/tools/man/ipa-adtrust-install.1
index b61da19088b40d6a9e53784f9a061913ecda4321..22337c3df8827670657bf405b6c49ba2f8624d6d 100644
--- a/install/tools/man/ipa-adtrust-install.1
+++ b/install/tools/man/ipa-adtrust-install.1
@@ -27,9 +27,6 @@ trust to an Active Directory domain. This requires that the IPA server is
already installed and configured.
.SH "OPTIONS"
.TP
-\fB\-p\fR \fIDM_PASSWORD\fR, \fB\-\-ds\-password\fR=\fIDM_PASSWORD\fR
-The password to be used by the Directory Server for the Directory Manager user
-.TP
\fB\-d\fR, \fB\-\-debug\fR
Enable debug logging when more verbose output is needed
.TP
diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py
index 20feec4df309b5793aa1c29fdf18bc5bfe180943..9dcbec2d61d935f90e74cc65b30a0f1d0c0f9d2a 100644
--- a/ipaserver/install/adtrustinstance.py
+++ b/ipaserver/install/adtrustinstance.py
@@ -96,10 +96,9 @@ class ADTRUSTInstance(service.Service):
OBJC_GROUP = "ipaNTGroupAttrs"
OBJC_DOMAIN = "ipaNTDomainAttrs"
- def __init__(self, fstore=None, dm_password=None):
+ def __init__(self, fstore=None):
self.fqdn = None
self.ip_address = None
- self.realm_name = None
self.domain_name = None
self.netbios_name = None
self.no_msdcs = None
@@ -118,7 +117,7 @@ class ADTRUSTInstance(service.Service):
self.rid_base = None
self.secondary_rid_base = None
- service.Service.__init__(self, "smb", dm_password=dm_password)
+ service.Service.__init__(self, "smb", dm_password=None, ldapi=True)
if fstore:
self.fstore = fstore
@@ -436,6 +435,8 @@ class ADTRUSTInstance(service.Service):
# We do not let the system start IPA components on its own,
# Instead we reply on the IPA init script to start only enabled
# components as found in our LDAP configuration tree
+ # Note that self.dm_password is None for ADTrustInstance because
+ # we ensure to be called as root and using ldapi to use autobind
try:
self.ldap_enable('ADTRUST', self.fqdn, self.dm_password, \
self.suffix)
@@ -449,7 +450,7 @@ class ADTRUSTInstance(service.Service):
root_logger.info("EXTID Service startup entry already exists.")
def __setup_sub_dict(self):
- self.sub_dict = dict(REALM = self.realm_name,
+ self.sub_dict = dict(REALM = self.realm,
SUFFIX = self.suffix,
NETBIOS_NAME = self.netbios_name,
SMB_DN = self.smb_dn,
@@ -460,16 +461,16 @@ class ADTRUSTInstance(service.Service):
rid_base, secondary_rid_base, no_msdcs=False, smbd_user="samba"):
self.fqdn = fqdn
self.ip_address = ip_address
- self.realm_name = realm_name
+ self.realm = realm_name
self.domain_name = domain_name
self.netbios_name = netbios_name
self.rid_base = rid_base
self.secondary_rid_base = secondary_rid_base
self.no_msdcs = no_msdcs
self.smbd_user = smbd_user
- self.suffix = ipautil.realm_to_suffix(self.realm_name)
+ self.suffix = ipautil.realm_to_suffix(self.realm)
self.ldapi_socket = "%%2fvar%%2frun%%2fslapd-%s.socket" % \
- realm_to_serverid(self.realm_name)
+ realm_to_serverid(self.realm)
self.smb_conf = "/etc/samba/smb.conf"
@@ -479,7 +480,7 @@ class ADTRUSTInstance(service.Service):
self.trust_dn = str(DN(api.env.container_trusts, self.suffix))
self.smb_dom_dn = str(DN(('cn', self.domain_name),
api.env.container_cifsdomains, self.suffix))
- self.cifs_principal = "cifs/" + self.fqdn + "@" + self.realm_name
+ self.cifs_principal = "cifs/" + self.fqdn + "@" + self.realm
self.cifs_agent = str(DN(('krbprincipalname', self.cifs_principal.lower()),
api.env.container_service,
self.suffix))
@@ -522,11 +523,11 @@ class ADTRUSTInstance(service.Service):
"range.\nAdd local ID range manually and try " \
"again!")
- entry = ipaldap.Entry(str(DN(('cn', ('%s_id_range' % self.realm_name)),
+ entry = ipaldap.Entry(str(DN(('cn', ('%s_id_range' % self.realm)),
api.env.container_ranges,
self.suffix)))
entry.setValue('objectclass', 'ipaDomainIDRange')
- entry.setValue('cn', ('%s_id_range' % self.realm_name))
+ entry.setValue('cn', ('%s_id_range' % self.realm))
entry.setValue('ipaBaseID', str(base_id))
entry.setValue('ipaIDRangeSize', str(id_range_size))
self.admin_conn.addEntry(entry)
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index c348cdbb278f222dfbc034cbe1220df26262cb9d..f320202eaa20fc5e8cf1e61ad11a769a4436ba47 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -448,7 +448,7 @@ class DnsBackup(object):
class BindInstance(service.Service):
def __init__(self, fstore=None, dm_password=None):
- service.Service.__init__(self, "named", dm_password=dm_password)
+ service.Service.__init__(self, "named", dm_password=dm_password, ldapi=False, autobind=service.DISABLED)
self.dns_backup = DnsBackup(self)
self.named_user = None
self.domain = None
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 2644689a0bc18fdb97d1e66d3f929af24cd101ba..dc4374ccef4f7bd64edb14d77efe35b46895bfb5 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -225,10 +225,9 @@ def get_outputList(data):
class CADSInstance(service.Service):
def __init__(self, host_name=None, realm_name=None, domain_name=None, dm_password=None):
- service.Service.__init__(self, "pkids")
+ service.Service.__init__(self, "pkids", dm_password=dm_password, ldapi=False, autobind=service.DISABLED)
self.serverid = "PKI-IPA"
self.realm_name = realm_name
- self.dm_password = dm_password
self.sub_dict = None
self.domain = domain_name
self.fqdn = host_name
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 25c449a6e865de01d789a739b31906cb70c6f212..9f3ae7252e45ab3289a85711a2b1202bbe04e137 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -160,7 +160,7 @@ info: IPA V2.0
class DsInstance(service.Service):
def __init__(self, realm_name=None, domain_name=None, dm_password=None, fstore=None):
- service.Service.__init__(self, "dirsrv", dm_password=dm_password)
+ service.Service.__init__(self, "dirsrv", dm_password=dm_password, ldapi=False, autobind=service.DISABLED)
self.realm_name = realm_name
self.sub_dict = None
self.domain = domain_name
diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py
index 2faf8e19693f891f28838df967399f0bfe2b51a4..8cc50fba4b0ba8d760cc892a624bd64ef09541a6 100644
--- a/ipaserver/install/krbinstance.py
+++ b/ipaserver/install/krbinstance.py
@@ -178,7 +178,7 @@ class KrbInstance(service.Service):
self.start_creation("Configuring Kerberos KDC", 30)
self.kpasswd = KpasswdInstance()
- self.kpasswd.create_instance('KPASSWD', self.fqdn, self.admin_password, self.suffix)
+ self.kpasswd.create_instance('KPASSWD', self.fqdn, self.admin_password, self.suffix, realm=self.realm)
def create_replica(self, realm_name,
master_fqdn, host_name,
diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py
index 5c2699e3fa4c115c972528d4c2cc6aa170711837..198cb387011be1239eedbff410863232922a21e1 100644
--- a/ipaserver/install/service.py
+++ b/ipaserver/install/service.py
@@ -35,6 +35,11 @@ from ipapython.ipa_log_manager import *
CACERT = "/etc/ipa/ca.crt"
+# Autobind modes
+AUTO = 1
+ENABLED = 2
+DISABLED = 3
+
# The service name as stored in cn=masters,cn=ipa,cn=etc. In the tuple
# the first value is the *nix service name, the second the start order.
SERVICE_LIST = {
@@ -55,13 +60,14 @@ def print_msg(message, output_fd=sys.stdout):
class Service(object):
- def __init__(self, service_name, sstore=None, dm_password=None, ldapi=False):
+ def __init__(self, service_name, sstore=None, dm_password=None, ldapi=True, autobind=AUTO):
self.service_name = service_name
self.service = ipaservices.service(service_name)
self.steps = []
self.output_fd = sys.stdout
self.dm_password = dm_password
self.ldapi = ldapi
+ self.autobind = autobind
self.fqdn = socket.gethostname()
self.admin_conn = None
@@ -77,12 +83,44 @@ class Service(object):
self.dercert = None
def ldap_connect(self):
- if self.ldapi:
- if not self.realm:
- raise RuntimeError('realm must be set to use ldapi connection')
- self.admin_conn = self.__get_conn(None, None, ldapi=True, realm=self.realm)
- else:
- self.admin_conn = self.__get_conn(self.fqdn, self.dm_password)
+ # If DM password is provided, we use it
+ # If autobind was requested, attempt autobind when root and ldapi
+ # If autobind was disabled or not succeeded, go with GSSAPI
+ # LDAPI can be used with either autobind or GSSAPI
+ # LDAPI requires realm to be set
+ try:
+ if self.ldapi:
+ if not self.realm:
+ raise errors.NotFound(reason="realm is missing for %s" % (self))
+ conn = ipaldap.IPAdmin(ldapi=self.ldapi, realm=self.realm)
+ else:
+ conn = ipaldap.IPAdmin(self.fqdn, port=389)
+ if self.dm_password:
+ conn.do_simple_bind(bindpw=self.dm_password)
+ elif self.autobind in [AUTO, ENABLED]:
+ if os.getegid() == 0 and self.ldapi:
+ try:
+ # autobind
+ pw_name = pwd.getpwuid(os.geteuid()).pw_name
+ conn.do_external_bind(pw_name)
+ except errors.NotFound, e:
+ if self.autobind == AUTO:
+ # Fall back
+ conn.do_sasl_gssapi_bind()
+ else:
+ # autobind was required and failed, raise
+ # exception that it failed
+ raise e
+ else:
+ conn.do_sasl_gssapi_bind()
+ else:
+ conn.do_sasl_gssapi_bind()
+ except Exception, e:
+ root_logger.debug("Could not connect to the Directory Server on %s: %s" % (self.fqdn, str(e)))
+ raise e
+
+ self.admin_conn = conn
+
def ldap_disconnect(self):
self.admin_conn.unbind()
@@ -93,7 +131,6 @@ class Service(object):
pw_name = None
fd = None
path = ipautil.SHARE_DIR + ldif
- hostname = installutils.get_fqdn()
nologlist=[]
if sub_dict is not None:
@@ -107,15 +144,25 @@ class Service(object):
if sub_dict.has_key('RANDOM_PASSWORD'):
nologlist.append(sub_dict['RANDOM_PASSWORD'])
+ args = ["/usr/bin/ldapmodify", "-v", "-f", path]
+
+ # As we always connect to the local host,
+ # use URI of admin connection
+ if not self.admin_conn:
+ self.ldap_connect()
+ args += ["-H", self.admin_conn._uri]
+
+ auth_parms = []
if self.dm_password:
[pw_fd, pw_name] = tempfile.mkstemp()
os.write(pw_fd, self.dm_password)
os.close(pw_fd)
auth_parms = ["-x", "-D", "cn=Directory Manager", "-y", pw_name]
else:
- auth_parms = ["-Y", "GSSAPI"]
+ # always try GSSAPI auth when not using DM password or not being root
+ if os.getegid() != 0:
+ auth_parms = ["-Y", "GSSAPI"]
- args = ["/usr/bin/ldapmodify", "-h", hostname, "-v", "-f", path]
args += auth_parms
try:
@@ -181,8 +228,19 @@ class Service(object):
This server cert should be in DER format.
"""
- if not self.admin_conn:
- self.ldap_connect()
+ # add_cert_to_service() is relatively rare operation
+ # we actually call it twice during ipa-server-install, for different
+ # instances: ds and cs. Unfortunately, it may happen that admin
+ # connection was created well before add_cert_to_service() is called
+ # If there are other operations in between, it will become stale and
+ # since we are using SimpleLDAPObject, not ReconnectLDAPObject, the
+ # action will fail. Thus, explicitly disconnect and connect again.
+ # Using ReconnectLDAPObject instead of SimpleLDAPObject was considered
+ # but consequences for other parts of the framework are largely
+ # unknown.
+ if self.admin_conn:
+ self.ldap_disconnect()
+ self.ldap_connect()
dn = "krbprincipalname=%s,cn=services,cn=accounts,%s" % (self.principal, self.suffix)
mod = [(ldap.MOD_ADD, 'userCertificate', self.dercert)]
@@ -268,33 +326,6 @@ class Service(object):
self.steps = []
- def __get_conn(self, fqdn, dm_password, ldapi=False, realm=None):
- # If we are passed a password we'll use it as the DM password
- # otherwise we'll do a GSSAPI bind.
- try:
-# conn = ipaldap.IPAdmin(fqdn, port=636, cacert=CACERT)
- if ldapi:
- conn = ipaldap.IPAdmin(ldapi=ldapi, realm=realm)
- else:
- conn = ipaldap.IPAdmin(fqdn, port=389)
- if dm_password:
- conn.do_simple_bind(bindpw=dm_password)
- elif os.getegid() == 0 and self.ldapi:
- try:
- # autobind
- pw_name = pwd.getpwuid(os.geteuid()).pw_name
- conn.do_external_bind(pw_name)
- except errors.NotFound:
- # Fall back
- conn.do_sasl_gssapi_bind()
- else:
- conn.do_sasl_gssapi_bind()
- except Exception, e:
- root_logger.debug("Could not connect to the Directory Server on %s: %s" % (fqdn, str(e)))
- raise e
-
- return conn
-
def ldap_enable(self, name, fqdn, dm_password, ldap_suffix):
self.disable()
if not self.admin_conn:
@@ -318,11 +349,14 @@ class Service(object):
raise e
class SimpleServiceInstance(Service):
- def create_instance(self, gensvc_name=None, fqdn=None, dm_password=None, ldap_suffix=None):
+ def create_instance(self, gensvc_name=None, fqdn=None, dm_password=None, ldap_suffix=None, realm=None):
self.gensvc_name = gensvc_name
self.fqdn = fqdn
self.dm_password = dm_password
self.suffix = ldap_suffix
+ self.realm = realm
+ if not realm:
+ self.ldapi = False
self.step("starting %s " % self.service_name, self.__start)
self.step("configuring %s to start on boot" % self.service_name, self.__enable)
--
1.7.11.2

View File

@ -0,0 +1,86 @@
From 7a2587e6a15b59b857ab973490b2f6eb9fc9ebe0 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvoborni@redhat.com>
Date: Fri, 27 Jul 2012 16:31:58 +0200
Subject: [PATCH 56/79] Fixed: Unable to select option in combobox in IE and
Chrome
There's probably a bug regarding z-index stacking in Chrome and IE. It appears when combobox is used in dialog. Combobox's select area had z-index=1010. When first jquery dialogs is open it has z-index=1000. Further dialogs have higher z-index. When dialog's z-index exceeds 1010 option in select control can't be selected. IMO it is a browser bug because select control lies in dialog content's stacking context so it should be functional even with z-index=1.
This patch raises select area's z-index to 9000000 which should prevent the issue for some time. Also it make's combobox's z-index configurable so we can solve combobox stacking (ie in service-add dialog).
Second part of:
https://fedorahosted.org/freeipa/ticket/2834
---
install/ui/ipa.css | 1 -
install/ui/widget.js | 14 ++++++++------
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/install/ui/ipa.css b/install/ui/ipa.css
index 4f9d35c1d2a5e458903793423c6fad4de657554e..e5395b4a0cdeadec539aa1f18306b666dfca807d 100644
--- a/install/ui/ipa.css
+++ b/install/ui/ipa.css
@@ -1343,7 +1343,6 @@ table.scrollable tbody {
position: absolute;
left: 0;
right: 0;
- z-index: 1010; /* need to be above dialog box */
}
.combobox-widget-list input {
diff --git a/install/ui/widget.js b/install/ui/widget.js
index 41767118e78dce3f2ff4c30bdcf8368e0d1e976a..8f9d8b075fbbcf640cc5f0cf43e6ba1ce6e1989e 100644
--- a/install/ui/widget.js
+++ b/install/ui/widget.js
@@ -2093,6 +2093,7 @@ IPA.combobox_widget = function(spec) {
that.empty_option = spec.empty_option === undefined ? true : spec.empty_option;
that.options = spec.options || [];
that.input_field_changed = IPA.observer();
+ that.z_index = spec.z_index ? spec.z_index + 9000000 : 9000000;
that.create = function(container) {
that.widget_create(container);
@@ -2151,7 +2152,8 @@ IPA.combobox_widget = function(spec) {
}).appendTo(that.input_container);
that.list_container = $('<div/>', {
- 'class': 'combobox-widget-list'
+ 'class': 'combobox-widget-list',
+ css: { 'z-index': that.z_index }
}).appendTo(that.input_container);
var div = $('<div/>', {
@@ -2187,7 +2189,8 @@ IPA.combobox_widget = function(spec) {
name: 'list',
size: that.size,
style: 'width: 100%',
- change: that.select_on_change
+ change: that.select_on_change,
+ click: that.select_on_change
}).appendTo(div);
if (that.undo) {
@@ -2201,7 +2204,7 @@ IPA.combobox_widget = function(spec) {
if (!that.is_open()) return;
- var value = $('option:selected', that.list).val();
+ var value = that.list.val();
that.input.val(value);
IPA.select_range(that.input, 0, 0);
@@ -2327,10 +2330,9 @@ IPA.combobox_widget = function(spec) {
};
that.create_option = function(label, value) {
- return $('<option/>', {
+ var option = $('<option/>', {
text: label,
- value: value,
- click:that.select_on_change
+ value: value
}).appendTo(that.list);
};
--
1.7.11.2

View File

@ -0,0 +1,40 @@
From fd31396d5129b1980d3ce979af7239f16d3f6fc5 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvoborni@redhat.com>
Date: Fri, 27 Jul 2012 17:12:25 +0200
Subject: [PATCH 57/79] Fixed: combobox stacking in service adder dialog
First select's content is displayed under second comboxes content when select is opened when second combobox is opened
Bonus for:
https://fedorahosted.org/freeipa/ticket/2834
---
install/ui/service.js | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/install/ui/service.js b/install/ui/service.js
index 413d2ee8841991dc60fc1fef85e7fddcd854c86e..feb5ade87cbefcf2a6a09d650baa512f8ac9b118 100644
--- a/install/ui/service.js
+++ b/install/ui/service.js
@@ -139,7 +139,8 @@ IPA.service.entity = function(spec) {
],
editable: true,
size: 10,
- required: true
+ required: true,
+ z_index: 2
},
{
type: 'entity_select',
@@ -147,7 +148,8 @@ IPA.service.entity = function(spec) {
other_entity: 'host',
other_field: 'fqdn',
label: IPA.messages.objects.service.host,
- required: true
+ required: true,
+ z_index: 1
},
{
type: 'checkbox',
--
1.7.11.2

View File

@ -0,0 +1,355 @@
From fb817d340139822d17414da93853be5bc3bf6086 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Wed, 1 Aug 2012 16:14:11 +0200
Subject: [PATCH 58/79] Add per-service option to store the types of PAC it
supports
Create a per-service default as well.
https://fedorahosted.org/freeipa/ticket/2184
---
API.txt | 12 ++++++++----
install/share/60basev2.ldif | 5 ++++-
install/share/60basev3.ldif | 1 +
install/updates/10-60basev3.update | 2 ++
install/updates/10-selinuxusermap.update | 5 +++++
install/updates/60-trusts.update | 4 ++++
ipalib/plugins/config.py | 9 ++++++++-
ipalib/plugins/service.py | 23 ++++++++++++++++++-----
tests/test_xmlrpc/test_host_plugin.py | 1 +
tests/test_xmlrpc/test_service_plugin.py | 13 +++++++++++++
10 files changed, 64 insertions(+), 11 deletions(-)
diff --git a/API.txt b/API.txt
index 691a9c4dec69f1006e52eafd3a94e351750165b7..e71b79a799837cde2c1e4a5a83c20c8e23fd650f 100644
--- a/API.txt
+++ b/API.txt
@@ -445,7 +445,7 @@ args: 1,0,1
arg: Str('request_id')
output: Output('result', None, None)
command: config_mod
-args: 0,23,3
+args: 0,24,3
option: Int('ipamaxusernamelength', attribute=True, autofill=False, cli_name='maxusername', minvalue=1, multivalue=False, required=False)
option: IA5Str('ipahomesrootdir', attribute=True, autofill=False, cli_name='homedirectory', multivalue=False, required=False)
option: Str('ipadefaultloginshell', attribute=True, autofill=False, cli_name='defaultshell', multivalue=False, required=False)
@@ -462,6 +462,7 @@ option: Int('ipapwdexpadvnotify', attribute=True, autofill=False, cli_name='pwde
option: StrEnum('ipaconfigstring', attribute=True, autofill=False, cli_name='ipaconfigstring', csv=True, multivalue=True, required=False, values=(u'AllowLMhash', u'AllowNThash', u'KDC:Disable Last Success', u'KDC:Disable Lockout'))
option: Str('ipaselinuxusermaporder', attribute=True, autofill=False, cli_name='ipaselinuxusermaporder', multivalue=False, required=False)
option: Str('ipaselinuxusermapdefault', attribute=True, autofill=False, cli_name='ipaselinuxusermapdefault', multivalue=False, required=False)
+option: StrEnum('ipakrbauthzdata', attribute=True, autofill=False, cli_name='pac_type', csv=True, multivalue=True, required=False, values=(u'MS-PAC', u'PAD'))
option: Str('setattr*', cli_name='setattr', exclude='webui')
option: Str('addattr*', cli_name='addattr', exclude='webui')
option: Str('delattr*', cli_name='delattr', exclude='webui')
@@ -2726,9 +2727,10 @@ output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
output: Output('value', <type 'unicode'>, None)
command: service_add
-args: 1,5,3
+args: 1,6,3
arg: Str('krbprincipalname', attribute=True, cli_name='principal', multivalue=False, primary_key=True, required=True)
option: Bytes('usercertificate', attribute=True, cli_name='certificate', multivalue=False, required=False)
+option: StrEnum('ipakrbauthzdata', attribute=True, cli_name='pac_type', csv=True, multivalue=True, required=False, values=(u'MS-PAC', u'PAD'))
option: Flag('force', autofill=True, default=False)
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
@@ -2760,9 +2762,10 @@ output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: Output('result', <type 'bool'>, None)
output: Output('value', <type 'unicode'>, None)
command: service_find
-args: 1,9,4
+args: 1,10,4
arg: Str('criteria?', noextrawhitespace=False)
option: Str('krbprincipalname', attribute=True, autofill=False, cli_name='principal', multivalue=False, primary_key=True, query=True, required=False)
+option: StrEnum('ipakrbauthzdata', attribute=True, autofill=False, cli_name='pac_type', csv=True, multivalue=True, query=True, required=False, values=(u'MS-PAC', u'PAD'))
option: Int('timelimit?', autofill=False, minvalue=0)
option: Int('sizelimit?', autofill=False, minvalue=0)
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
@@ -2776,9 +2779,10 @@ output: ListOfEntries('result', (<type 'list'>, <type 'tuple'>), Gettext('A list
output: Output('count', <type 'int'>, None)
output: Output('truncated', <type 'bool'>, None)
command: service_mod
-args: 1,8,3
+args: 1,9,3
arg: Str('krbprincipalname', attribute=True, cli_name='principal', multivalue=False, primary_key=True, query=True, required=True)
option: Bytes('usercertificate', attribute=True, autofill=False, cli_name='certificate', multivalue=False, required=False)
+option: StrEnum('ipakrbauthzdata', attribute=True, autofill=False, cli_name='pac_type', csv=True, multivalue=True, required=False, values=(u'MS-PAC', u'PAD'))
option: Str('setattr*', cli_name='setattr', exclude='webui')
option: Str('addattr*', cli_name='addattr', exclude='webui')
option: Str('delattr*', cli_name='delattr', exclude='webui')
diff --git a/install/share/60basev2.ldif b/install/share/60basev2.ldif
index a299904e958b28d78fe0de912747bb6eb9b4554f..3b05e370147f6cace12913e695e02eb6550c6010 100644
--- a/install/share/60basev2.ldif
+++ b/install/share/60basev2.ldif
@@ -10,11 +10,14 @@ attributeTypes: (2.16.840.1.113730.3.8.3.3 NAME 'enrolledBy' DESC 'DN of adminis
attributeTypes: (2.16.840.1.113730.3.8.3.4 NAME 'fqdn' DESC 'FQDN' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )
attributeTypes: (2.16.840.1.113730.3.8.3.18 NAME 'managedBy' DESC 'DNs of entries allowed to manage' SUP distinguishedName X-ORIGIN 'IPA v2')
attributeTypes: (2.16.840.1.113730.3.8.3.24 NAME 'ipaEntitlementId' DESC 'Entitlement Unique identifier' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )
+# ipaKrbAuthzData added here. Even though it is a v3 attribute it is updating
+# a v2 objectClass so needs to be here.
+attributeTypes: (2.16.840.1.113730.3.8.11.37 NAME 'ipaKrbAuthzData' DESC 'type of PAC preferred by a service' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v3' )
objectClasses: (2.16.840.1.113730.3.8.4.1 NAME 'ipaHost' AUXILIARY MUST ( fqdn ) MAY ( userPassword $ ipaClientVersion $ enrolledBy $ memberOf) X-ORIGIN 'IPA v2' )
objectClasses: (2.16.840.1.113730.3.8.4.12 NAME 'ipaObject' DESC 'IPA objectclass' AUXILIARY MUST ( ipaUniqueId ) X-ORIGIN 'IPA v2' )
objectClasses: (2.16.840.1.113730.3.8.4.14 NAME 'ipaEntitlement' DESC 'IPA Entitlement object' AUXILIARY MUST ( ipaEntitlementId ) MAY ( userPKCS12 $ userCertificate ) X-ORIGIN 'IPA v2' )
objectClasses: (2.16.840.1.113730.3.8.4.15 NAME 'ipaPermission' DESC 'IPA Permission objectclass' AUXILIARY MAY ( ipaPermissionType ) X-ORIGIN 'IPA v2' )
-objectClasses: (2.16.840.1.113730.3.8.4.2 NAME 'ipaService' DESC 'IPA service objectclass' AUXILIARY MAY ( memberOf $ managedBy ) X-ORIGIN 'IPA v2' )
+objectClasses: (2.16.840.1.113730.3.8.4.2 NAME 'ipaService' DESC 'IPA service objectclass' AUXILIARY MAY ( memberOf $ managedBy $ ipaKrbAuthzData) X-ORIGIN 'IPA v2' )
objectClasses: (2.16.840.1.113730.3.8.4.3 NAME 'nestedGroup' DESC 'Group that supports nesting' SUP groupOfNames STRUCTURAL MAY memberOf X-ORIGIN 'IPA v2' )
objectClasses: (2.16.840.1.113730.3.8.4.4 NAME 'ipaUserGroup' DESC 'IPA user group object class' SUP nestedGroup STRUCTURAL X-ORIGIN 'IPA v2' )
objectClasses: (2.16.840.1.113730.3.8.4.5 NAME 'ipaHostGroup' DESC 'IPA host group object class' SUP nestedGroup STRUCTURAL X-ORIGIN 'IPA v2' )
diff --git a/install/share/60basev3.ldif b/install/share/60basev3.ldif
index 03561d13f45768006eb22e3dc00f41f35944dc56..18b23a3d2d00d03424df1c1cd4a5e9ddeba0f6d4 100644
--- a/install/share/60basev3.ldif
+++ b/install/share/60basev3.ldif
@@ -33,6 +33,7 @@ attributeTypes: (2.16.840.1.113730.3.8.11.33 NAME 'ipaBaseID' DESC 'First value
attributeTypes: (2.16.840.1.113730.3.8.11.34 NAME 'ipaIDRangeSize' DESC 'Size of a Posix ID range' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA v3' )
attributeTypes: (2.16.840.1.113730.3.8.11.35 NAME 'ipaBaseRID' DESC 'First value of a RID range' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA v3' )
attributeTypes: (2.16.840.1.113730.3.8.11.36 NAME 'ipaSecondaryBaseRID' DESC 'First value of a secondary RID range' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA v3' )
+# 2.16.840.1.113730.3.8.11.37 ipaKrbAuthzData
objectClasses: (2.16.840.1.113730.3.8.12.1 NAME 'ipaExternalGroup' SUP top STRUCTURAL MUST ( cn ) MAY ( ipaExternalMember $ memberOf $ description $ owner) X-ORIGIN 'IPA v3' )
objectClasses: (2.16.840.1.113730.3.8.12.2 NAME 'ipaNTUserAttrs' SUP top AUXILIARY MUST ( ipaNTSecurityIdentifier ) MAY ( ipaNTHash $ ipaNTLogonScript $ ipaNTProfilePath $ ipaNTHomeDirectory $ ipaNTHomeDirectoryDrive ) X-ORIGIN 'IPA v3' )
objectClasses: (2.16.840.1.113730.3.8.12.3 NAME 'ipaNTGroupAttrs' SUP top AUXILIARY MUST ( ipaNTSecurityIdentifier ) X-ORIGIN 'IPA v3' )
diff --git a/install/updates/10-60basev3.update b/install/updates/10-60basev3.update
index 96d012c14d26133b07a503e78fa1e8b33d2a56d9..dbd68581e7321b3d544a918bc8154e6f2ecda946 100644
--- a/install/updates/10-60basev3.update
+++ b/install/updates/10-60basev3.update
@@ -5,4 +5,6 @@ add:attributeTypes: ( 2.16.840.1.113730.3.8.11.22 NAME 'ipaAllowedTarget' DESC '
add:objectClasses: (2.16.840.1.113730.3.8.12.6 NAME 'groupOfPrincipals' SUP top AUXILIARY MUST ( cn ) MAY ( memberPrincipal ) X-ORIGIN 'IPA v3' )
add:objectClasses: (2.16.840.1.113730.3.8.12.7 NAME 'ipaKrb5DelegationACL' SUP groupOfPrincipals STRUCTURAL MAY ( ipaAllowToImpersonate $$ ipaAllowedTarget ) X-ORIGIN 'IPA v3' )
add:attributeTypes: (2.16.840.1.113730.3.8.11.32 NAME 'ipaKrbPrincipalAlias' DESC 'IPA principal alias' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3')
+add:attributeTypes: (2.16.840.1.113730.3.8.11.37 NAME 'ipaKrbAuthzData' DESC 'type of PAC preferred by a service' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v3')
add:objectClasses: (2.16.840.1.113730.3.8.12.8 NAME 'ipaKrbPrincipal' SUP krbPrincipalAux AUXILIARY MUST ( krbPrincipalName $$ ipaKrbPrincipalAlias ) X-ORIGIN 'IPA v3' )
+replace:objectClasses: ( 2.16.840.1.113730.3.8.4.2 NAME 'ipaService' DESC 'IPA service objectclass' AUXILIARY MAY ( memberOf $$ managedBy ) X-ORIGIN 'IPA v2' )::( 2.16.840.1.113730.3.8.4.2 NAME 'ipaService' DESC 'IPA service objectclass' AUXILIARY MAY ( memberOf $$ managedBy $$ ipaKrbAuthzData) X-ORIGIN 'IPA v2' )
diff --git a/install/updates/10-selinuxusermap.update b/install/updates/10-selinuxusermap.update
index 431477adf87d2fd9aaf5ed288c8c9eaba7ca35f1..f9af01fadb219094ce4a748b417cd25635d1774e 100644
--- a/install/updates/10-selinuxusermap.update
+++ b/install/updates/10-selinuxusermap.update
@@ -21,6 +21,11 @@ add:attributeTypes:
X-ORIGIN 'IPA v3')
replace:objectClasses:( 2.16.840.1.113730.3.8.2.1 NAME 'ipaGuiConfig' AUXILIARY MAY ( ipaUserSearchFields $$ ipaGroupSearchFields $$ ipaSearchTimeLimit $$ ipaSearchRecordsLimit $$ ipaCustomFields $$ ipaHomesRootDir $$ ipaDefaultLoginShell $$ ipaDefaultPrimaryGroup $$ ipaMaxUsernameLength $$ ipaPwdExpAdvNotify $$ ipaUserObjectClasses $$ ipaGroupObjectClasses $$ ipaDefaultEmailDomain $$ ipaMigrationEnabled $$ ipaCertificateSubjectBase ) )::( 2.16.840.1.113730.3.8.2.1 NAME 'ipaGuiConfig' AUXILIARY MAY ( ipaUserSearchFields $$ ipaGroupSearchFields $$ ipaSearchTimeLimit $$ ipaSearchRecordsLimit $$ ipaCustomFields $$ ipaHomesRootDir $$ ipaDefaultLoginShell $$ ipaDefaultPrimaryGroup $$ ipaMaxUsernameLength $$ ipaPwdExpAdvNotify $$ ipaUserObjectClasses $$ ipaGroupObjectClasses $$ ipaDefaultEmailDomain $$ ipaMigrationEnabled $$ ipaCertificateSubjectBase $$ ipaSELinuxUserMapDefault $$ ipaSELinuxUserMapOrder) )
+# Add the default PAC service type relies on the new SELinux user map
+# values being there so add it here.
+dn: cn=schema
+replace:objectClasses:( 2.16.840.1.113730.3.8.2.1 NAME 'ipaGuiConfig' AUXILIARY MAY ( ipaUserSearchFields $$ ipaGroupSearchFields $$ ipaSearchTimeLimit $$ ipaSearchRecordsLimit $$ ipaCustomFields $$ ipaHomesRootDir $$ ipaDefaultLoginShell $$ ipaDefaultPrimaryGroup $$ ipaMaxUsernameLength $$ ipaPwdExpAdvNotify $$ ipaUserObjectClasses $$ ipaGroupObjectClasses $$ ipaDefaultEmailDomain $$ ipaMigrationEnabled $$ ipaCertificateSubjectBase $$ ipaSELinuxUserMapDefault $$ ipaSELinuxUserMapOrder ) )::( 2.16.840.1.113730.3.8.2.1 NAME 'ipaGuiConfig' AUXILIARY MAY ( ipaUserSearchFields $$ ipaGroupSearchFields $$ ipaSearchTimeLimit $$ ipaSearchRecordsLimit $$ ipaCustomFields $$ ipaHomesRootDir $$ ipaDefaultLoginShell $$ ipaDefaultPrimaryGroup $$ ipaMaxUsernameLength $$ ipaPwdExpAdvNotify $$ ipaUserObjectClasses $$ ipaGroupObjectClasses $$ ipaDefaultEmailDomain $$ ipaMigrationEnabled $$ ipaCertificateSubjectBase $$ ipaSELinuxUserMapDefault $$ ipaSELinuxUserMapOrder $$ ipaKrbAuthzData) )
+
# Add the SELinux User map schema
add:attributeTypes:
( 2.16.840.1.113730.3.8.11.30
diff --git a/install/updates/60-trusts.update b/install/updates/60-trusts.update
index 577bed27f449ced1160b5ee2aad5ae85ed2440fb..0e40ca4d16133f0c1e93300fc13a08dd5ba4ddf7 100644
--- a/install/updates/60-trusts.update
+++ b/install/updates/60-trusts.update
@@ -65,3 +65,7 @@ replace:aci:'(targetattr != "userPassword || krbPrincipalKey || sambaLMPassword
replace:aci:'(targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey || krbPrincipalName || krbCanonicalName || krbUPEnabled || krbTicketPolicyReference || krbPrincipalExpiration || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData || krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount || krbTicketFlags || ipaUniqueId || memberOf || serverHostName || enrolledBy")(version 3.0; acl "Admin can manage any entry"; allow (all) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)::(targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey || krbPrincipalName || krbCanonicalName || krbUPEnabled || krbTicketPolicyReference || krbPrincipalExpiration || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData || krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount || krbTicketFlags || ipaUniqueId || memberOf || serverHostName || enrolledBy || ipaNTHash")(version 3.0; acl "Admin can manage any entry"; allow (all) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)'
replace:aci:'(targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Admins can write passwords"; allow (add,delete,write) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)::(targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || ipaNTHash")(version 3.0; acl "Admins can write passwords"; allow (add,delete,write) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)'
replace: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";)::(targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || ipaNTHash")(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";)'
+
+# Add the default PAC type to configuration
+dn: cn=ipaConfig,cn=etc,$SUFFIX
+addifnew: ipaKrbAuthzData: MS-PAC
diff --git a/ipalib/plugins/config.py b/ipalib/plugins/config.py
index d632e2edf964919c4f99ee509b31e3bea7d373a3..9573bbb65dbaf8fb0b9c5c3bcc69b02c83db915b 100644
--- a/ipalib/plugins/config.py
+++ b/ipalib/plugins/config.py
@@ -90,7 +90,7 @@ class config(LDAPObject):
'ipasearchrecordslimit', 'ipausersearchfields', 'ipagroupsearchfields',
'ipamigrationenabled', 'ipacertificatesubjectbase',
'ipapwdexpadvnotify', 'ipaselinuxusermaporder',
- 'ipaselinuxusermapdefault', 'ipaconfigstring',
+ 'ipaselinuxusermapdefault', 'ipaconfigstring', 'ipakrbauthzdata',
]
label = _('Configuration')
@@ -189,6 +189,13 @@ class config(LDAPObject):
label=_('Default SELinux user'),
doc=_('Default SELinux user when no match is found in SELinux map rule'),
),
+ StrEnum('ipakrbauthzdata*',
+ cli_name='pac_type',
+ label=_('PAC type'),
+ doc=_('Default types of PAC for new services'),
+ values=(u'MS-PAC', u'PAD'),
+ csv=True,
+ ),
)
def get_dn(self, *keys, **kwargs):
diff --git a/ipalib/plugins/service.py b/ipalib/plugins/service.py
index 60035bf6d8d53a498c6565fef6d3097a85263d20..4f3051aa4d5ba6dfc1768190f3662180353a5006 100644
--- a/ipalib/plugins/service.py
+++ b/ipalib/plugins/service.py
@@ -23,7 +23,7 @@ import base64
import os
from ipalib import api, errors, util
-from ipalib import Str, Flag, Bytes
+from ipalib import Str, Flag, Bytes, StrEnum
from ipalib.plugins.baseldap import *
from ipalib import x509
from ipalib import _, ngettext
@@ -223,8 +223,9 @@ class service(LDAPObject):
'krbprincipal', 'krbprincipalaux', 'krbticketpolicyaux', 'ipaobject',
'ipaservice', 'pkiuser', 'ipakrbprincipal'
]
- search_attributes = ['krbprincipalname', 'managedby']
- default_attributes = ['krbprincipalname', 'usercertificate', 'managedby']
+ search_attributes = ['krbprincipalname', 'managedby', 'ipakrbauthzdata']
+ default_attributes = ['krbprincipalname', 'usercertificate', 'managedby',
+ 'ipakrbauthzdata',]
uuid_attribute = 'ipauniqueid'
attribute_members = {
'managedby': ['host'],
@@ -251,7 +252,14 @@ class service(LDAPObject):
label=_('Certificate'),
doc=_('Base-64 encoded server certificate'),
flags=['no_search',],
- )
+ ),
+ StrEnum('ipakrbauthzdata*',
+ cli_name='pac_type',
+ label=_('PAC type'),
+ doc=_('Types of PAC this service supports'),
+ values=(u'MS-PAC', u'PAD'),
+ csv=True,
+ ),
)
api.register(service)
@@ -291,7 +299,12 @@ class service_add(LDAPCreate):
# don't exist in DNS.
util.validate_host_dns(self.log, hostname)
if not 'managedby' in entry_attrs:
- entry_attrs['managedby'] = hostresult['dn']
+ entry_attrs['managedby'] = hostresult['dn']
+ if 'ipakrbauthzdata' not in entry_attrs:
+ config = ldap.get_ipa_config()[1]
+ default_pac_type = config.get('ipakrbauthzdata', [])
+ if default_pac_type:
+ entry_attrs['ipakrbauthzdata'] = default_pac_type
# Enforce ipaKrbPrincipalAlias to aid case-insensitive searches
# as krbPrincipalName/krbCanonicalName are case-sensitive in Kerberos
diff --git a/tests/test_xmlrpc/test_host_plugin.py b/tests/test_xmlrpc/test_host_plugin.py
index 019152586cf129e501875437f97cb358545bd9b7..03aa089a2739486f6033a9d1870d7567bfdf1f5a 100644
--- a/tests/test_xmlrpc/test_host_plugin.py
+++ b/tests/test_xmlrpc/test_host_plugin.py
@@ -615,6 +615,7 @@ class test_host(Declarative):
krbprincipalname=[service1],
objectclass=objectclasses.service,
managedby_host=[fqdn1],
+ ipakrbauthzdata=[u'MS-PAC'],
ipauniqueid=[fuzzy_uuid],
),
),
diff --git a/tests/test_xmlrpc/test_service_plugin.py b/tests/test_xmlrpc/test_service_plugin.py
index 5f089fbbb9099761a4552e0df83a3700b452d7df..28c6bb663429e2ca0336d9597d3d386c1c8d6da5 100644
--- a/tests/test_xmlrpc/test_service_plugin.py
+++ b/tests/test_xmlrpc/test_service_plugin.py
@@ -179,6 +179,7 @@ class test_service(Declarative):
krbprincipalname=[service1],
objectclass=objectclasses.service,
ipauniqueid=[fuzzy_uuid],
+ ipakrbauthzdata=[u'MS-PAC'],
managedby_host=[fqdn1],
),
),
@@ -207,6 +208,7 @@ class test_service(Declarative):
dn=lambda x: DN(x) == service1dn,
krbprincipalname=[service1],
has_keytab=False,
+ ipakrbauthzdata=[u'MS-PAC'],
managedby_host=[fqdn1],
),
),
@@ -226,6 +228,7 @@ class test_service(Declarative):
objectclass=objectclasses.service,
ipauniqueid=[fuzzy_uuid],
managedby_host=[fqdn1],
+ ipakrbauthzdata=[u'MS-PAC'],
has_keytab=False
),
),
@@ -244,6 +247,7 @@ class test_service(Declarative):
dn=lambda x: DN(x) == service1dn,
krbprincipalname=[service1],
managedby_host=[fqdn1],
+ ipakrbauthzdata=[u'MS-PAC'],
has_keytab=False,
),
],
@@ -265,6 +269,7 @@ class test_service(Declarative):
ipakrbprincipalalias=[service1],
objectclass=objectclasses.service,
ipauniqueid=[fuzzy_uuid],
+ ipakrbauthzdata=[u'MS-PAC'],
has_keytab=False,
managedby_host=[fqdn1],
),
@@ -282,6 +287,7 @@ class test_service(Declarative):
result=dict(
dn=lambda x: DN(x) == service1dn,
krbprincipalname=[service1],
+ ipakrbauthzdata=[u'MS-PAC'],
managedby_host=[fqdn1],
),
),
@@ -297,6 +303,7 @@ class test_service(Declarative):
result=dict(
dn=lambda x: DN(x) == service1dn,
krbprincipalname=[service1],
+ ipakrbauthzdata=[u'MS-PAC'],
managedby_host=[fqdn1],
),
),
@@ -312,6 +319,7 @@ class test_service(Declarative):
result=dict(
dn=lambda x: DN(x) == service1dn,
krbprincipalname=[service1],
+ ipakrbauthzdata=[u'MS-PAC'],
managedby_host=[fqdn1, fqdn2],
),
),
@@ -327,6 +335,7 @@ class test_service(Declarative):
result=dict(
dn=lambda x: DN(x) == service1dn,
krbprincipalname=[service1],
+ ipakrbauthzdata=[u'MS-PAC'],
managedby_host=[fqdn1],
),
),
@@ -342,6 +351,7 @@ class test_service(Declarative):
result=dict(
dn=lambda x: DN(x) == service1dn,
krbprincipalname=[service1],
+ ipakrbauthzdata=[u'MS-PAC'],
managedby_host=[fqdn1, fqdn3.lower()],
),
),
@@ -357,6 +367,7 @@ class test_service(Declarative):
result=dict(
dn=lambda x: DN(x) == service1dn,
krbprincipalname=[service1],
+ ipakrbauthzdata=[u'MS-PAC'],
managedby_host=[fqdn1],
),
),
@@ -381,6 +392,7 @@ class test_service(Declarative):
result=dict(
usercertificate=[base64.b64decode(servercert)],
krbprincipalname=[service1],
+ ipakrbauthzdata=[u'MS-PAC'],
managedby_host=[fqdn1],
valid_not_before=fuzzy_date,
valid_not_after=fuzzy_date,
@@ -408,6 +420,7 @@ class test_service(Declarative):
krbprincipalname=[service1],
has_keytab=False,
managedby_host=[fqdn1],
+ ipakrbauthzdata=[u'MS-PAC'],
# These values come from the servercert that is in this
# test case.
valid_not_before=fuzzy_date,
--
1.7.11.2

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,37 @@
From f805001242828380d3f71922b38882f48876b844 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvoborni@redhat.com>
Date: Tue, 24 Jul 2012 13:19:36 +0200
Subject: [PATCH 62/79] Fix for incorrect event handler definition
Clicks events should be better defined by jquery calls (usually addEventListener) not as elements attributes. Definition as element attribute causes problems after upgrade to jquery 1.7.2. Two occurances were removed.
https://fedorahosted.org/freeipa/ticket/2817
---
install/ui/widget.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/install/ui/widget.js b/install/ui/widget.js
index 8f9d8b075fbbcf640cc5f0cf43e6ba1ce6e1989e..80fc1da1d6f652b22b292ea9e5e80350592ced83 100644
--- a/install/ui/widget.js
+++ b/install/ui/widget.js
@@ -3212,7 +3212,7 @@ IPA.sshkey_widget = function(spec) {
href: '#show-certificate',
title: that.tooltip,
text: IPA.messages.objects.sshkeystore.show_set_key,
- onclick: function() {
+ click: function() {
that.open_edit_dialog();
return false;
}
@@ -3430,7 +3430,7 @@ IPA.action_panel = function(spec) {
href: '#',
text: action.label,
'class': classes.join(' '),
- onclick: function() {
+ click: function() {
that.action_clicked(action);
return false;
}
--
1.7.11.2

View File

@ -0,0 +1,204 @@
From 1c79e283b1a926e1e22d45f7a89785ef05dda0de Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvoborni@redhat.com>
Date: Tue, 24 Jul 2012 18:27:17 +0200
Subject: [PATCH 63/79] Removal of unnecessary overrides of jquery-ui styles
ipa.css had to be updated to work with updated jquery-ui. This patch removes several duplicate styles.
Following issues were fixed:
* dialogs titles in IE and Opera were black instead of green
* no black line in first navigation level in IE and Opera
* all browsers (FF, IE, Chrome, Opera) have the same style for buttons and headers
* dialogs has borders again (should we remove its shadow?)
Known issues:
* selected tab-1 in Chrome and Opera doesn't overlaps background line as in IE and FF. Not sure how to fix without breaking (there are border overlaps) the latter ones. I think it looks good enough.
* some buttons are missing padding. Will be fixed in next patch.
https://fedorahosted.org/freeipa/ticket/2817
---
install/ui/ipa.css | 83 +++++++++---------------------------------------------
1 file changed, 14 insertions(+), 69 deletions(-)
diff --git a/install/ui/ipa.css b/install/ui/ipa.css
index e5395b4a0cdeadec539aa1f18306b666dfca807d..6f6d862b03895646cacc58c6c0d93f34fce6aabc 100644
--- a/install/ui/ipa.css
+++ b/install/ui/ipa.css
@@ -123,10 +123,6 @@ body {
background-repeat: no-repeat;
}
-.ui-widget {
- font-size: 11px;
-}
-
.icon {
display: inline-block;
height: 16px;
@@ -286,8 +282,16 @@ div.tabs {
background: transparent;
}
+.tabs.ui-tabs, .tabs .ui-tabs {
+ padding: 0;
+}
+
/* ---- Tabs level 1 ---- */
+.tabs.ui-widget {
+ border: none;
+}
+
.tabs1 > .ui-tabs-nav {
background: transparent;
}
@@ -300,23 +304,22 @@ div.tabs {
padding: 33px 0 0;
margin: 0;
border: none;
- -moz-border-radius: 0;
- -webkit-border-radius: 0;
}
.tabs1 > .ui-tabs-nav li {
-moz-border-radius: 0 !important;
-webkit-border-radius: 0 !important;
+ border-radius: 0 !important;
+ border: 1px solid #A0A0A0;
+ background: none;
background-image: url(images/mainnav-tab-off.png);
margin: 0 0.4em 0 0;
- border-width: 0;
text-align: center;
vertical-align:baseline;
- border: 1px solid #A0A0A0;
}
.tabs1 > .ui-tabs-nav > li.ui-tabs-selected {
- padding: 0 0;
+ padding: 0;
background-image: url(images/mainnav-tab-on.png);
text-align: center;
}
@@ -362,6 +365,7 @@ span.main-nav-off > a:visited{
border: none;
-moz-border-radius: 0;
-webkit-border-radius: 0;
+ border-radius: 0;
background: transparent;
}
@@ -946,14 +950,6 @@ span.attrhint {
overflow-x: hidden;
}
-
-.ui-tabs {
- padding:0;
-}
-
-.ui-widget-content {
-}
-
a, .ui-widget-content a {
text-decoration: none;
color: #1d85d5;
@@ -961,13 +957,6 @@ a, .ui-widget-content a {
text-transform: none;
}
-.ui-widget-header {
- background: -moz-linear-gradient(center top , #225314, #1c400a) repeat scroll 0 0 transparent;
- background: -webkit-gradient(linear, left top, left bottom, from(#225314), to(#1c400a));
- border: 1px solid #319016;
- font-weight: bold;
-}
-
/* ---- Dialog ---- */
.ui-dialog {
@@ -976,39 +965,11 @@ a, .ui-widget-content a {
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.6);
}
-.ui-dialog .ui-dialog-titlebar-close span {
- background-color: transparent !important;
-}
.ui-dialog .ui-dialog-content {
word-wrap: break-word;
- /* this should go away once we can fix table scrolling */
- overflow: auto;
}
-.ui-dialog .ui-dialog-titlebar {
- padding: 0.5em 1em;
- position: relative;
-}
-
-.ui-dialog .ui-dialog-buttonpane button {
- cursor: pointer;
- margin: 0.5em 0.4em 0.5em 0;
- padding: 0.1em 0.2em;
-}
-
-.ui-dialog .ui-dialog-buttonpane {
- background-image: none;
- border-width: 1px 0 0;
- padding: 0.3em 1em 0.5em 0.4em;
- text-align: left;
-}
-
-/*
-.ui-dialog .ui-dialog-content {
- min-height: 26em !important;
-}
-*/
.dialog-message {
margin: 5px 5px 10px;
@@ -1021,22 +982,9 @@ a, .ui-widget-content a {
.ui-widget input, .ui-widget select,
.ui-widget textarea, .ui-widget button {
- font-family: "Liberation Sans", Arial, sans-serif;
- font-size: 11px;
margin-right: .1em;
}
-.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default, #content .ui-state-default {
- -moz-border-radius: .3em;
- -webkit-border-radius: .3em;
- background: -moz-linear-gradient(top, #959595, #5e5e5e);
- background: -webkit-gradient(linear, left top, left bottom, from(#959595), to(#5e5e5e));
- border: 1px solid #777777;
- color: #fff;
- font-weight: normal;
- padding: 0.4em 1em;
-}
-
span.sub-nav-off > a:link, span.sub-nav-off > a:visited{
color:white;
}
@@ -1150,10 +1098,6 @@ table.kerberos-key-status {
background-color: #daa520;
}
-.ui-widget-content {
- border:0;
-}
-
/* ---- Table ---- */
table.scrollable thead {
@@ -1711,6 +1655,7 @@ form#login {
margin-left: 10px;
}
+/* TODO: replace with button */
#content .facet-action-list div[name=apply] a.ui-state-default {
padding: 3px 5px 1px 5px;
}
--
1.7.11.2

View File

@ -0,0 +1,99 @@
From 17a6b3f29d20c46a279bc189d5d565a680354f63 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvoborni@redhat.com>
Date: Wed, 25 Jul 2012 12:32:39 +0200
Subject: [PATCH 64/79] Unified buttons
Buttons in association dialog and action list have different style and behavior than buttons in dialogs. This patch unifies it by using jquery.button widget.
https://fedorahosted.org/freeipa/ticket/2817
---
install/ui/ipa.css | 9 ++++-----
install/ui/widget.js | 31 ++++++++++++++++++++++++-------
2 files changed, 28 insertions(+), 12 deletions(-)
diff --git a/install/ui/ipa.css b/install/ui/ipa.css
index 6f6d862b03895646cacc58c6c0d93f34fce6aabc..ddbe71c1f13bafb6cdd381f871f6eaf6f28ea893 100644
--- a/install/ui/ipa.css
+++ b/install/ui/ipa.css
@@ -1238,6 +1238,10 @@ table.scrollable tbody {
width: 98%;
}
+.adder-dialog-buttons > div:first-child{
+ margin-bottom: 0.5em;
+}
+
/* ---- Widgets ---- */
.text-widget input {
@@ -1655,11 +1659,6 @@ form#login {
margin-left: 10px;
}
-/* TODO: replace with button */
- #content .facet-action-list div[name=apply] a.ui-state-default {
- padding: 3px 5px 1px 5px;
-}
-
.facet-action-list select {
font-size: 11px;
padding-left: 4px;
diff --git a/install/ui/widget.js b/install/ui/widget.js
index 80fc1da1d6f652b22b292ea9e5e80350592ced83..9e78c360b7debc2a4d4f7b49f83172a8c826799e 100644
--- a/install/ui/widget.js
+++ b/install/ui/widget.js
@@ -2455,12 +2455,6 @@ IPA.link_widget = function(spec) {
};
IPA.action_button = function(spec) {
- var button = IPA.button(spec);
- button.removeClass("ui-state-default").addClass("action-button");
- return button;
-};
-
-IPA.button = function(spec) {
spec = spec || {};
@@ -2469,7 +2463,7 @@ IPA.button = function(spec) {
name: spec.name,
href: spec.href || '#' + (spec.name || 'button'),
title: spec.title || spec.label,
- 'class': 'ui-state-default ui-corner-all button',
+ 'class': 'button action-button',
style: spec.style,
click: spec.click,
blur: spec.blur
@@ -2493,6 +2487,29 @@ IPA.button = function(spec) {
return button;
};
+IPA.button = function(spec) {
+
+ spec = spec || {};
+
+ var button = $('<a/>', {
+ id: spec.id,
+ name: spec.name,
+ href: spec.href || '#' + (spec.name || 'button')
+ });
+
+ var icons = { primary: spec.icon };
+ var label = spec.label;
+
+ button.button({
+ icons: icons,
+ label: label
+ });
+
+ button.click(spec.click);
+
+ return button;
+};
+
IPA.button_widget = function(spec) {
spec = spec || {};
--
1.7.11.2

View File

@ -0,0 +1,56 @@
From 8ce157910a86dc8abf16b4846cabe61052a6754d Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvoborni@redhat.com>
Date: Wed, 25 Jul 2012 13:06:42 +0200
Subject: [PATCH 65/79] Web UI tests fix
ACI tests were crashing because of misconfigured facet.
Entity link test were crashing because of incorrect jquery selector.
https://fedorahosted.org/freeipa/ticket/2817
---
install/ui/test/aci_tests.js | 5 +++--
install/ui/test/widget_tests.js | 2 +-
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/install/ui/test/aci_tests.js b/install/ui/test/aci_tests.js
index 4055120f22b59fcadd63228536d56836edb81f78..52fdc60376da67b2986456c663b7d883e98191f6 100644
--- a/install/ui/test/aci_tests.js
+++ b/install/ui/test/aci_tests.js
@@ -22,7 +22,7 @@
var target_container;
var target_widget;
var target_facet;
-var entity = IPA.entity({ name: 'bogus' });
+var entity = IPA.entity({ name: 'bogus', redirect_facet: 'details' });
var group_entity = IPA.entity({ name: 'group' });
module('aci', {
@@ -99,10 +99,11 @@ module('aci', {
IPA.permission_target_policy('target')
]
});
+ entity.add_facet('details', target_facet);
target_container = $('<div id="target"/>').appendTo(document.body);
+ target_facet.create(target_container);
target_widget = target_facet.widgets.get_widget('target');
- target_widget.create(target_container);
},
teardown: function() {
target_container.remove();
diff --git a/install/ui/test/widget_tests.js b/install/ui/test/widget_tests.js
index 489572c2c21077216f65dc47ac84919b85e71176..7ed93608ebbfef59986d81d1ff891c4e8abbc5a6 100644
--- a/install/ui/test/widget_tests.js
+++ b/install/ui/test/widget_tests.js
@@ -315,7 +315,7 @@ test("IPA.entity_link_widget" ,function(){
widget.is_link = true; //setting is_link is responsibility of field
widget.update(mock_record.gidnumber);
- link = widget_container.find('a[text=123456]');
+ link = widget_container.find('a:contains("123456")');
same(link.length, 1,'link is populated');
same(link.css('display'), 'inline','link is displayed');
--
1.7.11.2

View File

@ -0,0 +1,40 @@
From 1a94109f4ad5bcb304c4c23af868c3cf07ce92ec Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvoborni@redhat.com>
Date: Thu, 26 Jul 2012 10:13:00 +0200
Subject: [PATCH 66/79] Fixed incorrect use of jQuery.attr for setting
disabled attribute
Occurance: select_widget
Update to latest version of jQuery uncovered this issue.
https://fedorahosted.org/freeipa/ticket/2817
---
install/ui/widget.js | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/install/ui/widget.js b/install/ui/widget.js
index 9e78c360b7debc2a4d4f7b49f83172a8c826799e..ed7fcf76c3d5eca6c652c31b0053f60c52bddf27 100644
--- a/install/ui/widget.js
+++ b/install/ui/widget.js
@@ -928,15 +928,13 @@ IPA.select_widget = function(spec) {
that.set_options_enabled = function(enabled, options) {
- var html_value = enabled ? '' : 'disabled';
-
if (!options) {
- $('option', that.select).attr('disabled', html_value);
+ $('option', that.select).prop('disabled', !enabled);
} else {
for (var i=0; i<options.length;i++) {
var value = options[i];
var option = $('option[value="'+value+'"]', that.select);
- option.attr('disabled', html_value);
+ option.prop('disabled', !enabled);
}
}
};
--
1.7.11.2

View File

@ -0,0 +1,270 @@
From c2783b9b54ecae8299da0dc593c3813c2bd26fe2 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvoborni@redhat.com>
Date: Thu, 26 Jul 2012 11:17:28 +0200
Subject: [PATCH 67/79] Replace use of attr with prop for booleans
Recommened way of setting boolean HTML attributes is by $.prop(boolean) method not $.attr(boolean) because it sets DOM object property not an attribute. Latter works because of jquery's backward compatibility. This patch makes things clearer.
Some info about prop and attr: http://stackoverflow.com/a/5876747
https://fedorahosted.org/freeipa/ticket/2817
---
install/ui/aci.js | 2 +-
install/ui/association.js | 4 ++--
install/ui/dns.js | 8 ++++----
install/ui/hbactest.js | 12 ++++++------
install/ui/widget.js | 48 ++++++++++++++++++++---------------------------
5 files changed, 33 insertions(+), 41 deletions(-)
diff --git a/install/ui/aci.js b/install/ui/aci.js
index 63181efac5f335d28a4c23bfa1ae2da95b9a0e75..039e633234c0aa968dc6f2f81093507aa57f22f2 100644
--- a/install/ui/aci.js
+++ b/install/ui/aci.js
@@ -492,7 +492,7 @@ IPA.attributes_widget = function(spec) {
type: "checkbox",
click: function() {
$('.aci-attribute', that.table).
- attr('checked', $(this).attr('checked'));
+ prop('checked', $(this).prop('checked'));
that.value_changed.notify([], that);
}
})
diff --git a/install/ui/association.js b/install/ui/association.js
index 0594ea764e9b02742a983f127b865bc66bf7f3f3..be8b8459dded9b024e5d998311eab62c70e57756 100644
--- a/install/ui/association.js
+++ b/install/ui/association.js
@@ -1038,9 +1038,9 @@ IPA.association_facet = function (spec, no_init) {
that.refresh = function() {
if (that.association_type == 'direct') {
- if (that.direct_radio) that.direct_radio.attr('checked', true);
+ if (that.direct_radio) that.direct_radio.prop('checked', true);
} else {
- if (that.indirect_radio) that.indirect_radio.attr('checked', true);
+ if (that.indirect_radio) that.indirect_radio.prop('checked', true);
}
var pkey = that.entity.get_primary_key();
diff --git a/install/ui/dns.js b/install/ui/dns.js
index 1f4ba8ccdb98cda3e67d9d006139d42f99a3399e..cd8cb8e195eb60a72489773083dd90b9e0a947a8 100644
--- a/install/ui/dns.js
+++ b/install/ui/dns.js
@@ -512,8 +512,8 @@ IPA.add_dns_zone_name_policy = function() {
var name_from_ip_f = this.container.fields.get_field('name_from_ip');
idnsname_w.radio_clicked.attach(function() {
- idnsname_w.input.attr('disabled', false);
- name_from_ip_w.input.attr('disabled', true);
+ idnsname_w.input.prop('disabled', false);
+ name_from_ip_w.input.prop('disabled', true);
idnsname_f.set_required(true);
name_from_ip_f.set_required(false);
@@ -522,8 +522,8 @@ IPA.add_dns_zone_name_policy = function() {
});
name_from_ip_w.radio_clicked.attach(function() {
- idnsname_w.input.attr('disabled', true);
- name_from_ip_w.input.attr('disabled', false);
+ idnsname_w.input.prop('disabled', true);
+ name_from_ip_w.input.prop('disabled', false);
idnsname_f.set_required(false);
name_from_ip_f.set_required(true);
diff --git a/install/ui/hbactest.js b/install/ui/hbactest.js
index 373ff39b0c32424eeb2a6548074ec8ad008aa895..4b666ef29306d10cebc37014de444f1797f52103 100644
--- a/install/ui/hbactest.js
+++ b/install/ui/hbactest.js
@@ -279,7 +279,7 @@ IPA.hbac.test_select_facet = function(spec) {
that.table.set_values = function(values) {
if (values && values.length && values[0] === '__external__') {
- if (that.external_radio) that.external_radio.attr('checked', true);
+ if (that.external_radio) that.external_radio.prop('checked', true);
} else {
that.table.table_set_values(values);
}
@@ -393,7 +393,7 @@ IPA.hbac.test_select_facet = function(spec) {
that.reset = function() {
delete that.selected_values;
- if (that.external_radio) that.external_radio.attr('checked', false);
+ if (that.external_radio) that.external_radio.prop('checked', false);
if (that.external_text) that.external_text.val('');
};
@@ -482,8 +482,8 @@ IPA.hbac.test_rules_facet = function(spec) {
that.reset = function() {
delete that.selected_values;
- if (that.enabled) that.enabled.attr('checked', false);
- if (that.disabled) that.disabled.attr('checked', false);
+ if (that.enabled) that.enabled.prop('checked', false);
+ if (that.disabled) that.disabled.prop('checked', false);
};
that.save = function(record) {
@@ -655,8 +655,8 @@ IPA.hbac.test_run_facet = function(spec) {
delete that.data;
that.show_matched = true;
that.show_unmatched = true;
- if (that.matched_checkbox) that.matched_checkbox.attr('checked', true);
- if (that.unmatched_checkbox) that.unmatched_checkbox.attr('checked', true);
+ if (that.matched_checkbox) that.matched_checkbox.prop('checked', true);
+ if (that.unmatched_checkbox) that.unmatched_checkbox.prop('checked', true);
that.refresh();
};
diff --git a/install/ui/widget.js b/install/ui/widget.js
index ed7fcf76c3d5eca6c652c31b0053f60c52bddf27..9b15f2f1b236c1dd4dae027272664c7178218d97 100644
--- a/install/ui/widget.js
+++ b/install/ui/widget.js
@@ -297,11 +297,7 @@ IPA.text_widget = function(spec) {
that.set_enabled = function(value) {
- if(value) {
- that.input.removeAttr('disabled');
- } else {
- that.input.attr('disabled', 'disabled');
- }
+ that.input.prop('disabled', !value);
};
that.clear = function() {
@@ -669,11 +665,11 @@ IPA.checkbox_widget = function (spec) {
value = that.checked;
}
- that.input.attr('checked', value);
+ that.input.prop('checked', value);
};
that.clear = function() {
- that.input.attr('checked', false);
+ that.input.prop('checked', false);
};
that.checkbox_save = that.save;
@@ -741,18 +737,18 @@ IPA.checkboxes_widget = function (spec) {
that.update = function(values) {
var inputs = $('input[name="'+that.name+'"]', that.container);
- inputs.attr('checked', false);
+ inputs.prop('checked', false);
for (var j=0; values && j<values.length; j++) {
var value = values[j];
var input = $('input[name="'+that.name+'"][value="'+value+'"]', that.container);
if (!input.length) continue;
- input.attr('checked', true);
+ input.prop('checked', true);
}
};
that.clear = function() {
- $('input[name="'+that.name+'"]').attr('checked', false);
+ $('input[name="'+that.name+'"]').prop('checked', false);
};
that.add_option = function(option) {
@@ -829,21 +825,21 @@ IPA.radio_widget = function(spec) {
var value = values && values.length ? values[0] : '';
var input = $(that.selector+'[value="'+value+'"]', that.container);
if (input.length) {
- input.attr('checked', true);
+ input.prop('checked', true);
} else if (that.default_value) {
input = $(that.selector+'[value="'+that.default_value+'"]', that.container);
- input.attr('checked', true);
+ input.prop('checked', true);
}
that.value_changed.notify([that.save()], that);
};
that.clear = function() {
- $(that.selector, that.container).attr('checked', false);
+ $(that.selector, that.container).prop('checked', false);
if (that.default_value) {
var input = $(that.selector+'[value="'+that.default_value+'"]', that.container);
- input.attr('checked', true);
+ input.prop('checked', true);
}
};
@@ -915,7 +911,7 @@ IPA.select_widget = function(spec) {
var value = values[0];
var option = $('option[value="'+value+'"]', that.select);
if (!option.length) return;
- option.attr('selected', 'selected');
+ option.prop('selected', true);
};
that.empty = function() {
@@ -923,7 +919,7 @@ IPA.select_widget = function(spec) {
};
that.clear = function() {
- $('option', that.select).attr('selected', '');
+ $('option', that.select).prop('selected', false);
};
that.set_options_enabled = function(enabled, options) {
@@ -1521,24 +1517,24 @@ IPA.table_widget = function (spec) {
};
that.select_all = function() {
- $('input[name="'+that.name+'"]', that.thead).attr('checked', true).
+ $('input[name="'+that.name+'"]', that.thead).prop('checked', true).
attr('title', IPA.messages.search.unselect_all);
- $('input[name="'+that.name+'"]', that.tbody).attr('checked', true);
+ $('input[name="'+that.name+'"]', that.tbody).prop('checked', true);
that.select_changed();
};
that.unselect_all = function() {
- $('input[name="'+that.name+'"]', that.thead).attr('checked', false).
+ $('input[name="'+that.name+'"]', that.thead).prop('checked', false).
attr('title', IPA.messages.search.select_all);
- $('input[name="'+that.name+'"]', that.tbody).attr('checked', false);
+ $('input[name="'+that.name+'"]', that.tbody).prop('checked', false);
that.select_changed();
};
that.set_values = function(values) {
- $('input[name="'+that.name+'"]', that.tbody).attr('checked', false);
+ $('input[name="'+that.name+'"]', that.tbody).prop('checked', false);
for (var i=0; values && i<values.length; i++) {
var value = values[i];
- $('input[name="'+that.name+'"][value="'+value+'"]', that.tbody).attr('checked', true);
+ $('input[name="'+that.name+'"][value="'+value+'"]', that.tbody).prop('checked', true);
}
that.select_changed();
};
@@ -1697,11 +1693,7 @@ IPA.table_widget = function (spec) {
};
that.set_enabled = function(enabled) {
- if (enabled) {
- $('input[name="'+that.name+'"]', that.table).attr('disabled', false);
- } else {
- $('input[name="'+that.name+'"]', that.table).attr('disabled', true);
- }
+ $('input[name="'+that.name+'"]', that.table).prop('disabled', !enabled);
};
that.clear = function() {
@@ -2316,7 +2308,7 @@ IPA.combobox_widget = function(spec) {
// if no option found, skip
if (!option.length) return;
- option.attr('selected', 'selected');
+ option.prop('selected', true);
that.set_value(option.val());
that.value_changed.notify([], that);
--
1.7.11.2

View File

@ -0,0 +1,68 @@
From 79a427277a12925bca3f170cc7a255a2a9e45a10 Mon Sep 17 00:00:00 2001
From: Martin Kosek <mkosek@redhat.com>
Date: Tue, 31 Jul 2012 14:11:52 +0200
Subject: [PATCH 68/79] Avoid redundant info message during RPM update
A change to ipa-ldap-updater (and thus an RPM update %post scriptlet)
avoiding redundat "IPA is not configured" message in stderr introdocued
in c20d4c71b87365b3b8d9c53418a79f992e68cd00 was reverted in another
patch (b5c1ce88a4a3b35adb3b22bc68fb10b49322641a).
Return the change back to avoid this message during every RPM update
when IPA is not configured. admintool framework was also fixed to
avoid print an empty line when an exception without an error message
is raised.
https://fedorahosted.org/freeipa/ticket/2892
---
ipapython/admintool.py | 3 ++-
ipaserver/install/ipa_ldap_updater.py | 11 ++++++++---
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/ipapython/admintool.py b/ipapython/admintool.py
index 60096e083ef209e943886cbe33189e5cdf063787..1ba8b6bbbe478e4b462510337e157524967e7194 100644
--- a/ipapython/admintool.py
+++ b/ipapython/admintool.py
@@ -212,7 +212,8 @@ class AdminTool(object):
self.log
except AttributeError:
# Logging was not set up yet
- print >> sys.stderr, '\n', error_message
+ if error_message:
+ print >> sys.stderr, '\n', error_message
else:
self.info(''.join(traceback.format_tb(backtrace)))
self.info('The %s command failed, exception: %s: %s',
diff --git a/ipaserver/install/ipa_ldap_updater.py b/ipaserver/install/ipa_ldap_updater.py
index 0c7d940be9b0d9777b7739dc5b63a0fe79b534b9..794ea28b5518b3d7b02d9aa0f691361adecae67d 100644
--- a/ipaserver/install/ipa_ldap_updater.py
+++ b/ipaserver/install/ipa_ldap_updater.py
@@ -25,6 +25,7 @@
# save undo files?
import os
+import sys
import krbV
@@ -83,10 +84,14 @@ class LDAPUpdater(admintool.AdminTool):
raise admintool.ScriptError("%s: file not found" % filename)
if os.getegid() == 0:
- installutils.check_server_configuration()
+ try:
+ installutils.check_server_configuration()
+ except RuntimeError, e:
+ print unicode(e)
+ sys.exit(1)
elif not os.path.exists('/etc/ipa/default.conf'):
- raise admintool.ScriptError(
- "IPA is not configured on this system.")
+ print "IPA is not configured on this system."
+ sys.exit(1)
if options.password:
pw = ipautil.template_file(options.password, [])
--
1.7.11.2

View File

@ -0,0 +1,45 @@
From 8c7556db8339cf64f1c80e4ffec30ac3646f177e Mon Sep 17 00:00:00 2001
From: Martin Kosek <mkosek@redhat.com>
Date: Thu, 2 Aug 2012 16:25:15 +0200
Subject: [PATCH 69/79] Bump bind-dyndb-ldap version for F18
bind-dyndb-ldap with SOA serial autoincrement was released. Bump
the package version in the spec file. The version is bumped for
F18 only as it was released only to rawhide and we don't want to
break development on F17.
https://fedorahosted.org/freeipa/ticket/2554
---
freeipa.spec.in | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/freeipa.spec.in b/freeipa.spec.in
index 6b24a0b0dc5f4e38ec0adab74fbbbeb20f25bb8a..84aaa0dfe5d553ab2fa57779ac019529a3953cc4 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -175,7 +175,11 @@ Requires: keyutils
# We have a soft-requires on bind. It is an optional part of
# IPA but if it is configured we need a way to require versions
# that work for us.
+%if 0%{?fedora} >= 18
+Conflicts: bind-dyndb-ldap < 1.1.0-0.15.rc1
+%else
Conflicts: bind-dyndb-ldap < 1.1.0-0.12.rc1
+%endif
Conflicts: bind < 9.8.2-0.4.rc2
# mod_proxy provides a single API to communicate over SSL. If mod_ssl
@@ -747,6 +751,10 @@ fi
%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/ca.crt
%changelog
+* Thu Aug 2 2012 Martin Kosek <mkosek@redhat.com> - 2.99.0-40
+- Set min for bind-dyndb-ldap to 1.1.0-0.15.rc1 to pick up SOA serial autoincrement
+ feature
+
* Tue Jul 24 2012 Rob Crittenden <rcritten@redhat.com> - 2.99.0-39
- Set minimum certmonger to 0.58 for dogtag cert renewal
--
1.7.11.2

View File

@ -0,0 +1,164 @@
From 560b9416f608ec5106b52fa56db3962b3542812c Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce@redhat.com>
Date: Mon, 9 Jul 2012 09:15:51 -0400
Subject: [PATCH 70/79] Move mspac structure to be a private pointer
By keeping it's definition in the mspac file it is easier to modify and make
sure any opertion on it is handled in the same file.
---
daemons/ipa-kdb/ipa_kdb.h | 9 ++------
daemons/ipa-kdb/ipa_kdb_mspac.c | 49 ++++++++++++++++++++++++++---------------
2 files changed, 33 insertions(+), 25 deletions(-)
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
index c1cc7a7d8ecdf86b10606233078abbb8685f6750..0a179dbcf0e9c17c0eb468638cd7436dc60d31a5 100644
--- a/daemons/ipa-kdb/ipa_kdb.h
+++ b/daemons/ipa-kdb/ipa_kdb.h
@@ -74,12 +74,7 @@
#define IPA_SETUP "ipa-setup-override-restrictions"
-struct ipadb_wincompat {
- char *flat_domain_name;
- char *flat_server_name;
- char *fallback_group;
- uint32_t fallback_rid;
-};
+struct ipadb_mspac;
struct ipadb_context {
char *uri;
@@ -91,7 +86,7 @@ struct ipadb_context {
bool override_restrictions;
krb5_key_salt_tuple *supp_encs;
int n_supp_encs;
- struct ipadb_wincompat wc;
+ struct ipadb_mspac *mspac;
bool disable_last_success;
bool disable_lockout;
};
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
index 1c7487c3c8f75d02466a2e0746fbef5d36e3d995..44cf522a00e4973077d716a9545f69f325e870ba 100644
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
@@ -26,6 +26,13 @@
#include "util/time.h"
#include "gen_ndr/ndr_krb5pac.h"
+struct ipadb_mspac {
+ char *flat_domain_name;
+ char *flat_server_name;
+ char *fallback_group;
+ uint32_t fallback_rid;
+};
+
int krb5_klog_syslog(int, const char *, ...);
@@ -460,8 +467,8 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
}
if (info3->base.primary_gid == 0) {
- if (ipactx->wc.fallback_rid) {
- info3->base.primary_gid = ipactx->wc.fallback_rid;
+ if (ipactx->mspac->fallback_rid) {
+ info3->base.primary_gid = ipactx->mspac->fallback_rid;
} else {
/* can't give a pack without a primary group rid */
return ENOENT;
@@ -474,9 +481,9 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
/* always zero out, not used for Krb, only NTLM */
memset(&info3->base.key, '\0', sizeof(info3->base.key));
- if (ipactx->wc.flat_server_name) {
+ if (ipactx->mspac->flat_server_name) {
info3->base.logon_server.string =
- talloc_strdup(memctx, ipactx->wc.flat_server_name);
+ talloc_strdup(memctx, ipactx->mspac->flat_server_name);
if (!info3->base.logon_server.string) {
return ENOMEM;
}
@@ -485,9 +492,9 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
return ENOENT;
}
- if (ipactx->wc.flat_domain_name) {
+ if (ipactx->mspac->flat_domain_name) {
info3->base.logon_domain.string =
- talloc_strdup(memctx, ipactx->wc.flat_domain_name);
+ talloc_strdup(memctx, ipactx->mspac->flat_domain_name);
if (!info3->base.logon_domain.string) {
return ENOMEM;
}
@@ -1318,11 +1325,17 @@ krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx)
int ret;
/* clean up in case we had old values around */
- free(ipactx->wc.flat_domain_name);
- ipactx->wc.flat_domain_name = NULL;
- free(ipactx->wc.fallback_group);
- ipactx->wc.fallback_group = NULL;
- ipactx->wc.fallback_rid = 0;
+ if (ipactx->mspac) {
+ free(ipactx->mspac->flat_domain_name);
+ free(ipactx->mspac->fallback_group);
+ free(ipactx->mspac);
+ }
+
+ ipactx->mspac = calloc(1, sizeof(struct ipadb_mspac));
+ if (!ipactx->mspac) {
+ kerr = ENOMEM;
+ goto done;
+ }
kerr = ipadb_simple_search(ipactx, ipactx->base, LDAP_SCOPE_SUBTREE,
"(objectclass=ipaNTDomainAttrs)", dom_attrs,
@@ -1341,22 +1354,22 @@ krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx)
ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
"ipaNTFlatName",
- &ipactx->wc.flat_domain_name);
+ &ipactx->mspac->flat_domain_name);
if (ret) {
kerr = ret;
goto done;
}
- free(ipactx->wc.flat_server_name);
- ipactx->wc.flat_server_name = get_server_netbios_name();
- if (!ipactx->wc.flat_server_name) {
+ free(ipactx->mspac->flat_server_name);
+ ipactx->mspac->flat_server_name = get_server_netbios_name();
+ if (!ipactx->mspac->flat_server_name) {
kerr = ENOMEM;
goto done;
}
ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
"ipaNTFallbackPrimaryGroup",
- &ipactx->wc.fallback_group);
+ &ipactx->mspac->fallback_group);
if (ret && ret != ENOENT) {
kerr = ret;
goto done;
@@ -1368,7 +1381,7 @@ krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx)
lentry = NULL;
if (ret != ENOENT) {
- kerr = ipadb_simple_search(ipactx, ipactx->wc.fallback_group,
+ kerr = ipadb_simple_search(ipactx, ipactx->mspac->fallback_group,
LDAP_SCOPE_BASE,
"(objectclass=posixGroup)",
grp_attrs, &result);
@@ -1397,7 +1410,7 @@ krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx)
kerr = ret;
goto done;
}
- ret = sid_split_rid(&gsid, &ipactx->wc.fallback_rid);
+ ret = sid_split_rid(&gsid, &ipactx->mspac->fallback_rid);
if (ret) {
kerr = ret;
goto done;
--
1.7.11.2

View File

@ -0,0 +1,160 @@
From 4baf6ad21ccc8ef26d494b74e074758d38222eb6 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce@redhat.com>
Date: Tue, 10 Jul 2012 10:50:14 -0400
Subject: [PATCH 71/79] Load list of trusted domain on connecting to ldap
This list is used to validate data in mspac filtering
---
daemons/ipa-kdb/ipa_kdb_mspac.c | 110 +++++++++++++++++++++++++++++++++++++---
1 file changed, 104 insertions(+), 6 deletions(-)
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
index 44cf522a00e4973077d716a9545f69f325e870ba..2ed093d30a0fea20ef620b8df9858ec4802d1191 100644
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
@@ -26,11 +26,20 @@
#include "util/time.h"
#include "gen_ndr/ndr_krb5pac.h"
+struct ipadb_adtrusts {
+ char *domain_name;
+ char *flat_name;
+ char *domain_sid;
+};
+
struct ipadb_mspac {
char *flat_domain_name;
char *flat_server_name;
char *fallback_group;
uint32_t fallback_rid;
+
+ int num_trusts;
+ struct ipadb_adtrusts *trusts;
};
@@ -1311,6 +1320,99 @@ static char *get_server_netbios_name(void)
return strdup(hostname);
}
+void ipadb_mspac_struct_free(struct ipadb_mspac **mspac)
+{
+ int i;
+
+ if (!*mspac) return;
+
+ free((*mspac)->flat_domain_name);
+ free((*mspac)->fallback_group);
+
+ if ((*mspac)->num_trusts) {
+ for (i = 0; i < (*mspac)->num_trusts; i++) {
+ free((*mspac)->trusts[i].domain_name);
+ free((*mspac)->trusts[i].flat_name);
+ free((*mspac)->trusts[i].domain_sid);
+ }
+ }
+
+ *mspac = NULL;
+}
+
+krb5_error_code ipadb_mspac_get_trusted_domains(struct ipadb_context *ipactx)
+{
+ struct ipadb_adtrusts *t;
+ LDAP *lc = ipactx->lcontext;
+ char *attrs[] = { "ipaNTTrustPartner", "ipaNTFlatName",
+ "ipaNTTrustedDomainSID", NULL };
+ char *filter = "(objectclass=ipaNTTrustedDomain)";
+ krb5_error_code kerr;
+ LDAPMessage *res = NULL;
+ LDAPMessage *le;
+ char *base = NULL;
+ int ret, n;
+
+ ret = asprintf(&base, "cn=ad,cn=trusts,%s", ipactx->base);
+ if (ret == -1) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ kerr = ipadb_simple_search(ipactx, base, LDAP_SCOPE_SUBTREE,
+ filter, attrs, &res);
+ if (kerr == KRB5_KDB_NOENTRY) {
+ /* nothing to do, there are no trusts */
+ ret = 0;
+ goto done;
+ } else if (kerr != 0) {
+ ret = EIO;
+ goto done;
+ }
+
+ for (le = ldap_first_entry(lc, res); le; le = ldap_next_entry(lc, le)) {
+ n = ipactx->mspac->num_trusts;
+ ipactx->mspac->num_trusts++;
+ t = realloc(ipactx->mspac->trusts,
+ sizeof(struct ipadb_adtrusts) * ipactx->mspac->num_trusts);
+ if (!t) {
+ ret = ENOMEM;
+ goto done;
+ }
+ ipactx->mspac->trusts = t;
+
+ ret = ipadb_ldap_attr_to_str(lc, le, "ipaNTTrustPartner",
+ &t[n].domain_name);
+ if (ret) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ ret = ipadb_ldap_attr_to_str(lc, le, "ipaNTFlatName",
+ &t[n].flat_name);
+ if (ret) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ ret = ipadb_ldap_attr_to_str(lc, le, "ipaNTTrustedDomainSID",
+ &t[n].domain_sid);
+ if (ret) {
+ ret = EINVAL;
+ goto done;
+ }
+ }
+
+ ret = 0;
+
+done:
+ if (ret != 0) {
+ krb5_klog_syslog(LOG_ERR, "Failed to read list of trusted domains");
+ }
+ free(base);
+ return ret;
+}
+
krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx)
{
char *dom_attrs[] = { "ipaNTFlatName",
@@ -1325,11 +1427,7 @@ krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx)
int ret;
/* clean up in case we had old values around */
- if (ipactx->mspac) {
- free(ipactx->mspac->flat_domain_name);
- free(ipactx->mspac->fallback_group);
- free(ipactx->mspac);
- }
+ ipadb_mspac_struct_free(&ipactx->mspac);
ipactx->mspac = calloc(1, sizeof(struct ipadb_mspac));
if (!ipactx->mspac) {
@@ -1419,7 +1517,7 @@ krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx)
}
}
- kerr = 0;
+ kerr = ipadb_mspac_get_trusted_domains(ipactx);
done:
ldap_msgfree(result);
--
1.7.11.2

View File

@ -0,0 +1,190 @@
From 1bb9eb7da33be66bd06864f505ec730262ff90ce Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce@redhat.com>
Date: Fri, 13 Jul 2012 12:02:06 -0400
Subject: [PATCH 72/79] Properly name function to add ipa external groups
The function filter_pac was not filtering the pac at all, it was merely
augmenting it with additional data relevant to the IPA server.
Change the name of the function to avoid confusion.
While there I also simplified and cleaed up the code a bit with regard to
variable names and usage.
---
daemons/ipa-kdb/ipa_kdb_mspac.c | 74 ++++++++++++++++++++++-------------------
1 file changed, 39 insertions(+), 35 deletions(-)
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
index 2ed093d30a0fea20ef620b8df9858ec4802d1191..7e6e71d5b316022cc53438a67dfd3ec4595f0245 100644
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
@@ -900,8 +900,8 @@ done:
return kerr;
}
-static krb5_error_code filter_pac(krb5_context context, krb5_data *old_data,
- krb5_data *new_data)
+static krb5_error_code add_local_groups(krb5_context context,
+ krb5_data *pac_blob)
{
DATA_BLOB pac_data;
union PAC_INFO pac_info;
@@ -918,8 +918,8 @@ static krb5_error_code filter_pac(krb5_context context, krb5_data *old_data,
return ENOMEM;
}
- pac_data.length = old_data->length;
- pac_data.data = (uint8_t *) old_data->data;
+ pac_data.length = pac_blob->length;
+ pac_data.data = (uint8_t *)pac_blob->data;
ndr_err = ndr_pull_union_blob(&pac_data, tmpctx, &pac_info,
PAC_TYPE_LOGON_INFO,
@@ -962,14 +962,15 @@ static krb5_error_code filter_pac(krb5_context context, krb5_data *old_data,
goto done;
}
- new_data->magic = KV5M_DATA;
- new_data->data = malloc(pac_data.length);
- if (new_data->data == NULL) {
+ free(pac_blob->data);
+ pac_blob->data = malloc(pac_data.length);
+ if (pac_blob->data == NULL) {
+ pac_blob->length = 0;
kerr = ENOMEM;
goto done;
}
- memcpy(new_data->data, pac_data.data, pac_data.length);
- new_data->length = pac_data.length;
+ memcpy(pac_blob->data, pac_data.data, pac_data.length);
+ pac_blob->length = pac_data.length;
kerr = 0;
@@ -993,12 +994,13 @@ static krb5_error_code ipadb_verify_pac(krb5_context context,
krb5_keyblock *srv_key = NULL;
krb5_keyblock *priv_key = NULL;
krb5_error_code kerr;
- krb5_ui_4 *buffer_types = NULL;
+ krb5_ui_4 *types = NULL;
size_t num_buffers;
krb5_pac old_pac = NULL;
krb5_pac new_pac = NULL;
krb5_data data;
- krb5_data filtered_data;
+ krb5_data pac_blob = { 0 , 0, NULL};
+ bool is_cross_realm = false;
size_t i;
kerr = krb5_pac_parse(context,
@@ -1009,7 +1011,6 @@ static krb5_error_code ipadb_verify_pac(krb5_context context,
goto done;
}
- memset(&filtered_data, 0, sizeof(filtered_data));
/* for cross realm trusts cases we need to check the right checksum.
* when the PAC is signed by our realm, we can always just check it
* passing our realm krbtgt key as the kdc checksum key (privsvr).
@@ -1018,6 +1019,7 @@ static krb5_error_code ipadb_verify_pac(krb5_context context,
* realm krbtgt to check the 'server' checksum instead. */
if (is_cross_realm_krbtgt(krbtgt->princ)) {
/* krbtgt from a trusted realm */
+ is_cross_realm = true;
/* FIXME:
* We must refuse a PAC that comes signed with a cross realm TGT
@@ -1028,15 +1030,6 @@ static krb5_error_code ipadb_verify_pac(krb5_context context,
/* TODO: Here is where we need to plug our PAC Filtering, later on */
srv_key = krbtgt_key;
- kerr = krb5_pac_get_buffer(context, old_pac, KRB5_PAC_LOGON_INFO, &data);
- if (kerr != 0) {
- goto done;
- }
-
- kerr = filter_pac(context, &data, &filtered_data);
- if (kerr != 0) {
- goto done;
- }
} else {
/* krbtgt from our own realm */
priv_key = krbtgt_key;
@@ -1048,6 +1041,20 @@ static krb5_error_code ipadb_verify_pac(krb5_context context,
goto done;
}
+ /* Now that the PAc is verified augment it with additional info if
+ * it is coming from a different realm */
+ if (is_cross_realm) {
+ kerr = krb5_pac_get_buffer(context, old_pac,
+ KRB5_PAC_LOGON_INFO, &pac_blob);
+ if (kerr != 0) {
+ goto done;
+ }
+
+ kerr = add_local_groups(context, &pac_blob);
+ if (kerr != 0) {
+ goto done;
+ }
+ }
/* extract buffers and rebuilt pac from scratch so that when re-signing
* with a different cksum type does not cause issues due to mismatching
* signature buffer lengths */
@@ -1056,22 +1063,20 @@ static krb5_error_code ipadb_verify_pac(krb5_context context,
goto done;
}
- kerr = krb5_pac_get_types(context, old_pac, &num_buffers, &buffer_types);
+ kerr = krb5_pac_get_types(context, old_pac, &num_buffers, &types);
if (kerr) {
goto done;
}
for (i = 0; i < num_buffers; i++) {
- if (buffer_types[i] == KRB5_PAC_SERVER_CHECKSUM ||
- buffer_types[i] == KRB5_PAC_PRIVSVR_CHECKSUM) {
+ if (types[i] == KRB5_PAC_SERVER_CHECKSUM ||
+ types[i] == KRB5_PAC_PRIVSVR_CHECKSUM) {
continue;
}
- if (buffer_types[i] == KRB5_PAC_LOGON_INFO &&
- filtered_data.length != 0) {
- kerr = krb5_pac_add_buffer(context, new_pac,
- buffer_types[i], &filtered_data);
- krb5_free_data_contents(context, &filtered_data);
+ if (types[i] == KRB5_PAC_LOGON_INFO &&
+ pac_blob.length != 0) {
+ kerr = krb5_pac_add_buffer(context, new_pac, types[i], &pac_blob);
if (kerr) {
krb5_pac_free(context, new_pac);
goto done;
@@ -1080,13 +1085,11 @@ static krb5_error_code ipadb_verify_pac(krb5_context context,
continue;
}
- kerr = krb5_pac_get_buffer(context, old_pac,
- buffer_types[i], &data);
+ kerr = krb5_pac_get_buffer(context, old_pac, types[i], &data);
if (kerr == 0) {
- kerr = krb5_pac_add_buffer(context, new_pac,
- buffer_types[i], &data);
+ kerr = krb5_pac_add_buffer(context, new_pac, types[i], &data);
+ krb5_free_data_contents(context, &data);
}
- krb5_free_data_contents(context, &data);
if (kerr) {
krb5_pac_free(context, new_pac);
goto done;
@@ -1098,7 +1101,8 @@ static krb5_error_code ipadb_verify_pac(krb5_context context,
done:
krb5_free_authdata(context, authdata);
krb5_pac_free(context, old_pac);
- free(buffer_types);
+ krb5_free_data_contents(context, &pac_blob);
+ free(types);
return kerr;
}
--
1.7.11.2

View File

@ -0,0 +1,183 @@
From 754d0bea06206cbedf0bc238efc501d14e51acfd Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce@redhat.com>
Date: Fri, 13 Jul 2012 12:42:11 -0400
Subject: [PATCH 73/79] Split out manipulation of logon_info blob
This way multiple functions can manipulate the logon info structure until all
operations we want to do on it are done and then fold it back once.
---
daemons/ipa-kdb/ipa_kdb_mspac.c | 117 +++++++++++++++++++++++++---------------
1 file changed, 73 insertions(+), 44 deletions(-)
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
index 7e6e71d5b316022cc53438a67dfd3ec4595f0245..2a48c4f8ca7cee30d01380fbc12dddb928472963 100644
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
@@ -900,83 +900,112 @@ done:
return kerr;
}
+static krb5_error_code get_logon_info(krb5_context context,
+ TALLOC_CTX *memctx,
+ krb5_data *pac_blob,
+ struct PAC_LOGON_INFO_CTR *info)
+{
+ DATA_BLOB pac_data;
+ enum ndr_err_code ndr_err;
+
+ pac_data.length = pac_blob->length;
+ pac_data.data = (uint8_t *)pac_blob->data;
+
+ ndr_err = ndr_pull_union_blob(&pac_data, memctx, info,
+ PAC_TYPE_LOGON_INFO,
+ (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return KRB5_KDB_INTERNAL_ERROR;
+ }
+
+ return 0;
+}
+
static krb5_error_code add_local_groups(krb5_context context,
- krb5_data *pac_blob)
+ TALLOC_CTX *memctx,
+ struct PAC_LOGON_INFO_CTR *info)
{
- DATA_BLOB pac_data;
- union PAC_INFO pac_info;
- krb5_error_code kerr;
- enum ndr_err_code ndr_err;
- TALLOC_CTX *tmpctx;
int ret;
char **group_sids = NULL;
size_t ipa_group_sids_count = 0;
struct dom_sid *ipa_group_sids = NULL;
- tmpctx = talloc_new(NULL);
- if (!tmpctx) {
- return ENOMEM;
- }
-
- pac_data.length = pac_blob->length;
- pac_data.data = (uint8_t *)pac_blob->data;
-
- ndr_err = ndr_pull_union_blob(&pac_data, tmpctx, &pac_info,
- PAC_TYPE_LOGON_INFO,
- (ndr_pull_flags_fn_t) ndr_pull_PAC_INFO);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- krb5_klog_syslog(LOG_ERR, "ndr_pull_union_blob failed");
- kerr = KRB5_KDB_INTERNAL_ERROR;
- goto done;
- }
-
- ret = get_group_sids(tmpctx, &pac_info.logon_info, &group_sids);
+ ret = get_group_sids(memctx, info, &group_sids);
if (ret != 0) {
- krb5_klog_syslog(LOG_ERR, "get_group_sids failed");
- kerr = KRB5_KDB_INTERNAL_ERROR;
- goto done;
+ return KRB5_KDB_INTERNAL_ERROR;
}
- ret = map_groups(tmpctx, context, group_sids, &ipa_group_sids_count,
+ ret = map_groups(memctx, context, group_sids, &ipa_group_sids_count,
&ipa_group_sids);
if (ret != 0) {
- krb5_klog_syslog(LOG_ERR, "map_groups failed");
- kerr = KRB5_KDB_INTERNAL_ERROR;
- goto done;
+ return KRB5_KDB_INTERNAL_ERROR;
}
- ret = add_groups(tmpctx, &pac_info.logon_info, ipa_group_sids_count,
- ipa_group_sids);
+ ret = add_groups(memctx, info, ipa_group_sids_count, ipa_group_sids);
if (ret != 0) {
krb5_klog_syslog(LOG_ERR, "add_groups failed");
- kerr = KRB5_KDB_INTERNAL_ERROR;
- goto done;
+ return KRB5_KDB_INTERNAL_ERROR;
}
- ndr_err = ndr_push_union_blob(&pac_data, tmpctx, &pac_info,
+ return 0;
+}
+
+static krb5_error_code save_logon_info(krb5_context context,
+ TALLOC_CTX *memctx,
+ struct PAC_LOGON_INFO_CTR *info,
+ krb5_data *pac_blob)
+{
+ DATA_BLOB pac_data;
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_push_union_blob(&pac_data, memctx, info,
PAC_TYPE_LOGON_INFO,
(ndr_push_flags_fn_t)ndr_push_PAC_INFO);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- krb5_klog_syslog(LOG_ERR, "ndr_push_union_blob failed");
- kerr = KRB5_KDB_INTERNAL_ERROR;
- goto done;
+ return KRB5_KDB_INTERNAL_ERROR;
}
free(pac_blob->data);
pac_blob->data = malloc(pac_data.length);
if (pac_blob->data == NULL) {
pac_blob->length = 0;
- kerr = ENOMEM;
- goto done;
+ return ENOMEM;
}
memcpy(pac_blob->data, pac_data.data, pac_data.length);
pac_blob->length = pac_data.length;
- kerr = 0;
+ return 0;
+}
+
+static krb5_error_code ipadb_check_logon_info(krb5_context context,
+ krb5_data *pac_blob)
+{
+ struct PAC_LOGON_INFO_CTR info;
+ krb5_error_code kerr;
+ TALLOC_CTX *tmpctx;
+
+ tmpctx = talloc_new(NULL);
+ if (!tmpctx) {
+ return ENOMEM;
+ }
+
+ kerr = get_logon_info(context, tmpctx, pac_blob, &info);
+ if (kerr) {
+ goto done;
+ }
+
+ kerr = add_local_groups(context, tmpctx, &info);
+ if (kerr) {
+ goto done;
+ }
+
+ kerr = save_logon_info(context, tmpctx, &info, pac_blob);
+ if (kerr) {
+ goto done;
+ }
done:
talloc_free(tmpctx);
-
return kerr;
}
@@ -1050,7 +1079,7 @@ static krb5_error_code ipadb_verify_pac(krb5_context context,
goto done;
}
- kerr = add_local_groups(context, &pac_blob);
+ kerr = ipadb_check_logon_info(context, &pac_blob);
if (kerr != 0) {
goto done;
}
--
1.7.11.2

View File

@ -0,0 +1,158 @@
From c58836f29dbff9bda9ecb307329fc11942b9d0e0 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce@redhat.com>
Date: Fri, 13 Jul 2012 12:19:03 -0400
Subject: [PATCH 74/79] Add PAC filtering
This check the PAC we receive is consistent.
realm, flat name and domain sid must much our understanding or the trustd
realm and no additional sids beyond the own realm ones must be present.
Ticket #2849
---
daemons/ipa-kdb/ipa_kdb_mspac.c | 108 +++++++++++++++++++++++++++++++++++++---
1 file changed, 100 insertions(+), 8 deletions(-)
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
index 2a48c4f8ca7cee30d01380fbc12dddb928472963..b5346fed1230d02a88c94ab913507112990a1651 100644
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
@@ -977,7 +977,101 @@ static krb5_error_code save_logon_info(krb5_context context,
return 0;
}
+static struct ipadb_adtrusts *get_domain_from_realm(krb5_context context,
+ krb5_data realm)
+{
+ struct ipadb_context *ipactx;
+ struct ipadb_adtrusts *domain;
+ int i;
+
+ ipactx = ipadb_get_context(context);
+ if (!ipactx) {
+ return NULL;
+ }
+
+ if (ipactx->mspac == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < ipactx->mspac->num_trusts; i++) {
+ domain = &ipactx->mspac->trusts[i];
+ if (strlen(domain->domain_name) != realm.length) {
+ continue;
+ }
+ if (strncasecmp(domain->domain_name, realm.data, realm.length) == 0) {
+ return domain;
+ }
+ }
+
+ return NULL;
+}
+
+static krb5_error_code filter_logon_info(krb5_context context,
+ TALLOC_CTX *memctx,
+ krb5_data realm,
+ struct PAC_LOGON_INFO_CTR *info)
+{
+
+ /* We must refuse a PAC that comes signed with a cross realm TGT
+ * where the client pretends to be from a different realm. It is an
+ * attempt at getting us to sign fake credentials with the help of a
+ * compromised trusted realm */
+
+ struct ipadb_adtrusts *domain;
+ char *domsid;
+
+ domain = get_domain_from_realm(context, realm);
+ if (!domain) {
+ return EINVAL;
+ }
+
+ /* check netbios/flat name */
+ if (strcasecmp(info->info->info3.base.logon_domain.string,
+ domain->flat_name) != 0) {
+ krb5_klog_syslog(LOG_ERR, "PAC Info mismatch: domain = %s, "
+ "expected flat name = %s, "
+ "found logon name = %s",
+ domain->domain_name, domain->flat_name,
+ info->info->info3.base.logon_domain.string);
+ return EINVAL;
+ }
+
+ /* check sid */
+ domsid = dom_sid_string(NULL, info->info->info3.base.domain_sid);
+ if (!domsid) {
+ return EINVAL;
+ }
+
+ if (strcmp(domsid, domain->domain_sid) != 0) {
+ krb5_klog_syslog(LOG_ERR, "PAC Info mismatch: domain = %s, "
+ "expected domain SID = %s, "
+ "found domain SID = %s",
+ domain->domain_name, domain->domain_sid,
+ domsid);
+ talloc_free(domsid);
+ return EINVAL;
+ }
+ talloc_free(domsid);
+
+ /* According to MS-KILE, info->info->info3.sids must be zero, so check
+ * that it is the case here */
+ if (info->info->info3.sidcount != 0) {
+ return EINVAL;
+ }
+
+ /* According to MS-KILE, ResourceGroups must be zero, so check
+ * that it is the case here */
+ if (info->info->res_group_dom_sid != NULL &&
+ info->info->res_groups.count != 0) {
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+
static krb5_error_code ipadb_check_logon_info(krb5_context context,
+ krb5_data origin_realm,
krb5_data *pac_blob)
{
struct PAC_LOGON_INFO_CTR info;
@@ -994,6 +1088,11 @@ static krb5_error_code ipadb_check_logon_info(krb5_context context,
goto done;
}
+ kerr = filter_logon_info(context, tmpctx, origin_realm, &info);
+ if (kerr) {
+ goto done;
+ }
+
kerr = add_local_groups(context, tmpctx, &info);
if (kerr) {
goto done;
@@ -1050,13 +1149,6 @@ static krb5_error_code ipadb_verify_pac(krb5_context context,
/* krbtgt from a trusted realm */
is_cross_realm = true;
- /* FIXME:
- * We must refuse a PAC that comes signed with a cross realm TGT
- * where the client pretends to be from our realm. It is an attempt
- * at getting us to sign fake credentials with the help of a
- * compromised trusted realm */
-
- /* TODO: Here is where we need to plug our PAC Filtering, later on */
srv_key = krbtgt_key;
} else {
@@ -1079,7 +1171,7 @@ static krb5_error_code ipadb_verify_pac(krb5_context context,
goto done;
}
- kerr = ipadb_check_logon_info(context, &pac_blob);
+ kerr = ipadb_check_logon_info(context, client_princ->realm, &pac_blob);
if (kerr != 0) {
goto done;
}
--
1.7.11.2

View File

@ -0,0 +1,166 @@
From 9bfa905e722767de1c075e281012a152e7abc190 Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jcholast@redhat.com>
Date: Fri, 3 Aug 2012 03:04:58 -0400
Subject: [PATCH 75/79] Add --{set,add,del}attr options to commands which are
missing them.
ticket 2963
---
API.txt | 22 +++++++++++++++++-----
VERSION | 2 +-
ipalib/plugins/automember.py | 4 ++--
ipalib/plugins/host.py | 2 +-
ipalib/plugins/service.py | 2 +-
ipalib/plugins/trust.py | 2 +-
6 files changed, 23 insertions(+), 11 deletions(-)
diff --git a/API.txt b/API.txt
index e71b79a799837cde2c1e4a5a83c20c8e23fd650f..6f14fccc3762503a66034794ad2fd9370748318d 100644
--- a/API.txt
+++ b/API.txt
@@ -101,9 +101,11 @@ output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
output: Output('value', <type 'unicode'>, None)
command: automember_add
-args: 1,5,3
+args: 1,7,3
arg: Str('cn', cli_name='automember_rule')
option: Str('description', attribute=True, cli_name='desc', multivalue=False, required=False)
+option: Str('setattr*', cli_name='setattr', exclude='webui')
+option: Str('addattr*', cli_name='addattr', exclude='webui')
option: StrEnum('type', values=(u'group', u'hostgroup'))
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
@@ -177,9 +179,13 @@ output: ListOfEntries('result', (<type 'list'>, <type 'tuple'>), Gettext('A list
output: Output('count', <type 'int'>, None)
output: Output('truncated', <type 'bool'>, None)
command: automember_mod
-args: 1,5,3
+args: 1,9,3
arg: Str('cn', cli_name='automember_rule')
option: Str('description', attribute=True, autofill=False, cli_name='desc', multivalue=False, required=False)
+option: Str('setattr*', cli_name='setattr', exclude='webui')
+option: Str('addattr*', cli_name='addattr', exclude='webui')
+option: Str('delattr*', cli_name='delattr', exclude='webui')
+option: Flag('rights', autofill=True, default=False)
option: StrEnum('type', values=(u'group', u'hostgroup'))
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
@@ -1652,7 +1658,7 @@ output: Output('notmatched', (<type 'list'>, <type 'tuple'>, <type 'NoneType'>),
output: Output('error', (<type 'list'>, <type 'tuple'>, <type 'NoneType'>), None)
output: Output('value', <type 'bool'>, None)
command: host_add
-args: 1,16,3
+args: 1,18,3
arg: Str('fqdn', attribute=True, cli_name='hostname', multivalue=False, primary_key=True, required=True)
option: Str('description', attribute=True, cli_name='desc', multivalue=False, required=False)
option: Str('l', attribute=True, cli_name='locality', multivalue=False, required=False)
@@ -1664,6 +1670,8 @@ option: Flag('random', attribute=False, autofill=True, cli_name='random', defaul
option: Bytes('usercertificate', attribute=True, cli_name='certificate', multivalue=False, required=False)
option: Str('macaddress', attribute=True, cli_name='macaddress', csv=True, multivalue=True, pattern='^([a-fA-F0-9]{2}[:|\\-]?){5}[a-fA-F0-9]{2}$', required=False)
option: Bytes('ipasshpubkey', attribute=True, cli_name='sshpubkey', multivalue=True, required=False)
+option: Str('setattr*', cli_name='setattr', exclude='webui')
+option: Str('addattr*', cli_name='addattr', exclude='webui')
option: Flag('force', autofill=True, default=False)
option: Flag('no_reverse', autofill=True, default=False)
option: Str('ip_address?')
@@ -2727,10 +2735,12 @@ output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
output: Output('value', <type 'unicode'>, None)
command: service_add
-args: 1,6,3
+args: 1,8,3
arg: Str('krbprincipalname', attribute=True, cli_name='principal', multivalue=False, primary_key=True, required=True)
option: Bytes('usercertificate', attribute=True, cli_name='certificate', multivalue=False, required=False)
option: StrEnum('ipakrbauthzdata', attribute=True, cli_name='pac_type', csv=True, multivalue=True, required=False, values=(u'MS-PAC', u'PAD'))
+option: Str('setattr*', cli_name='setattr', exclude='webui')
+option: Str('addattr*', cli_name='addattr', exclude='webui')
option: Flag('force', autofill=True, default=False)
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
@@ -3190,8 +3200,10 @@ output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
output: Output('value', <type 'unicode'>, None)
command: trust_add
-args: 1,8,3
+args: 1,10,3
arg: Str('cn', attribute=True, cli_name='realm', multivalue=False, primary_key=True, required=True)
+option: Str('setattr*', cli_name='setattr', exclude='webui')
+option: Str('addattr*', cli_name='addattr', exclude='webui')
option: StrEnum('trust_type', autofill=True, cli_name='type', default=u'ad', values=(u'ad',))
option: Str('realm_admin?', cli_name='admin')
option: Password('realm_passwd?', cli_name='password', confirm=False)
diff --git a/VERSION b/VERSION
index 8d9efe6573bd148f2e74961c6ce7247f9bc3393d..11ecb6dec2d1f306ea5dc43e247f20f9683fa41a 100644
--- a/VERSION
+++ b/VERSION
@@ -79,4 +79,4 @@ IPA_DATA_VERSION=20100614120000
# #
########################################################
IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=40
+IPA_API_VERSION_MINOR=41
diff --git a/ipalib/plugins/automember.py b/ipalib/plugins/automember.py
index bf4cb355ced9760399bf05ceb3ef5d045570c0de..7ccb0bb2f91a3380edb1af73c83906a0ba96c92d 100644
--- a/ipalib/plugins/automember.py
+++ b/ipalib/plugins/automember.py
@@ -233,7 +233,7 @@ class automember_add(LDAPCreate):
__doc__ = _("""
Add an automember rule.
""")
- takes_options = group_type
+ takes_options = LDAPCreate.takes_options + group_type
takes_args = automember_rule
msg_summary = _('Added automember rule "%(value)s"')
@@ -440,7 +440,7 @@ class automember_mod(LDAPUpdate):
Modify an automember rule.
""")
takes_args = automember_rule
- takes_options = group_type
+ takes_options = LDAPUpdate.takes_options + group_type
msg_summary = _('Modified automember rule "%(value)s"')
def execute(self, *keys, **options):
diff --git a/ipalib/plugins/host.py b/ipalib/plugins/host.py
index 9680d7c024ea8976f92a71bf576d6712c44a2bcf..e8967b8c0df4c348be01ec6c9e94571d5674ca3f 100644
--- a/ipalib/plugins/host.py
+++ b/ipalib/plugins/host.py
@@ -364,7 +364,7 @@ class host_add(LDAPCreate):
has_output_params = LDAPCreate.has_output_params + host_output_params
msg_summary = _('Added host "%(value)s"')
member_attributes = ['managedby']
- takes_options = (
+ takes_options = LDAPCreate.takes_options + (
Flag('force',
label=_('Force'),
doc=_('force host name even if not in DNS'),
diff --git a/ipalib/plugins/service.py b/ipalib/plugins/service.py
index 4f3051aa4d5ba6dfc1768190f3662180353a5006..7cb7b80306e4ac748555096928e6d616a808802a 100644
--- a/ipalib/plugins/service.py
+++ b/ipalib/plugins/service.py
@@ -271,7 +271,7 @@ class service_add(LDAPCreate):
msg_summary = _('Added service "%(value)s"')
member_attributes = ['managedby']
has_output_params = LDAPCreate.has_output_params + output_params
- takes_options = (
+ takes_options = LDAPCreate.takes_options + (
Flag('force',
label=_('Force'),
doc=_('force principal name even if not in DNS'),
diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py
index 792e6cac2a2f9ebb61f84cc74d01be325995863e..acb65b388eea123b89394cd75bb3dd051b412f74 100644
--- a/ipalib/plugins/trust.py
+++ b/ipalib/plugins/trust.py
@@ -115,7 +115,7 @@ def make_trust_dn(env, trust_type, dn):
class trust_add(LDAPCreate):
__doc__ = _('Add new trust to use')
- takes_options = (
+ takes_options = LDAPCreate.takes_options + (
StrEnum('trust_type',
cli_name='type',
label=_('Trust type (ad for Active Directory, default)'),
--
1.7.11.2

View File

@ -0,0 +1,172 @@
From 1be46b322f1fe469cf3cc5e5a77a96b29f8beb7f Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Wed, 1 Aug 2012 10:14:09 +0300
Subject: [PATCH 76/79] Handle exceptions when establishing trusts
Translate exceptions produced by DCERPC bindings when establishing trusts.
There are two types of errors that may be produced by DCERPC bindings:
- RuntimeError with a text (RuntimeError('NT_STATUS_OBJECT_NAME_NOT_FOUND')
- RuntimeError with a numeric code and 'friendly' message
Error codes could have two prefixes:
- NT error codes, start with NT_STATUS_ prefix
- Windows error codes, start with WERR_ prefix
Full list of errors is available in Samba source code:
libcli/util/ntstatus.h: NT_STATUS error codes
libcli/util/werror.h: Windows error codes
Majority of errors returned when dealing with trusts are of NT_STATUS type,
these also include all typical POSIX errors mapped to corresponding NT errors.
Unfortunately, in the textual RuntimeError case very little can be done to
get better clarification of the error. More error paths will need to be added
as they will be discovered -- DCERPC error messaging is complex.
https://fedorahosted.org/freeipa/ticket/2868
---
ipaserver/dcerpc.py | 75 ++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 60 insertions(+), 15 deletions(-)
diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
index 6b830f65b854b74fcf080b071212e7658f334adf..982e12b31a9525a35c5d921e6559471a7633e025 100644
--- a/ipaserver/dcerpc.py
+++ b/ipaserver/dcerpc.py
@@ -28,6 +28,7 @@ from ipalib.parameters import Enum
from ipalib import Command
from ipalib import errors
from ipapython import ipautil
+from ipapython.ipa_log_manager import *
from ipaserver.install import installutils
import os, string, struct, copy
@@ -49,6 +50,31 @@ The code in this module relies heavily on samba4-python package
and Samba4 python bindings.
""")
+access_denied_error = errors.ACIError(info='CIFS server denied your credentials')
+dcerpc_error_codes = {
+ -1073741823: errors.RemoteRetrieveError(reason='communication with CIFS server was unsuccessful'),
+ -1073741790: access_denied_error,
+ -1073741715: access_denied_error,
+ -1073741614: access_denied_error,
+ -1073741603: errors.ValidationError(name='AD domain controller', error='unsupported functional level'),
+}
+
+dcerpc_error_messages = {
+ "NT_STATUS_OBJECT_NAME_NOT_FOUND": errors.NotFound(reason='Cannot find specified domain or server name'),
+ "NT_STATUS_INVALID_PARAMETER_MIX": errors.RequirementError(name='At least the domain or IP address should be specified'),
+}
+
+def assess_dcerpc_exception(num=None,message=None):
+ """
+ Takes error returned by Samba bindings and converts it into
+ an IPA error class.
+ """
+ if num and num in dcerpc_error_codes:
+ return dcerpc_error_codes[num]
+ if message and message in dcerpc_error_messages:
+ return dcerpc_error_messages[message]
+ return errors.RemoteRetrieveError(reason='CIFS server communication error: code "%s", message "%s" (both may be "None")' % (num, message))
+
class ExtendedDNControl(_ldap.controls.RequestControl):
def __init__(self):
self.controlType = "1.2.840.113556.1.4.529"
@@ -151,8 +177,8 @@ class TrustDomainInstance(object):
try:
result = lsa.lsarpc(binding, self.parm, self.creds)
return result
- except:
- return None
+ except RuntimeError, (num, message):
+ raise assess_dcerpc_exception(num=num, message=message)
def __init_lsa_pipe(self, remote_host):
"""
@@ -168,13 +194,21 @@ class TrustDomainInstance(object):
if self._pipe:
return
+ attempts = 0
bindings = self.__gen_lsa_bindings(remote_host)
for binding in bindings:
- self._pipe = self.__gen_lsa_connection(binding)
- if self._pipe:
- break
+ try:
+ self._pipe = self.__gen_lsa_connection(binding)
+ if self._pipe:
+ break
+ except errors.ACIError, e:
+ attempts = attempts + 1
+
+ if self._pipe is None and attempts == len(bindings):
+ raise errors.ACIError(info='CIFS server %s denied your credentials' % (remote_host))
+
if self._pipe is None:
- raise errors.RequirementError(name='Working LSA pipe')
+ raise errors.RemoteRetrieveError(reason='Cannot establish LSA connection to %s. Is CIFS server running?' % (remote_host))
def __gen_lsa_bindings(self, remote_host):
"""
@@ -195,10 +229,14 @@ class TrustDomainInstance(object):
When retrieving DC information anonymously, we can't get SID of the domain
"""
netrc = net.Net(creds=self.creds, lp=self.parm)
- if discover_srv:
- result = netrc.finddc(domain=remote_host, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)
- else:
- result = netrc.finddc(address=remote_host, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)
+ try:
+ if discover_srv:
+ result = netrc.finddc(domain=remote_host, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)
+ else:
+ result = netrc.finddc(address=remote_host, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS)
+ except RuntimeError, e:
+ raise assess_dcerpc_exception(message=str(e))
+
if not result:
return False
self.info['name'] = unicode(result.domain_name)
@@ -217,7 +255,7 @@ class TrustDomainInstance(object):
result = res['defaultNamingContext'][0]
self.info['dns_hostname'] = res['dnsHostName'][0]
except _ldap.LDAPError, e:
- print "LDAP error when connecting to %s: %s" % (unicode(result.pdc_name), str(e))
+ root_logger.error("LDAP error when connecting to %s: %s" % (unicode(result.pdc_name), str(e)))
if result:
self.info['sid'] = self.parse_naming_context(result)
@@ -232,8 +270,12 @@ class TrustDomainInstance(object):
objectAttribute = lsa.ObjectAttribute()
objectAttribute.sec_qos = lsa.QosInfo()
- self._policy_handle = self._pipe.OpenPolicy2(u"", objectAttribute, security.SEC_FLAG_MAXIMUM_ALLOWED)
- result = self._pipe.QueryInfoPolicy2(self._policy_handle, lsa.LSA_POLICY_INFO_DNS)
+ try:
+ self._policy_handle = self._pipe.OpenPolicy2(u"", objectAttribute, security.SEC_FLAG_MAXIMUM_ALLOWED)
+ result = self._pipe.QueryInfoPolicy2(self._policy_handle, lsa.LSA_POLICY_INFO_DNS)
+ except RuntimeError, (num, message):
+ raise assess_dcerpc_exception(num=num, message=message)
+
self.info['name'] = unicode(result.name.string)
self.info['dns_domain'] = unicode(result.dns_domain.string)
self.info['dns_forest'] = unicode(result.dns_forest.string)
@@ -315,9 +357,12 @@ class TrustDomainInstance(object):
dname.string = another_domain.info['dns_domain']
res = self._pipe.QueryTrustedDomainInfoByName(self._policy_handle, dname, lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)
self._pipe.DeleteTrustedDomain(self._policy_handle, res.info_ex.sid)
- except:
+ except RuntimeError, e:
pass
- self._pipe.CreateTrustedDomainEx2(self._policy_handle, info, self.auth_info, security.SEC_STD_DELETE)
+ try:
+ self._pipe.CreateTrustedDomainEx2(self._policy_handle, info, self.auth_info, security.SEC_STD_DELETE)
+ except RuntimeError, (num, message):
+ raise assess_dcerpc_exception(num=num, message=message)
class TrustDomainJoins(object):
def __init__(self, api):
--
1.7.11.2

View File

@ -0,0 +1,76 @@
From c8abd24ebe612a3a0d415cece508b94a57c636fe Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori@redhat.com>
Date: Thu, 19 Jul 2012 09:07:23 -0400
Subject: [PATCH 77/79] Create /etc/sysconfig/network if it doesn't exist
When the --hostname option is given to ipa-client-install, we
write HOSTNAME to /etc/sysconfig/network. When that file didn't exist,
the installer crashed.
Create the file if it doesn't exist and we need to write to it.
https://fedorahosted.org/freeipa/ticket/2840
---
ipapython/ipautil.py | 4 +++-
ipapython/platform/redhat.py | 16 +++++++++++++---
2 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
index bed5435b5dfb3ff6e36d50b9eba422660fa25571..1b05977636f7bda6da02d0cea6e54aae9c35de4c 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -991,13 +991,15 @@ $)''', re.VERBOSE)
return old_values
-def backup_config_and_replace_variables(fstore, filepath, replacevars=dict(), appendvars=dict()):
+def backup_config_and_replace_variables(
+ fstore, filepath, replacevars=dict(), appendvars=dict()):
"""
Take a key=value based configuration file, back up it, and
write new version with certain values replaced or appended
All (key,value) pairs from replacevars and appendvars that
were not found in the configuration file, will be added there.
+ The file must exist before this function is called.
It is responsibility of a caller to ensure that replacevars and
appendvars do not overlap.
diff --git a/ipapython/platform/redhat.py b/ipapython/platform/redhat.py
index d3c23ab0debbcfa58eefa9607fe5cac8fcbf592b..3f35cfcc9607bd0c9a05659d936a9903ec198f1b 100644
--- a/ipapython/platform/redhat.py
+++ b/ipapython/platform/redhat.py
@@ -24,6 +24,8 @@ import os
import stat
import sys
import socket
+import stat
+
from ipapython import ipautil
from ipapython.platform import base
from ipalib import api
@@ -187,10 +189,18 @@ def backup_and_replace_hostname(fstore, statestore, hostname):
except ipautil.CalledProcessError, e:
print >>sys.stderr, "Failed to set this machine hostname to %s (%s)." % (hostname, str(e))
replacevars = {'HOSTNAME':hostname}
- old_values = ipautil.backup_config_and_replace_variables(fstore,
- "/etc/sysconfig/network",
- replacevars=replacevars)
+
+ filepath = '/etc/sysconfig/network'
+ if not os.path.exists(filepath):
+ # file doesn't exist; create it with correct ownership & mode
+ open(filepath, 'a').close()
+ os.chmod(filepath,
+ stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
+ os.chown(filepath, 0, 0)
+ old_values = ipautil.backup_config_and_replace_variables(
+ fstore, filepath, replacevars=replacevars)
restore_context("/etc/sysconfig/network")
+
if 'HOSTNAME' in old_values:
statestore.backup_state('network', 'hostname', old_values['HOSTNAME'])
else:
--
1.7.11.2

View File

@ -0,0 +1,285 @@
From 72cc54bc2798125a7e0ca3eb08fcc8b973b8844e Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jcholast@redhat.com>
Date: Tue, 31 Jul 2012 06:37:14 -0400
Subject: [PATCH 78/79] Make --{set,add,del}attr more robust.
This fixes --addattr on single value attributes in add commands and --delattr
on non-unicode attributes in mod commands.
ticket 2954
---
ipalib/plugins/baseldap.py | 89 +++++++++++++++++++++++-------------------
tests/test_xmlrpc/test_attr.py | 85 ++++++++++++++++++++++++++++++++++++++--
2 files changed, 131 insertions(+), 43 deletions(-)
diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py
index 6a37995c57cd9d57280186d15f209426aa0776f2..32dae5160a00c927855990211305706f332e77db 100644
--- a/ipalib/plugins/baseldap.py
+++ b/ipalib/plugins/baseldap.py
@@ -784,36 +784,45 @@ last, after all sets and adds."""),
:param attrs: A list of name/value pair strings, in the "name=value"
format. May also be a single string, or None.
"""
-
- newdict = {}
if attrs is None:
- attrs = []
- elif not type(attrs) in (list, tuple):
+ return {}
+
+ if not isinstance(attrs, (tuple, list)):
attrs = [attrs]
+
+ newdict = {}
for a in attrs:
- m = re.match("\s*(.*?)\s*=\s*(.*?)\s*$", a)
- attr = str(m.group(1)).lower()
- value = m.group(2)
+ m = re.match("^\s*(?P<attr>.*?)\s*=\s*(?P<value>.*?)\s*$", a)
+ attr = str(m.group('attr').lower())
+ value = m.group('value')
+
if attr in self.obj.params and attr not in self.params:
# The attribute is managed by IPA, but it didn't get cloned
# to the command. This happens with no_update/no_create attrs.
raise errors.ValidationError(
name=attr, error=_('attribute is not configurable'))
- if len(value) == 0:
- # None means "delete this attribute"
- value = None
- if attr in newdict:
- if type(value) in (tuple,):
- newdict[attr] += list(value)
- else:
- newdict[attr].append(value)
- else:
- if type(value) in (tuple,):
- newdict[attr] = list(value)
- else:
- newdict[attr] = [value]
+
+ newdict.setdefault(attr, []).append(value)
+
return newdict
+ def _convert_entry(self, entry_attrs):
+ result = {}
+ for attr, val in entry_attrs.iteritems():
+ if val is None:
+ val = []
+ elif not isinstance(val, (tuple, list)):
+ val = [val]
+
+ result[attr] = []
+ for v in val:
+ if isinstance(v, str):
+ # This is a Binary value, base64 encode it
+ v = base64.b64encode(v)
+ result[attr].append(unicode(v))
+
+ return result
+
def process_attr_options(self, entry_attrs, dn, keys, options):
"""
Process all --setattr, --addattr, and --delattr options and add the
@@ -860,19 +869,20 @@ last, after all sets and adds."""),
direct_del = setattrs & delattrs
needldapattrs = list((addattrs | delattrs) - setattrs)
+ mod_attrs = self._convert_entry(entry_attrs)
+
for attr, val in setdict.iteritems():
- entry_attrs[attr] = val
+ mod_attrs[attr] = val
for attr in direct_add:
- entry_attrs.setdefault(attr, []).extend(adddict[attr])
+ mod_attrs.setdefault(attr, []).extend(adddict[attr])
for attr in direct_del:
for delval in deldict[attr]:
try:
- entry_attrs[attr].remove(delval)
+ mod_attrs[attr].remove(delval)
except ValueError:
- raise errors.AttrValueNotFound(attr=attr,
- value=delval)
+ raise errors.AttrValueNotFound(attr=attr, value=delval)
if needldapattrs:
try:
@@ -891,28 +901,27 @@ last, after all sets and adds."""),
raise errors.ValidationError(name=del_nonexisting.pop(),
error=_('No such attribute on this entry'))
+ old_entry = self._convert_entry(old_entry)
+
for attr in needldapattrs:
- entry_attrs[attr] = old_entry.get(attr, [])
+ mod_attrs[attr] = old_entry.get(attr, [])
if attr in addattrs:
- entry_attrs[attr].extend(adddict.get(attr, []))
+ mod_attrs[attr].extend(adddict.get(attr, []))
for delval in deldict.get(attr, []):
try:
- entry_attrs[attr].remove(delval)
+ mod_attrs[attr].remove(delval)
except ValueError:
- if isinstance(delval, str):
- # This is a Binary value, base64 encode it
- delval = unicode(base64.b64encode(delval))
raise errors.AttrValueNotFound(attr=attr, value=delval)
# normalize all values
changedattrs = setattrs | addattrs | delattrs
for attr in changedattrs:
+ value = mod_attrs[attr]
if attr in self.params and self.params[attr].attribute:
- # convert single-value params to scalars
param = self.params[attr]
- value = entry_attrs[attr]
+ # convert single-value params to scalars
if not param.multivalue:
if len(value) == 1:
value = value[0]
@@ -922,19 +931,19 @@ last, after all sets and adds."""),
raise errors.OnlyOneValueAllowed(attr=attr)
# validate, convert and encode params
try:
- value = param(value)
+ value = param(value)
except errors.ValidationError, err:
raise errors.ValidationError(name=attr, error=err.error)
except errors.ConversionError, err:
raise errors.ConversionError(name=attr, error=err.error)
- entry_attrs[attr] = value
else:
# unknown attribute: remove duplicite and invalid values
- entry_attrs[attr] = list(set([val for val in entry_attrs[attr] if val]))
- if not entry_attrs[attr]:
- entry_attrs[attr] = None
- elif isinstance(entry_attrs[attr], (tuple, list)) and len(entry_attrs[attr]) == 1:
- entry_attrs[attr] = entry_attrs[attr][0]
+ value = list(set([val for val in value if val]))
+ if not value:
+ value = None
+ elif isinstance(value, (tuple, list)) and len(value) == 1:
+ value = value[0]
+ entry_attrs[attr] = value
@classmethod
def register_pre_callback(cls, callback, first=False):
diff --git a/tests/test_xmlrpc/test_attr.py b/tests/test_xmlrpc/test_attr.py
index 8b78c97b460421d36134e4a545cad8738e96f8ce..f5003c403b733abcfbd54f9f13f0b252cbf31959 100644
--- a/tests/test_xmlrpc/test_attr.py
+++ b/tests/test_xmlrpc/test_attr.py
@@ -21,17 +21,29 @@
Test --setattr and --addattr and other attribute-specific issues
"""
-from ipalib import api, errors
+from ipalib import api, errors, x509
from tests.test_xmlrpc import objectclasses
-from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid
+from xmlrpc_test import (Declarative, fuzzy_digits, fuzzy_uuid, fuzzy_date,
+ fuzzy_hex, fuzzy_hash, fuzzy_issuer)
from ipalib.dn import *
+import base64
-user1=u'tuser1'
+user1 = u'tuser1'
+fqdn1 = u'testhost1.%s' % api.env.domain
+
+# We can use the same cert we generated for the service tests
+fd = open('tests/test_xmlrpc/service.crt', 'r')
+servercert = fd.readlines()
+servercert = u''.join(servercert)
+servercert = x509.strip_header(servercert)
+servercert = servercert.replace('\n', '')
+fd.close()
class test_attr(Declarative):
cleanup_commands = [
('user_del', [user1], {}),
+ ('host_del', [fqdn1], {}),
]
tests = [
@@ -551,4 +563,71 @@ class test_attr(Declarative):
desc='Server is unwilling to perform', info=''),
),
+ dict(
+ desc='Try to create %r with description and --addattr description' % fqdn1,
+ command=('host_add', [fqdn1],
+ dict(
+ description=u'Test host 1',
+ addattr=u'description=Test host 2',
+ force=True,
+ ),
+ ),
+ expected=errors.OnlyOneValueAllowed(attr='description'),
+ ),
+
+ dict(
+ desc='Create %r with a certificate' % fqdn1,
+ command=('host_add', [fqdn1],
+ dict(
+ usercertificate=servercert,
+ force=True,
+ ),
+ ),
+ expected=dict(
+ value=fqdn1,
+ summary=u'Added host "%s"' % fqdn1,
+ result=dict(
+ dn=lambda x: DN(x) == DN(('fqdn',fqdn1),('cn','computers'),
+ ('cn','accounts'),api.env.basedn),
+ fqdn=[fqdn1],
+ krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)],
+ objectclass=objectclasses.host,
+ ipauniqueid=[fuzzy_uuid],
+ managedby_host=[fqdn1],
+ usercertificate=[base64.b64decode(servercert)],
+ valid_not_before=fuzzy_date,
+ valid_not_after=fuzzy_date,
+ subject=lambda x: DN(x) == \
+ DN(('CN',api.env.host),x509.subject_base()),
+ serial_number=fuzzy_digits,
+ serial_number_hex=fuzzy_hex,
+ md5_fingerprint=fuzzy_hash,
+ sha1_fingerprint=fuzzy_hash,
+ issuer=fuzzy_issuer,
+ has_keytab=False,
+ has_password=False,
+ ),
+ ),
+ ),
+
+ dict(
+ desc='Remove %r certificate using --delattr' % fqdn1,
+ command=('host_mod', [fqdn1],
+ dict(
+ delattr=u'usercertificate=%s' % servercert,
+ ),
+ ),
+ expected=dict(
+ value=fqdn1,
+ summary=u'Modified host "%s"' % fqdn1,
+ result=dict(
+ fqdn=[fqdn1],
+ krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)],
+ managedby_host=[fqdn1],
+ has_keytab=False,
+ has_password=False,
+ ),
+ ),
+ ),
+
]
--
1.7.11.2

View File

@ -0,0 +1,58 @@
From 36c4778bc66a6435b578268143a2eee766ab9f9c Mon Sep 17 00:00:00 2001
From: Tomas Babej <tbabej@redhat.com>
Date: Fri, 3 Aug 2012 09:29:31 -0400
Subject: [PATCH 79/79] Adds check for ipa-join.
If the executable ipa-client/ipa-join is not found, the relevant
tests are skipped. Implemented in setUpClass() method, also moved
the mkstemp() call there.
https://fedorahosted.org/freeipa/ticket/2905
---
tests/test_xmlrpc/test_host_plugin.py | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/tests/test_xmlrpc/test_host_plugin.py b/tests/test_xmlrpc/test_host_plugin.py
index 03aa089a2739486f6033a9d1870d7567bfdf1f5a..c9ec6a2bdda6eaebed72b1088e9e3cbb223d528b 100644
--- a/tests/test_xmlrpc/test_host_plugin.py
+++ b/tests/test_xmlrpc/test_host_plugin.py
@@ -28,6 +28,7 @@ from ipapython import ipautil
from ipalib import api, errors, x509
from ipalib.dn import *
from nose.tools import raises, assert_raises
+from nose.plugins.skip import Skip, SkipTest
from tests.test_xmlrpc.xmlrpc_test import (Declarative, XMLRPC_test,
fuzzy_uuid, fuzzy_digits, fuzzy_hash, fuzzy_date, fuzzy_issuer,
fuzzy_hex)
@@ -751,10 +752,17 @@ class test_host_false_pwd_change(XMLRPC_test):
fqdn1 = u'testhost1.%s' % api.env.domain
short1 = u'testhost1'
new_pass = u'pass_123'
-
command = "ipa-client/ipa-join"
- [keytabfd, keytabname] = tempfile.mkstemp()
- os.close(keytabfd)
+
+ @classmethod
+ def setUpClass(cls):
+ [cls.keytabfd,cls.keytabname] = tempfile.mkstemp()
+ os.close(cls.keytabfd)
+
+ does_command_exist = os.path.isfile(cls.command)
+
+ if not does_command_exist:
+ raise SkipTest("Command '%s' not found" % cls.command)
# auxiliary function for checking whether the join operation has set
# correct attributes
@@ -767,6 +775,7 @@ class test_host_false_pwd_change(XMLRPC_test):
"""
Create a test host and join him into IPA.
"""
+
# create a test host with bulk enrollment password
random_pass = api.Command['host_add'](self.fqdn1, random=True, force=True)['result']['randompassword']
--
1.7.11.2